mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 17:28:13 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into orange
This commit is contained in:
commit
ce09f73b5c
22 changed files with 1309 additions and 718 deletions
|
@ -6,7 +6,8 @@
|
||||||
{
|
{
|
||||||
"name": "access_token",
|
"name": "access_token",
|
||||||
"label": "Access Token",
|
"label": "Access Token",
|
||||||
"help": "This is an access token generated on the <a href='https://metaverse.highfidelity.com/user/security' target='_blank'>My Security</a> page of your High Fidelity account.<br/>Generate a token with the 'domains' scope and paste it here.<br/>This is required to associate this domain-server with a domain in your account."
|
"help": "This is your OAuth access token to connect this domain-server with your High Fidelity account. <br/>It can be generated by clicking the 'Connect Account' button above.<br/>You can also go to the <a href='https://metaverse.highfidelity.com/user/security' target='_blank'>My Security</a> page of your account and generate a token with the 'domains' scope and paste it here.",
|
||||||
|
"advanced": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "id",
|
"name": "id",
|
||||||
|
@ -45,11 +46,12 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Paths",
|
"label": "Places / Paths",
|
||||||
|
"html_id": "places_paths",
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"name": "paths",
|
"name": "paths",
|
||||||
"label": "",
|
"label": "Paths",
|
||||||
"help": "Clients can enter a path to reach an exact viewpoint in your domain.<br/>Add rows to the table below to map a path to a viewpoint.<br/>The index path ( / ) is where clients will enter if they do not enter an explicit path.",
|
"help": "Clients can enter a path to reach an exact viewpoint in your domain.<br/>Add rows to the table below to map a path to a viewpoint.<br/>The index path ( / ) is where clients will enter if they do not enter an explicit path.",
|
||||||
"type": "table",
|
"type": "table",
|
||||||
"key": {
|
"key": {
|
||||||
|
|
|
@ -62,7 +62,7 @@ span.port {
|
||||||
}
|
}
|
||||||
|
|
||||||
td.buttons {
|
td.buttons {
|
||||||
width: 14px;
|
width: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
td .glyphicon {
|
td .glyphicon {
|
||||||
|
@ -78,6 +78,11 @@ td.reorder-buttons .glyphicon {
|
||||||
display: inherit;
|
display: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td a.glyphicon {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
tr.new-row {
|
tr.new-row {
|
||||||
color: #3c763d;
|
color: #3c763d;
|
||||||
background-color: #dff0d8;
|
background-color: #dff0d8;
|
||||||
|
@ -86,3 +91,61 @@ tr.new-row {
|
||||||
.highchart-modal .modal-dialog {
|
.highchart-modal .modal-dialog {
|
||||||
width: 650px;
|
width: 650px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
table-layout: fixed;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xs-advanced-container {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#advanced-toggle-button-xs {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
margin: 30px auto 0;
|
||||||
|
width: 70px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner > div {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
background-color: #333;
|
||||||
|
|
||||||
|
border-radius: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
-webkit-animation: bouncedelay 1.4s infinite ease-in-out;
|
||||||
|
animation: bouncedelay 1.4s infinite ease-in-out;
|
||||||
|
/* Prevent first frame from flickering when animation starts */
|
||||||
|
-webkit-animation-fill-mode: both;
|
||||||
|
animation-fill-mode: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner .bounce1 {
|
||||||
|
-webkit-animation-delay: -0.32s;
|
||||||
|
animation-delay: -0.32s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner .bounce2 {
|
||||||
|
-webkit-animation-delay: -0.16s;
|
||||||
|
animation-delay: -0.16s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes bouncedelay {
|
||||||
|
0%, 80%, 100% { -webkit-transform: scale(0.0) }
|
||||||
|
40% { -webkit-transform: scale(1.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bouncedelay {
|
||||||
|
0%, 80%, 100% {
|
||||||
|
transform: scale(0.0);
|
||||||
|
-webkit-transform: scale(0.0);
|
||||||
|
} 40% {
|
||||||
|
transform: scale(1.0);
|
||||||
|
-webkit-transform: scale(1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
|
body.stop-scrolling {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden; }
|
||||||
|
|
||||||
.sweet-overlay {
|
.sweet-overlay {
|
||||||
|
background-color: black;
|
||||||
|
/* IE8 */
|
||||||
|
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
|
||||||
|
/* IE8 */
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -6,11 +14,11 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
display: none;
|
display: none;
|
||||||
z-index: 1000; }
|
z-index: 10000; }
|
||||||
|
|
||||||
.sweet-alert {
|
.sweet-alert {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
font-family: sans-serif;
|
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||||
width: 478px;
|
width: 478px;
|
||||||
padding: 17px;
|
padding: 17px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
@ -22,7 +30,7 @@
|
||||||
margin-top: -200px;
|
margin-top: -200px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: none;
|
display: none;
|
||||||
z-index: 2000; }
|
z-index: 99999; }
|
||||||
@media all and (max-width: 540px) {
|
@media all and (max-width: 540px) {
|
||||||
.sweet-alert {
|
.sweet-alert {
|
||||||
width: auto;
|
width: auto;
|
||||||
|
@ -36,15 +44,120 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
position: relative; }
|
position: relative;
|
||||||
|
margin: 25px 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 40px;
|
||||||
|
display: block; }
|
||||||
.sweet-alert p {
|
.sweet-alert p {
|
||||||
color: #797979;
|
color: #797979;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
text-align: inherit;
|
||||||
|
float: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
line-height: normal; }
|
line-height: normal; }
|
||||||
|
.sweet-alert fieldset {
|
||||||
|
border: none;
|
||||||
|
position: relative; }
|
||||||
|
.sweet-alert .sa-error-container {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
margin-left: -17px;
|
||||||
|
margin-right: -17px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0 10px;
|
||||||
|
max-height: 0;
|
||||||
|
webkit-transition: padding 0.15s, max-height 0.15s;
|
||||||
|
transition: padding 0.15s, max-height 0.15s; }
|
||||||
|
.sweet-alert .sa-error-container.show {
|
||||||
|
padding: 10px 0;
|
||||||
|
max-height: 100px;
|
||||||
|
webkit-transition: padding 0.2s, max-height 0.2s;
|
||||||
|
transition: padding 0.25s, max-height 0.25s; }
|
||||||
|
.sweet-alert .sa-error-container .icon {
|
||||||
|
display: inline-block;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #ea7d7d;
|
||||||
|
color: white;
|
||||||
|
line-height: 24px;
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 3px; }
|
||||||
|
.sweet-alert .sa-error-container p {
|
||||||
|
display: inline-block; }
|
||||||
|
.sweet-alert .sa-input-error {
|
||||||
|
position: absolute;
|
||||||
|
top: 29px;
|
||||||
|
right: 26px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transform: scale(0.5);
|
||||||
|
transform: scale(0.5);
|
||||||
|
-webkit-transform-origin: 50% 50%;
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
-webkit-transition: all 0.1s;
|
||||||
|
transition: all 0.1s; }
|
||||||
|
.sweet-alert .sa-input-error::before, .sweet-alert .sa-input-error::after {
|
||||||
|
content: "";
|
||||||
|
width: 20px;
|
||||||
|
height: 6px;
|
||||||
|
background-color: #f06e57;
|
||||||
|
border-radius: 3px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -4px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -9px; }
|
||||||
|
.sweet-alert .sa-input-error::before {
|
||||||
|
-webkit-transform: rotate(-45deg);
|
||||||
|
transform: rotate(-45deg); }
|
||||||
|
.sweet-alert .sa-input-error::after {
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
|
transform: rotate(45deg); }
|
||||||
|
.sweet-alert .sa-input-error.show {
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
transform: scale(1); }
|
||||||
|
.sweet-alert input {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid #d7d7d7;
|
||||||
|
height: 43px;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 17px;
|
||||||
|
font-size: 18px;
|
||||||
|
box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.06);
|
||||||
|
padding: 0 12px;
|
||||||
|
display: none;
|
||||||
|
-webkit-transition: all 0.3s;
|
||||||
|
transition: all 0.3s; }
|
||||||
|
.sweet-alert input:focus {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0px 0px 3px #c4e6f5;
|
||||||
|
border: 1px solid #b4dbed; }
|
||||||
|
.sweet-alert input:focus::-moz-placeholder {
|
||||||
|
transition: opacity 0.3s 0.03s ease;
|
||||||
|
opacity: 0.5; }
|
||||||
|
.sweet-alert input:focus:-ms-input-placeholder {
|
||||||
|
transition: opacity 0.3s 0.03s ease;
|
||||||
|
opacity: 0.5; }
|
||||||
|
.sweet-alert input:focus::-webkit-input-placeholder {
|
||||||
|
transition: opacity 0.3s 0.03s ease;
|
||||||
|
opacity: 0.5; }
|
||||||
|
.sweet-alert input::-moz-placeholder {
|
||||||
|
color: #bdbdbd; }
|
||||||
|
.sweet-alert input:-ms-input-placeholder {
|
||||||
|
color: #bdbdbd; }
|
||||||
|
.sweet-alert input::-webkit-input-placeholder {
|
||||||
|
color: #bdbdbd; }
|
||||||
|
.sweet-alert.show-input input {
|
||||||
|
display: block; }
|
||||||
.sweet-alert button {
|
.sweet-alert button {
|
||||||
background-color: #AEDEF4;
|
background-color: #AEDEF4;
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -52,6 +165,7 @@
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 10px 32px;
|
padding: 10px 32px;
|
||||||
margin: 26px 5px 0 5px;
|
margin: 26px 5px 0 5px;
|
||||||
|
@ -71,22 +185,29 @@
|
||||||
background-color: #b6b6b6; }
|
background-color: #b6b6b6; }
|
||||||
.sweet-alert button.cancel:focus {
|
.sweet-alert button.cancel:focus {
|
||||||
box-shadow: rgba(197, 205, 211, 0.8) 0px 0px 2px, rgba(0, 0, 0, 0.0470588) 0px 0px 0px 1px inset !important; }
|
box-shadow: rgba(197, 205, 211, 0.8) 0px 0px 2px, rgba(0, 0, 0, 0.0470588) 0px 0px 0px 1px inset !important; }
|
||||||
|
.sweet-alert button::-moz-focus-inner {
|
||||||
|
border: 0; }
|
||||||
.sweet-alert[data-has-cancel-button=false] button {
|
.sweet-alert[data-has-cancel-button=false] button {
|
||||||
box-shadow: none !important; }
|
box-shadow: none !important; }
|
||||||
.sweet-alert .icon {
|
.sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false] {
|
||||||
|
padding-bottom: 40px; }
|
||||||
|
.sweet-alert .sa-icon {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
border: 4px solid gray;
|
border: 4px solid gray;
|
||||||
|
-webkit-border-radius: 40px;
|
||||||
|
border-radius: 40px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
|
padding: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: content-box; }
|
box-sizing: content-box; }
|
||||||
.sweet-alert .icon.error {
|
.sweet-alert .sa-icon.sa-error {
|
||||||
border-color: #F27474; }
|
border-color: #F27474; }
|
||||||
.sweet-alert .icon.error .x-mark {
|
.sweet-alert .sa-icon.sa-error .sa-x-mark {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block; }
|
display: block; }
|
||||||
.sweet-alert .icon.error .line {
|
.sweet-alert .sa-icon.sa-error .sa-line {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
width: 47px;
|
width: 47px;
|
||||||
|
@ -94,37 +215,39 @@
|
||||||
display: block;
|
display: block;
|
||||||
top: 37px;
|
top: 37px;
|
||||||
border-radius: 2px; }
|
border-radius: 2px; }
|
||||||
.sweet-alert .icon.error .line.left {
|
.sweet-alert .sa-icon.sa-error .sa-line.sa-left {
|
||||||
-webkit-transform: rotate(45deg);
|
-webkit-transform: rotate(45deg);
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
left: 17px; }
|
left: 17px; }
|
||||||
.sweet-alert .icon.error .line.right {
|
.sweet-alert .sa-icon.sa-error .sa-line.sa-right {
|
||||||
-webkit-transform: rotate(-45deg);
|
-webkit-transform: rotate(-45deg);
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
right: 16px; }
|
right: 16px; }
|
||||||
.sweet-alert .icon.warning {
|
.sweet-alert .sa-icon.sa-warning {
|
||||||
border-color: #F8BB86; }
|
border-color: #F8BB86; }
|
||||||
.sweet-alert .icon.warning .body {
|
.sweet-alert .sa-icon.sa-warning .sa-body {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 47px;
|
height: 47px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
|
-webkit-border-radius: 2px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
margin-left: -2px;
|
margin-left: -2px;
|
||||||
background-color: #F8BB86; }
|
background-color: #F8BB86; }
|
||||||
.sweet-alert .icon.warning .dot {
|
.sweet-alert .sa-icon.sa-warning .sa-dot {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 7px;
|
width: 7px;
|
||||||
height: 7px;
|
height: 7px;
|
||||||
|
-webkit-border-radius: 50%;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin-left: -3px;
|
margin-left: -3px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
background-color: #F8BB86; }
|
background-color: #F8BB86; }
|
||||||
.sweet-alert .icon.info {
|
.sweet-alert .sa-icon.sa-info {
|
||||||
border-color: #C9DAE1; }
|
border-color: #C9DAE1; }
|
||||||
.sweet-alert .icon.info::before {
|
.sweet-alert .sa-icon.sa-info::before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 5px;
|
width: 5px;
|
||||||
|
@ -134,7 +257,7 @@
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
margin-left: -2px;
|
margin-left: -2px;
|
||||||
background-color: #C9DAE1; }
|
background-color: #C9DAE1; }
|
||||||
.sweet-alert .icon.info::after {
|
.sweet-alert .sa-icon.sa-info::after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 7px;
|
width: 7px;
|
||||||
|
@ -143,17 +266,21 @@
|
||||||
margin-left: -3px;
|
margin-left: -3px;
|
||||||
top: 19px;
|
top: 19px;
|
||||||
background-color: #C9DAE1; }
|
background-color: #C9DAE1; }
|
||||||
.sweet-alert .icon.success {
|
.sweet-alert .sa-icon.sa-success {
|
||||||
border-color: #A5DC86; }
|
border-color: #A5DC86; }
|
||||||
.sweet-alert .icon.success::before, .sweet-alert .icon.success::after {
|
.sweet-alert .sa-icon.sa-success::before, .sweet-alert .sa-icon.sa-success::after {
|
||||||
content: '';
|
content: '';
|
||||||
|
-webkit-border-radius: 40px;
|
||||||
|
border-radius: 40px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 120px;
|
height: 120px;
|
||||||
background: white;
|
background: white;
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
transform: rotate(45deg); }
|
transform: rotate(45deg); }
|
||||||
.sweet-alert .icon.success::before {
|
.sweet-alert .sa-icon.sa-success::before {
|
||||||
|
-webkit-border-radius: 120px 0 0 120px;
|
||||||
border-radius: 120px 0 0 120px;
|
border-radius: 120px 0 0 120px;
|
||||||
top: -7px;
|
top: -7px;
|
||||||
left: -33px;
|
left: -33px;
|
||||||
|
@ -161,7 +288,8 @@
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
-webkit-transform-origin: 60px 60px;
|
-webkit-transform-origin: 60px 60px;
|
||||||
transform-origin: 60px 60px; }
|
transform-origin: 60px 60px; }
|
||||||
.sweet-alert .icon.success::after {
|
.sweet-alert .sa-icon.sa-success::after {
|
||||||
|
-webkit-border-radius: 0 120px 120px 0;
|
||||||
border-radius: 0 120px 120px 0;
|
border-radius: 0 120px 120px 0;
|
||||||
top: -11px;
|
top: -11px;
|
||||||
left: 30px;
|
left: 30px;
|
||||||
|
@ -169,17 +297,19 @@
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
-webkit-transform-origin: 0px 60px;
|
-webkit-transform-origin: 0px 60px;
|
||||||
transform-origin: 0px 60px; }
|
transform-origin: 0px 60px; }
|
||||||
.sweet-alert .icon.success .placeholder {
|
.sweet-alert .sa-icon.sa-success .sa-placeholder {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
border: 4px solid rgba(165, 220, 134, 0.2);
|
border: 4px solid rgba(165, 220, 134, 0.2);
|
||||||
|
-webkit-border-radius: 40px;
|
||||||
|
border-radius: 40px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -4px;
|
left: -4px;
|
||||||
top: -4px;
|
top: -4px;
|
||||||
z-index: 2; }
|
z-index: 2; }
|
||||||
.sweet-alert .icon.success .fix {
|
.sweet-alert .sa-icon.sa-success .sa-fix {
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 90px;
|
height: 90px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
@ -189,26 +319,26 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
-webkit-transform: rotate(-45deg);
|
-webkit-transform: rotate(-45deg);
|
||||||
transform: rotate(-45deg); }
|
transform: rotate(-45deg); }
|
||||||
.sweet-alert .icon.success .line {
|
.sweet-alert .sa-icon.sa-success .sa-line {
|
||||||
height: 5px;
|
height: 5px;
|
||||||
background-color: #A5DC86;
|
background-color: #A5DC86;
|
||||||
display: block;
|
display: block;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2; }
|
z-index: 2; }
|
||||||
.sweet-alert .icon.success .line.tip {
|
.sweet-alert .sa-icon.sa-success .sa-line.sa-tip {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
left: 14px;
|
left: 14px;
|
||||||
top: 46px;
|
top: 46px;
|
||||||
-webkit-transform: rotate(45deg);
|
-webkit-transform: rotate(45deg);
|
||||||
transform: rotate(45deg); }
|
transform: rotate(45deg); }
|
||||||
.sweet-alert .icon.success .line.long {
|
.sweet-alert .sa-icon.sa-success .sa-line.sa-long {
|
||||||
width: 47px;
|
width: 47px;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
top: 38px;
|
top: 38px;
|
||||||
-webkit-transform: rotate(-45deg);
|
-webkit-transform: rotate(-45deg);
|
||||||
transform: rotate(-45deg); }
|
transform: rotate(-45deg); }
|
||||||
.sweet-alert .icon.custom {
|
.sweet-alert .sa-icon.sa-custom {
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -222,238 +352,274 @@
|
||||||
0% {
|
0% {
|
||||||
transform: scale(0.7);
|
transform: scale(0.7);
|
||||||
-webkit-transform: scale(0.7); }
|
-webkit-transform: scale(0.7); }
|
||||||
|
|
||||||
45% {
|
45% {
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
-webkit-transform: scale(1.05); }
|
-webkit-transform: scale(1.05); }
|
||||||
|
|
||||||
80% {
|
80% {
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
-webkit-tranform: scale(0.95); }
|
-webkit-transform: scale(0.95); }
|
||||||
100% {
|
|
||||||
transform: scale(1);
|
|
||||||
-webkit-transform: scale(1); } }
|
|
||||||
@-moz-keyframes showSweetAlert {
|
|
||||||
0% {
|
|
||||||
transform: scale(0.7);
|
|
||||||
-webkit-transform: scale(0.7); }
|
|
||||||
45% {
|
|
||||||
transform: scale(1.05);
|
|
||||||
-webkit-transform: scale(1.05); }
|
|
||||||
80% {
|
|
||||||
transform: scale(0.95);
|
|
||||||
-webkit-tranform: scale(0.95); }
|
|
||||||
100% {
|
100% {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
-webkit-transform: scale(1); } }
|
-webkit-transform: scale(1); } }
|
||||||
|
|
||||||
@keyframes showSweetAlert {
|
@keyframes showSweetAlert {
|
||||||
0% {
|
0% {
|
||||||
transform: scale(0.7);
|
transform: scale(0.7);
|
||||||
-webkit-transform: scale(0.7); }
|
-webkit-transform: scale(0.7); }
|
||||||
|
|
||||||
45% {
|
45% {
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
-webkit-transform: scale(1.05); }
|
-webkit-transform: scale(1.05); }
|
||||||
|
|
||||||
80% {
|
80% {
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
-webkit-tranform: scale(0.95); }
|
-webkit-transform: scale(0.95); }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
-webkit-transform: scale(1); } }
|
-webkit-transform: scale(1); } }
|
||||||
|
|
||||||
@-webkit-keyframes hideSweetAlert {
|
@-webkit-keyframes hideSweetAlert {
|
||||||
0% {
|
0% {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
-webkit-transform: scale(1); }
|
-webkit-transform: scale(1); }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: scale(0.5);
|
transform: scale(0.5);
|
||||||
-webkit-transform: scale(0.5); } }
|
-webkit-transform: scale(0.5); } }
|
||||||
@-moz-keyframes hideSweetAlert {
|
|
||||||
0% {
|
|
||||||
transform: scale(1);
|
|
||||||
-webkit-transform: scale(1); }
|
|
||||||
100% {
|
|
||||||
transform: scale(0.5);
|
|
||||||
-webkit-transform: scale(0.5); } }
|
|
||||||
@keyframes hideSweetAlert {
|
@keyframes hideSweetAlert {
|
||||||
0% {
|
0% {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
-webkit-transform: scale(1); }
|
-webkit-transform: scale(1); }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: scale(0.5);
|
transform: scale(0.5);
|
||||||
-webkit-transform: scale(0.5); } }
|
-webkit-transform: scale(0.5); } }
|
||||||
.showSweetAlert {
|
|
||||||
-webkit-animation: showSweetAlert 0.3s;
|
|
||||||
-moz-animation: showSweetAlert 0.3s;
|
|
||||||
animation: showSweetAlert 0.3s; }
|
|
||||||
|
|
||||||
.hideSweetAlert {
|
@-webkit-keyframes slideFromTop {
|
||||||
|
0% {
|
||||||
|
top: 0%; }
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 50%; } }
|
||||||
|
|
||||||
|
@keyframes slideFromTop {
|
||||||
|
0% {
|
||||||
|
top: 0%; }
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 50%; } }
|
||||||
|
|
||||||
|
@-webkit-keyframes slideToTop {
|
||||||
|
0% {
|
||||||
|
top: 50%; }
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 0%; } }
|
||||||
|
|
||||||
|
@keyframes slideToTop {
|
||||||
|
0% {
|
||||||
|
top: 50%; }
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 0%; } }
|
||||||
|
|
||||||
|
@-webkit-keyframes slideFromBottom {
|
||||||
|
0% {
|
||||||
|
top: 70%; }
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 50%; } }
|
||||||
|
|
||||||
|
@keyframes slideFromBottom {
|
||||||
|
0% {
|
||||||
|
top: 70%; }
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 50%; } }
|
||||||
|
|
||||||
|
@-webkit-keyframes slideToBottom {
|
||||||
|
0% {
|
||||||
|
top: 50%; }
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 70%; } }
|
||||||
|
|
||||||
|
@keyframes slideToBottom {
|
||||||
|
0% {
|
||||||
|
top: 50%; }
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 70%; } }
|
||||||
|
|
||||||
|
.showSweetAlert[data-animation=pop] {
|
||||||
|
-webkit-animation: showSweetAlert 0.3s;
|
||||||
|
animation: showSweetAlert 0.3s; }
|
||||||
|
.showSweetAlert[data-animation=none] {
|
||||||
|
-webkit-animation: none;
|
||||||
|
animation: none; }
|
||||||
|
.showSweetAlert[data-animation=slide-from-top] {
|
||||||
|
-webkit-animation: slideFromTop 0.3s;
|
||||||
|
animation: slideFromTop 0.3s; }
|
||||||
|
.showSweetAlert[data-animation=slide-from-bottom] {
|
||||||
|
-webkit-animation: slideFromBottom 0.3s;
|
||||||
|
animation: slideFromBottom 0.3s; }
|
||||||
|
|
||||||
|
.hideSweetAlert[data-animation=pop] {
|
||||||
-webkit-animation: hideSweetAlert 0.2s;
|
-webkit-animation: hideSweetAlert 0.2s;
|
||||||
-moz-animation: hideSweetAlert 0.2s;
|
|
||||||
animation: hideSweetAlert 0.2s; }
|
animation: hideSweetAlert 0.2s; }
|
||||||
|
.hideSweetAlert[data-animation=none] {
|
||||||
|
-webkit-animation: none;
|
||||||
|
animation: none; }
|
||||||
|
.hideSweetAlert[data-animation=slide-from-top] {
|
||||||
|
-webkit-animation: slideToTop 0.4s;
|
||||||
|
animation: slideToTop 0.4s; }
|
||||||
|
.hideSweetAlert[data-animation=slide-from-bottom] {
|
||||||
|
-webkit-animation: slideToBottom 0.3s;
|
||||||
|
animation: slideToBottom 0.3s; }
|
||||||
|
|
||||||
@-webkit-keyframes animateSuccessTip {
|
@-webkit-keyframes animateSuccessTip {
|
||||||
0% {
|
0% {
|
||||||
width: 0;
|
width: 0;
|
||||||
left: 1px;
|
left: 1px;
|
||||||
top: 19px; }
|
top: 19px; }
|
||||||
|
|
||||||
54% {
|
54% {
|
||||||
width: 0;
|
width: 0;
|
||||||
left: 1px;
|
left: 1px;
|
||||||
top: 19px; }
|
top: 19px; }
|
||||||
|
|
||||||
70% {
|
70% {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
left: -8px;
|
left: -8px;
|
||||||
top: 37px; }
|
top: 37px; }
|
||||||
|
|
||||||
84% {
|
84% {
|
||||||
width: 17px;
|
width: 17px;
|
||||||
left: 21px;
|
left: 21px;
|
||||||
top: 48px; }
|
top: 48px; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
left: 14px;
|
left: 14px;
|
||||||
top: 45px; } }
|
top: 45px; } }
|
||||||
@-moz-keyframes animateSuccessTip {
|
|
||||||
0% {
|
|
||||||
width: 0;
|
|
||||||
left: 1px;
|
|
||||||
top: 19px; }
|
|
||||||
54% {
|
|
||||||
width: 0;
|
|
||||||
left: 1px;
|
|
||||||
top: 19px; }
|
|
||||||
70% {
|
|
||||||
width: 50px;
|
|
||||||
left: -8px;
|
|
||||||
top: 37px; }
|
|
||||||
84% {
|
|
||||||
width: 17px;
|
|
||||||
left: 21px;
|
|
||||||
top: 48px; }
|
|
||||||
100% {
|
|
||||||
width: 25px;
|
|
||||||
left: 14px;
|
|
||||||
top: 45px; } }
|
|
||||||
@keyframes animateSuccessTip {
|
@keyframes animateSuccessTip {
|
||||||
0% {
|
0% {
|
||||||
width: 0;
|
width: 0;
|
||||||
left: 1px;
|
left: 1px;
|
||||||
top: 19px; }
|
top: 19px; }
|
||||||
|
|
||||||
54% {
|
54% {
|
||||||
width: 0;
|
width: 0;
|
||||||
left: 1px;
|
left: 1px;
|
||||||
top: 19px; }
|
top: 19px; }
|
||||||
|
|
||||||
70% {
|
70% {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
left: -8px;
|
left: -8px;
|
||||||
top: 37px; }
|
top: 37px; }
|
||||||
|
|
||||||
84% {
|
84% {
|
||||||
width: 17px;
|
width: 17px;
|
||||||
left: 21px;
|
left: 21px;
|
||||||
top: 48px; }
|
top: 48px; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
left: 14px;
|
left: 14px;
|
||||||
top: 45px; } }
|
top: 45px; } }
|
||||||
|
|
||||||
@-webkit-keyframes animateSuccessLong {
|
@-webkit-keyframes animateSuccessLong {
|
||||||
0% {
|
0% {
|
||||||
width: 0;
|
width: 0;
|
||||||
right: 46px;
|
right: 46px;
|
||||||
top: 54px; }
|
top: 54px; }
|
||||||
|
|
||||||
65% {
|
65% {
|
||||||
width: 0;
|
width: 0;
|
||||||
right: 46px;
|
right: 46px;
|
||||||
top: 54px; }
|
top: 54px; }
|
||||||
|
|
||||||
84% {
|
84% {
|
||||||
width: 55px;
|
width: 55px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
top: 35px; }
|
top: 35px; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
width: 47px;
|
width: 47px;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
top: 38px; } }
|
top: 38px; } }
|
||||||
@-moz-keyframes animateSuccessLong {
|
|
||||||
0% {
|
|
||||||
width: 0;
|
|
||||||
right: 46px;
|
|
||||||
top: 54px; }
|
|
||||||
65% {
|
|
||||||
width: 0;
|
|
||||||
right: 46px;
|
|
||||||
top: 54px; }
|
|
||||||
84% {
|
|
||||||
width: 55px;
|
|
||||||
right: 0px;
|
|
||||||
top: 35px; }
|
|
||||||
100% {
|
|
||||||
width: 47px;
|
|
||||||
right: 8px;
|
|
||||||
top: 38px; } }
|
|
||||||
@keyframes animateSuccessLong {
|
@keyframes animateSuccessLong {
|
||||||
0% {
|
0% {
|
||||||
width: 0;
|
width: 0;
|
||||||
right: 46px;
|
right: 46px;
|
||||||
top: 54px; }
|
top: 54px; }
|
||||||
|
|
||||||
65% {
|
65% {
|
||||||
width: 0;
|
width: 0;
|
||||||
right: 46px;
|
right: 46px;
|
||||||
top: 54px; }
|
top: 54px; }
|
||||||
|
|
||||||
84% {
|
84% {
|
||||||
width: 55px;
|
width: 55px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
top: 35px; }
|
top: 35px; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
width: 47px;
|
width: 47px;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
top: 38px; } }
|
top: 38px; } }
|
||||||
|
|
||||||
@-webkit-keyframes rotatePlaceholder {
|
@-webkit-keyframes rotatePlaceholder {
|
||||||
0% {
|
0% {
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
-webkit-transform: rotate(-45deg); }
|
-webkit-transform: rotate(-45deg); }
|
||||||
|
|
||||||
5% {
|
5% {
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
-webkit-transform: rotate(-45deg); }
|
-webkit-transform: rotate(-45deg); }
|
||||||
|
|
||||||
12% {
|
12% {
|
||||||
transform: rotate(-405deg);
|
transform: rotate(-405deg);
|
||||||
-webkit-transform: rotate(-405deg); }
|
-webkit-transform: rotate(-405deg); }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: rotate(-405deg);
|
transform: rotate(-405deg);
|
||||||
-webkit-transform: rotate(-405deg); } }
|
-webkit-transform: rotate(-405deg); } }
|
||||||
@-moz-keyframes rotatePlaceholder {
|
|
||||||
0% {
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
-webkit-transform: rotate(-45deg); }
|
|
||||||
5% {
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
-webkit-transform: rotate(-45deg); }
|
|
||||||
12% {
|
|
||||||
transform: rotate(-405deg);
|
|
||||||
-webkit-transform: rotate(-405deg); }
|
|
||||||
100% {
|
|
||||||
transform: rotate(-405deg);
|
|
||||||
-webkit-transform: rotate(-405deg); } }
|
|
||||||
@keyframes rotatePlaceholder {
|
@keyframes rotatePlaceholder {
|
||||||
0% {
|
0% {
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
-webkit-transform: rotate(-45deg); }
|
-webkit-transform: rotate(-45deg); }
|
||||||
|
|
||||||
5% {
|
5% {
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
-webkit-transform: rotate(-45deg); }
|
-webkit-transform: rotate(-45deg); }
|
||||||
|
|
||||||
12% {
|
12% {
|
||||||
transform: rotate(-405deg);
|
transform: rotate(-405deg);
|
||||||
-webkit-transform: rotate(-405deg); }
|
-webkit-transform: rotate(-405deg); }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: rotate(-405deg);
|
transform: rotate(-405deg);
|
||||||
-webkit-transform: rotate(-405deg); } }
|
-webkit-transform: rotate(-405deg); } }
|
||||||
|
|
||||||
.animateSuccessTip {
|
.animateSuccessTip {
|
||||||
-webkit-animation: animateSuccessTip 0.75s;
|
-webkit-animation: animateSuccessTip 0.75s;
|
||||||
-moz-animation: animateSuccessTip 0.75s;
|
|
||||||
animation: animateSuccessTip 0.75s; }
|
animation: animateSuccessTip 0.75s; }
|
||||||
|
|
||||||
.animateSuccessLong {
|
.animateSuccessLong {
|
||||||
-webkit-animation: animateSuccessLong 0.75s;
|
-webkit-animation: animateSuccessLong 0.75s;
|
||||||
-moz-animation: animateSuccessLong 0.75s;
|
|
||||||
animation: animateSuccessLong 0.75s; }
|
animation: animateSuccessLong 0.75s; }
|
||||||
|
|
||||||
.icon.success.animate::after {
|
.sa-icon.sa-success.animate::after {
|
||||||
-webkit-animation: rotatePlaceholder 4.25s ease-in;
|
-webkit-animation: rotatePlaceholder 4.25s ease-in;
|
||||||
-moz-animation: rotatePlaceholder 4.25s ease-in;
|
|
||||||
animation: rotatePlaceholder 4.25s ease-in; }
|
animation: rotatePlaceholder 4.25s ease-in; }
|
||||||
|
|
||||||
@-webkit-keyframes animateErrorIcon {
|
@-webkit-keyframes animateErrorIcon {
|
||||||
|
@ -461,31 +627,25 @@
|
||||||
transform: rotateX(100deg);
|
transform: rotateX(100deg);
|
||||||
-webkit-transform: rotateX(100deg);
|
-webkit-transform: rotateX(100deg);
|
||||||
opacity: 0; }
|
opacity: 0; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: rotateX(0deg);
|
transform: rotateX(0deg);
|
||||||
-webkit-transform: rotateX(0deg);
|
-webkit-transform: rotateX(0deg);
|
||||||
opacity: 1; } }
|
opacity: 1; } }
|
||||||
@-moz-keyframes animateErrorIcon {
|
|
||||||
0% {
|
|
||||||
transform: rotateX(100deg);
|
|
||||||
-webkit-transform: rotateX(100deg);
|
|
||||||
opacity: 0; }
|
|
||||||
100% {
|
|
||||||
transform: rotateX(0deg);
|
|
||||||
-webkit-transform: rotateX(0deg);
|
|
||||||
opacity: 1; } }
|
|
||||||
@keyframes animateErrorIcon {
|
@keyframes animateErrorIcon {
|
||||||
0% {
|
0% {
|
||||||
transform: rotateX(100deg);
|
transform: rotateX(100deg);
|
||||||
-webkit-transform: rotateX(100deg);
|
-webkit-transform: rotateX(100deg);
|
||||||
opacity: 0; }
|
opacity: 0; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: rotateX(0deg);
|
transform: rotateX(0deg);
|
||||||
-webkit-transform: rotateX(0deg);
|
-webkit-transform: rotateX(0deg);
|
||||||
opacity: 1; } }
|
opacity: 1; } }
|
||||||
|
|
||||||
.animateErrorIcon {
|
.animateErrorIcon {
|
||||||
-webkit-animation: animateErrorIcon 0.5s;
|
-webkit-animation: animateErrorIcon 0.5s;
|
||||||
-moz-animation: animateErrorIcon 0.5s;
|
|
||||||
animation: animateErrorIcon 0.5s; }
|
animation: animateErrorIcon 0.5s; }
|
||||||
|
|
||||||
@-webkit-keyframes animateXMark {
|
@-webkit-keyframes animateXMark {
|
||||||
|
@ -494,108 +654,104 @@
|
||||||
-webkit-transform: scale(0.4);
|
-webkit-transform: scale(0.4);
|
||||||
margin-top: 26px;
|
margin-top: 26px;
|
||||||
opacity: 0; }
|
opacity: 0; }
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
transform: scale(0.4);
|
transform: scale(0.4);
|
||||||
-webkit-transform: scale(0.4);
|
-webkit-transform: scale(0.4);
|
||||||
margin-top: 26px;
|
margin-top: 26px;
|
||||||
opacity: 0; }
|
opacity: 0; }
|
||||||
|
|
||||||
80% {
|
80% {
|
||||||
transform: scale(1.15);
|
transform: scale(1.15);
|
||||||
-webkit-transform: scale(1.15);
|
-webkit-transform: scale(1.15);
|
||||||
margin-top: -6px; }
|
margin-top: -6px; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
-webkit-transform: scale(1);
|
-webkit-transform: scale(1);
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
opacity: 1; } }
|
opacity: 1; } }
|
||||||
@-moz-keyframes animateXMark {
|
|
||||||
0% {
|
|
||||||
transform: scale(0.4);
|
|
||||||
-webkit-transform: scale(0.4);
|
|
||||||
margin-top: 26px;
|
|
||||||
opacity: 0; }
|
|
||||||
50% {
|
|
||||||
transform: scale(0.4);
|
|
||||||
-webkit-transform: scale(0.4);
|
|
||||||
margin-top: 26px;
|
|
||||||
opacity: 0; }
|
|
||||||
80% {
|
|
||||||
transform: scale(1.15);
|
|
||||||
-webkit-transform: scale(1.15);
|
|
||||||
margin-top: -6px; }
|
|
||||||
100% {
|
|
||||||
transform: scale(1);
|
|
||||||
-webkit-transform: scale(1);
|
|
||||||
margin-top: 0;
|
|
||||||
opacity: 1; } }
|
|
||||||
@keyframes animateXMark {
|
@keyframes animateXMark {
|
||||||
0% {
|
0% {
|
||||||
transform: scale(0.4);
|
transform: scale(0.4);
|
||||||
-webkit-transform: scale(0.4);
|
-webkit-transform: scale(0.4);
|
||||||
margin-top: 26px;
|
margin-top: 26px;
|
||||||
opacity: 0; }
|
opacity: 0; }
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
transform: scale(0.4);
|
transform: scale(0.4);
|
||||||
-webkit-transform: scale(0.4);
|
-webkit-transform: scale(0.4);
|
||||||
margin-top: 26px;
|
margin-top: 26px;
|
||||||
opacity: 0; }
|
opacity: 0; }
|
||||||
|
|
||||||
80% {
|
80% {
|
||||||
transform: scale(1.15);
|
transform: scale(1.15);
|
||||||
-webkit-transform: scale(1.15);
|
-webkit-transform: scale(1.15);
|
||||||
margin-top: -6px; }
|
margin-top: -6px; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
-webkit-transform: scale(1);
|
-webkit-transform: scale(1);
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
opacity: 1; } }
|
opacity: 1; } }
|
||||||
|
|
||||||
.animateXMark {
|
.animateXMark {
|
||||||
-webkit-animation: animateXMark 0.5s;
|
-webkit-animation: animateXMark 0.5s;
|
||||||
-moz-animation: animateXMark 0.5s;
|
|
||||||
animation: animateXMark 0.5s; }
|
animation: animateXMark 0.5s; }
|
||||||
|
|
||||||
/*@include keyframes(simpleRotate) {
|
|
||||||
0% { transform: rotateY(0deg); }
|
|
||||||
100% { transform: rotateY(-360deg); }
|
|
||||||
}
|
|
||||||
.simpleRotate {
|
|
||||||
@include animation('simpleRotate 0.75s');
|
|
||||||
}*/
|
|
||||||
@-webkit-keyframes pulseWarning {
|
@-webkit-keyframes pulseWarning {
|
||||||
0% {
|
0% {
|
||||||
border-color: #F8D486; }
|
border-color: #F8D486; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
border-color: #F8BB86; } }
|
border-color: #F8BB86; } }
|
||||||
@-moz-keyframes pulseWarning {
|
|
||||||
0% {
|
|
||||||
border-color: #F8D486; }
|
|
||||||
100% {
|
|
||||||
border-color: #F8BB86; } }
|
|
||||||
@keyframes pulseWarning {
|
@keyframes pulseWarning {
|
||||||
0% {
|
0% {
|
||||||
border-color: #F8D486; }
|
border-color: #F8D486; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
border-color: #F8BB86; } }
|
border-color: #F8BB86; } }
|
||||||
|
|
||||||
.pulseWarning {
|
.pulseWarning {
|
||||||
-webkit-animation: pulseWarning 0.75s infinite alternate;
|
-webkit-animation: pulseWarning 0.75s infinite alternate;
|
||||||
-moz-animation: pulseWarning 0.75s infinite alternate;
|
|
||||||
animation: pulseWarning 0.75s infinite alternate; }
|
animation: pulseWarning 0.75s infinite alternate; }
|
||||||
|
|
||||||
@-webkit-keyframes pulseWarningIns {
|
@-webkit-keyframes pulseWarningIns {
|
||||||
0% {
|
0% {
|
||||||
background-color: #F8D486; }
|
background-color: #F8D486; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
background-color: #F8BB86; } }
|
background-color: #F8BB86; } }
|
||||||
@-moz-keyframes pulseWarningIns {
|
|
||||||
0% {
|
|
||||||
background-color: #F8D486; }
|
|
||||||
100% {
|
|
||||||
background-color: #F8BB86; } }
|
|
||||||
@keyframes pulseWarningIns {
|
@keyframes pulseWarningIns {
|
||||||
0% {
|
0% {
|
||||||
background-color: #F8D486; }
|
background-color: #F8D486; }
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
background-color: #F8BB86; } }
|
background-color: #F8BB86; } }
|
||||||
|
|
||||||
.pulseWarningIns {
|
.pulseWarningIns {
|
||||||
-webkit-animation: pulseWarningIns 0.75s infinite alternate;
|
-webkit-animation: pulseWarningIns 0.75s infinite alternate;
|
||||||
-moz-animation: pulseWarningIns 0.75s infinite alternate;
|
|
||||||
animation: pulseWarningIns 0.75s infinite alternate; }
|
animation: pulseWarningIns 0.75s infinite alternate; }
|
||||||
|
|
||||||
|
/* Internet Explorer 9 has some special quirks that are fixed here */
|
||||||
|
/* The icons are not animated. */
|
||||||
|
/* This file is automatically merged into sweet-alert.min.js through Gulp */
|
||||||
|
/* Error icon */
|
||||||
|
.sweet-alert .sa-icon.sa-error .sa-line.sa-left {
|
||||||
|
-ms-transform: rotate(45deg) \9; }
|
||||||
|
|
||||||
|
.sweet-alert .sa-icon.sa-error .sa-line.sa-right {
|
||||||
|
-ms-transform: rotate(-45deg) \9; }
|
||||||
|
|
||||||
|
/* Success icon */
|
||||||
|
.sweet-alert .sa-icon.sa-success {
|
||||||
|
border-color: transparent\9; }
|
||||||
|
|
||||||
|
.sweet-alert .sa-icon.sa-success .sa-line.sa-tip {
|
||||||
|
-ms-transform: rotate(45deg) \9; }
|
||||||
|
|
||||||
|
.sweet-alert .sa-icon.sa-success .sa-line.sa-long {
|
||||||
|
-ms-transform: rotate(-45deg) \9; }
|
|
@ -3,10 +3,10 @@
|
||||||
<head>
|
<head>
|
||||||
<title>domain-server</title>
|
<title>domain-server</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||||
<link href="/css/style.css" rel="stylesheet" media="screen">
|
<link href="/css/style.css" rel="stylesheet" media="screen">
|
||||||
<link href="/css/sweet-alert.css" rel="stylesheet" media="screen">
|
<link href="/css/sweetalert.css" rel="stylesheet" media="screen">
|
||||||
<link href="/stats/css/json.human.css" rel="stylesheet" media="screen">
|
<link href="/stats/css/json.human.css" rel="stylesheet" media="screen">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="/">domain-server</a>
|
<a class="navbar-brand" href="/">domain-server</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
|
|
5
domain-server/resources/web/js/query-string.js
Normal file
5
domain-server/resources/web/js/query-string.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
function qs(key) {
|
||||||
|
key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, "\\$&"); // escape RegEx meta chars
|
||||||
|
var match = location.search.match(new RegExp("[?&]"+key+"=([^&]+)(&|$)"));
|
||||||
|
return match && decodeURIComponent(match[1].replace(/\+/g, " "));
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
var Settings = {
|
var Settings = {
|
||||||
showAdvanced: false,
|
showAdvanced: false,
|
||||||
|
METAVERSE_URL: 'https://metaverse.highfidelity.com',
|
||||||
ADVANCED_CLASS: 'advanced-setting',
|
ADVANCED_CLASS: 'advanced-setting',
|
||||||
TRIGGER_CHANGE_CLASS: 'trigger-change',
|
TRIGGER_CHANGE_CLASS: 'trigger-change',
|
||||||
DATA_ROW_CLASS: 'value-row',
|
DATA_ROW_CLASS: 'value-row',
|
||||||
|
@ -17,16 +18,24 @@ var Settings = {
|
||||||
ADD_DEL_BUTTONS_CLASSES: 'buttons add-del-buttons',
|
ADD_DEL_BUTTONS_CLASSES: 'buttons add-del-buttons',
|
||||||
REORDER_BUTTONS_CLASS: 'reorder-buttons',
|
REORDER_BUTTONS_CLASS: 'reorder-buttons',
|
||||||
REORDER_BUTTONS_CLASSES: 'buttons reorder-buttons',
|
REORDER_BUTTONS_CLASSES: 'buttons reorder-buttons',
|
||||||
NEW_ROW_CLASS: 'new-row'
|
NEW_ROW_CLASS: 'new-row',
|
||||||
|
CONNECT_ACCOUNT_BTN_ID: 'connect-account-btn',
|
||||||
|
DISCONNECT_ACCOUNT_BTN_ID: 'disconnect-account-btn',
|
||||||
|
CREATE_DOMAIN_ID_BTN_ID: 'create-domain-btn',
|
||||||
|
CHOOSE_DOMAIN_ID_BTN_ID: 'choose-domain-btn',
|
||||||
|
GET_TEMPORARY_NAME_BTN_ID: 'get-temp-name-btn',
|
||||||
|
DOMAIN_ID_SELECTOR: '[name="metaverse.id"]',
|
||||||
|
ACCESS_TOKEN_SELECTOR: '[name="metaverse.access_token"]',
|
||||||
|
PLACES_TABLE_ID: 'places-table',
|
||||||
|
FORM_ID: 'settings-form'
|
||||||
};
|
};
|
||||||
|
|
||||||
var viewHelpers = {
|
var viewHelpers = {
|
||||||
getFormGroup: function(keypath, setting, values, isAdvanced, isLocked) {
|
getFormGroup: function(keypath, setting, values, isAdvanced, isLocked) {
|
||||||
form_group = "<div class='form-group " + (isAdvanced ? Settings.ADVANCED_CLASS : "") + "'>";
|
form_group = "<div class='form-group " + (isAdvanced ? Settings.ADVANCED_CLASS : "") + "' data-keypath='" + keypath + "'>";
|
||||||
|
|
||||||
setting_value = _(values).valueForKeyPath(keypath);
|
setting_value = _(values).valueForKeyPath(keypath);
|
||||||
|
|
||||||
if (setting_value === undefined || setting_value === null) {
|
if (typeof setting_value == 'undefined' || setting_value === null) {
|
||||||
if (_.has(setting, 'default')) {
|
if (_.has(setting, 'default')) {
|
||||||
setting_value = setting.default;
|
setting_value = setting.default;
|
||||||
} else {
|
} else {
|
||||||
|
@ -39,9 +48,13 @@ var viewHelpers = {
|
||||||
label_class += ' locked';
|
label_class += ' locked';
|
||||||
}
|
}
|
||||||
|
|
||||||
common_attrs = " class='" + (setting.type !== 'checkbox' ? 'form-control' : '')
|
function common_attrs(extra_classes) {
|
||||||
+ " " + Settings.TRIGGER_CHANGE_CLASS + "' data-short-name='" + setting.name + "' name='" + keypath + "' "
|
extra_classes = (typeof extra_classes !== 'undefined' ? extra_classes : "");
|
||||||
+ "id='" + keypath + "'";
|
return " class='" + (setting.type !== 'checkbox' ? 'form-control' : '')
|
||||||
|
+ " " + Settings.TRIGGER_CHANGE_CLASS + " " + extra_classes + "' data-short-name='"
|
||||||
|
+ setting.name + "' name='" + keypath + "' "
|
||||||
|
+ "id='" + (typeof setting.html_id !== 'undefined' ? setting.html_id : keypath) + "'";
|
||||||
|
}
|
||||||
|
|
||||||
if (setting.type === 'checkbox') {
|
if (setting.type === 'checkbox') {
|
||||||
if (setting.label) {
|
if (setting.label) {
|
||||||
|
@ -49,7 +62,7 @@ var viewHelpers = {
|
||||||
}
|
}
|
||||||
form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>"
|
form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>"
|
||||||
form_group += "<label for='" + keypath + "'>"
|
form_group += "<label for='" + keypath + "'>"
|
||||||
form_group += "<input type='checkbox'" + common_attrs + (setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>"
|
form_group += "<input type='checkbox'" + common_attrs() + (setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>"
|
||||||
form_group += " " + setting.help + "</label>";
|
form_group += " " + setting.help + "</label>";
|
||||||
form_group += "</div>"
|
form_group += "</div>"
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,14 +85,29 @@ var viewHelpers = {
|
||||||
|
|
||||||
form_group += "</select>"
|
form_group += "</select>"
|
||||||
|
|
||||||
form_group += "<input type='hidden'" + common_attrs + "value='" + setting_value + "'>"
|
form_group += "<input type='hidden'" + common_attrs() + "value='" + setting_value + "'>"
|
||||||
|
} else if (input_type === 'button') {
|
||||||
|
// Is this a button that should link to something directly?
|
||||||
|
// If so, we use an anchor tag instead of a button tag
|
||||||
|
|
||||||
|
if (setting.href) {
|
||||||
|
form_group += "<a href='" + setting.href + "'style='display: block;' role='button'"
|
||||||
|
+ (isLocked ? " disabled" : "")
|
||||||
|
+ common_attrs("btn " + setting.classes) + " target='_blank'>"
|
||||||
|
+ setting.button_label + "</a>";
|
||||||
|
} else {
|
||||||
|
form_group += "<button " + common_attrs("btn " + setting.classes)
|
||||||
|
+ (isLocked ? " disabled" : "") + ">"
|
||||||
|
+ setting.button_label + "</button>";
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (input_type == 'integer') {
|
if (input_type == 'integer') {
|
||||||
input_type = "text"
|
input_type = "text"
|
||||||
}
|
}
|
||||||
|
|
||||||
form_group += "<input type='" + input_type + "'" + common_attrs +
|
form_group += "<input type='" + input_type + "'" + common_attrs() +
|
||||||
"placeholder='" + (_.has(setting, 'placeholder') ? setting.placeholder : "") +
|
"placeholder='" + (_.has(setting, 'placeholder') ? setting.placeholder : "") +
|
||||||
"' value='" + setting_value + "'" + (isLocked ? " disabled" : "") + "/>"
|
"' value='" + setting_value + "'" + (isLocked ? " disabled" : "") + "/>"
|
||||||
}
|
}
|
||||||
|
@ -112,71 +140,107 @@ $(document).ready(function(){
|
||||||
|
|
||||||
resizeFn();
|
resizeFn();
|
||||||
$(window).resize(resizeFn);
|
$(window).resize(resizeFn);
|
||||||
})
|
});
|
||||||
|
|
||||||
$('#settings-form').on('click', '.' + Settings.ADD_ROW_BUTTON_CLASS, function(){
|
$('#' + Settings.FORM_ID).on('click', '.' + Settings.ADD_ROW_BUTTON_CLASS, function(){
|
||||||
addTableRow(this);
|
addTableRow(this);
|
||||||
})
|
});
|
||||||
|
|
||||||
$('#settings-form').on('click', '.' + Settings.DEL_ROW_BUTTON_CLASS, function(){
|
$('#' + Settings.FORM_ID).on('click', '.' + Settings.DEL_ROW_BUTTON_CLASS, function(){
|
||||||
deleteTableRow(this);
|
deleteTableRow(this);
|
||||||
})
|
});
|
||||||
|
|
||||||
$('#settings-form').on('click', '.' + Settings.MOVE_UP_BUTTON_CLASS, function(){
|
$('#' + Settings.FORM_ID).on('click', '.' + Settings.MOVE_UP_BUTTON_CLASS, function(){
|
||||||
moveTableRow(this, true);
|
moveTableRow(this, true);
|
||||||
})
|
});
|
||||||
|
|
||||||
$('#settings-form').on('click', '.' + Settings.MOVE_DOWN_BUTTON_CLASS, function(){
|
$('#' + Settings.FORM_ID).on('click', '.' + Settings.MOVE_DOWN_BUTTON_CLASS, function(){
|
||||||
moveTableRow(this, false);
|
moveTableRow(this, false);
|
||||||
})
|
});
|
||||||
|
|
||||||
$('#settings-form').on('keypress', 'table input', function(e){
|
$('#' + Settings.FORM_ID).on('keyup', function(e){
|
||||||
|
var $target = $(e.target);
|
||||||
if (e.keyCode == 13) {
|
if (e.keyCode == 13) {
|
||||||
// capture enter in table input
|
if ($target.is('table input')) {
|
||||||
// if we have a sibling next to us that has an input, jump to it, otherwise check if we have a glyphicon for add to click
|
// capture enter in table input
|
||||||
sibling = $(this).parent('td').next();
|
// if we have a sibling next to us that has an input, jump to it, otherwise check if we have a glyphicon for add to click
|
||||||
|
sibling = $target.parent('td').next();
|
||||||
|
|
||||||
if (sibling.hasClass(Settings.DATA_COL_CLASS)) {
|
if (sibling.hasClass(Settings.DATA_COL_CLASS)) {
|
||||||
// set focus to next input
|
// set focus to next input
|
||||||
sibling.find('input').focus()
|
sibling.find('input').focus()
|
||||||
} else if (sibling.hasClass(Settings.ADD_DEL_BUTTONS_CLASS)) {
|
} else if (sibling.hasClass(Settings.ADD_DEL_BUTTONS_CLASS)) {
|
||||||
sibling.find('.' + Settings.ADD_ROW_BUTTON_CLASS).click()
|
sibling.find('.' + Settings.ADD_ROW_BUTTON_CLASS).click()
|
||||||
|
|
||||||
// set focus to the first input in the new row
|
// set focus to the first input in the new row
|
||||||
$(this).closest('table').find('tr.inputs input:first').focus()
|
$target.closest('table').find('tr.inputs input:first').focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ($target.is('input')) {
|
||||||
|
$target.change().blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#settings-form').on('change', '.' + Settings.TRIGGER_CHANGE_CLASS , function(){
|
$('#' + Settings.FORM_ID).on('keypress', function(e){
|
||||||
|
if (e.keyCode == 13) {
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#' + Settings.FORM_ID).on('change', '.' + Settings.TRIGGER_CHANGE_CLASS , function(){
|
||||||
// this input was changed, add the changed data attribute to it
|
// this input was changed, add the changed data attribute to it
|
||||||
$(this).attr('data-changed', true)
|
$(this).attr('data-changed', true)
|
||||||
|
|
||||||
badgeSidebarForDifferences($(this))
|
badgeSidebarForDifferences($(this))
|
||||||
})
|
})
|
||||||
|
|
||||||
$('#advanced-toggle-button').click(function(){
|
$('.advanced-toggle').click(function(){
|
||||||
Settings.showAdvanced = !Settings.showAdvanced
|
Settings.showAdvanced = !Settings.showAdvanced
|
||||||
var advancedSelector = $('.' + Settings.ADVANCED_CLASS)
|
var advancedSelector = $('.' + Settings.ADVANCED_CLASS)
|
||||||
|
|
||||||
if (Settings.showAdvanced) {
|
if (Settings.showAdvanced) {
|
||||||
advancedSelector.show()
|
advancedSelector.show();
|
||||||
$(this).html("Hide advanced")
|
$(this).html("Hide advanced")
|
||||||
} else {
|
} else {
|
||||||
advancedSelector.hide()
|
advancedSelector.hide();
|
||||||
$(this).html("Show advanced")
|
$(this).html("Show advanced")
|
||||||
}
|
}
|
||||||
|
|
||||||
$(this).blur()
|
$(this).blur();
|
||||||
})
|
})
|
||||||
|
|
||||||
$('#settings-form').on('click', '#choose-domain-btn', function(){
|
$('#' + Settings.FORM_ID).on('click', '#' + Settings.CREATE_DOMAIN_ID_BTN_ID, function(){
|
||||||
|
$(this).blur();
|
||||||
|
showDomainCreationAlert(false);
|
||||||
|
})
|
||||||
|
|
||||||
|
$('#' + Settings.FORM_ID).on('click', '#' + Settings.CHOOSE_DOMAIN_ID_BTN_ID, function(){
|
||||||
|
$(this).blur();
|
||||||
chooseFromHighFidelityDomains($(this))
|
chooseFromHighFidelityDomains($(this))
|
||||||
})
|
});
|
||||||
|
|
||||||
$('#settings-form').on('change', 'select', function(){
|
$('#' + Settings.FORM_ID).on('click', '#' + Settings.GET_TEMPORARY_NAME_BTN_ID, function(){
|
||||||
|
$(this).blur();
|
||||||
|
createTemporaryDomain();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$('#' + Settings.FORM_ID).on('change', 'select', function(){
|
||||||
$("input[name='" + $(this).attr('data-hidden-input') + "']").val($(this).val()).change()
|
$("input[name='" + $(this).attr('data-hidden-input') + "']").val($(this).val()).change()
|
||||||
})
|
});
|
||||||
|
|
||||||
|
$('#' + Settings.FORM_ID).on('click', '#' + Settings.DISCONNECT_ACCOUNT_BTN_ID, function(e){
|
||||||
|
disonnectHighFidelityAccount();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#' + Settings.FORM_ID).on('click', '#' + Settings.CONNECT_ACCOUNT_BTN_ID, function(e){
|
||||||
|
$(this).blur();
|
||||||
|
prepareAccessTokenPrompt();
|
||||||
|
});
|
||||||
|
|
||||||
var panelsSource = $('#panels-template').html()
|
var panelsSource = $('#panels-template').html()
|
||||||
Settings.panelsTemplate = _.template(panelsSource)
|
Settings.panelsTemplate = _.template(panelsSource)
|
||||||
|
@ -187,7 +251,460 @@ $(document).ready(function(){
|
||||||
// $('body').scrollspy({ target: '#setup-sidebar'})
|
// $('body').scrollspy({ target: '#setup-sidebar'})
|
||||||
|
|
||||||
reloadSettings();
|
reloadSettings();
|
||||||
})
|
});
|
||||||
|
|
||||||
|
function dynamicButton(button_id, text) {
|
||||||
|
return $("<button type='button' id='" + button_id + "' class='btn btn-primary'>" + text + "</button>");
|
||||||
|
}
|
||||||
|
|
||||||
|
function postSettings(jsonSettings) {
|
||||||
|
// POST the form JSON to the domain-server settings.json endpoint so the settings are saved
|
||||||
|
$.ajax('/settings.json', {
|
||||||
|
data: JSON.stringify(jsonSettings),
|
||||||
|
contentType: 'application/json',
|
||||||
|
type: 'POST'
|
||||||
|
}).done(function(data){
|
||||||
|
if (data.status == "success") {
|
||||||
|
showRestartModal();
|
||||||
|
} else {
|
||||||
|
showErrorMessage("Error", SETTINGS_ERROR_MESSAGE)
|
||||||
|
reloadSettings();
|
||||||
|
}
|
||||||
|
}).fail(function(){
|
||||||
|
showErrorMessage("Error", SETTINGS_ERROR_MESSAGE)
|
||||||
|
reloadSettings();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupHFAccountButton() {
|
||||||
|
// figure out how we should handle the HF connect button
|
||||||
|
var accessToken = Settings.data.values.metaverse.access_token;
|
||||||
|
|
||||||
|
// setup an object for the settings we want our button to have
|
||||||
|
var buttonSetting = {
|
||||||
|
type: 'button',
|
||||||
|
name: 'connected_account',
|
||||||
|
label: 'Connected Account',
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasAccessToken = accessToken.length > 0;
|
||||||
|
|
||||||
|
if (hasAccessToken) {
|
||||||
|
buttonSetting.help = "Click the button above to clear your OAuth token and disconnect your High Fidelity account.";
|
||||||
|
buttonSetting.classes = "btn-danger";
|
||||||
|
buttonSetting.button_label = "Disconnect High Fidelity Account";
|
||||||
|
buttonSetting.html_id = Settings.DISCONNECT_ACCOUNT_BTN_ID;
|
||||||
|
} else {
|
||||||
|
buttonSetting.help = "Click the button above to connect your High Fidelity account.";
|
||||||
|
buttonSetting.classes = "btn-primary";
|
||||||
|
buttonSetting.button_label = "Connect High Fidelity Account";
|
||||||
|
buttonSetting.html_id = Settings.CONNECT_ACCOUNT_BTN_ID;
|
||||||
|
|
||||||
|
buttonSetting.href = Settings.METAVERSE_URL + "/user/tokens/new?for_domain_server=true";
|
||||||
|
|
||||||
|
// since we do not have an access token we change hide domain ID and auto networking settings
|
||||||
|
// without an access token niether of them can do anything
|
||||||
|
$("[data-keypath='metaverse.id']").hide();
|
||||||
|
$("[data-keypath='metaverse.automatic_networking']").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenLocked = _(Settings.data).valueForKeyPath("locked.metaverse.access_token");
|
||||||
|
|
||||||
|
// use the existing getFormGroup helper to ask for a button
|
||||||
|
var buttonGroup = viewHelpers.getFormGroup('', buttonSetting, Settings.data.values, false, tokenLocked);
|
||||||
|
|
||||||
|
// add the button group to the top of the metaverse panel
|
||||||
|
$('#metaverse .panel-body').prepend(buttonGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disonnectHighFidelityAccount() {
|
||||||
|
// the user clicked on the disconnect account btn - give them a sweet alert to make sure this is what they want to do
|
||||||
|
swal({
|
||||||
|
title: "Are you sure?",
|
||||||
|
text: "This will remove your domain-server OAuth access token."
|
||||||
|
+ "</br></br>This could cause your domain to appear offline and no longer be reachable via any place names.",
|
||||||
|
type: "warning",
|
||||||
|
html: true,
|
||||||
|
showCancelButton: true,
|
||||||
|
}, function(){
|
||||||
|
// we need to post to settings to clear the access-token
|
||||||
|
$(Settings.ACCESS_TOKEN_SELECTOR).val('').change();
|
||||||
|
saveSettings();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareAccessTokenPrompt() {
|
||||||
|
swal({
|
||||||
|
title: "Connect Account",
|
||||||
|
type: "input",
|
||||||
|
text: "Paste your created access token here." +
|
||||||
|
"</br></br>If you did not successfully create an access token click cancel below and attempt to connect your account again.</br></br>",
|
||||||
|
showCancelButton: true,
|
||||||
|
closeOnConfirm: false,
|
||||||
|
html: true
|
||||||
|
}, function(inputValue){
|
||||||
|
if (inputValue === false) return false;
|
||||||
|
|
||||||
|
if (inputValue === "") {
|
||||||
|
swal.showInputError("Please paste your access token in the input field.")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have an input value - set the access token input with this and save settings
|
||||||
|
$(Settings.ACCESS_TOKEN_SELECTOR).val(inputValue).change();
|
||||||
|
|
||||||
|
// if the user doesn't have a domain ID set, give them the option to create one now
|
||||||
|
if (!Settings.data.values.metaverse.id) {
|
||||||
|
// show domain ID selection alert
|
||||||
|
showDomainIDChoiceAlert();
|
||||||
|
} else {
|
||||||
|
swal.close();
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDomainIDChoiceAlert() {
|
||||||
|
swal({
|
||||||
|
title: 'Domain ID',
|
||||||
|
type: 'info',
|
||||||
|
text: "You do not currently have a domain ID." +
|
||||||
|
"</br></br>This is required to point place names at your domain and to use automatic networking.</br></br>" +
|
||||||
|
"Would you like to create a domain ID via the Metaverse API?</br></br>",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Create new domain ID",
|
||||||
|
cancelButtonText: "Skip",
|
||||||
|
closeOnConfirm: false,
|
||||||
|
html: true
|
||||||
|
}, function(isConfirm){
|
||||||
|
if (isConfirm) {
|
||||||
|
// show the swal to create a new domain via API
|
||||||
|
showDomainCreationAlert(true);
|
||||||
|
} else {
|
||||||
|
// user cancelled, close this swal and save the access token we got
|
||||||
|
swal.close();
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSpinnerAlert(title) {
|
||||||
|
swal({
|
||||||
|
title: title,
|
||||||
|
text: '<div class="spinner" style="color:black;"><div class="bounce1"></div><div class="bounce2"></div><div class="bounce3"></div></div>',
|
||||||
|
html: true,
|
||||||
|
showConfirmButton: false,
|
||||||
|
allowEscapeKey: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDomainCreationAlert(justConnected) {
|
||||||
|
swal({
|
||||||
|
title: 'Create new domain ID',
|
||||||
|
type: 'input',
|
||||||
|
text: 'Enter a short description for this machine.</br></br>This will help you identify which domain ID belongs to which machine.</br></br>',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: "Create",
|
||||||
|
closeOnConfirm: false,
|
||||||
|
html: true
|
||||||
|
}, function(inputValue){
|
||||||
|
if (inputValue === false) {
|
||||||
|
swal.close();
|
||||||
|
|
||||||
|
// user cancelled domain ID creation - if we're supposed to save after cancel then save here
|
||||||
|
if (justConnected) {
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we're going to change the alert to a new one with a spinner while we create this domain
|
||||||
|
showSpinnerAlert('Creating domain ID');
|
||||||
|
createNewDomainID(inputValue, justConnected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNewDomainID(description, justConnected) {
|
||||||
|
// get the JSON object ready that we'll use to create a new domain
|
||||||
|
var domainJSON = {
|
||||||
|
"domain": {
|
||||||
|
"description": description
|
||||||
|
},
|
||||||
|
"access_token": $(Settings.ACCESS_TOKEN_SELECTOR).val()
|
||||||
|
}
|
||||||
|
|
||||||
|
$.post(Settings.METAVERSE_URL + "/api/v1/domains", domainJSON, function(data){
|
||||||
|
if (data.status == "success") {
|
||||||
|
// we successfully created a domain ID, set it on that field
|
||||||
|
var domainID = data.domain.id;
|
||||||
|
$(Settings.DOMAIN_ID_SELECTOR).val(domainID).change();
|
||||||
|
|
||||||
|
if (justConnected) {
|
||||||
|
var successText = "We connnected your High Fidelity account and created a new domain ID for this machine."
|
||||||
|
} else {
|
||||||
|
var successText = "We created a new domain ID for this machine."
|
||||||
|
}
|
||||||
|
|
||||||
|
successText += "</br></br>Click the button below to save your new settings and restart your domain-server.";
|
||||||
|
|
||||||
|
// show a sweet alert to say we are all finished up and that we need to save
|
||||||
|
swal({
|
||||||
|
title: 'Success!',
|
||||||
|
type: 'success',
|
||||||
|
text: successText,
|
||||||
|
html: true,
|
||||||
|
confirmButtonText: 'Save'
|
||||||
|
}, function(){
|
||||||
|
saveSettings();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).fail(function(){
|
||||||
|
|
||||||
|
var errorText = "There was a problem creating your new domain ID. Do you want to try again or";
|
||||||
|
|
||||||
|
if (justConnected) {
|
||||||
|
errorText += " just save your new access token?</br></br>You can always create a new domain ID later.";
|
||||||
|
} else {
|
||||||
|
errorText += " cancel?"
|
||||||
|
}
|
||||||
|
|
||||||
|
// we failed to create the new domain ID, show a sweet-alert that lets them try again or cancel
|
||||||
|
swal({
|
||||||
|
title: '',
|
||||||
|
type: 'error',
|
||||||
|
text: errorText,
|
||||||
|
html: true,
|
||||||
|
confirmButtonText: 'Try again',
|
||||||
|
showCancelButton: true,
|
||||||
|
closeOnConfirm: false
|
||||||
|
}, function(isConfirm){
|
||||||
|
if (isConfirm) {
|
||||||
|
// they want to try creating a domain ID again
|
||||||
|
showDomainCreationAlert(justConnected);
|
||||||
|
} else {
|
||||||
|
// they want to cancel
|
||||||
|
if (justConnected) {
|
||||||
|
// since they just connected we need to save the access token here
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupPlacesTable() {
|
||||||
|
// create a dummy table using our view helper
|
||||||
|
var placesTableSetting = {
|
||||||
|
type: 'table',
|
||||||
|
name: 'places',
|
||||||
|
label: 'Places',
|
||||||
|
html_id: Settings.PLACES_TABLE_ID,
|
||||||
|
help: "The following places currently point to this domain.</br>To point places to this domain, "
|
||||||
|
+ " go to the <a href='https://metaverse.highfidelity.com/user/places'>My Places</a> "
|
||||||
|
+ "page in your High Fidelity Metaverse account.",
|
||||||
|
read_only: true,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"label": "Name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "path",
|
||||||
|
"label": "Path"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "edit",
|
||||||
|
"label": "",
|
||||||
|
"class": "buttons"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a table for the places
|
||||||
|
var placesTableGroup = viewHelpers.getFormGroup('', placesTableSetting, Settings.data.values, false, false);
|
||||||
|
|
||||||
|
// append the places table in the right place
|
||||||
|
$('#places_paths .panel-body').prepend(placesTableGroup);
|
||||||
|
|
||||||
|
// do we have a domain ID?
|
||||||
|
if (Settings.data.values.metaverse.id.length > 0) {
|
||||||
|
// now, ask the API for what places, if any, point to this domain
|
||||||
|
reloadPlacesOrTemporaryName();
|
||||||
|
} else {
|
||||||
|
// we don't have a domain ID - add a button to offer the user a chance to get a temporary one
|
||||||
|
var temporaryPlaceButton = dynamicButton(Settings.GET_TEMPORARY_NAME_BTN_ID, 'Get a temporary place name');
|
||||||
|
$('#' + Settings.PLACES_TABLE_ID).after(temporaryPlaceButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeTableRow(name, path, isTemporary) {
|
||||||
|
var name_link = "<a href='hifi://" + name + "'>" + (isTemporary ? name + " (temporary)" : name) + "</a>";
|
||||||
|
|
||||||
|
if (isTemporary) {
|
||||||
|
var editColumn = "<td class='buttons'></td>";
|
||||||
|
} else {
|
||||||
|
var editColumn = "<td class='buttons'><a class='glyphicon glyphicon-pencil'"
|
||||||
|
+ " href='" + Settings.METAVERSE_URL + "/user/places/" + name + "/edit" + "'</a></td>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<tr><td>" + name_link + "</td><td>" + path + "</td>" + editColumn + "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeTableRowForPlaceObject(place) {
|
||||||
|
var placePathOrIndex = (place.path ? place.path : "/");
|
||||||
|
return placeTableRow(place.name, placePathOrIndex, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadPlacesOrTemporaryName() {
|
||||||
|
// we only need to do this if we have a current domain ID
|
||||||
|
var domainID = Settings.data.values.metaverse.id;
|
||||||
|
if (domainID.length > 0) {
|
||||||
|
var domainURL = Settings.METAVERSE_URL + "/api/v1/domains/" + domainID;
|
||||||
|
|
||||||
|
$.getJSON(domainURL, function(data){
|
||||||
|
// check if we have owner_places (for a real domain) or a name (for a temporary domain)
|
||||||
|
if (data.status == "success") {
|
||||||
|
if (data.domain.owner_places) {
|
||||||
|
// add a table row for each of these names
|
||||||
|
_.each(data.domain.owner_places, function(place){
|
||||||
|
$('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRowForPlaceObject(place));
|
||||||
|
});
|
||||||
|
} else if (data.domain.name) {
|
||||||
|
// add a table row for this temporary domain name
|
||||||
|
$('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRow(data.domain.name, '/', true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendDomainIDButtons() {
|
||||||
|
var domainIDInput = $(Settings.DOMAIN_ID_SELECTOR);
|
||||||
|
|
||||||
|
var createButton = dynamicButton(Settings.CREATE_DOMAIN_ID_BTN_ID, "Create new domain ID");
|
||||||
|
createButton.css('margin-top', '10px');
|
||||||
|
var chooseButton = dynamicButton(Settings.CHOOSE_DOMAIN_ID_BTN_ID, "Choose from my domains");
|
||||||
|
chooseButton.css('margin', '10px 0px 0px 10px');
|
||||||
|
|
||||||
|
domainIDInput.after(chooseButton);
|
||||||
|
domainIDInput.after(createButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
function chooseFromHighFidelityDomains(clickedButton) {
|
||||||
|
// setup the modal to help user pick their domain
|
||||||
|
if (Settings.initialValues.metaverse.access_token) {
|
||||||
|
|
||||||
|
// add a spinner to the choose button
|
||||||
|
clickedButton.html("Loading domains...")
|
||||||
|
clickedButton.attr('disabled', 'disabled')
|
||||||
|
|
||||||
|
// get a list of user domains from data-web
|
||||||
|
data_web_domains_url = Settings.METAVERSE_URL + "/api/v1/domains?access_token="
|
||||||
|
$.getJSON(data_web_domains_url + Settings.initialValues.metaverse.access_token, function(data){
|
||||||
|
|
||||||
|
modal_buttons = {
|
||||||
|
cancel: {
|
||||||
|
label: 'Cancel',
|
||||||
|
className: 'btn-default'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.data.domains.length) {
|
||||||
|
// setup a select box for the returned domains
|
||||||
|
modal_body = "<p>Choose the High Fidelity domain you want this domain-server to represent.<br/>This will set your domain ID on the settings page.</p>"
|
||||||
|
domain_select = $("<select id='domain-name-select' class='form-control'></select>")
|
||||||
|
_.each(data.data.domains, function(domain){
|
||||||
|
var domainString = "";
|
||||||
|
|
||||||
|
if (domain.description) {
|
||||||
|
domainString += '"' + domain.description + '" - ';
|
||||||
|
}
|
||||||
|
|
||||||
|
domainString += domain.id;
|
||||||
|
|
||||||
|
domain_select.append("<option value='" + domain.id + "'>" + domainString + "</option>");
|
||||||
|
})
|
||||||
|
modal_body += "<label for='domain-name-select'>Domains</label>" + domain_select[0].outerHTML
|
||||||
|
modal_buttons["success"] = {
|
||||||
|
label: 'Choose domain',
|
||||||
|
callback: function() {
|
||||||
|
domainID = $('#domain-name-select').val()
|
||||||
|
// set the domain ID on the form
|
||||||
|
$(Settings.DOMAIN_ID_SELECTOR).val(domainID).change();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
modal_buttons["success"] = {
|
||||||
|
label: 'Create new domain',
|
||||||
|
callback: function() {
|
||||||
|
window.open("https://metaverse.highfidelity.com/user/domains", '_blank');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modal_body = "<p>You do not have any domains in your High Fidelity account." +
|
||||||
|
"<br/><br/>Go to your domains page to create a new one. Once your domain is created re-open this dialog to select it.</p>"
|
||||||
|
}
|
||||||
|
|
||||||
|
bootbox.dialog({
|
||||||
|
title: "Choose matching domain",
|
||||||
|
message: modal_body,
|
||||||
|
buttons: modal_buttons
|
||||||
|
})
|
||||||
|
|
||||||
|
// remove the spinner from the choose button
|
||||||
|
clickedButton.html("Choose from my domains")
|
||||||
|
clickedButton.removeAttr('disabled')
|
||||||
|
})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
bootbox.alert({
|
||||||
|
message: "You must have an access token to query your High Fidelity domains.<br><br>" +
|
||||||
|
"Please follow the instructions on the settings page to add an access token.",
|
||||||
|
title: "Access token required"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTemporaryDomain() {
|
||||||
|
swal({
|
||||||
|
title: 'Create temporary place name',
|
||||||
|
text: "This will create a temporary place name and domain ID (valid for 30 days)"
|
||||||
|
+ " so other users can easily connect to your domain.</br></br>"
|
||||||
|
+ "In order to make your domain reachable, this will also enable full automatic networking.",
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'Create',
|
||||||
|
closeOnConfirm: false,
|
||||||
|
html: true
|
||||||
|
}, function(isConfirm){
|
||||||
|
if (isConfirm) {
|
||||||
|
showSpinnerAlert('Creating temporary place name');
|
||||||
|
|
||||||
|
// make a get request to get a temporary domain
|
||||||
|
$.post(Settings.METAVERSE_URL + '/api/v1/domains/temporary', function(data){
|
||||||
|
if (data.status == "success") {
|
||||||
|
var domain = data.data.domain;
|
||||||
|
|
||||||
|
// we should have a new domain ID - set it on the domain ID value
|
||||||
|
$(Settings.DOMAIN_ID_SELECTOR).val(domain.id).change();
|
||||||
|
|
||||||
|
// we also need to make sure auto networking is set to full
|
||||||
|
$('[data-hidden-input="metaverse.automatic_networking"]').val("full").change();
|
||||||
|
|
||||||
|
swal({
|
||||||
|
type: 'success',
|
||||||
|
title: 'Success!',
|
||||||
|
text: "We have created a temporary name and domain ID for you.</br></br>"
|
||||||
|
+ "Your temporary place name is <strong>" + domain.name + "</strong>.</br></br>"
|
||||||
|
+ "Press the button below to save your new settings and restart your domain-server.",
|
||||||
|
confirmButtonText: 'Save',
|
||||||
|
html: true
|
||||||
|
}, function(){
|
||||||
|
saveSettings();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function reloadSettings() {
|
function reloadSettings() {
|
||||||
$.getJSON('/settings.json', function(data){
|
$.getJSON('/settings.json', function(data){
|
||||||
|
@ -196,30 +713,32 @@ function reloadSettings() {
|
||||||
$('.nav-stacked').html(Settings.sidebarTemplate(data))
|
$('.nav-stacked').html(Settings.sidebarTemplate(data))
|
||||||
$('#panels').html(Settings.panelsTemplate(data))
|
$('#panels').html(Settings.panelsTemplate(data))
|
||||||
|
|
||||||
|
Settings.data = data;
|
||||||
Settings.initialValues = form2js('settings-form', ".", false, cleanupFormValues, true);
|
Settings.initialValues = form2js('settings-form', ".", false, cleanupFormValues, true);
|
||||||
|
|
||||||
|
if (!_.has(data["locked"], "metaverse") && !_.has(data["locked"]["metaverse"], "id")) {
|
||||||
|
// append the domain selection modal, as long as it's not locked
|
||||||
|
appendDomainIDButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call our method to setup the HF account button
|
||||||
|
setupHFAccountButton();
|
||||||
|
|
||||||
|
// call our method to setup the place names table
|
||||||
|
setupPlacesTable();
|
||||||
|
|
||||||
// add tooltip to locked settings
|
// add tooltip to locked settings
|
||||||
$('label.locked').tooltip({
|
$('label.locked').tooltip({
|
||||||
placement: 'right',
|
placement: 'right',
|
||||||
title: 'This setting is in the master config file and cannot be changed'
|
title: 'This setting is in the master config file and cannot be changed'
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!_.has(data["locked"], "metaverse") && !_.has(data["locked"]["metaverse"], "id")) {
|
|
||||||
// append the domain selection modal, as long as it's not locked
|
|
||||||
appendDomainSelectionModal()
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendDomainSelectionModal() {
|
|
||||||
var metaverseInput = $("[name='metaverse.id']");
|
|
||||||
var chooseButton = $("<button type='button' id='choose-domain-btn' class='btn btn-primary' style='margin-top:10px'>Choose ID from my domains</button>");
|
|
||||||
metaverseInput.after(chooseButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
var SETTINGS_ERROR_MESSAGE = "There was a problem saving domain settings. Please try again!";
|
var SETTINGS_ERROR_MESSAGE = "There was a problem saving domain settings. Please try again!";
|
||||||
|
|
||||||
$('body').on('click', '.save-button', function(e){
|
function saveSettings() {
|
||||||
// disable any inputs not changed
|
// disable any inputs not changed
|
||||||
$("input:not([data-changed])").each(function(){
|
$("input:not([data-changed])").each(function(){
|
||||||
$(this).prop('disabled', true);
|
$(this).prop('disabled', true);
|
||||||
|
@ -236,25 +755,14 @@ $('body').on('click', '.save-button', function(e){
|
||||||
});
|
});
|
||||||
|
|
||||||
// remove focus from the button
|
// remove focus from the button
|
||||||
$(this).blur()
|
$(this).blur();
|
||||||
|
|
||||||
// POST the form JSON to the domain-server settings.json endpoint so the settings are saved
|
// POST the form JSON to the domain-server settings.json endpoint so the settings are saved
|
||||||
$.ajax('/settings.json', {
|
postSettings(formJSON);
|
||||||
data: JSON.stringify(formJSON),
|
}
|
||||||
contentType: 'application/json',
|
|
||||||
type: 'POST'
|
|
||||||
}).done(function(data){
|
|
||||||
if (data.status == "success") {
|
|
||||||
showRestartModal();
|
|
||||||
} else {
|
|
||||||
showErrorMessage("Error", SETTINGS_ERROR_MESSAGE)
|
|
||||||
reloadSettings();
|
|
||||||
}
|
|
||||||
}).fail(function(){
|
|
||||||
showErrorMessage("Error", SETTINGS_ERROR_MESSAGE)
|
|
||||||
reloadSettings();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
$('body').on('click', '.save-button', function(e){
|
||||||
|
saveSettings();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -272,7 +780,7 @@ function makeTable(setting, keypath, setting_value, isLocked) {
|
||||||
}
|
}
|
||||||
|
|
||||||
html += "<table class='table table-bordered " + (isLocked ? "locked-table" : "") + "' data-short-name='" + setting.name
|
html += "<table class='table table-bordered " + (isLocked ? "locked-table" : "") + "' data-short-name='" + setting.name
|
||||||
+ "' name='" + keypath + "' data-setting-type='" + (isArray ? 'array' : 'hash') + "'>"
|
+ "' name='" + keypath + "' id='" + setting.html_id + "' data-setting-type='" + (isArray ? 'array' : 'hash') + "'>";
|
||||||
|
|
||||||
// Column names
|
// Column names
|
||||||
html += "<tr class='headers'>"
|
html += "<tr class='headers'>"
|
||||||
|
@ -286,66 +794,68 @@ function makeTable(setting, keypath, setting_value, isLocked) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_.each(setting.columns, function(col) {
|
_.each(setting.columns, function(col) {
|
||||||
html += "<td class='data'><strong>" + col.label + "</strong></td>" // Data
|
html += "<td class='data " + (col.class ? col.class : '') + "'><strong>" + col.label + "</strong></td>" // Data
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!isLocked) {
|
if (!isLocked && !setting.read_only) {
|
||||||
if (setting.can_order) {
|
if (setting.can_order) {
|
||||||
html += "<td class=" + Settings.REORDER_BUTTONS_CLASSES +
|
html += "<td class=" + Settings.REORDER_BUTTONS_CLASSES +
|
||||||
"><span class='glyphicon glyphicon-sort'></span></td>";
|
"><a href='javascript:void(0);' class='glyphicon glyphicon-sort'></a></td>";
|
||||||
}
|
}
|
||||||
html += "<td class=" + Settings.ADD_DEL_BUTTONS_CLASSES + "></td></tr>"
|
html += "<td class='" + Settings.ADD_DEL_BUTTONS_CLASSES + "'></td></tr>"
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate rows in the table from existing values
|
// populate rows in the table from existing values
|
||||||
var row_num = 1
|
var row_num = 1;
|
||||||
|
|
||||||
_.each(setting_value, function(row, indexOrName) {
|
if (keypath.length > 0 && _.size(setting_value) > 0) {
|
||||||
html += "<tr class='" + Settings.DATA_ROW_CLASS + "'" + (isArray ? "" : "name='" + keypath + "." + indexOrName + "'") + ">"
|
_.each(setting_value, function(row, indexOrName) {
|
||||||
|
html += "<tr class='" + Settings.DATA_ROW_CLASS + "'" + (isArray ? "" : "name='" + keypath + "." + indexOrName + "'") + ">"
|
||||||
|
|
||||||
if (setting.numbered === true) {
|
if (setting.numbered === true) {
|
||||||
html += "<td class='numbered'>" + row_num + "</td>"
|
html += "<td class='numbered'>" + row_num + "</td>"
|
||||||
}
|
|
||||||
|
|
||||||
if (setting.key) {
|
|
||||||
html += "<td class='key'>" + indexOrName + "</td>"
|
|
||||||
}
|
|
||||||
|
|
||||||
_.each(setting.columns, function(col) {
|
|
||||||
html += "<td class='" + Settings.DATA_COL_CLASS + "'>"
|
|
||||||
|
|
||||||
if (isArray) {
|
|
||||||
rowIsObject = setting.columns.length > 1
|
|
||||||
colValue = rowIsObject ? row[col.name] : row
|
|
||||||
html += colValue
|
|
||||||
|
|
||||||
// for arrays we add a hidden input to this td so that values can be posted appropriately
|
|
||||||
html += "<input type='hidden' name='" + keypath + "[" + indexOrName + "]"
|
|
||||||
+ (rowIsObject ? "." + col.name : "") + "' value='" + colValue + "'/>"
|
|
||||||
} else if (row.hasOwnProperty(col.name)) {
|
|
||||||
html += row[col.name]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html += "</td>"
|
if (setting.key) {
|
||||||
})
|
html += "<td class='key'>" + indexOrName + "</td>"
|
||||||
|
|
||||||
if (!isLocked) {
|
|
||||||
if (setting.can_order) {
|
|
||||||
html += "<td class='" + Settings.REORDER_BUTTONS_CLASSES+
|
|
||||||
"'><span class='" + Settings.MOVE_UP_SPAN_CLASSES + "'></span><span class='" +
|
|
||||||
Settings.MOVE_DOWN_SPAN_CLASSES + "'></span></td>"
|
|
||||||
}
|
}
|
||||||
html += "<td class='" + Settings.ADD_DEL_BUTTONS_CLASSES +
|
|
||||||
"'><span class='" + Settings.DEL_ROW_SPAN_CLASSES + "'></span></td>"
|
|
||||||
}
|
|
||||||
|
|
||||||
html += "</tr>"
|
_.each(setting.columns, function(col) {
|
||||||
|
html += "<td class='" + Settings.DATA_COL_CLASS + "'>"
|
||||||
|
|
||||||
row_num++
|
if (isArray) {
|
||||||
})
|
rowIsObject = setting.columns.length > 1
|
||||||
|
colValue = rowIsObject ? row[col.name] : row
|
||||||
|
html += colValue
|
||||||
|
|
||||||
|
// for arrays we add a hidden input to this td so that values can be posted appropriately
|
||||||
|
html += "<input type='hidden' name='" + keypath + "[" + indexOrName + "]"
|
||||||
|
+ (rowIsObject ? "." + col.name : "") + "' value='" + colValue + "'/>"
|
||||||
|
} else if (row.hasOwnProperty(col.name)) {
|
||||||
|
html += row[col.name]
|
||||||
|
}
|
||||||
|
|
||||||
|
html += "</td>"
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!isLocked && !setting.read_only) {
|
||||||
|
if (setting.can_order) {
|
||||||
|
html += "<td class='" + Settings.REORDER_BUTTONS_CLASSES+
|
||||||
|
"'><a href='javascript:void(0);' class='" + Settings.MOVE_UP_SPAN_CLASSES + "'></a>"
|
||||||
|
+ "<a href='javascript:void(0);' class='" + Settings.MOVE_DOWN_SPAN_CLASSES + "'></a></td>"
|
||||||
|
}
|
||||||
|
html += "<td class='" + Settings.ADD_DEL_BUTTONS_CLASSES +
|
||||||
|
"'><a href='javascript:void(0);' class='" + Settings.DEL_ROW_SPAN_CLASSES + "'></a></td>"
|
||||||
|
}
|
||||||
|
|
||||||
|
html += "</tr>"
|
||||||
|
|
||||||
|
row_num++
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// populate inputs in the table for new values
|
// populate inputs in the table for new values
|
||||||
if (!isLocked) {
|
if (!isLocked && !setting.read_only) {
|
||||||
html += makeTableInputs(setting)
|
html += makeTableInputs(setting)
|
||||||
}
|
}
|
||||||
html += "</table>"
|
html += "</table>"
|
||||||
|
@ -377,7 +887,7 @@ function makeTableInputs(setting) {
|
||||||
html += "<td class='" + Settings.REORDER_BUTTONS_CLASSES + "'></td>"
|
html += "<td class='" + Settings.REORDER_BUTTONS_CLASSES + "'></td>"
|
||||||
}
|
}
|
||||||
html += "<td class='" + Settings.ADD_DEL_BUTTONS_CLASSES +
|
html += "<td class='" + Settings.ADD_DEL_BUTTONS_CLASSES +
|
||||||
"'><span class='glyphicon glyphicon-plus " + Settings.ADD_ROW_BUTTON_CLASS + "'></span></td>"
|
"'><a href='javascript:void(0);' class='glyphicon glyphicon-plus " + Settings.ADD_ROW_BUTTON_CLASS + "'></a></td>"
|
||||||
html += "</tr>"
|
html += "</tr>"
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
@ -385,10 +895,10 @@ function makeTableInputs(setting) {
|
||||||
|
|
||||||
function badgeSidebarForDifferences(changedElement) {
|
function badgeSidebarForDifferences(changedElement) {
|
||||||
// figure out which group this input is in
|
// figure out which group this input is in
|
||||||
var panelParentID = changedElement.closest('.panel').attr('id')
|
var panelParentID = changedElement.closest('.panel').attr('id');
|
||||||
|
|
||||||
// if the panel contains non-grouped settings, the initial value is Settings.initialValues
|
// if the panel contains non-grouped settings, the initial value is Settings.initialValues
|
||||||
var isGrouped = $(panelParentID).hasClass('grouped');
|
var isGrouped = $('#' + panelParentID).hasClass('grouped');
|
||||||
|
|
||||||
if (isGrouped) {
|
if (isGrouped) {
|
||||||
var initialPanelJSON = Settings.initialValues[panelParentID];
|
var initialPanelJSON = Settings.initialValues[panelParentID];
|
||||||
|
@ -483,13 +993,14 @@ function addTableRow(add_glyphicon) {
|
||||||
$(element).html(1)
|
$(element).html(1)
|
||||||
}
|
}
|
||||||
} else if ($(element).hasClass(Settings.REORDER_BUTTONS_CLASS)) {
|
} else if ($(element).hasClass(Settings.REORDER_BUTTONS_CLASS)) {
|
||||||
$(element).html("<td class='" + Settings.REORDER_BUTTONS_CLASSES + "'><span class='" + Settings.MOVE_UP_SPAN_CLASSES +
|
$(element).html("<td class='" + Settings.REORDER_BUTTONS_CLASSES + "'><a href='javascript:void(0);'"
|
||||||
"'></span><span class='" + Settings.MOVE_DOWN_SPAN_CLASSES + "'></span></td>")
|
+ " class='" + Settings.MOVE_UP_SPAN_CLASSES + "'></a><a href='javascript:void(0);' class='"
|
||||||
|
+ Settings.MOVE_DOWN_SPAN_CLASSES + "'></span></td>")
|
||||||
} else if ($(element).hasClass(Settings.ADD_DEL_BUTTONS_CLASS)) {
|
} else if ($(element).hasClass(Settings.ADD_DEL_BUTTONS_CLASS)) {
|
||||||
// Change buttons
|
// Change buttons
|
||||||
var span = $(element).children("span")
|
var anchor = $(element).children("a")
|
||||||
span.removeClass(Settings.ADD_ROW_SPAN_CLASSES)
|
anchor.removeClass(Settings.ADD_ROW_SPAN_CLASSES)
|
||||||
span.addClass(Settings.DEL_ROW_SPAN_CLASSES)
|
anchor.addClass(Settings.DEL_ROW_SPAN_CLASSES)
|
||||||
} else if ($(element).hasClass("key")) {
|
} else if ($(element).hasClass("key")) {
|
||||||
var input = $(element).children("input")
|
var input = $(element).children("input")
|
||||||
$(element).html(input.val())
|
$(element).html(input.val())
|
||||||
|
@ -658,70 +1169,3 @@ function cleanupFormValues(node) {
|
||||||
function showErrorMessage(title, message) {
|
function showErrorMessage(title, message) {
|
||||||
swal(title, message)
|
swal(title, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
function chooseFromHighFidelityDomains(clickedButton) {
|
|
||||||
// setup the modal to help user pick their domain
|
|
||||||
if (Settings.initialValues.metaverse.access_token) {
|
|
||||||
|
|
||||||
// add a spinner to the choose button
|
|
||||||
clickedButton.html("Loading domains...")
|
|
||||||
clickedButton.attr('disabled', 'disabled')
|
|
||||||
|
|
||||||
// get a list of user domains from data-web
|
|
||||||
data_web_domains_url = "https://metaverse.highfidelity.com/api/v1/domains?access_token="
|
|
||||||
$.getJSON(data_web_domains_url + Settings.initialValues.metaverse.access_token, function(data){
|
|
||||||
|
|
||||||
modal_buttons = {
|
|
||||||
cancel: {
|
|
||||||
label: 'Cancel',
|
|
||||||
className: 'btn-default'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.data.domains.length) {
|
|
||||||
// setup a select box for the returned domains
|
|
||||||
modal_body = "<p>Choose the High Fidelity domain you want this domain-server to represent.<br/>This will set your domain ID on the settings page.</p>"
|
|
||||||
domain_select = $("<select id='domain-name-select' class='form-control'></select>")
|
|
||||||
_.each(data.data.domains, function(domain){
|
|
||||||
domain_select.append("<option value='" + domain.id + "'>(" + domain.id + ")" + (domain.names.length > 0 ? " [" + domain.names + "]" : "") + "</option>");
|
|
||||||
})
|
|
||||||
modal_body += "<label for='domain-name-select'>Domains</label>" + domain_select[0].outerHTML
|
|
||||||
modal_buttons["success"] = {
|
|
||||||
label: 'Choose domain',
|
|
||||||
callback: function() {
|
|
||||||
domainID = $('#domain-name-select').val()
|
|
||||||
// set the domain ID on the form
|
|
||||||
$("[name='metaverse.id']").val(domainID).change();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
modal_buttons["success"] = {
|
|
||||||
label: 'Create new domain',
|
|
||||||
callback: function() {
|
|
||||||
window.open("https://metaverse.highfidelity.com/user/domains", '_blank');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
modal_body = "<p>You do not have any domains in your High Fidelity account." +
|
|
||||||
"<br/><br/>Go to your domains page to create a new one. Once your domain is created re-open this dialog to select it.</p>"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bootbox.dialog({
|
|
||||||
title: "Choose matching domain",
|
|
||||||
message: modal_body,
|
|
||||||
buttons: modal_buttons
|
|
||||||
})
|
|
||||||
|
|
||||||
// remove the spinner from the choose button
|
|
||||||
clickedButton.html("Choose from my domains")
|
|
||||||
clickedButton.removeAttr('disabled')
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
|
||||||
bootbox.alert({
|
|
||||||
message: "You must have an access token to query your High Fidelity domains.<br><br>" +
|
|
||||||
"Please follow the instructions on the settings page to add an access token.",
|
|
||||||
title: "Access token required"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
$(document).ready(function(){
|
|
||||||
/*
|
|
||||||
* Clamped-width.
|
|
||||||
* Usage:
|
|
||||||
* <div data-clampedwidth=".myParent">This long content will force clamped width</div>
|
|
||||||
*
|
|
||||||
* Author: LV
|
|
||||||
*/
|
|
||||||
|
|
||||||
$('[data-clampedwidth]').each(function () {
|
|
||||||
var elem = $(this);
|
|
||||||
var parentPanel = elem.data('clampedwidth');
|
|
||||||
var resizeFn = function () {
|
|
||||||
var sideBarNavWidth = $(parentPanel).width() - parseInt(elem.css('paddingLeft')) - parseInt(elem.css('paddingRight')) - parseInt(elem.css('marginLeft')) - parseInt(elem.css('marginRight')) - parseInt(elem.css('borderLeftWidth')) - parseInt(elem.css('borderRightWidth'));
|
|
||||||
elem.css('width', sideBarNavWidth);
|
|
||||||
};
|
|
||||||
|
|
||||||
resizeFn();
|
|
||||||
$(window).resize(resizeFn);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var listSource = $('#list-group-template').html();
|
|
||||||
var listTemplate = _.template(listSource);
|
|
||||||
|
|
||||||
reloadSettings();
|
|
||||||
|
|
||||||
function reloadSettings() {
|
|
||||||
$.getJSON('describe-setup.json', function(data){
|
|
||||||
$('.list-group').html(listTemplate(data));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
File diff suppressed because one or more lines are too long
1
domain-server/resources/web/js/sweetalert.min.js
vendored
Executable file
1
domain-server/resources/web/js/sweetalert.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
|
@ -1,75 +1,80 @@
|
||||||
<!--#include virtual="header.html"-->
|
<!--#include virtual="header.html"-->
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-10 col-md-offset-1">
|
<div class="col-md-10 col-md-offset-1">
|
||||||
<div class="col-md-12">
|
<div class="row">
|
||||||
<div class="alert" style="display:none;"></div>
|
<div class="col-md-12">
|
||||||
</div>
|
<div class="alert" style="display:none;"></div>
|
||||||
|
|
||||||
<div class="col-md-3 col-sm-3" id="setup-sidebar-col">
|
|
||||||
<div id="setup-sidebar" data-clampedwidth="#setup-sidebar-col" class="hidden-xs" data-spy="affix" data-offset-top="55">
|
|
||||||
<script id="list-group-template" type="text/template">
|
|
||||||
<% _.each(descriptions, function(group){ %>
|
|
||||||
<% panelID = group.name ? group.name : group.label %>
|
|
||||||
<li>
|
|
||||||
<a href="#<%- panelID %>" class="list-group-item">
|
|
||||||
<span class="badge"></span>
|
|
||||||
<%- group.label %>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<% }); %>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<ul class="nav nav-pills nav-stacked">
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<button id="advanced-toggle-button" hidden=true class="btn btn-info">Show advanced</button>
|
|
||||||
<button class="btn btn-success save-button">Save and restart</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-9 col-sm-9 col-xs-12">
|
<div class="row">
|
||||||
<form id="settings-form" role="form">
|
<div class="col-md-3 col-sm-3" id="setup-sidebar-col">
|
||||||
|
<div id="setup-sidebar" class="hidden-xs" data-spy="affix" data-offset-top="55" data-clampedwidth="#setup-sidebar-col">
|
||||||
|
<script id="list-group-template" type="text/template">
|
||||||
|
<% _.each(descriptions, function(group){ %>
|
||||||
|
<% panelID = group.name ? group.name : group.label %>
|
||||||
|
<li>
|
||||||
|
<a href="#<%- panelID %>" class="list-group-item">
|
||||||
|
<span class="badge"></span>
|
||||||
|
<%- group.label %>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<% }); %>
|
||||||
|
</script>
|
||||||
|
|
||||||
<script id="panels-template" type="text/template">
|
<ul class="nav nav-pills nav-stacked">
|
||||||
<% _.each(descriptions, function(group){ %>
|
</ul>
|
||||||
<% split_settings = _.partition(group.settings, function(value, index) { return !value.advanced }) %>
|
|
||||||
<% isAdvanced = _.isEmpty(split_settings[0]) %>
|
|
||||||
<% if (isAdvanced) { %>
|
|
||||||
<% $("a[href=#" + group.name + "]").addClass('advanced-setting').hide() %>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<% isGrouped = !!group.name %>
|
<button id="advanced-toggle-button" hidden=true class="btn btn-info advanced-toggle">Show advanced</button>
|
||||||
<% panelID = isGrouped ? group.name : group.label %>
|
<button class="btn btn-success save-button">Save and restart</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-default<%- (isAdvanced) ? ' advanced-setting' : '' %><%- (isGrouped) ? ' grouped' : '' %>"
|
<div class="col-md-9 col-sm-9 col-xs-12">
|
||||||
id="<%- panelID %>">
|
<div id="xs-advanced-container" class="col-xs-12 hidden-sm hidden-md hidden-lg">
|
||||||
<div class="panel-heading">
|
<button id="advanced-toggle-button-xs" class="btn btn-info advanced-toggle">Show advanced</button>
|
||||||
<h3 class="panel-title"><%- group.label %></h3>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
<div class="col-xs-12">
|
||||||
<% _.each(split_settings[0], function(setting) { %>
|
<form id="settings-form" role="form">
|
||||||
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
|
||||||
<%= getFormGroup(keypath, setting, values, false,
|
<script id="panels-template" type="text/template">
|
||||||
(_.has(locked, group.name) && _.has(locked[group.name], setting.name))) %>
|
<% _.each(descriptions, function(group){ %>
|
||||||
<% }); %>
|
<% split_settings = _.partition(group.settings, function(value, index) { return !value.advanced }) %>
|
||||||
<% if (!_.isEmpty(split_settings[1])) { %>
|
<% isAdvanced = _.isEmpty(split_settings[0]) %>
|
||||||
<% $("#advanced-toggle-button").show() %>
|
<% if (isAdvanced) { %>
|
||||||
<% _.each(split_settings[1], function(setting) { %>
|
<% $("a[href=#" + group.name + "]").addClass('advanced-setting').hide() %>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% isGrouped = !!group.name %>
|
||||||
|
<% panelID = isGrouped ? group.name : group.html_id %>
|
||||||
|
|
||||||
|
<div class="panel panel-default<%- (isAdvanced) ? ' advanced-setting' : '' %><%- (isGrouped) ? ' grouped' : '' %>"
|
||||||
|
id="<%- panelID %>">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title"><%- group.label %></h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<% _.each(split_settings[0], function(setting) { %>
|
||||||
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
||||||
<%= getFormGroup(keypath, setting, values, true,
|
<%= getFormGroup(keypath, setting, values, false,
|
||||||
(_.has(locked, group.name) && _.has(locked[group.name], setting.name))) %>
|
(_.has(locked, group.name) && _.has(locked[group.name], setting.name))) %>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
<% }%>
|
<% if (!_.isEmpty(split_settings[1])) { %>
|
||||||
|
<% $("#advanced-toggle-button").show() %>
|
||||||
|
<% _.each(split_settings[1], function(setting) { %>
|
||||||
|
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
||||||
|
<%= getFormGroup(keypath, setting, values, true,
|
||||||
|
(_.has(locked, group.name) && _.has(locked[group.name], setting.name))) %>
|
||||||
|
<% }); %>
|
||||||
|
<% }%>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<% }); %>
|
||||||
|
</script>
|
||||||
<% }); %>
|
<div id="panels"></div>
|
||||||
</script>
|
</form>
|
||||||
|
</div>
|
||||||
<div id="panels"></div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-12 hidden-sm hidden-md hidden-lg">
|
<div class="col-xs-12 hidden-sm hidden-md hidden-lg">
|
||||||
|
@ -94,7 +99,7 @@
|
||||||
<script src='/js/underscore-min.js'></script>
|
<script src='/js/underscore-min.js'></script>
|
||||||
<script src='/js/underscore-keypath.min.js'></script>
|
<script src='/js/underscore-keypath.min.js'></script>
|
||||||
<script src='/js/bootbox.min.js'></script>
|
<script src='/js/bootbox.min.js'></script>
|
||||||
<script src='/js/sweet-alert.min.js'></script>
|
<script src='/js/sweetalert.min.js'></script>
|
||||||
<script src='/js/settings.js'></script>
|
<script src='/js/settings.js'></script>
|
||||||
<script src='/js/form2js.min.js'></script>
|
<script src='/js/form2js.min.js'></script>
|
||||||
<!--#include virtual="page-end.html"-->
|
<!--#include virtual="page-end.html"-->
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12" id="stats-container"></div>
|
<div class="col-xs-12" id="stats-container"></div>
|
||||||
<!--#include virtual="footer.html"-->
|
<!--#include virtual="footer.html"-->
|
||||||
|
<script src='/js/query-string.js'></script>
|
||||||
<script src='js/stats.js'></script>
|
<script src='js/stats.js'></script>
|
||||||
<script src='js/json.human.js'></script>
|
<script src='js/json.human.js'></script>
|
||||||
<script src='js/highcharts-custom.js'></script>
|
<script src='js/highcharts-custom.js'></script>
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
function qs(key) {
|
|
||||||
key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, "\\$&"); // escape RegEx meta chars
|
|
||||||
var match = location.search.match(new RegExp("[?&]"+key+"=([^&]+)(&|$)"));
|
|
||||||
return match && decodeURIComponent(match[1].replace(/\+/g, " "));
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
var currentHighchart;
|
var currentHighchart;
|
||||||
|
|
||||||
// setup a function to grab the nodeStats
|
// setup a function to grab the nodeStats
|
||||||
function getNodeStats() {
|
function getNodeStats() {
|
||||||
|
|
||||||
var uuid = qs("uuid");
|
var uuid = qs("uuid");
|
||||||
|
|
||||||
$.getJSON("/nodes/" + uuid + ".json", function(json){
|
$.getJSON("/nodes/" + uuid + ".json", function(json){
|
||||||
|
|
||||||
// update the table header with the right node type
|
// update the table header with the right node type
|
||||||
$('#stats-lead h3').html(json.node_type + " stats (" + uuid + ")");
|
$('#stats-lead h3').html(json.node_type + " stats (" + uuid + ")");
|
||||||
|
|
||||||
delete json.node_type;
|
delete json.node_type;
|
||||||
|
|
||||||
var stats = JsonHuman.format(json);
|
var stats = JsonHuman.format(json);
|
||||||
|
|
||||||
$('#stats-container').html(stats);
|
$('#stats-container').html(stats);
|
||||||
|
@ -27,33 +21,33 @@ $(document).ready(function(){
|
||||||
var x = (new Date()).getTime();
|
var x = (new Date()).getTime();
|
||||||
|
|
||||||
// get the last value using underscore-keypath
|
// get the last value using underscore-keypath
|
||||||
var y = _(json).valueForKeyPath(graphKeypath);
|
var y = _(json).valueForKeyPath(graphKeypath);
|
||||||
|
|
||||||
// start shifting the chart once we hit 20 data points
|
// start shifting the chart once we hit 20 data points
|
||||||
var shift = currentHighchart.series[0].data.length > 20;
|
var shift = currentHighchart.series[0].data.length > 20;
|
||||||
currentHighchart.series[0].addPoint([x, y], true, shift);
|
currentHighchart.series[0].addPoint([x, y], true, shift);
|
||||||
}
|
}
|
||||||
}).fail(function(data) {
|
}).fail(function(data) {
|
||||||
$('#stats-container th').each(function(){
|
$('#stats-container th').each(function(){
|
||||||
$(this).addClass('stale');
|
$(this).addClass('stale');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// do the first GET on page load
|
// do the first GET on page load
|
||||||
getNodeStats();
|
getNodeStats();
|
||||||
// grab the new assignments JSON every second
|
// grab the new assignments JSON every second
|
||||||
var getNodeStatsInterval = setInterval(getNodeStats, 1000);
|
var getNodeStatsInterval = setInterval(getNodeStats, 1000);
|
||||||
|
|
||||||
var graphKeypath = "";
|
var graphKeypath = "";
|
||||||
|
|
||||||
// set the global Highcharts option
|
// set the global Highcharts option
|
||||||
Highcharts.setOptions({
|
Highcharts.setOptions({
|
||||||
global: {
|
global: {
|
||||||
useUTC: false
|
useUTC: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// add a function to help create the graph modal
|
// add a function to help create the graph modal
|
||||||
function createGraphModal() {
|
function createGraphModal() {
|
||||||
var chartModal = bootbox.dialog({
|
var chartModal = bootbox.dialog({
|
||||||
|
@ -66,7 +60,7 @@ $(document).ready(function(){
|
||||||
chartModal.on('hidden.bs.modal', function(e) {
|
chartModal.on('hidden.bs.modal', function(e) {
|
||||||
currentHighchart.destroy();
|
currentHighchart.destroy();
|
||||||
currentHighchart = null;
|
currentHighchart = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
currentHighchart = new Highcharts.Chart({
|
currentHighchart = new Highcharts.Chart({
|
||||||
chart: {
|
chart: {
|
||||||
|
@ -94,11 +88,11 @@ $(document).ready(function(){
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle clicks on numerical values - this lets the user show a line graph in a modal
|
// handle clicks on numerical values - this lets the user show a line graph in a modal
|
||||||
$('#stats-container').on('click', '.jh-type-number', function(){
|
$('#stats-container').on('click', '.jh-type-number', function(){
|
||||||
graphKeypath = $(this).data('keypath');
|
graphKeypath = $(this).data('keypath');
|
||||||
|
|
||||||
// setup the new graph modal
|
// setup the new graph modal
|
||||||
createGraphModal();
|
createGraphModal();
|
||||||
});
|
});
|
||||||
|
|
|
@ -279,16 +279,19 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServer::didSetupAccountManagerWithAccessToken() {
|
bool DomainServer::didSetupAccountManagerWithAccessToken() {
|
||||||
AccountManager& accountManager = AccountManager::getInstance();
|
if (AccountManager::getInstance().hasValidAccessToken()) {
|
||||||
|
|
||||||
if (accountManager.hasValidAccessToken()) {
|
|
||||||
// we already gave the account manager a valid access token
|
// we already gave the account manager a valid access token
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return resetAccountManagerAccessToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
||||||
|
|
||||||
|
bool DomainServer::resetAccountManagerAccessToken() {
|
||||||
if (!_oauthProviderURL.isEmpty()) {
|
if (!_oauthProviderURL.isEmpty()) {
|
||||||
// check for an access-token in our settings, can optionally be overidden by env value
|
// check for an access-token in our settings, can optionally be overidden by env value
|
||||||
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
|
||||||
const QString ENV_ACCESS_TOKEN_KEY = "DOMAIN_SERVER_ACCESS_TOKEN";
|
const QString ENV_ACCESS_TOKEN_KEY = "DOMAIN_SERVER_ACCESS_TOKEN";
|
||||||
|
|
||||||
QString accessToken = QProcessEnvironment::systemEnvironment().value(ENV_ACCESS_TOKEN_KEY);
|
QString accessToken = QProcessEnvironment::systemEnvironment().value(ENV_ACCESS_TOKEN_KEY);
|
||||||
|
@ -310,7 +313,7 @@ bool DomainServer::didSetupAccountManagerWithAccessToken() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// give this access token to the AccountManager
|
// give this access token to the AccountManager
|
||||||
accountManager.setAccessTokenForCurrentAuthURL(accessToken);
|
AccountManager::getInstance().setAccessTokenForCurrentAuthURL(accessToken);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -1509,12 +1512,15 @@ QString pathForAssignmentScript(const QUuid& assignmentUUID) {
|
||||||
return newPath;
|
return newPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString URI_OAUTH = "/oauth";
|
||||||
|
|
||||||
bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||||
const QString JSON_MIME_TYPE = "application/json";
|
const QString JSON_MIME_TYPE = "application/json";
|
||||||
|
|
||||||
const QString URI_ASSIGNMENT = "/assignment";
|
const QString URI_ASSIGNMENT = "/assignment";
|
||||||
const QString URI_ASSIGNMENT_SCRIPTS = URI_ASSIGNMENT + "/scripts";
|
const QString URI_ASSIGNMENT_SCRIPTS = URI_ASSIGNMENT + "/scripts";
|
||||||
const QString URI_NODES = "/nodes";
|
const QString URI_NODES = "/nodes";
|
||||||
|
const QString URI_SETTINGS = "/settings";
|
||||||
|
|
||||||
const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
||||||
|
|
||||||
|
@ -1792,7 +1798,6 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
||||||
const QString HIFI_SESSION_COOKIE_KEY = "DS_WEB_SESSION_UUID";
|
const QString HIFI_SESSION_COOKIE_KEY = "DS_WEB_SESSION_UUID";
|
||||||
|
|
||||||
bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &url, bool skipSubHandler) {
|
bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &url, bool skipSubHandler) {
|
||||||
const QString URI_OAUTH = "/oauth";
|
|
||||||
qDebug() << "HTTPS request received at" << url.toString();
|
qDebug() << "HTTPS request received at" << url.toString();
|
||||||
if (url.path() == URI_OAUTH) {
|
if (url.path() == URI_OAUTH) {
|
||||||
|
|
||||||
|
|
|
@ -72,9 +72,11 @@ private:
|
||||||
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
||||||
bool optionallySetupOAuth();
|
bool optionallySetupOAuth();
|
||||||
bool optionallyReadX509KeyAndCertificate();
|
bool optionallyReadX509KeyAndCertificate();
|
||||||
bool didSetupAccountManagerWithAccessToken();
|
|
||||||
bool optionallySetupAssignmentPayment();
|
bool optionallySetupAssignmentPayment();
|
||||||
|
|
||||||
|
bool didSetupAccountManagerWithAccessToken();
|
||||||
|
bool resetAccountManagerAccessToken();
|
||||||
|
|
||||||
void setupAutomaticNetworking();
|
void setupAutomaticNetworking();
|
||||||
void sendHeartbeatToDataServer(const QString& networkAddress);
|
void sendHeartbeatToDataServer(const QString& networkAddress);
|
||||||
void processICEPingReply(const QByteArray& packet, const HifiSockAddr& senderSockAddr);
|
void processICEPingReply(const QByteArray& packet, const HifiSockAddr& senderSockAddr);
|
||||||
|
|
|
@ -101,10 +101,8 @@ QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QStrin
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString SETTINGS_PATH = "/settings.json";
|
|
||||||
|
|
||||||
bool DomainServerSettingsManager::handlePublicHTTPRequest(HTTPConnection* connection, const QUrl &url) {
|
bool DomainServerSettingsManager::handlePublicHTTPRequest(HTTPConnection* connection, const QUrl &url) {
|
||||||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == SETTINGS_PATH) {
|
if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == SETTINGS_PATH_JSON) {
|
||||||
// this is a GET operation for our settings
|
// this is a GET operation for our settings
|
||||||
|
|
||||||
// check if there is a query parameter for settings affecting a particular type of assignment
|
// check if there is a query parameter for settings affecting a particular type of assignment
|
||||||
|
@ -127,7 +125,7 @@ bool DomainServerSettingsManager::handlePublicHTTPRequest(HTTPConnection* connec
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) {
|
bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) {
|
||||||
if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == SETTINGS_PATH) {
|
if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == SETTINGS_PATH_JSON) {
|
||||||
// this is a POST operation to change one or more settings
|
// this is a POST operation to change one or more settings
|
||||||
QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent());
|
QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent());
|
||||||
QJsonObject postedObject = postedDocument.object();
|
QJsonObject postedObject = postedDocument.object();
|
||||||
|
@ -149,7 +147,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection
|
||||||
QTimer::singleShot(DOMAIN_SERVER_RESTART_TIMER_MSECS, qApp, SLOT(restart()));
|
QTimer::singleShot(DOMAIN_SERVER_RESTART_TIMER_MSECS, qApp, SLOT(restart()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == SETTINGS_PATH) {
|
} else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == SETTINGS_PATH_JSON) {
|
||||||
// setup a JSON Object with descriptions and non-omitted settings
|
// setup a JSON Object with descriptions and non-omitted settings
|
||||||
const QString SETTINGS_RESPONSE_DESCRIPTION_KEY = "descriptions";
|
const QString SETTINGS_RESPONSE_DESCRIPTION_KEY = "descriptions";
|
||||||
const QString SETTINGS_RESPONSE_VALUE_KEY = "values";
|
const QString SETTINGS_RESPONSE_VALUE_KEY = "values";
|
||||||
|
@ -254,7 +252,6 @@ QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& ty
|
||||||
|
|
||||||
void DomainServerSettingsManager::updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
|
void DomainServerSettingsManager::updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
|
||||||
const QJsonObject& settingDescription) {
|
const QJsonObject& settingDescription) {
|
||||||
|
|
||||||
if (newValue.isString()) {
|
if (newValue.isString()) {
|
||||||
if (newValue.toString().isEmpty()) {
|
if (newValue.toString().isEmpty()) {
|
||||||
// this is an empty value, clear it in settings variant so the default is sent
|
// this is an empty value, clear it in settings variant so the default is sent
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
|
|
||||||
const QString SETTINGS_PATHS_KEY = "paths";
|
const QString SETTINGS_PATHS_KEY = "paths";
|
||||||
|
|
||||||
|
const QString SETTINGS_PATH = "/settings";
|
||||||
|
const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json";
|
||||||
|
|
||||||
class DomainServerSettingsManager : public QObject {
|
class DomainServerSettingsManager : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -30,6 +33,7 @@ public:
|
||||||
void setupConfigMap(const QStringList& argumentList);
|
void setupConfigMap(const QStringList& argumentList);
|
||||||
QVariant valueOrDefaultValueForKeyPath(const QString& keyPath);
|
QVariant valueOrDefaultValueForKeyPath(const QString& keyPath);
|
||||||
|
|
||||||
|
QVariantMap& getUserSettingsMap() { return _configMap.getUserConfig(); }
|
||||||
QVariantMap& getSettingsMap() { return _configMap.getMergedConfig(); }
|
QVariantMap& getSettingsMap() { return _configMap.getMergedConfig(); }
|
||||||
private:
|
private:
|
||||||
QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false);
|
QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false);
|
||||||
|
|
|
@ -15,7 +15,7 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
|
|
||||||
Script.include([
|
Script.include([
|
||||||
"libraries/stringHelpers.js",
|
"libraries/stringHelpers.js",
|
||||||
"libraries/dataviewHelpers.js",
|
"libraries/dataViewHelpers.js",
|
||||||
"libraries/toolBars.js",
|
"libraries/toolBars.js",
|
||||||
"libraries/progressDialog.js",
|
"libraries/progressDialog.js",
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ var FIELD_LENGTH = 1.92;
|
||||||
var FLOOR_THICKNESS = 0.20;
|
var FLOOR_THICKNESS = 0.20;
|
||||||
var EDGE_THICKESS = 0.10;
|
var EDGE_THICKESS = 0.10;
|
||||||
var EDGE_HEIGHT = 0.10;
|
var EDGE_HEIGHT = 0.10;
|
||||||
var DROP_HEIGHT = 0.3;
|
var DROP_HEIGHT = 0.25;
|
||||||
var PUCK_SIZE = 0.15;
|
var PUCK_SIZE = 0.15;
|
||||||
var PUCK_THICKNESS = 0.05;
|
var PUCK_THICKNESS = 0.05;
|
||||||
var PADDLE_SIZE = 0.15;
|
var PADDLE_SIZE = 0.15;
|
||||||
|
@ -71,7 +71,18 @@ var edgeRestitution = 0.9;
|
||||||
var floorFriction = 0.01;
|
var floorFriction = 0.01;
|
||||||
|
|
||||||
var paddle1Pos, paddle2Pos;
|
var paddle1Pos, paddle2Pos;
|
||||||
var names = ['floor', 'table', 'paddle', 'edge', 'puck', 'hockeyLight'];
|
// use some names that wont collide with other content
|
||||||
|
var names = ["air-hockey-table-23j4h1jh82jsjfw91jf232n2k", // keep this synchronized with what's in grabHockey.js
|
||||||
|
"air-hockey-paddle-23j4h1jh82jsjfw91jf232n2k",
|
||||||
|
"air-hockey-puck-23j4h1jh82jsjfw91jf232n2k",
|
||||||
|
"air-hockey-light-23j4h1jh82jsjfw91jf232n2k",
|
||||||
|
"air-hockey-floor-23j4h1jh82jsjfw91jf232n2k"];
|
||||||
|
var table_name_index = 0;
|
||||||
|
var paddle_name_index = 1;
|
||||||
|
var puck_name_index = 2;
|
||||||
|
var light_name_index = 3;
|
||||||
|
var floor_name_index = 4;
|
||||||
|
|
||||||
|
|
||||||
var deleteButton = Overlays.addOverlay("image", {
|
var deleteButton = Overlays.addOverlay("image", {
|
||||||
x: screenSize.x / 2 - BUTTON_SIZE,
|
x: screenSize.x / 2 - BUTTON_SIZE,
|
||||||
|
@ -112,7 +123,7 @@ var paddle1, paddle2;
|
||||||
function makeNewProp(which, position) {
|
function makeNewProp(which, position) {
|
||||||
if (which == "puck") {
|
if (which == "puck") {
|
||||||
return Entities.addEntity({
|
return Entities.addEntity({
|
||||||
name: 'puck',
|
name: names[puck_name_index],
|
||||||
type: "Model",
|
type: "Model",
|
||||||
modelURL: puckModel,
|
modelURL: puckModel,
|
||||||
compoundShapeURL: puckCollisionModel,
|
compoundShapeURL: puckCollisionModel,
|
||||||
|
@ -150,7 +161,7 @@ function makeNewProp(which, position) {
|
||||||
z: FIELD_LENGTH * 0.35
|
z: FIELD_LENGTH * 0.35
|
||||||
});
|
});
|
||||||
return Entities.addEntity({
|
return Entities.addEntity({
|
||||||
name: "paddle",
|
name: names[paddle_name_index],
|
||||||
type: "Model",
|
type: "Model",
|
||||||
modelURL: paddleModel,
|
modelURL: paddleModel,
|
||||||
compoundShapeURL: paddleCollisionModel,
|
compoundShapeURL: paddleCollisionModel,
|
||||||
|
@ -184,7 +195,7 @@ function makeNewProp(which, position) {
|
||||||
z: -FIELD_LENGTH * 0.35
|
z: -FIELD_LENGTH * 0.35
|
||||||
});
|
});
|
||||||
return Entities.addEntity({
|
return Entities.addEntity({
|
||||||
name: "paddle",
|
name: names[paddle_name_index],
|
||||||
type: "Model",
|
type: "Model",
|
||||||
modelURL: paddleModel,
|
modelURL: paddleModel,
|
||||||
compoundShapeURL: paddleCollisionModel,
|
compoundShapeURL: paddleCollisionModel,
|
||||||
|
@ -280,9 +291,11 @@ function mousePressEvent(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function spawnAllTheThings() {
|
function spawnAllTheThings() {
|
||||||
center = Vec3.sum(MyAvatar.position, Vec3.multiply((FIELD_WIDTH + FIELD_LENGTH) * 0.60, Quat.getFront(Camera.getOrientation())));
|
center = Vec3.sum(MyAvatar.position,
|
||||||
floor = Entities.addEntity({
|
Vec3.multiply((FIELD_WIDTH + FIELD_LENGTH) * 0.60, Quat.getFront(Camera.getOrientation())));
|
||||||
name: "floor",
|
|
||||||
|
Entities.addEntity({
|
||||||
|
name: names[floor_name_index],
|
||||||
type: "Box",
|
type: "Box",
|
||||||
position: Vec3.subtract(center, {
|
position: Vec3.subtract(center, {
|
||||||
x: 0,
|
x: 0,
|
||||||
|
@ -311,202 +324,18 @@ function spawnAllTheThings() {
|
||||||
lifetime: LIFETIME
|
lifetime: LIFETIME
|
||||||
});
|
});
|
||||||
|
|
||||||
edge1 = Entities.addEntity({
|
Entities.addEntity({
|
||||||
name: 'edge',
|
name: names[table_name_index],
|
||||||
type: "Box",
|
|
||||||
collisionSoundURL: hitSideSound,
|
|
||||||
position: Vec3.sum(center, {
|
|
||||||
x: FIELD_WIDTH / 2.0,
|
|
||||||
y: FLOOR_THICKNESS / 2.0,
|
|
||||||
z: 0
|
|
||||||
}),
|
|
||||||
dimensions: {
|
|
||||||
x: EDGE_THICKESS,
|
|
||||||
y: EDGE_HEIGHT,
|
|
||||||
z: FIELD_LENGTH + EDGE_THICKESS
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
red: 100,
|
|
||||||
green: 100,
|
|
||||||
blue: 100
|
|
||||||
},
|
|
||||||
gravity: {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
ignoreCollisions: false,
|
|
||||||
visible: debugVisible,
|
|
||||||
restitution: edgeRestitution,
|
|
||||||
locked: true,
|
|
||||||
lifetime: LIFETIME
|
|
||||||
});
|
|
||||||
|
|
||||||
edge2 = Entities.addEntity({
|
|
||||||
name: 'edge',
|
|
||||||
type: "Box",
|
|
||||||
collisionSoundURL: hitSideSound,
|
|
||||||
position: Vec3.sum(center, {
|
|
||||||
x: -FIELD_WIDTH / 2.0,
|
|
||||||
y: FLOOR_THICKNESS / 2.0,
|
|
||||||
z: 0
|
|
||||||
}),
|
|
||||||
dimensions: {
|
|
||||||
x: EDGE_THICKESS,
|
|
||||||
y: EDGE_HEIGHT,
|
|
||||||
z: FIELD_LENGTH + EDGE_THICKESS
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
red: 100,
|
|
||||||
green: 100,
|
|
||||||
blue: 100
|
|
||||||
},
|
|
||||||
gravity: {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
ignoreCollisions: false,
|
|
||||||
visible: debugVisible,
|
|
||||||
restitution: edgeRestitution,
|
|
||||||
locked: true,
|
|
||||||
lifetime: LIFETIME
|
|
||||||
});
|
|
||||||
|
|
||||||
edge3a = Entities.addEntity({
|
|
||||||
name: 'edge',
|
|
||||||
type: "Box",
|
|
||||||
collisionSoundURL: hitSideSound,
|
|
||||||
position: Vec3.sum(center, {
|
|
||||||
x: FIELD_WIDTH / 4.0 + (GOAL_WIDTH / 4.0),
|
|
||||||
y: FLOOR_THICKNESS / 2.0,
|
|
||||||
z: -FIELD_LENGTH / 2.0
|
|
||||||
}),
|
|
||||||
dimensions: {
|
|
||||||
x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0,
|
|
||||||
y: EDGE_HEIGHT,
|
|
||||||
z: EDGE_THICKESS
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
red: 100,
|
|
||||||
green: 100,
|
|
||||||
blue: 100
|
|
||||||
},
|
|
||||||
gravity: {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
ignoreCollisions: false,
|
|
||||||
visible: debugVisible,
|
|
||||||
restitution: edgeRestitution,
|
|
||||||
locked: true,
|
|
||||||
lifetime: LIFETIME
|
|
||||||
});
|
|
||||||
|
|
||||||
edge3b = Entities.addEntity({
|
|
||||||
name: 'edge',
|
|
||||||
type: "Box",
|
|
||||||
collisionSoundURL: hitSideSound,
|
|
||||||
position: Vec3.sum(center, {
|
|
||||||
x: -FIELD_WIDTH / 4.0 - (GOAL_WIDTH / 4.0),
|
|
||||||
y: FLOOR_THICKNESS / 2.0,
|
|
||||||
z: -FIELD_LENGTH / 2.0
|
|
||||||
}),
|
|
||||||
dimensions: {
|
|
||||||
x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0,
|
|
||||||
y: EDGE_HEIGHT,
|
|
||||||
z: EDGE_THICKESS
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
red: 100,
|
|
||||||
green: 100,
|
|
||||||
blue: 100
|
|
||||||
},
|
|
||||||
gravity: {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
ignoreCollisions: false,
|
|
||||||
visible: debugVisible,
|
|
||||||
restitution: edgeRestitution,
|
|
||||||
locked: true,
|
|
||||||
lifetime: LIFETIME
|
|
||||||
});
|
|
||||||
|
|
||||||
edge4a = Entities.addEntity({
|
|
||||||
name: 'edge',
|
|
||||||
type: "Box",
|
|
||||||
collisionSoundURL: hitSideSound,
|
|
||||||
position: Vec3.sum(center, {
|
|
||||||
x: FIELD_WIDTH / 4.0 + (GOAL_WIDTH / 4.0),
|
|
||||||
y: FLOOR_THICKNESS / 2.0,
|
|
||||||
z: FIELD_LENGTH / 2.0
|
|
||||||
}),
|
|
||||||
dimensions: {
|
|
||||||
x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0,
|
|
||||||
y: EDGE_HEIGHT,
|
|
||||||
z: EDGE_THICKESS
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
red: 100,
|
|
||||||
green: 100,
|
|
||||||
blue: 100
|
|
||||||
},
|
|
||||||
gravity: {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
ignoreCollisions: false,
|
|
||||||
visible: debugVisible,
|
|
||||||
restitution: edgeRestitution,
|
|
||||||
locked: true,
|
|
||||||
lifetime: LIFETIME
|
|
||||||
});
|
|
||||||
|
|
||||||
edge4b = Entities.addEntity({
|
|
||||||
name: 'edge',
|
|
||||||
type: "Box",
|
|
||||||
collisionSoundURL: hitSideSound,
|
|
||||||
position: Vec3.sum(center, {
|
|
||||||
x: -FIELD_WIDTH / 4.0 - (GOAL_WIDTH / 4.0),
|
|
||||||
y: FLOOR_THICKNESS / 2.0,
|
|
||||||
z: FIELD_LENGTH / 2.0
|
|
||||||
}),
|
|
||||||
dimensions: {
|
|
||||||
x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0,
|
|
||||||
y: EDGE_HEIGHT,
|
|
||||||
z: EDGE_THICKESS
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
red: 100,
|
|
||||||
green: 100,
|
|
||||||
blue: 100
|
|
||||||
},
|
|
||||||
gravity: {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
ignoreCollisions: false,
|
|
||||||
visible: debugVisible,
|
|
||||||
restitution: edgeRestitution,
|
|
||||||
locked: true,
|
|
||||||
lifetime: LIFETIME
|
|
||||||
});
|
|
||||||
|
|
||||||
table = Entities.addEntity({
|
|
||||||
name: "table",
|
|
||||||
type: "Model",
|
type: "Model",
|
||||||
modelURL: polyTable,
|
modelURL: polyTable,
|
||||||
|
compoundShapeURL: "http://headache.hungry.com/~seth/hifi/airhockey-table-hull.obj",
|
||||||
dimensions: Vec3.multiply({
|
dimensions: Vec3.multiply({
|
||||||
x: 0.8,
|
x: 0.8,
|
||||||
y: 0.45,
|
y: 0.45,
|
||||||
z: 1.31
|
z: 1.31
|
||||||
}, MODEL_SCALE),
|
}, MODEL_SCALE),
|
||||||
position: Vec3.sum(center, MODEL_OFFSET),
|
position: Vec3.sum(center, MODEL_OFFSET),
|
||||||
|
restitution: edgeRestitution,
|
||||||
ignoreCollisions: false,
|
ignoreCollisions: false,
|
||||||
visible: true,
|
visible: true,
|
||||||
locked: true,
|
locked: true,
|
||||||
|
@ -514,7 +343,7 @@ function spawnAllTheThings() {
|
||||||
});
|
});
|
||||||
|
|
||||||
light = Entities.addEntity({
|
light = Entities.addEntity({
|
||||||
name: "hockeyLight",
|
name: names[light_name_index],
|
||||||
type: "Light",
|
type: "Light",
|
||||||
dimensions: {
|
dimensions: {
|
||||||
x: 5,
|
x: 5,
|
||||||
|
@ -540,14 +369,13 @@ function spawnAllTheThings() {
|
||||||
|
|
||||||
function deleteAllTheThings() {
|
function deleteAllTheThings() {
|
||||||
|
|
||||||
Script.update.disconnect(update);
|
|
||||||
//delete all nearby entitites that are named any the names from our names array
|
//delete all nearby entitites that are named any the names from our names array
|
||||||
var nearbyEntities = Entities.findEntities(MyAvatar.position, ENTITY_SEARCH_RANGE);
|
var nearbyEntities = Entities.findEntities(MyAvatar.position, ENTITY_SEARCH_RANGE);
|
||||||
for (var i = 0; i < nearbyEntities.length; i++) {
|
for (var i = 0; i < nearbyEntities.length; i++) {
|
||||||
var entityName = Entities.getEntityProperties(nearbyEntities[i]).name;
|
var entityName = Entities.getEntityProperties(nearbyEntities[i]).name;
|
||||||
for (var j = 0; j < names.length; j++) {
|
for (var j = 0; j < names.length; j++) {
|
||||||
if (names[j] === entityName) {
|
if (names[j] === entityName) {
|
||||||
//We have a mach- delete this entity
|
//We have a match - delete this entity
|
||||||
Entities.editEntity(nearbyEntities[i], {
|
Entities.editEntity(nearbyEntities[i], {
|
||||||
locked: false
|
locked: false
|
||||||
});
|
});
|
||||||
|
@ -556,7 +384,7 @@ function deleteAllTheThings() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Script.update.disconnect(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
function scriptEnding() {
|
function scriptEnding() {
|
||||||
|
@ -607,4 +435,4 @@ function scriptEnding() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.mousePressEvent.connect(mousePressEvent);
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
// grab.js
|
// grab.js
|
||||||
// examples
|
// examples
|
||||||
//
|
//
|
||||||
|
@ -11,12 +10,32 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// these are hand-measured bounds of the AirHockey table
|
||||||
|
var fieldMaxOffset = {
|
||||||
|
x: 0.475,
|
||||||
|
y: 0.315,
|
||||||
|
z: 0.82
|
||||||
|
};
|
||||||
|
var fieldMinOffset = {
|
||||||
|
x: -0.460, // yes, smaller than max
|
||||||
|
y: 0.315,
|
||||||
|
z: -0.830
|
||||||
|
};
|
||||||
|
var halfCornerBoxWidth = 0.84;
|
||||||
|
|
||||||
|
var tablePosition = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
}
|
||||||
var isGrabbing = false;
|
var isGrabbing = false;
|
||||||
var grabbedEntity = null;
|
var grabbedEntity = null;
|
||||||
var prevMouse = {};
|
var prevMouse = {};
|
||||||
var deltaMouse = {
|
var deltaMouse = {
|
||||||
z: 0
|
z: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var TABLE_SEARCH_RANGE = 10;
|
||||||
var entityProps;
|
var entityProps;
|
||||||
var moveUpDown = false;
|
var moveUpDown = false;
|
||||||
var CLOSE_ENOUGH = 0.001;
|
var CLOSE_ENOUGH = 0.001;
|
||||||
|
@ -26,8 +45,13 @@ var DAMPING_RATE = 0.80;
|
||||||
var ANGULAR_DAMPING_RATE = 0.40;
|
var ANGULAR_DAMPING_RATE = 0.40;
|
||||||
var SCREEN_TO_METERS = 0.001;
|
var SCREEN_TO_METERS = 0.001;
|
||||||
var currentPosition, currentVelocity, cameraEntityDistance, currentRotation;
|
var currentPosition, currentVelocity, cameraEntityDistance, currentRotation;
|
||||||
|
var grabHeight;
|
||||||
var velocityTowardTarget, desiredVelocity, addedVelocity, newVelocity, dPosition, camYaw, distanceToTarget, targetPosition;
|
var velocityTowardTarget, desiredVelocity, addedVelocity, newVelocity, dPosition, camYaw, distanceToTarget, targetPosition;
|
||||||
var originalGravity = {x: 0, y: 0, z: 0};
|
var originalGravity = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
var shouldRotate = false;
|
var shouldRotate = false;
|
||||||
var dQ, theta, axisAngle, dT;
|
var dQ, theta, axisAngle, dT;
|
||||||
var angularVelocity = {
|
var angularVelocity = {
|
||||||
|
@ -58,11 +82,11 @@ var dropLine = Overlays.addOverlay("line3d", {
|
||||||
|
|
||||||
|
|
||||||
function vectorIsZero(v) {
|
function vectorIsZero(v) {
|
||||||
return v.x == 0 && v.y == 0 && v.z == 0;
|
return v.x == 0 && v.y == 0 && v.z == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nearLinePoint(targetPosition) {
|
function nearLinePoint(targetPosition) {
|
||||||
// var handPosition = Vec3.sum(MyAvatar.position, {x:0, y:0.2, z:0});
|
// var handPosition = Vec3.sum(MyAvatar.position, {x:0, y:0.2, z:0});
|
||||||
var handPosition = MyAvatar.getRightPalmPosition();
|
var handPosition = MyAvatar.getRightPalmPosition();
|
||||||
var along = Vec3.subtract(targetPosition, handPosition);
|
var along = Vec3.subtract(targetPosition, handPosition);
|
||||||
along = Vec3.normalize(along);
|
along = Vec3.normalize(along);
|
||||||
|
@ -75,9 +99,15 @@ function mousePressEvent(event) {
|
||||||
if (!event.isLeftButton) {
|
if (!event.isLeftButton) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
prevMouse.x = event.x;
|
||||||
|
prevMouse.y = event.y;
|
||||||
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
|
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
|
||||||
if (intersection.intersects && intersection.properties.collisionsWillMove) {
|
if (!intersection.intersects) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (intersection.properties.collisionsWillMove) {
|
||||||
grabbedEntity = intersection.entityID;
|
grabbedEntity = intersection.entityID;
|
||||||
var props = Entities.getEntityProperties(grabbedEntity)
|
var props = Entities.getEntityProperties(grabbedEntity)
|
||||||
isGrabbing = true;
|
isGrabbing = true;
|
||||||
|
@ -87,15 +117,35 @@ function mousePressEvent(event) {
|
||||||
currentVelocity = props.velocity;
|
currentVelocity = props.velocity;
|
||||||
updateDropLine(targetPosition);
|
updateDropLine(targetPosition);
|
||||||
|
|
||||||
|
// remember the height of the object when first grabbed
|
||||||
|
// we'll try to maintain this height during the rest of this grab
|
||||||
|
grabHeight = currentPosition.y;
|
||||||
|
|
||||||
Entities.editEntity(grabbedEntity, {
|
Entities.editEntity(grabbedEntity, {
|
||||||
gravity: {x: 0, y: 0, z: 0}
|
gravity: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Audio.playSound(grabSound, {
|
Audio.playSound(grabSound, {
|
||||||
position: props.position,
|
position: props.position,
|
||||||
volume: VOLUME
|
volume: VOLUME
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
//We want to detect table once user grabs something that may be on a table...
|
||||||
|
var potentialTables = Entities.findEntities(MyAvatar.position, TABLE_SEARCH_RANGE);
|
||||||
|
potentialTables.forEach(function(table) {
|
||||||
|
var props = Entities.getEntityProperties(table);
|
||||||
|
// keep this name synchronized with what's in airHockey.js
|
||||||
|
if (props.name === "air-hockey-table-23j4h1jh82jsjfw91jf232n2k") {
|
||||||
|
// need to remember the table's position so we can clamp the targetPositon
|
||||||
|
// to remain on the playing field
|
||||||
|
tablePosition = props.position;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDropLine(position) {
|
function updateDropLine(position) {
|
||||||
|
@ -127,7 +177,7 @@ function mouseReleaseEvent() {
|
||||||
// 5. interface B releases the entity and puts the original gravity back (to zero)
|
// 5. interface B releases the entity and puts the original gravity back (to zero)
|
||||||
if (!vectorIsZero(originalGravity)) {
|
if (!vectorIsZero(originalGravity)) {
|
||||||
Entities.editEntity(grabbedEntity, {
|
Entities.editEntity(grabbedEntity, {
|
||||||
gravity: originalGravity
|
gravity: originalGravity
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +194,7 @@ function mouseReleaseEvent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// new mouseMoveEvent
|
||||||
function mouseMoveEvent(event) {
|
function mouseMoveEvent(event) {
|
||||||
if (isGrabbing) {
|
if (isGrabbing) {
|
||||||
// see if something added/restored gravity
|
// see if something added/restored gravity
|
||||||
|
@ -152,24 +203,15 @@ function mouseMoveEvent(event) {
|
||||||
originalGravity = props.gravity;
|
originalGravity = props.gravity;
|
||||||
}
|
}
|
||||||
|
|
||||||
deltaMouse.x = event.x - prevMouse.x;
|
if (shouldRotate) {
|
||||||
if (!moveUpDown) {
|
deltaMouse.x = event.x - prevMouse.x;
|
||||||
deltaMouse.z = event.y - prevMouse.y;
|
if (!moveUpDown) {
|
||||||
deltaMouse.y = 0;
|
deltaMouse.z = event.y - prevMouse.y;
|
||||||
} else {
|
deltaMouse.y = 0;
|
||||||
deltaMouse.y = (event.y - prevMouse.y) * -1;
|
} else {
|
||||||
deltaMouse.z = 0;
|
deltaMouse.y = (event.y - prevMouse.y) * -1;
|
||||||
}
|
deltaMouse.z = 0;
|
||||||
// Update the target position by the amount the mouse moved
|
}
|
||||||
camYaw = Quat.safeEulerAngles(Camera.getOrientation()).y;
|
|
||||||
dPosition = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, camYaw, 0), deltaMouse);
|
|
||||||
if (!shouldRotate) {
|
|
||||||
// Adjust target position for the object by the mouse move
|
|
||||||
cameraEntityDistance = Vec3.distance(Camera.getPosition(), currentPosition);
|
|
||||||
// Scale distance we want to move by the distance from the camera to the grabbed object
|
|
||||||
// TODO: Correct SCREEN_TO_METERS to be correct for the actual FOV, resolution
|
|
||||||
targetPosition = Vec3.sum(targetPosition, Vec3.multiply(dPosition, cameraEntityDistance * SCREEN_TO_METERS));
|
|
||||||
} else if (shouldRotate) {
|
|
||||||
var transformedDeltaMouse = {
|
var transformedDeltaMouse = {
|
||||||
x: deltaMouse.z,
|
x: deltaMouse.z,
|
||||||
y: deltaMouse.x,
|
y: deltaMouse.x,
|
||||||
|
@ -180,15 +222,60 @@ function mouseMoveEvent(event) {
|
||||||
theta = 2 * Math.acos(dQ.w);
|
theta = 2 * Math.acos(dQ.w);
|
||||||
axisAngle = Quat.axis(dQ);
|
axisAngle = Quat.axis(dQ);
|
||||||
angularVelocity = Vec3.multiply((theta / dT), axisAngle);
|
angularVelocity = Vec3.multiply((theta / dT), axisAngle);
|
||||||
}
|
} else {
|
||||||
|
var relativePosition = Vec3.subtract(currentPosition, Camera.getPosition());
|
||||||
|
if (relativePosition.y < 0) {
|
||||||
|
// grabee is below camera, so movement is valid
|
||||||
|
// compute intersectionPoint where mouse ray hits grabee's current x-z plane
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
var mousePosition = pickRay.direction;
|
||||||
|
var length = relativePosition.y / mousePosition.y;
|
||||||
|
mousePosition = Vec3.multiply(mousePosition, length);
|
||||||
|
mousePosition = Vec3.sum(Camera.getPosition(), mousePosition);
|
||||||
|
|
||||||
|
// translate mousePosition into local-frame
|
||||||
|
mousePosition = Vec3.subtract(mousePosition, tablePosition);
|
||||||
|
|
||||||
|
// clamp local mousePosition to table field
|
||||||
|
if (mousePosition.x > fieldMaxOffset.x) {
|
||||||
|
mousePosition.x = fieldMaxOffset.x;
|
||||||
|
} else if (mousePosition.x < fieldMinOffset.x) {
|
||||||
|
mousePosition.x = fieldMinOffset.x;
|
||||||
|
}
|
||||||
|
if (mousePosition.z > fieldMaxOffset.z) {
|
||||||
|
mousePosition.z = fieldMaxOffset.z;
|
||||||
|
} else if (mousePosition.z < fieldMinOffset.z) {
|
||||||
|
mousePosition.z = fieldMinOffset.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clamp to rotated square (for cut corners)
|
||||||
|
var rotation = Quat.angleAxis(45, { x:0, y:1, z:0 });
|
||||||
|
mousePosition = Vec3.multiplyQbyV(rotation, mousePosition);
|
||||||
|
if (mousePosition.x > halfCornerBoxWidth) {
|
||||||
|
mousePosition.x = halfCornerBoxWidth;
|
||||||
|
} else if (mousePosition.x < -halfCornerBoxWidth) {
|
||||||
|
mousePosition.x = -halfCornerBoxWidth;
|
||||||
|
}
|
||||||
|
if (mousePosition.z > halfCornerBoxWidth) {
|
||||||
|
mousePosition.z = halfCornerBoxWidth;
|
||||||
|
} else if (mousePosition.z < -halfCornerBoxWidth) {
|
||||||
|
mousePosition.z = -halfCornerBoxWidth;
|
||||||
|
}
|
||||||
|
// rotate back into local frame
|
||||||
|
rotation.y = -rotation.y;
|
||||||
|
mousePosition = Vec3.multiplyQbyV(rotation, mousePosition);
|
||||||
|
// translate into world-frame
|
||||||
|
mousePosition = Vec3.sum(tablePosition, mousePosition);
|
||||||
|
|
||||||
|
mousePosition.y = grabHeight;
|
||||||
|
targetPosition = mousePosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
prevMouse.x = event.x;
|
prevMouse.x = event.x;
|
||||||
prevMouse.y = event.y;
|
prevMouse.y = event.y;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function keyReleaseEvent(event) {
|
function keyReleaseEvent(event) {
|
||||||
if (event.text === "SHIFT") {
|
if (event.text === "SHIFT") {
|
||||||
moveUpDown = false;
|
moveUpDown = false;
|
||||||
|
@ -237,14 +324,24 @@ function update(deltaTime) {
|
||||||
newVelocity = Vec3.subtract(newVelocity, Vec3.multiply(newVelocity, DAMPING_RATE));
|
newVelocity = Vec3.subtract(newVelocity, Vec3.multiply(newVelocity, DAMPING_RATE));
|
||||||
// Update entity
|
// Update entity
|
||||||
} else {
|
} else {
|
||||||
newVelocity = {x: 0, y: 0, z: 0};
|
newVelocity = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (shouldRotate) {
|
if (shouldRotate) {
|
||||||
angularVelocity = Vec3.subtract(angularVelocity, Vec3.multiply(angularVelocity, ANGULAR_DAMPING_RATE));
|
angularVelocity = Vec3.subtract(angularVelocity, Vec3.multiply(angularVelocity, ANGULAR_DAMPING_RATE));
|
||||||
} else {
|
} else {
|
||||||
angularVelocity = entityProps.angularVelocity;
|
angularVelocity = entityProps.angularVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enforce that grabee's rotation is only about y-axis while being grabbed
|
||||||
|
currentRotation.x = 0;
|
||||||
|
currentRotation.z = 0;
|
||||||
|
currentRotation.y = Math.sqrt(1.0 - currentRotation.w * currentRotation.w);
|
||||||
|
// Hrm... slamming the currentRotation doesn't seem to work
|
||||||
|
|
||||||
Entities.editEntity(grabbedEntity, {
|
Entities.editEntity(grabbedEntity, {
|
||||||
position: currentPosition,
|
position: currentPosition,
|
||||||
rotation: currentRotation,
|
rotation: currentRotation,
|
||||||
|
|
|
@ -65,7 +65,7 @@ public:
|
||||||
const QUrl& getAuthURL() const { return _authURL; }
|
const QUrl& getAuthURL() const { return _authURL; }
|
||||||
void setAuthURL(const QUrl& authURL);
|
void setAuthURL(const QUrl& authURL);
|
||||||
bool hasAuthEndpoint() { return !_authURL.isEmpty(); }
|
bool hasAuthEndpoint() { return !_authURL.isEmpty(); }
|
||||||
|
|
||||||
void disableSettingsFilePersistence() { _shouldPersistToSettingsFile = false; }
|
void disableSettingsFilePersistence() { _shouldPersistToSettingsFile = false; }
|
||||||
|
|
||||||
bool isLoggedIn() { return !_authURL.isEmpty() && hasValidAccessToken(); }
|
bool isLoggedIn() { return !_authURL.isEmpty() && hasValidAccessToken(); }
|
||||||
|
@ -79,7 +79,7 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void requestAccessToken(const QString& login, const QString& password);
|
void requestAccessToken(const QString& login, const QString& password);
|
||||||
|
|
||||||
void requestAccessTokenFinished();
|
void requestAccessTokenFinished();
|
||||||
void requestProfileFinished();
|
void requestProfileFinished();
|
||||||
void requestAccessTokenError(QNetworkReply::NetworkError error);
|
void requestAccessTokenError(QNetworkReply::NetworkError error);
|
||||||
|
@ -105,7 +105,7 @@ private:
|
||||||
AccountManager();
|
AccountManager();
|
||||||
AccountManager(AccountManager const& other); // not implemented
|
AccountManager(AccountManager const& other); // not implemented
|
||||||
void operator=(AccountManager const& other); // not implemented
|
void operator=(AccountManager const& other); // not implemented
|
||||||
|
|
||||||
void persistAccountToSettings();
|
void persistAccountToSettings();
|
||||||
|
|
||||||
void passSuccessToCallback(QNetworkReply* reply);
|
void passSuccessToCallback(QNetworkReply* reply);
|
||||||
|
|
|
@ -555,6 +555,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
|
||||||
// If we hit the models box, then consider the submeshes...
|
// If we hit the models box, then consider the submeshes...
|
||||||
|
_mutex.lock();
|
||||||
foreach(const AABox& subMeshBox, _calculatedMeshBoxes) {
|
foreach(const AABox& subMeshBox, _calculatedMeshBoxes) {
|
||||||
|
|
||||||
if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) {
|
if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) {
|
||||||
|
@ -590,6 +591,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
||||||
}
|
}
|
||||||
subMeshIndex++;
|
subMeshIndex++;
|
||||||
}
|
}
|
||||||
|
_mutex.unlock();
|
||||||
|
|
||||||
if (intersectedSomething) {
|
if (intersectedSomething) {
|
||||||
distance = bestDistance;
|
distance = bestDistance;
|
||||||
|
@ -625,6 +627,7 @@ bool Model::convexHullContains(glm::vec3 point) {
|
||||||
// we can use the AABox's contains() by mapping our point into the model frame
|
// we can use the AABox's contains() by mapping our point into the model frame
|
||||||
// and testing there.
|
// and testing there.
|
||||||
if (modelFrameBox.contains(modelFramePoint)){
|
if (modelFrameBox.contains(modelFramePoint)){
|
||||||
|
_mutex.lock();
|
||||||
if (!_calculatedMeshTrianglesValid) {
|
if (!_calculatedMeshTrianglesValid) {
|
||||||
recalculateMeshBoxes(true);
|
recalculateMeshBoxes(true);
|
||||||
}
|
}
|
||||||
|
@ -646,17 +649,23 @@ bool Model::convexHullContains(glm::vec3 point) {
|
||||||
}
|
}
|
||||||
if (insideMesh) {
|
if (insideMesh) {
|
||||||
// It's inside this mesh, return true.
|
// It's inside this mesh, return true.
|
||||||
|
_mutex.unlock();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subMeshIndex++;
|
subMeshIndex++;
|
||||||
}
|
}
|
||||||
|
_mutex.unlock();
|
||||||
}
|
}
|
||||||
// It wasn't in any mesh, return false.
|
// It wasn't in any mesh, return false.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we seem to call this too often when things haven't actually changed... look into optimizing this
|
// TODO: we seem to call this too often when things haven't actually changed... look into optimizing this
|
||||||
|
// Any script might trigger findRayIntersectionAgainstSubMeshes (and maybe convexHullContains), so these
|
||||||
|
// can occur multiple times. In addition, rendering does it's own ray picking in order to decide which
|
||||||
|
// entity-scripts to call. I think it would be best to do the picking once-per-frame (in cpu, or gpu if possible)
|
||||||
|
// and then the calls use the most recent such result.
|
||||||
void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
||||||
bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid;
|
bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid;
|
||||||
|
|
||||||
|
@ -739,7 +748,9 @@ void Model::renderSetup(RenderArgs* args) {
|
||||||
// against. We cache the results of these calculations so long as the model hasn't been
|
// against. We cache the results of these calculations so long as the model hasn't been
|
||||||
// simulated and the mesh hasn't changed.
|
// simulated and the mesh hasn't changed.
|
||||||
if (args && !_calculatedMeshBoxesValid) {
|
if (args && !_calculatedMeshBoxesValid) {
|
||||||
|
_mutex.lock();
|
||||||
recalculateMeshBoxes();
|
recalculateMeshBoxes();
|
||||||
|
_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up dilated textures on first render after load/simulate
|
// set up dilated textures on first render after load/simulate
|
||||||
|
@ -963,6 +974,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
|
||||||
|
|
||||||
void Model::renderDebugMeshBoxes() {
|
void Model::renderDebugMeshBoxes() {
|
||||||
int colorNdx = 0;
|
int colorNdx = 0;
|
||||||
|
_mutex.lock();
|
||||||
foreach(AABox box, _calculatedMeshBoxes) {
|
foreach(AABox box, _calculatedMeshBoxes) {
|
||||||
if (_debugMeshBoxesID == GeometryCache::UNKNOWN_ID) {
|
if (_debugMeshBoxesID == GeometryCache::UNKNOWN_ID) {
|
||||||
_debugMeshBoxesID = DependencyManager::get<GeometryCache>()->allocateID();
|
_debugMeshBoxesID = DependencyManager::get<GeometryCache>()->allocateID();
|
||||||
|
@ -1012,6 +1024,7 @@ void Model::renderDebugMeshBoxes() {
|
||||||
DependencyManager::get<GeometryCache>()->renderVertices(gpu::LINES, _debugMeshBoxesID);
|
DependencyManager::get<GeometryCache>()->renderVertices(gpu::LINES, _debugMeshBoxesID);
|
||||||
colorNdx++;
|
colorNdx++;
|
||||||
}
|
}
|
||||||
|
_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
Extents Model::getBindExtents() const {
|
Extents Model::getBindExtents() const {
|
||||||
|
@ -2059,6 +2072,12 @@ void Model::segregateMeshGroups() {
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
||||||
|
|
||||||
|
// all of our mesh vectors must match in size
|
||||||
|
if (networkMeshes.size() != geometry.meshes.size() ||
|
||||||
|
geometry.meshes.size() != _meshStates.size()) {
|
||||||
|
qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||||
for (int i = 0; i < networkMeshes.size(); i++) {
|
for (int i = 0; i < networkMeshes.size(); i++) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <QBitArray>
|
#include <QBitArray>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -348,6 +349,7 @@ private:
|
||||||
|
|
||||||
QVector< QVector<Triangle> > _calculatedMeshTriangles; // world coordinate triangles for all sub meshes
|
QVector< QVector<Triangle> > _calculatedMeshTriangles; // world coordinate triangles for all sub meshes
|
||||||
bool _calculatedMeshTrianglesValid;
|
bool _calculatedMeshTrianglesValid;
|
||||||
|
QMutex _mutex;
|
||||||
|
|
||||||
void recalculateMeshBoxes(bool pickAgainstTriangles = false);
|
void recalculateMeshBoxes(bool pickAgainstTriangles = false);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue