Adds dial-out UI.
This commit is contained in:
parent
a1476c68f1
commit
2855ea1500
|
@ -1295,6 +1295,12 @@ export default {
|
||||||
APP.UI.onSharedVideoStop(id);
|
APP.UI.onSharedVideoStop(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
room.on(ConferenceEvents.USER_STATUS_CHANGED, (id, status) => {
|
||||||
|
let user = room.getParticipantById(id);
|
||||||
|
if (user) {
|
||||||
|
APP.UI.updateUserStatus(user, status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
room.on(ConferenceEvents.USER_ROLE_CHANGED, (id, role) => {
|
room.on(ConferenceEvents.USER_ROLE_CHANGED, (id, role) => {
|
||||||
if (this.isLocalId(id)) {
|
if (this.isLocalId(id)) {
|
||||||
|
@ -1651,13 +1657,6 @@ export default {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
APP.UI.addListener(UIEvents.SIP_DIAL, (sipNumber) => {
|
|
||||||
room.dial(sipNumber)
|
|
||||||
.catch((err) => {
|
|
||||||
logger.error("Error dialing out", err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
APP.UI.addListener(UIEvents.RESOLUTION_CHANGED,
|
APP.UI.addListener(UIEvents.RESOLUTION_CHANGED,
|
||||||
(id, oldResolution, newResolution, delay) => {
|
(id, oldResolution, newResolution, delay) => {
|
||||||
var logObject = {
|
var logObject = {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
/**
|
||||||
|
* The dialog content element.
|
||||||
|
*/
|
||||||
|
.dial-out-content {
|
||||||
|
margin-top: 5px;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The style of the flag icon.
|
||||||
|
*/
|
||||||
|
.dial-out-flag-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The style of the dial code element.
|
||||||
|
*/
|
||||||
|
.dial-out-code {
|
||||||
|
padding-left: 25px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dial-out dialog error element.
|
||||||
|
*/
|
||||||
|
.dial-out-error {
|
||||||
|
color: $errorColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The style of the dial input element.
|
||||||
|
*/
|
||||||
|
.dial-out-input {
|
||||||
|
padding-left: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-styling the default dropdown inside the dial-out-content.
|
||||||
|
*/
|
||||||
|
.dropdown {
|
||||||
|
left: $formPadding;
|
||||||
|
position: absolute !important;
|
||||||
|
width: 65px
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-styling the default form-control inside the dial-out-content.
|
||||||
|
*/
|
||||||
|
.form-control {
|
||||||
|
padding-bottom: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-trigger-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
.flag-icon-background {
|
||||||
|
background-size: contain;
|
||||||
|
background-position: 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
.flag-icon {
|
||||||
|
background-size: contain;
|
||||||
|
background-position: 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 1.33333333em;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
.flag-icon:before {
|
||||||
|
content: "\00a0";
|
||||||
|
}
|
||||||
|
.flag-icon-au {
|
||||||
|
background-image: url(../images/countries/au.svg);
|
||||||
|
}
|
||||||
|
.flag-icon-ca {
|
||||||
|
background-image: url(../images/countries/ca.svg);
|
||||||
|
}
|
||||||
|
.flag-icon-de {
|
||||||
|
background-image: url(../images/countries/de.svg);
|
||||||
|
}
|
||||||
|
.flag-icon-gb {
|
||||||
|
background-image: url(../images/countries/gb.svg);
|
||||||
|
}
|
||||||
|
.flag-icon-fr {
|
||||||
|
background-image: url(../images/countries/fr.svg);
|
||||||
|
}
|
||||||
|
.flag-icon-us {
|
||||||
|
background-image: url(../images/countries/us.svg);
|
||||||
|
}
|
|
@ -149,6 +149,7 @@ $inputControlEmColor: #f29424;
|
||||||
//buttons
|
//buttons
|
||||||
$linkFontColor: #489afe;
|
$linkFontColor: #489afe;
|
||||||
$linkHoverFontColor: #287ade;
|
$linkHoverFontColor: #287ade;
|
||||||
|
$formPadding: 16px;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsupported browser
|
* Unsupported browser
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.form-control {
|
.form-control {
|
||||||
padding: 16px 0;
|
padding: $formPadding 0;
|
||||||
|
|
||||||
&:first-child {
|
&:first-child {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
|
|
|
@ -26,11 +26,13 @@
|
||||||
|
|
||||||
@import 'font';
|
@import 'font';
|
||||||
@import 'font-awesome';
|
@import 'font-awesome';
|
||||||
|
|
||||||
/* Fonts END */
|
/* Fonts END */
|
||||||
|
|
||||||
|
@import 'flag-icon';
|
||||||
|
|
||||||
/* Modules BEGIN */
|
/* Modules BEGIN */
|
||||||
|
|
||||||
|
@import 'dial-out';
|
||||||
@import 'toastr';
|
@import 'toastr';
|
||||||
@import 'base';
|
@import 'base';
|
||||||
@import 'utils';
|
@import 'utils';
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||||
|
<g stroke-width="1pt">
|
||||||
|
<path fill="#006" d="M0 0h640v480H0z"/>
|
||||||
|
<path d="M0 0v27.95L307.037 250h38.647v-27.95L38.647 0H0zm345.684 0v27.95L38.647 250H0v-27.95L307.037 0h38.647z" fill="#fff"/>
|
||||||
|
<path d="M144.035 0v250h57.614V0h-57.615zM0 83.333v83.333h345.684V83.333H0z" fill="#fff"/>
|
||||||
|
<path d="M0 100v50h345.684v-50H0zM155.558 0v250h34.568V0h-34.568zM0 250l115.228-83.334h25.765L25.765 250H0zM0 0l115.228 83.333H89.463L0 18.633V0zm204.69 83.333L319.92 0h25.764L230.456 83.333H204.69zM345.685 250l-115.228-83.334h25.765l89.464 64.7V250z" fill="#c00"/>
|
||||||
|
<path d="M299.762 392.523l-43.653 3.795 6.013 43.406-30.187-31.764-30.186 31.764 6.014-43.406-43.653-3.795 37.68-22.364-24.244-36.495 40.97 15.514 13.42-41.713 13.42 41.712 40.97-15.515-24.242 36.494m224.444 62.372l-10.537-15.854 17.81 6.742 5.824-18.125 5.825 18.126 17.807-6.742-10.537 15.854 16.37 9.718-18.965 1.65 2.616 18.85-13.116-13.793-13.117 13.794 2.616-18.85-18.964-1.65m16.368-291.815l-10.537-15.856 17.81 6.742 5.824-18.122 5.825 18.12 17.807-6.74-10.537 15.855 16.37 9.717-18.965 1.65 2.616 18.85-13.116-13.793-13.117 13.794 2.616-18.85-18.964-1.65m-89.418 104.883l-10.537-15.853 17.808 6.742 5.825-18.125 5.825 18.125 17.808-6.742-10.536 15.853 16.37 9.72-18.965 1.65 2.615 18.85-13.117-13.795-13.117 13.795 2.617-18.85-18.964-1.65m216.212-37.929l-10.558-15.854 17.822 6.742 5.782-18.125 5.854 18.125 17.772-6.742-10.508 15.854 16.362 9.718-18.97 1.65 2.608 18.85-13.118-13.793-13.117 13.793 2.61-18.85-18.936-1.65m-22.251 73.394l-10.367 6.425 2.914-11.84-9.316-7.863 12.165-.896 4.605-11.29 4.606 11.29 12.165.897-9.317 7.863 2.912 11.84" fill-rule="evenodd" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||||
|
<g transform="translate(74.118) scale(.9375)">
|
||||||
|
<path fill="#fff" d="M81.137 0h362.276v512H81.137z"/>
|
||||||
|
<path fill="#bf0a30" d="M-100 0H81.138v512H-100zm543.413 0H624.55v512H443.414zM135.31 247.41l-14.067 4.808 65.456 57.446c4.95 14.764-1.72 19.116-5.97 26.86l71.06-9.02-1.85 71.512 14.718-.423-3.21-70.918 71.13 8.432c-4.402-9.297-8.32-14.233-4.247-29.098l65.414-54.426-11.447-4.144c-9.36-7.222 4.044-34.784 6.066-52.178 0 0-38.195 13.135-40.698 6.262l-9.727-18.685-34.747 38.17c-3.796.91-5.413-.6-6.304-3.808l16.053-79.766-25.42 14.297c-2.128.91-4.256.125-5.658-2.355l-24.45-49.06-25.21 50.95c-1.9 1.826-3.803 2.037-5.382.796l-24.204-13.578 14.53 79.143c-1.156 3.14-3.924 4.025-7.18 2.324l-33.216-37.737c-4.345 6.962-7.29 18.336-13.033 20.885-5.744 2.387-24.98-4.823-37.873-7.637 4.404 15.895 18.176 42.302 9.46 50.957z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 934 B |
|
@ -0,0 +1,5 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||||
|
<path fill="#ffce00" d="M0 320h640v160.002H0z"/>
|
||||||
|
<path d="M0 0h640v160H0z"/>
|
||||||
|
<path fill="#d00" d="M0 160h640v160H0z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 220 B |
|
@ -0,0 +1,7 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||||
|
<g fill-rule="evenodd" stroke-width="1pt">
|
||||||
|
<path fill="#fff" d="M0 0h640v480H0z"/>
|
||||||
|
<path fill="#00267f" d="M0 0h213.337v480H0z"/>
|
||||||
|
<path fill="#f31830" d="M426.662 0H640v480H426.662z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 301 B |
|
@ -0,0 +1,15 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||||
|
<defs>
|
||||||
|
<clipPath id="a">
|
||||||
|
<path fill-opacity=".67" d="M-85.333 0h682.67v512h-682.67z"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<g clip-path="url(#a)" transform="translate(80) scale(.94)">
|
||||||
|
<g stroke-width="1pt">
|
||||||
|
<path fill="#006" d="M-256 0H768.02v512.01H-256z"/>
|
||||||
|
<path d="M-256 0v57.244l909.535 454.768H768.02V454.77L-141.515 0H-256zM768.02 0v57.243L-141.515 512.01H-256v-57.243L653.535 0H768.02z" fill="#fff"/>
|
||||||
|
<path d="M170.675 0v512.01h170.67V0h-170.67zM-256 170.67v170.67H768.02V170.67H-256z" fill="#fff"/>
|
||||||
|
<path d="M-256 204.804v102.402H768.02V204.804H-256zM204.81 0v512.01h102.4V0h-102.4zM-256 512.01L85.34 341.34h76.324l-341.34 170.67H-256zM-256 0L85.34 170.67H9.016L-256 38.164V0zm606.356 170.67L691.696 0h76.324L426.68 170.67h-76.324zM768.02 512.01L426.68 341.34h76.324L768.02 473.848v38.162z" fill="#c00"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 956 B |
|
@ -0,0 +1,18 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
|
||||||
|
<g fill-rule="evenodd" transform="scale(.9375)">
|
||||||
|
<g stroke-width="1pt">
|
||||||
|
<path d="M0 0h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0z" fill="#bd3d44"/>
|
||||||
|
<path d="M0 39.385h972.81V78.77H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0zm0 78.77h972.81v39.385H0z" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
<path fill="#192f5d" d="M0 0h389.12v275.69H0z"/>
|
||||||
|
<g fill="#fff">
|
||||||
|
<path d="M32.427 11.8l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458zM64.855 39.37l3.54 10.896h11.458L70.583 57l3.542 10.897-9.27-6.734-9.269 6.734L59.126 57l-9.269-6.734h11.458zm64.852 0l3.54 10.896h11.457L135.435 57l3.54 10.897-9.268-6.734-9.27 6.734L123.978 57l-9.27-6.734h11.458zm64.855 0l3.54 10.896h11.458L200.29 57l3.541 10.897-9.27-6.734-9.268 6.734L188.833 57l-9.269-6.734h11.457zm64.855 0l3.54 10.896h11.458L265.145 57l3.541 10.897-9.269-6.734-9.27 6.734L253.69 57l-9.27-6.734h11.458zm64.852 0l3.54 10.896h11.457L329.997 57l3.54 10.897-9.268-6.734-9.27 6.734L318.54 57l-9.27-6.734h11.458zM32.427 66.939l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458zM64.855 94.508l3.54 10.897h11.458l-9.27 6.734 3.542 10.897-9.27-6.734-9.269 6.734 3.54-10.897-9.269-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.27-6.734-9.268 6.734 3.54-10.897-9.269-6.734h11.457zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.269-6.734-9.27 6.734 3.542-10.897-9.27-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458zM32.427 122.078l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458zM64.855 149.647l3.54 10.897h11.458l-9.27 6.734 3.542 10.897-9.27-6.734-9.269 6.734 3.54-10.897-9.269-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.27-6.734-9.268 6.734 3.54-10.897-9.269-6.734h11.457zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.269-6.734-9.27 6.734 3.542-10.897-9.27-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458z"/>
|
||||||
|
<g>
|
||||||
|
<path d="M32.427 177.217l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458zM64.855 204.786l3.54 10.897h11.458l-9.27 6.734 3.542 10.897-9.27-6.734-9.269 6.734 3.54-10.897-9.269-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.27-6.734-9.268 6.734 3.54-10.897-9.269-6.734h11.457zm64.855 0l3.54 10.897h11.458l-9.27 6.734 3.541 10.897-9.269-6.734-9.27 6.734 3.542-10.897-9.27-6.734h11.458zm64.852 0l3.54 10.897h11.457l-9.269 6.734 3.54 10.897-9.268-6.734-9.27 6.734 3.541-10.897-9.27-6.734h11.458z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path d="M32.427 232.356l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.853 0l3.541 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735H93.74zm64.856 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.269 6.734 3.54-10.896-9.269-6.735h11.458zm64.852 0l3.54 10.896h11.457l-9.269 6.735 3.54 10.896-9.268-6.734-9.27 6.734 3.541-10.896-9.27-6.735h11.458zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.27-6.734-9.268 6.734 3.54-10.896-9.269-6.735h11.457zm64.855 0l3.54 10.896h11.458l-9.27 6.735 3.541 10.896-9.269-6.734-9.27 6.734 3.542-10.896-9.27-6.735h11.458z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
|
@ -38,7 +38,7 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
|
||||||
//main toolbar
|
//main toolbar
|
||||||
'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'hangup',
|
'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'hangup',
|
||||||
//extended toolbar
|
//extended toolbar
|
||||||
'profile', 'contacts', 'chat', 'recording', 'etherpad', 'sharedvideo', 'sip', 'settings', 'raisehand', 'filmstrip'], // jshint ignore:line
|
'profile', 'contacts', 'chat', 'recording', 'etherpad', 'sharedvideo', 'dialout', 'settings', 'raisehand', 'filmstrip'], // jshint ignore:line
|
||||||
/**
|
/**
|
||||||
* Main Toolbar Buttons
|
* Main Toolbar Buttons
|
||||||
* All of them should be in TOOLBAR_BUTTONS
|
* All of them should be in TOOLBAR_BUTTONS
|
||||||
|
|
|
@ -277,8 +277,6 @@
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"recording": "Recording",
|
"recording": "Recording",
|
||||||
"recordingToken": "Enter recording token",
|
"recordingToken": "Enter recording token",
|
||||||
"Dial": "Dial",
|
|
||||||
"sipMsg": "Enter SIP number",
|
|
||||||
"passwordCheck": "Are you sure you would like to remove your password?",
|
"passwordCheck": "Are you sure you would like to remove your password?",
|
||||||
"passwordMsg": "Set a password to lock your room",
|
"passwordMsg": "Set a password to lock your room",
|
||||||
"shareLink": "Share the link to the call",
|
"shareLink": "Share the link to the call",
|
||||||
|
@ -447,9 +445,16 @@
|
||||||
"unlocked": "This call is unlocked. Any new caller with the link may join the call."
|
"unlocked": "This call is unlocked. Any new caller with the link may join the call."
|
||||||
},
|
},
|
||||||
"videoStatus": {
|
"videoStatus": {
|
||||||
"hd": "HD",
|
"hd": "HD",
|
||||||
"hdVideo": "HD video",
|
"hdVideo": "HD video",
|
||||||
"sd": "SD",
|
"sd": "SD",
|
||||||
"sdVideo": "SD video"
|
"sdVideo": "SD video"
|
||||||
|
},
|
||||||
|
"dialOut": {
|
||||||
|
"dial": "Dial",
|
||||||
|
"dialOut": "Call a phone number",
|
||||||
|
"statusMessage": "is now __status__",
|
||||||
|
"enterPhone": "Enter phone number",
|
||||||
|
"phoneNotAllowed": "Oh, we don't support that destination yet! Sorry!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ import {
|
||||||
showDialPadButton,
|
showDialPadButton,
|
||||||
showEtherpadButton,
|
showEtherpadButton,
|
||||||
showSharedVideoButton,
|
showSharedVideoButton,
|
||||||
showSIPCallButton,
|
showDialOutButton,
|
||||||
showToolbox
|
showToolbox
|
||||||
} from '../../react/features/toolbox';
|
} from '../../react/features/toolbox';
|
||||||
|
|
||||||
|
@ -544,7 +544,7 @@ UI.onPeerVideoTypeChanged
|
||||||
UI.updateLocalRole = isModerator => {
|
UI.updateLocalRole = isModerator => {
|
||||||
VideoLayout.showModeratorIndicator();
|
VideoLayout.showModeratorIndicator();
|
||||||
|
|
||||||
APP.store.dispatch(showSIPCallButton(isModerator));
|
APP.store.dispatch(showDialOutButton(isModerator));
|
||||||
APP.store.dispatch(showSharedVideoButton());
|
APP.store.dispatch(showSharedVideoButton());
|
||||||
|
|
||||||
Recording.showRecordingButton(isModerator);
|
Recording.showRecordingButton(isModerator);
|
||||||
|
@ -589,6 +589,21 @@ UI.updateUserRole = user => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the user status.
|
||||||
|
*
|
||||||
|
* @param {JitsiParticipant} user - The user which status we need to update.
|
||||||
|
* @param {string} status - The new status.
|
||||||
|
*/
|
||||||
|
UI.updateUserStatus = (user, status) => {
|
||||||
|
let displayName = user.getDisplayName();
|
||||||
|
messageHandler.notify(
|
||||||
|
displayName, '', 'connected', "dialOut.statusMessage",
|
||||||
|
{
|
||||||
|
status: UIUtil.escapeHtml(status)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles smileys in the chat.
|
* Toggles smileys in the chat.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { Symbol } from '../base/react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the action which signals a check for a dial-out phone number has
|
||||||
|
* succeeded.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: PHONE_NUMBER_CHECKED,
|
||||||
|
* response: Object
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const PHONE_NUMBER_CHECKED
|
||||||
|
= Symbol('PHONE_NUMBER_CHECKED');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the action which signals a cancel of the dial-out operation.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: DIAL_OUT_CANCELED,
|
||||||
|
* response: Object
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const DIAL_OUT_CANCELED
|
||||||
|
= Symbol('DIAL_OUT_CANCELED');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the action which signals a request for dial-out country codes has
|
||||||
|
* succeeded.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: DIAL_OUT_CODES_UPDATED,
|
||||||
|
* response: Object
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const DIAL_OUT_CODES_UPDATED
|
||||||
|
= Symbol('DIAL_OUT_CODES_UPDATED');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the action which signals a failure in some of dial-out service
|
||||||
|
* requests.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: DIAL_OUT_SERVICE_FAILED,
|
||||||
|
* response: Object
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const DIAL_OUT_SERVICE_FAILED
|
||||||
|
= Symbol('DIAL_OUT_SERVICE_FAILED');
|
|
@ -0,0 +1,97 @@
|
||||||
|
import { openDialog } from '../../features/base/dialog';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DIAL_OUT_CANCELED,
|
||||||
|
DIAL_OUT_CODES_UPDATED,
|
||||||
|
DIAL_OUT_SERVICE_FAILED,
|
||||||
|
PHONE_NUMBER_CHECKED
|
||||||
|
} from './actionTypes';
|
||||||
|
|
||||||
|
import { DialOutDialog } from './components';
|
||||||
|
|
||||||
|
declare var $: Function;
|
||||||
|
declare var config: Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dials the given number.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function cancel() {
|
||||||
|
return {
|
||||||
|
type: DIAL_OUT_CANCELED
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dials the given number.
|
||||||
|
*
|
||||||
|
* @param {string} dialNumber - The number to dial.
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function dial(dialNumber) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const { conference } = getState()['features/base/conference'];
|
||||||
|
|
||||||
|
conference.dial(dialNumber);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an ajax request for dial-out country codes.
|
||||||
|
*
|
||||||
|
* @param {string} dialNumber - The dial number to check for validity.
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function checkDialNumber(dialNumber) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const { dialOutAuthUrl } = getState()['features/base/config'];
|
||||||
|
|
||||||
|
const fullUrl = `${dialOutAuthUrl}?phone=${dialNumber}`;
|
||||||
|
|
||||||
|
$.getJSON(fullUrl)
|
||||||
|
.success(response =>
|
||||||
|
dispatch({
|
||||||
|
type: PHONE_NUMBER_CHECKED,
|
||||||
|
response
|
||||||
|
}))
|
||||||
|
.error(error =>
|
||||||
|
dispatch({
|
||||||
|
type: DIAL_OUT_SERVICE_FAILED,
|
||||||
|
error
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the dial-out dialog.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function openDialOutDialog() {
|
||||||
|
return openDialog(DialOutDialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an ajax request for dial-out country codes.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function updateDialOutCodes() {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const { dialOutCodesUrl } = getState()['features/base/config'];
|
||||||
|
|
||||||
|
$.getJSON(dialOutCodesUrl)
|
||||||
|
.success(response =>
|
||||||
|
dispatch({
|
||||||
|
type: DIAL_OUT_CODES_UPDATED,
|
||||||
|
response
|
||||||
|
}))
|
||||||
|
.error(error =>
|
||||||
|
dispatch({
|
||||||
|
type: DIAL_OUT_SERVICE_FAILED,
|
||||||
|
error
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements a React Component to render a country flag icon.
|
||||||
|
*/
|
||||||
|
class CountryIcon extends Component {
|
||||||
|
/**
|
||||||
|
* {@code CountryIcon}'s property types.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
static propTypes = {
|
||||||
|
/**
|
||||||
|
* The css style class name.
|
||||||
|
*/
|
||||||
|
className: React.PropTypes.string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 2-letter country code.
|
||||||
|
*/
|
||||||
|
countryCode: React.PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements React's {@link Component#render()}.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @returns {ReactElement}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const iconClassName
|
||||||
|
= `flag-icon flag-icon-${this.props.countryCode}
|
||||||
|
flag-icon-squared ${this.props.className}`;
|
||||||
|
|
||||||
|
return <span className = { iconClassName } />;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CountryIcon;
|
|
@ -0,0 +1,226 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { translate } from '../../base/i18n';
|
||||||
|
import { Dialog } from '../../base/dialog';
|
||||||
|
|
||||||
|
import { cancel, checkDialNumber, dial } from '../actions';
|
||||||
|
import DialOutNumbersForm from './DialOutNumbersForm';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements a React Component which allows the user to dial out from the
|
||||||
|
* conference.
|
||||||
|
*/
|
||||||
|
class DialOutDialog extends Component {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code DialOutDialog} component's property types.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
static propTypes = {
|
||||||
|
/**
|
||||||
|
* Property indicating if a dial number is allowed.
|
||||||
|
*/
|
||||||
|
_isDialNumberAllowed: React.PropTypes.bool,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function performing the cancel action.
|
||||||
|
*/
|
||||||
|
cancel: React.PropTypes.func,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function performing the phone number validity check.
|
||||||
|
*/
|
||||||
|
checkDialNumber: React.PropTypes.func,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function performing the dial action.
|
||||||
|
*/
|
||||||
|
dial: React.PropTypes.func,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked to obtain translated strings.
|
||||||
|
*/
|
||||||
|
t: React.PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new {@code DialOutNumbersForm} instance.
|
||||||
|
*
|
||||||
|
* @param {Object} props - The read-only properties with which the new
|
||||||
|
* instance is to be initialized.
|
||||||
|
*/
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
/**
|
||||||
|
* The number to dial.
|
||||||
|
*/
|
||||||
|
dialNumber: '',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the dial input is currently empty.
|
||||||
|
*/
|
||||||
|
isDialInputEmpty: true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind event handlers so they are only bound once for every instance.
|
||||||
|
this._onDialNumberChange = this._onDialNumberChange.bind(this);
|
||||||
|
this._onCancel = this._onCancel.bind(this);
|
||||||
|
this._onSubmit = this._onSubmit.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements React's {@link Component#render()}.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @returns {ReactElement}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const { _isDialNumberAllowed } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
okDisabled = { this.state.isDialInputEmpty
|
||||||
|
|| !_isDialNumberAllowed }
|
||||||
|
okTitleKey = 'dialOut.dial'
|
||||||
|
onCancel = { this._onCancel }
|
||||||
|
onSubmit = { this._onSubmit }
|
||||||
|
titleKey = 'dialOut.dialOut'
|
||||||
|
width = 'small'>
|
||||||
|
{ this._renderContent() }
|
||||||
|
</Dialog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the dial number in a way to remove all non digital characters
|
||||||
|
* from it (including spaces, brackets, dash, dot, etc.).
|
||||||
|
*
|
||||||
|
* @param {string} dialNumber - The phone number to format.
|
||||||
|
* @private
|
||||||
|
* @returns {string} - The formatted phone number.
|
||||||
|
*/
|
||||||
|
_formatDialNumber(dialNumber) {
|
||||||
|
return dialNumber.replace(/\D/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the dialog content.
|
||||||
|
*
|
||||||
|
* @returns {XML}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_renderContent() {
|
||||||
|
const { _isDialNumberAllowed } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className = 'dial-out-content'>
|
||||||
|
{ _isDialNumberAllowed ? '' : this._renderErrorMessage() }
|
||||||
|
<DialOutNumbersForm
|
||||||
|
onChange = { this._onDialNumberChange } />
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the error message to display if the dial phone number is not
|
||||||
|
* allowed.
|
||||||
|
*
|
||||||
|
* @returns {XML}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_renderErrorMessage() {
|
||||||
|
const { t } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className = 'dial-out-error'>
|
||||||
|
{ t('dialOut.phoneNotAllowed') }
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel the dial out.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {boolean} - Returns true to indicate that the dialog should be
|
||||||
|
* closed.
|
||||||
|
*/
|
||||||
|
_onCancel() {
|
||||||
|
this.props.cancel();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dials the number.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {boolean} - Returns true to indicate that the dialog should be
|
||||||
|
* closed.
|
||||||
|
*/
|
||||||
|
_onSubmit() {
|
||||||
|
if (this.props._isDialNumberAllowed) {
|
||||||
|
this.props.dial(this.state.dialNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dialNumber and check for validity.
|
||||||
|
*
|
||||||
|
* @param {string} dialCode - The dial code value.
|
||||||
|
* @param {string} dialInput - The dial input value.
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_onDialNumberChange(dialCode, dialInput) {
|
||||||
|
// We remove all starting zeros from the dial input before attaching it
|
||||||
|
// to the country code.
|
||||||
|
const formattedDialInput = dialInput.replace(/^(0+)/, '');
|
||||||
|
|
||||||
|
const dialNumber = `${dialCode}${formattedDialInput}`;
|
||||||
|
|
||||||
|
const formattedNumber = this._formatDialNumber(dialNumber);
|
||||||
|
|
||||||
|
this.props.checkDialNumber(formattedNumber);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
dialNumber: formattedNumber,
|
||||||
|
isDialInputEmpty: !formattedDialInput
|
||||||
|
|| formattedDialInput.length === 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps (parts of) the Redux state to the associated
|
||||||
|
* {@code DialOutDialog}'s props.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The Redux state.
|
||||||
|
* @private
|
||||||
|
* @returns {{
|
||||||
|
* _isDialNumberAllowed: React.PropTypes.bool
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
function _mapStateToProps(state) {
|
||||||
|
const { isDialNumberAllowed } = state['features/dial-out'];
|
||||||
|
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* Property indicating if a dial number is allowed.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
_isDialNumberAllowed: isDialNumberAllowed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate(
|
||||||
|
connect(_mapStateToProps, {
|
||||||
|
cancel,
|
||||||
|
dial,
|
||||||
|
checkDialNumber
|
||||||
|
})(DialOutDialog));
|
|
@ -0,0 +1,346 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import ExpandIcon from '@atlaskit/icon/glyph/expand';
|
||||||
|
import { StatelessDropdownMenu } from '@atlaskit/dropdown-menu';
|
||||||
|
|
||||||
|
import { translate } from '../../base/i18n';
|
||||||
|
import CountryIcon from './CountryIcon';
|
||||||
|
import { updateDialOutCodes } from '../actions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The expand icon of the dropdown menu.
|
||||||
|
*
|
||||||
|
* @type {XML}
|
||||||
|
*/
|
||||||
|
const EXPAND_ICON = <ExpandIcon label = 'expand' />;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default value of the country if the fetch service is unavailable.
|
||||||
|
*
|
||||||
|
* @type {{name: string, dialCode: string, code: string}}
|
||||||
|
*/
|
||||||
|
const DEFAULT_COUNTRY = {
|
||||||
|
name: 'United States',
|
||||||
|
dialCode: '+1',
|
||||||
|
code: 'US'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React {@code Component} responsible for fetching and displaying dial-out
|
||||||
|
* country codes, as well as dialing a phone number.
|
||||||
|
*
|
||||||
|
* @extends Component
|
||||||
|
*/
|
||||||
|
class DialOutNumbersForm extends Component {
|
||||||
|
/**
|
||||||
|
* {@code DialOutNumbersForm}'s property types.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
static propTypes = {
|
||||||
|
/**
|
||||||
|
* The redux state representing the list of dial-out codes.
|
||||||
|
*/
|
||||||
|
_dialOutCodes: React.PropTypes.array,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function called on every dial input change.
|
||||||
|
*/
|
||||||
|
onChange: React.PropTypes.func,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked to obtain translated strings.
|
||||||
|
*/
|
||||||
|
t: React.PropTypes.func,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked to send an ajax request for dial-out codes.
|
||||||
|
*/
|
||||||
|
updateDialOutCodes: React.PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new {@code DialOutNumbersForm} instance.
|
||||||
|
*
|
||||||
|
* @param {Object} props - The read-only properties with which the new
|
||||||
|
* instance is to be initialized.
|
||||||
|
*/
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
dialInput: '',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the dropdown should be open.
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
isDropdownOpen: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selected country.
|
||||||
|
*
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
selectedCountry: DEFAULT_COUNTRY
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal reference to the DOM/HTML element backing the React
|
||||||
|
* {@code Component} text input.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type {HTMLInputElement}
|
||||||
|
*/
|
||||||
|
this._dialInputElem = null;
|
||||||
|
|
||||||
|
// Bind event handlers so they are only bound once for every instance.
|
||||||
|
this._onInputChange = this._onInputChange.bind(this);
|
||||||
|
this._onOpenChange = this._onOpenChange.bind(this);
|
||||||
|
this._onSelect = this._onSelect.bind(this);
|
||||||
|
this._setDialInputElement = this._setDialInputElement.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches a request for dial out codes if not already present in the
|
||||||
|
* redux store. If dial out codes are present, sets a default code to
|
||||||
|
* display in the dropdown trigger.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* returns {void}
|
||||||
|
*/
|
||||||
|
componentDidMount() {
|
||||||
|
const dialOutCodes = this.props._dialOutCodes;
|
||||||
|
|
||||||
|
if (dialOutCodes) {
|
||||||
|
this._setDefaultCode(dialOutCodes);
|
||||||
|
} else {
|
||||||
|
this.props.updateDialOutCodes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitors for dial out code updates and sets a default code to display in
|
||||||
|
* the dropdown trigger if not already set.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* returns {void}
|
||||||
|
*/
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (!this.state.selectedCountry && nextProps._dialOutCodes) {
|
||||||
|
this._setDefaultCode(nextProps._dialOutCodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements React's {@link Component#render()}.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @returns {ReactElement}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const { t, _dialOutCodes } = this.props;
|
||||||
|
|
||||||
|
const items
|
||||||
|
= _dialOutCodes ? this._formatCountryCodes(_dialOutCodes) : [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className = 'form-control'>
|
||||||
|
{ this._createDropdownMenu(items) }
|
||||||
|
<div className = 'dial-out-input'>
|
||||||
|
<input
|
||||||
|
autoFocus = { true }
|
||||||
|
className = 'input-control'
|
||||||
|
onChange = { this._onInputChange }
|
||||||
|
placeholder = { t('dialOut.enterPhone') }
|
||||||
|
ref = { this._setDialInputElement }
|
||||||
|
type = 'text' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@code StatelessDropdownMenu} instance.
|
||||||
|
*
|
||||||
|
* @param {Array} items - The content to display within the dropdown.
|
||||||
|
* @returns {ReactElement}
|
||||||
|
*/
|
||||||
|
_createDropdownMenu(items) {
|
||||||
|
const { code, dialCode } = this.state.selectedCountry;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StatelessDropdownMenu
|
||||||
|
isOpen = { this.state.isDropdownOpen }
|
||||||
|
items = { [ { items } ] }
|
||||||
|
onItemActivated = { this._onSelect }
|
||||||
|
onOpenChange = { this._onOpenChange }
|
||||||
|
shouldFitContainer = { true }>
|
||||||
|
{ this._createDropdownTrigger(dialCode, code) }
|
||||||
|
</StatelessDropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a React {@code Component} with a readonly HTMLInputElement as a
|
||||||
|
* trigger for displaying the dropdown menu. The {@code Component} will also
|
||||||
|
* display the currently selected number.
|
||||||
|
*
|
||||||
|
* @param {string} dialCode - The +xx dial code.
|
||||||
|
* @param {string} countryCode - The country 2 letter code.
|
||||||
|
* @private
|
||||||
|
* @returns {ReactElement}
|
||||||
|
*/
|
||||||
|
_createDropdownTrigger(dialCode, countryCode) {
|
||||||
|
return (
|
||||||
|
<div className = 'dropdown'>
|
||||||
|
<CountryIcon
|
||||||
|
className = 'dial-out-flag-icon'
|
||||||
|
countryCode = { `${countryCode}` } />
|
||||||
|
<input
|
||||||
|
className = 'input-control dial-out-code'
|
||||||
|
readOnly = { true }
|
||||||
|
type = 'text'
|
||||||
|
value = { dialCode || '' } />
|
||||||
|
<span className = 'dropdown-trigger-icon'>
|
||||||
|
{ EXPAND_ICON }
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms the passed in numbers object into an array of objects that can
|
||||||
|
* be parsed by {@code StatelessDropdownMenu}.
|
||||||
|
*
|
||||||
|
* @param {Object} countryCodes - The list of country codes.
|
||||||
|
* @private
|
||||||
|
* @returns {Array<Object>}
|
||||||
|
*/
|
||||||
|
_formatCountryCodes(countryCodes) {
|
||||||
|
|
||||||
|
return countryCodes.map(country => {
|
||||||
|
const countryIcon
|
||||||
|
= <CountryIcon countryCode = { `${country.code}` } />;
|
||||||
|
|
||||||
|
const countryElement
|
||||||
|
= <span>{countryIcon} { country.name }</span>;
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: `${country.dialCode}`,
|
||||||
|
elemBefore: countryElement,
|
||||||
|
country
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dialNumber when changes to the dial text or code happen.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_onDialNumberChange() {
|
||||||
|
const { dialCode } = this.state.selectedCountry;
|
||||||
|
|
||||||
|
this.props.onChange(dialCode, this.state.dialInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dialInput state when the input changes.
|
||||||
|
*
|
||||||
|
* @param {Object} e - The event notifying us of the change.
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_onInputChange(e) {
|
||||||
|
this.setState({
|
||||||
|
dialInput: e.target.value
|
||||||
|
}, () => {
|
||||||
|
this._onDialNumberChange();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the internal state to either open or close the dropdown. If the
|
||||||
|
* dropdown is disabled, the state will always be set to false.
|
||||||
|
*
|
||||||
|
* @param {Object} dropdownEvent - The even returned from clicking on the
|
||||||
|
* dropdown trigger.
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_onOpenChange(dropdownEvent) {
|
||||||
|
this.setState({
|
||||||
|
isDropdownOpen: dropdownEvent.isOpen
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the internal state of the currently selected country code.
|
||||||
|
*
|
||||||
|
* @param {Object} selection - Event from choosing an dropdown option.
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_onSelect(selection) {
|
||||||
|
this.setState({
|
||||||
|
isDropdownOpen: false,
|
||||||
|
selectedCountry: selection.item.country
|
||||||
|
}, () => {
|
||||||
|
this._onDialNumberChange();
|
||||||
|
|
||||||
|
this._dialInputElem.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the internal state of the currently selected number by defaulting
|
||||||
|
* to the first available number.
|
||||||
|
*
|
||||||
|
* @param {Object} countryCodes - The list of country codes to choose from
|
||||||
|
* for setting a default code.
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_setDefaultCode(countryCodes) {
|
||||||
|
this.setState({
|
||||||
|
selectedCountry: countryCodes[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the internal reference to the DOM/HTML element backing the React
|
||||||
|
* {@code Component} dial input.
|
||||||
|
*
|
||||||
|
* @param {HTMLInputElement} input - The DOM/HTML element for this
|
||||||
|
* {@code Component}'s text input.
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_setDialInputElement(input) {
|
||||||
|
this._dialInputElem = input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps (parts of) the Redux state to the associated
|
||||||
|
* {@code DialOutNumbersForm}'s props.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The Redux state.
|
||||||
|
* @private
|
||||||
|
* @returns {{
|
||||||
|
* _dialOutCodes: React.PropTypes.object
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
function _mapStateToProps(state) {
|
||||||
|
const { dialOutCodes } = state['features/dial-out'];
|
||||||
|
|
||||||
|
return {
|
||||||
|
_dialOutCodes: dialOutCodes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate(connect(_mapStateToProps,
|
||||||
|
{ updateDialOutCodes })(DialOutNumbersForm));
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as DialOutDialog } from './DialOutDialog';
|
|
@ -0,0 +1,4 @@
|
||||||
|
export * from './actions';
|
||||||
|
export * from './components';
|
||||||
|
|
||||||
|
import './reducer';
|
|
@ -0,0 +1,48 @@
|
||||||
|
import {
|
||||||
|
ReducerRegistry
|
||||||
|
} from '../base/redux';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DIAL_OUT_CANCELED,
|
||||||
|
DIAL_OUT_CODES_UPDATED,
|
||||||
|
DIAL_OUT_SERVICE_FAILED,
|
||||||
|
PHONE_NUMBER_CHECKED
|
||||||
|
} from './actionTypes';
|
||||||
|
|
||||||
|
const DEFAULT_STATE = {
|
||||||
|
dialOutCodes: null,
|
||||||
|
error: null,
|
||||||
|
isDialNumberAllowed: true
|
||||||
|
};
|
||||||
|
|
||||||
|
ReducerRegistry.register(
|
||||||
|
'features/dial-out',
|
||||||
|
(state = DEFAULT_STATE, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case DIAL_OUT_CANCELED: {
|
||||||
|
return DEFAULT_STATE;
|
||||||
|
}
|
||||||
|
case DIAL_OUT_CODES_UPDATED: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: null,
|
||||||
|
dialOutCodes: action.response
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case DIAL_OUT_SERVICE_FAILED: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: action.error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case PHONE_NUMBER_CHECKED: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: null,
|
||||||
|
isDialNumberAllowed: action.response.allow
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
});
|
|
@ -192,7 +192,7 @@ class DialInNumbersForm extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a React {@code Component} with a redonly HTMLInputElement as a
|
* Creates a React {@code Component} with a readonly HTMLInputElement as a
|
||||||
* trigger for displaying the dropdown menu. The {@code Component} will also
|
* trigger for displaying the dropdown menu. The {@code Component} will also
|
||||||
* display the currently selected number.
|
* display the currently selected number.
|
||||||
*
|
*
|
||||||
|
@ -269,7 +269,7 @@ class DialInNumbersForm extends Component {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const formattedNumbeers = phoneRegions.map(region => {
|
const formattedNumbers = phoneRegions.map(region => {
|
||||||
const numbers = dialInNumbers[region];
|
const numbers = dialInNumbers[region];
|
||||||
|
|
||||||
return numbers.map(number => {
|
return numbers.map(number => {
|
||||||
|
@ -280,7 +280,7 @@ class DialInNumbersForm extends Component {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return Array.prototype.concat(...formattedNumbeers);
|
return Array.prototype.concat(...formattedNumbers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -215,14 +215,15 @@ export function showSharedVideoButton(): Function {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows SIP call button if it's required and appropriate flag is passed.
|
* Shows the dial out button if it's required and appropriate
|
||||||
|
* flag is passed.
|
||||||
*
|
*
|
||||||
* @param {boolean} show - Flag showing whether to show button or not.
|
* @param {boolean} show - Flag showing whether to show button or not.
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function showSIPCallButton(show: boolean): Function {
|
export function showDialOutButton(show: boolean): Function {
|
||||||
return (dispatch: Dispatch<*>, getState: Function) => {
|
return (dispatch: Dispatch<*>, getState: Function) => {
|
||||||
const buttonName = 'sip';
|
const buttonName = 'dialout';
|
||||||
|
|
||||||
if (show
|
if (show
|
||||||
&& APP.conference.sipGatewayEnabled()
|
&& APP.conference.sipGatewayEnabled()
|
||||||
|
|
|
@ -5,39 +5,11 @@ import React from 'react';
|
||||||
import UIEvents from '../../../service/UI/UIEvents';
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
|
|
||||||
import { openInviteDialog } from '../invite';
|
import { openInviteDialog } from '../invite';
|
||||||
|
import { openDialOutDialog } from '../dial-out';
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
declare var config: Object;
|
|
||||||
declare var JitsiMeetJS: Object;
|
declare var JitsiMeetJS: Object;
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows SIP number dialog.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
function _showSIPNumberInput() {
|
|
||||||
const defaultNumber = config.defaultSipNumber || '';
|
|
||||||
const msgString
|
|
||||||
= `<input class="input-control" name="sipNumber" type="text" value="${
|
|
||||||
defaultNumber}" autofocus>`;
|
|
||||||
|
|
||||||
APP.UI.messageHandler.openTwoButtonDialog({
|
|
||||||
focus: ':input:first',
|
|
||||||
leftButtonKey: 'dialog.Dial',
|
|
||||||
msgString,
|
|
||||||
titleKey: 'dialog.sipMsg',
|
|
||||||
|
|
||||||
// eslint-disable-next-line max-params
|
|
||||||
submitFunction(event, value, message, formValues) {
|
|
||||||
const { sipNumber } = formValues;
|
|
||||||
|
|
||||||
if (value && sipNumber) {
|
|
||||||
APP.UI.emitEvent(UIEvents.SIP_DIAL, sipNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All toolbar buttons' descriptors.
|
* All toolbar buttons' descriptors.
|
||||||
*/
|
*/
|
||||||
|
@ -169,6 +141,23 @@ export default {
|
||||||
tooltipKey: 'toolbar.sharescreen'
|
tooltipKey: 'toolbar.sharescreen'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The descriptor of the dial out toolbar button.
|
||||||
|
*/
|
||||||
|
dialout: {
|
||||||
|
classNames: [ 'button', 'icon-telephone' ],
|
||||||
|
enabled: true,
|
||||||
|
|
||||||
|
// Will be displayed once the SIP calls functionality is detected.
|
||||||
|
hidden: true,
|
||||||
|
id: 'toolbar_button_dial_out',
|
||||||
|
onClick() {
|
||||||
|
JitsiMeetJS.analytics.sendEvent('toolbar.sip.clicked');
|
||||||
|
APP.store.dispatch(openDialOutDialog());
|
||||||
|
},
|
||||||
|
tooltipKey: 'dialOut.dialOut'
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The descriptor of the dialpad toolbar button.
|
* The descriptor of the dialpad toolbar button.
|
||||||
*/
|
*/
|
||||||
|
@ -395,22 +384,5 @@ export default {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
tooltipKey: 'toolbar.sharedvideo'
|
tooltipKey: 'toolbar.sharedvideo'
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The descriptor of the SIP call toolbar button.
|
|
||||||
*/
|
|
||||||
sip: {
|
|
||||||
classNames: [ 'button', 'icon-telephone' ],
|
|
||||||
enabled: true,
|
|
||||||
|
|
||||||
// Will be displayed once the SIP calls functionality is detected.
|
|
||||||
hidden: true,
|
|
||||||
id: 'toolbar_button_sip',
|
|
||||||
onClick() {
|
|
||||||
JitsiMeetJS.analytics.sendEvent('toolbar.sip.clicked');
|
|
||||||
_showSIPNumberInput();
|
|
||||||
},
|
|
||||||
tooltipKey: 'toolbar.sip'
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,7 +71,6 @@ export default {
|
||||||
HANGUP: "UI.hangup",
|
HANGUP: "UI.hangup",
|
||||||
LOGOUT: "UI.logout",
|
LOGOUT: "UI.logout",
|
||||||
RECORDING_TOGGLED: "UI.recording_toggled",
|
RECORDING_TOGGLED: "UI.recording_toggled",
|
||||||
SIP_DIAL: "UI.sip_dial",
|
|
||||||
SUBJECT_CHANGED: "UI.subject_changed",
|
SUBJECT_CHANGED: "UI.subject_changed",
|
||||||
VIDEO_DEVICE_CHANGED: "UI.video_device_changed",
|
VIDEO_DEVICE_CHANGED: "UI.video_device_changed",
|
||||||
AUDIO_DEVICE_CHANGED: "UI.audio_device_changed",
|
AUDIO_DEVICE_CHANGED: "UI.audio_device_changed",
|
||||||
|
|
Loading…
Reference in New Issue