Actualización
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/* Main Container */
|
||||
.joubel-help-text-dialog-box {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
color: #555;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Background for help dialog */
|
||||
.joubel-help-text-dialog-background {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #555555;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
/* ------------------------------------ Main content container ------------------------ */
|
||||
.joubel-help-text-dialog-container {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 3.5%;
|
||||
left: 20%;
|
||||
width: 60%;
|
||||
background: #fff;
|
||||
opacity: 1;
|
||||
max-height: 93%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.joubel-help-text-header {
|
||||
font-size: 1.1em;
|
||||
border-bottom: 1px solid #E0E0E0;
|
||||
padding: 0.75em 3em 0.75em 1.5em;
|
||||
}
|
||||
|
||||
/* Body */
|
||||
.joubel-help-text-body {
|
||||
padding: 0.5em 1.5em;
|
||||
margin: 1em 0 2em;
|
||||
}
|
||||
|
||||
/* Close help dialog container */
|
||||
.joubel-help-text-remove {
|
||||
position: absolute;
|
||||
right: 1.5em;
|
||||
top: 0.8em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.joubel-help-text-remove:hover {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.joubel-help-text-remove:before {
|
||||
font-family: 'H5PFontAwesome4';
|
||||
content: '\f00d';
|
||||
font-size: 1.3em;
|
||||
right: 0em;
|
||||
top: 0em;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
[class^="joubel-icon-"], [class*=" joubel-icon-"] {
|
||||
/* use !important to prevent issues with browser extensions that change fonts */
|
||||
font-family: 'H5PFontIcons' !important;
|
||||
speak: none;
|
||||
font-size: 1.5em;
|
||||
line-height: 1.5em;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
word-wrap: normal;
|
||||
cursor: pointer;
|
||||
|
||||
/* Better Font Rendering =========== */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* Comment icon */
|
||||
.joubel-icon-comment-normal .h5p-icon-shadow:before {
|
||||
content: "\e90a";
|
||||
color: rgb(221, 221, 221);
|
||||
}
|
||||
.joubel-icon-comment-normal .h5p-icon-speech-bubble:before {
|
||||
content: "\e908";
|
||||
margin-left: -1em;
|
||||
color: rgb(206, 114, 193);
|
||||
}
|
||||
.joubel-icon-comment-normal .h5p-icon-question:before {
|
||||
content: "\e906";
|
||||
margin-left: -1em;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
.joubel-icon-comment-normal:hover .h5p-icon-speech-bubble:before {
|
||||
color: rgb(188, 92, 163);
|
||||
}
|
||||
.joubel-icon-comment-normal:active .h5p-icon-speech-bubble:before {
|
||||
color: rgb(206, 114, 193);
|
||||
position: relative;
|
||||
top: 0.05em;
|
||||
left: 0.05em;
|
||||
}
|
||||
.joubel-icon-comment-normal:active .h5p-icon-question:before {
|
||||
position: relative;
|
||||
top: 0.05em;
|
||||
left: 0.05em;
|
||||
}
|
||||
|
||||
/* Tip icon */
|
||||
.joubel-icon-tip-normal .h5p-icon-shadow:before {
|
||||
content: "\e90a";
|
||||
color: rgb(221, 221, 221);
|
||||
}
|
||||
.joubel-icon-tip-normal .h5p-icon-speech-bubble:before {
|
||||
content: "\e908";
|
||||
margin-left: -1em;
|
||||
color: rgb(53, 128, 195);
|
||||
}
|
||||
.joubel-icon-tip-normal .h5p-icon-info:before {
|
||||
content: "\e905";
|
||||
margin-left: -1em;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
.joubel-icon-tip-normal:hover .h5p-icon-speech-bubble:before {
|
||||
color: rgb(72, 155, 213);
|
||||
}
|
||||
.joubel-icon-tip-normal:active .h5p-icon-speech-bubble:before {
|
||||
color: rgb(72, 155, 213);
|
||||
position: relative;
|
||||
top: 0.05em;
|
||||
left: 0.05em;
|
||||
}
|
||||
.joubel-icon-tip-normal:active .h5p-icon-info:before {
|
||||
position: relative;
|
||||
top: 0.05em;
|
||||
left: 0.05em;
|
||||
}
|
||||
|
||||
/* Edit icon */
|
||||
.joubel-icon-edit .h5p-icon-circle:before {
|
||||
content: "\e90d";
|
||||
color: #1d74c8;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.joubel-icon-edit .h5p-icon-pencil:before {
|
||||
content: "\e90c";
|
||||
color: #1d74c8;
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
margin-left: -1.42em;
|
||||
}
|
||||
.joubel-icon-edit:hover .h5p-icon-circle:before {
|
||||
content: "\e90e";
|
||||
color: #1d74c8;
|
||||
}
|
||||
.joubel-icon-edit:hover .h5p-icon-pencil:before {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Approve icon */
|
||||
.joubel-icon-approve .h5p-icon-circle:before {
|
||||
content: "\e90d";
|
||||
color: #3ea35f;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.joubel-icon-approve .h5p-icon-check:before {
|
||||
content: "\e601";
|
||||
color: #3ea35f;
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
margin-left: -1.42em;
|
||||
}
|
||||
.joubel-icon-approve:hover .h5p-icon-circle:before {
|
||||
content: "\e90e";
|
||||
}
|
||||
.joubel-icon-approve:hover .h5p-icon-check:before {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Cancel icon */
|
||||
.joubel-icon-cancel .h5p-icon-circle:before {
|
||||
content: "\e90d";
|
||||
color: #de3354;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.joubel-icon-cancel .h5p-icon-cross:before {
|
||||
content: "\e600";
|
||||
color: #de3354;
|
||||
font-size: 0.85em;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
margin-left: -1.38em;
|
||||
}
|
||||
.joubel-icon-cancel:hover .h5p-icon-circle:before {
|
||||
content: "\e90e";
|
||||
}
|
||||
.joubel-icon-cancel:hover .h5p-icon-cross:before {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Custom override CSS */
|
||||
.joubel-icon-tip-normal.help-icon:before {
|
||||
font-family: 'H5PFontAwesome4';
|
||||
content: "\f059";
|
||||
}
|
||||
|
||||
/* Hide icon layers if using font awesome */
|
||||
.joubel-icon-tip-normal.help-icon > span {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
@CHARSET "UTF-8";
|
||||
|
||||
.joubel-message-dialog {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
padding: .3em;
|
||||
z-index: 11;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
border-top: 1px solid #ffcd0d;
|
||||
background-color: #fcffcc;
|
||||
text-align: center;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.joubel-message-dialog:before {
|
||||
font-family: 'H5PFontAwesome4';
|
||||
content: '\f05a';
|
||||
padding-right: .5em;
|
||||
font-size: 1.3em;
|
||||
position: relative;
|
||||
top: 0.1em;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
.joubel-progress-circle-wrapper{
|
||||
display: inline-block;
|
||||
padding: 0em 1em;
|
||||
}
|
||||
.joubel-progress-circle-percentage{
|
||||
position: relative;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.joubel-progress-circle-circle{
|
||||
-webkit-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
|
||||
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||
display: -ms-flexbox; /* TWEENER - IE 10 */
|
||||
display: -webkit-flex; /* NEW - Chrome */
|
||||
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
|
||||
-webkit-justify-content: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
|
||||
position: relative;
|
||||
|
||||
top: 0.151em;
|
||||
left: 0.151em;
|
||||
text-align: center;
|
||||
width: 2.7em;
|
||||
height: 2.7em;
|
||||
|
||||
-webkit-border-radius: 100%; /* Safari 3-4, iOS 1-3.2, Android 1.6- */
|
||||
-moz-border-radius: 100%; /* Firefox 1-3.6 */
|
||||
border-radius: 100%; /* Opera 10.5, IE 9, Safari 5, Chrome, Firefox 4, iOS 4, Android 2.1+ */
|
||||
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.joubel-progress-circle-active-border{
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
|
||||
-webkit-border-radius: 100%; /* Safari 3-4, iOS 1-3.2, Android 1.6- */
|
||||
-moz-border-radius: 100%; /* Firefox 1-3.6 */
|
||||
border-radius: 100%; /* Opera 10.5, IE 9, Safari 5, Chrome, Firefox 4, iOS 4, Android 2.1+ */
|
||||
|
||||
background-color: #1a73d9;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
.h5p-joubelui-progressbar {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
height: .25em;
|
||||
background: #fff;
|
||||
-webkit-box-shadow: 0px -1px 3px 0px rgba(1,72,118,0.75);
|
||||
-moz-box-shadow: 0px -1px 3px 0px rgba(1,72,118,0.75);
|
||||
box-shadow: 0px -1px 3px 0px rgba(1,72,118,0.75);
|
||||
}
|
||||
|
||||
.h5p-joubelui-progressbar-slide-status-text {
|
||||
font-size: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.h5p-joubelui-progressbar-background {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
background-color: #014876;
|
||||
-webkit-transition: width .3s ease-in-out;
|
||||
-moz-transition: width .3s ease-in-out;
|
||||
-o-transition: width .3s ease-in-out;
|
||||
transition: width .3s ease-in-out;
|
||||
}
|
||||
.h5p-joubelui-drop {
|
||||
z-index: 1;
|
||||
}
|
||||
.drop-element.h5p-joubelui-drop .drop-content {
|
||||
padding: .2em .8em;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
.h5p-joubelui-score-bar {
|
||||
display: inline-flex;
|
||||
display: -webkit-inline-flexbox;
|
||||
display: -ms-inline-flexbox;
|
||||
display: -webkit-inline-flex;
|
||||
width: 15em;
|
||||
max-width: 100%;
|
||||
background: #fff;
|
||||
border-radius: 1.5em;
|
||||
padding: 0.625em;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
.h5p-joubelui-score-bar-visuals {
|
||||
flex: 1;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex: 1;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
.h5p-joubelui-score-bar-progress-wrapper {
|
||||
position: relative;
|
||||
margin-right: 1.7em;
|
||||
height: 0.917em;
|
||||
border-top-left-radius: 1.5em;
|
||||
border-bottom-left-radius: 1.5em;
|
||||
background: #ddd;
|
||||
}
|
||||
.h5p-joubelui-score-bar-progress {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
color: transparent;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
border-top-left-radius: .5em;
|
||||
border-bottom-left-radius: .5em;
|
||||
background: #48b57e; /* For browsers not supporting linear-gradient */
|
||||
background: linear-gradient(to right, #52ca8d, #48b57e);
|
||||
-webkit-transition: width 0.4s ease-in-out;
|
||||
-moz-transition: width 0.4s ease-in-out;
|
||||
-o-transition: width 0.4s ease-in-out;
|
||||
transition: width 0.4s ease-in-out;
|
||||
-webkit-backface-visibility: hidden;
|
||||
}
|
||||
/* The star */
|
||||
.h5p-joubelui-score-bar-star {
|
||||
height: 1.8em;
|
||||
width: 2.1em;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -0.4em;
|
||||
overflow: visible;
|
||||
}
|
||||
.h5p-joubelui-score-bar-full-score.h5p-joubelui-score-bar-animation-active .h5p-joubelui-score-bar-star {
|
||||
-webkit-animation: pound 0.8s 1;
|
||||
animation: pound 0.8s 1;
|
||||
}
|
||||
@keyframes pound {
|
||||
from {
|
||||
transform: scale(0);
|
||||
}
|
||||
20% {
|
||||
transform: scale(1.4);
|
||||
}
|
||||
60% {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
80% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes pound {
|
||||
from {
|
||||
-webkit-transform: scale(0);
|
||||
}
|
||||
20% {
|
||||
-webkit-transform: scale(1.4);
|
||||
}
|
||||
60% {
|
||||
-webkit-transform: scale(0.8);
|
||||
}
|
||||
80% {
|
||||
-webkit-transform: scale(1.2);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: scale(1);
|
||||
}
|
||||
}
|
||||
/* Styling the star */
|
||||
.h5p-joubelui-score-bar-star svg {
|
||||
overflow: visible;
|
||||
}
|
||||
.h5p-joubelui-score-bar-star-shadow {
|
||||
fill: #fff;
|
||||
}
|
||||
.h5p-joubelui-score-bar-star-border {
|
||||
fill: none;
|
||||
stroke: #ddd;
|
||||
stroke-miterlimit: 10;
|
||||
stroke-width: 3px;
|
||||
}
|
||||
.h5p-joubelui-score-bar-star-fill {
|
||||
fill: #ddd;
|
||||
}
|
||||
.h5p-joubelui-score-bar-full-score .h5p-joubelui-score-bar-star-border {
|
||||
stroke: #ab741a;
|
||||
stroke-width: 6;
|
||||
}
|
||||
.h5p-joubelui-score-bar-star-fill-full-score {
|
||||
visibility: hidden;
|
||||
fill: #ffc80b;
|
||||
}
|
||||
.h5p-joubelui-score-bar-full-score .h5p-joubelui-score-bar-star-fill {
|
||||
/* This will be a fallback for browsers not supporting the filter,
|
||||
i.e. Safari */
|
||||
fill: #ffc80b;
|
||||
}
|
||||
.h5p-joubelui-score-bar-full-score .h5p-joubelui-score-bar-star-fill-full-score {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* The numeric part on the end (score / maxScore) */
|
||||
.h5p-joubelui-score-numeric {
|
||||
margin: 0em 0.4em;
|
||||
font-size: 1.333em;
|
||||
line-height: 0.7;
|
||||
font-weight: bold;
|
||||
}
|
||||
.h5p-score-bar-has-help .h5p-joubelui-score-numeric {
|
||||
/* Need more space when icon is displayed */
|
||||
margin-right: 0.625em;
|
||||
}
|
||||
.h5p-joubelui-score-number {
|
||||
color: #333;
|
||||
}
|
||||
.h5p-joubelui-score-number-separator {
|
||||
color: #999;
|
||||
padding: 0 0.1em;
|
||||
}
|
||||
.h5p-joubelui-score-bar .joubel-tip-container {
|
||||
position: absolute;
|
||||
top: 0.1em;
|
||||
right: 0.3em;
|
||||
font-size: 1em;
|
||||
line-height: 1;
|
||||
color: #1a73d9;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
.h5p-joubelui-score-bar .joubel-tip-container > .help-icon {
|
||||
font-size: 1em;
|
||||
line-height: 1;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
.joubel-simple-rounded-button {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin: 0.25em 0;
|
||||
padding: 0.3em 1.2em;
|
||||
border-radius: 2em;
|
||||
background-color: #1a73d9;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.joubel-simple-rounded-button:hover,
|
||||
.joubel-simple-rounded-button:focus {
|
||||
background-color: #1356a3;
|
||||
}
|
||||
|
||||
.joubel-simple-rounded-button:active {
|
||||
position: relative;
|
||||
background-color: #104888;
|
||||
|
||||
-webkit-box-shadow: inset 0 4px 0px #0e407a;
|
||||
-moz-box-shadow: inset 0 4px 0px #0e407a;
|
||||
box-shadow: inset 0 4px 0px #0e407a;
|
||||
}
|
||||
|
||||
.joubel-simple-rounded-button:active .joubel-simple-rounded-button-text {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
.h5p-joubel-ui-slider {
|
||||
-webkit-transition: -webkit-transform 0.3s ease-in-out;
|
||||
-moz-transition: -moz-transform 0.3s ease-in-out;
|
||||
-ms-transition: -ms-transform 0.3s ease-in-out;
|
||||
transition: transform 0.3s ease-in-out;
|
||||
|
||||
/* Avoid flickering */
|
||||
-webkit-transform: translateX(0);
|
||||
-moz-transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
|
||||
height: 100%;
|
||||
}
|
||||
.h5p-joubel-ui-slide {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
display: none;
|
||||
}
|
||||
.h5p-joubel-ui-slide.current {
|
||||
display: block;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
@CHARSET "UTF-8";
|
||||
|
||||
.joubel-speech-bubble {
|
||||
position: absolute;
|
||||
color: #333;
|
||||
z-index: 301;
|
||||
margin-top: 0.45em;
|
||||
min-width: 1em;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
.joubel-speech-bubble p {
|
||||
margin: 0.75em 0;
|
||||
}
|
||||
.joubel-speech-bubble p:first-child {
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
.joubel-speech-bubble p:last-child {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
.joubel-speech-bubble.show {
|
||||
opacity: 1;
|
||||
}
|
||||
.joubel-speech-bubble-inner {
|
||||
background: #fbfbfb;
|
||||
box-shadow: 0 0 0.5em #2c2c2c;
|
||||
border-radius: 0.5em;
|
||||
padding: 0.2em 0.5em;
|
||||
text-align: left;
|
||||
position: relative;
|
||||
word-wrap: break-word; /* Long words have to break */
|
||||
z-index: 1;
|
||||
}
|
||||
.joubel-speech-bubble-inner-tail,
|
||||
.joubel-speech-bubble-tail {
|
||||
position: absolute;
|
||||
/* Setting these in pixels is intentional. We use it when calculating placement of bubble */
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: #fbfbfb;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
-o-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
z-index: -1;
|
||||
}
|
||||
.joubel-speech-bubble-tail {
|
||||
box-shadow: 0 0 0.5em #2c2c2c;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
.joubel-tip-container {
|
||||
display: inline-block;
|
||||
font-weight: normal;
|
||||
color: #777;
|
||||
cursor: pointer;
|
||||
}
|
||||
.joubel-tip-container:hover {
|
||||
color: #333;
|
||||
}
|
||||
.joubel-tip-container:focus {
|
||||
outline: 0;
|
||||
box-shadow: 0px 0px 5px 2px rgba(140,185,240,1);
|
||||
outline: rgba(140,185,240,1) solid 1px;
|
||||
}
|
||||
.using-mouse .joubel-tip-container:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.joubel-tip-container.be-quiet:focus {
|
||||
outline: none;
|
||||
}
|
||||
.joubel-tip-container.be-quiet {
|
||||
pointer-events: none;
|
||||
}
|
||||
.joubel-tip-icon {
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
line-height: 1.5em;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
pointer-events: none;
|
||||
}
|
||||
.joubel-tip-icon:before {
|
||||
font-family: Joubel;
|
||||
content: "\e888";
|
||||
|
||||
/* Better Font Rendering */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.joubel-tip-icon.help-icon:before {
|
||||
font-family: 'H5PFontAwesome4';
|
||||
content: "\f059";
|
||||
}
|
||||
|
||||
.joubel-tip-container * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.joubel-tip-container .hidden-but-read {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
@CHARSET "UTF-8";
|
||||
|
||||
/* Styling of button */
|
||||
.h5peditor .ui-dialog .h5p-joubelui-button,
|
||||
.h5peditor .h5p-joubelui-button,
|
||||
.h5p-joubelui-button {
|
||||
font-size: 1em;
|
||||
line-height: 1.2;
|
||||
margin: 0 0.5em 1em;
|
||||
padding: 0.5em 1.25em;
|
||||
border-radius: 2em;
|
||||
|
||||
background: #1a73d9;
|
||||
color: #ffffff;
|
||||
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
text-shadow: none;
|
||||
text-decoration: none;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
.h5p-joubelui-button:first-child {
|
||||
margin: 0 0.5em 1em 0;
|
||||
}
|
||||
|
||||
.h5p-joubelui-button:last-child {
|
||||
margin: 0 0 1em 0.5em;
|
||||
}
|
||||
|
||||
.h5p-joubelui-button:first-child:last-child {
|
||||
margin: 0 0 1em;
|
||||
}
|
||||
|
||||
/* Truncated buttons */
|
||||
.h5p-joubelui-button.truncated {
|
||||
width: 2.235em;
|
||||
height: 2.235em;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.h5p-joubelui-button.truncated:before {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.h5p-joubelui-button:hover,
|
||||
.h5p-joubelui-button:focus {
|
||||
background: #1356a3;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
-webkit-transition: initial;
|
||||
-moz-transition: initial;
|
||||
-o-transition: initial;
|
||||
transition: initial;
|
||||
}
|
||||
.h5p-joubelui-button:active {
|
||||
position: relative;
|
||||
background: #104888;
|
||||
|
||||
-webkit-box-shadow: inset 0 4px 0 #0e407a;
|
||||
-moz-box-shadow: inset 0 4px 0 #0e407a;
|
||||
box-shadow: inset 0 4px 0 #0e407a;
|
||||
}
|
||||
.h5p-joubelui-button:active .h5p-joubelui-button-text {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.h5p-joubelui-button:before {
|
||||
font-family: 'H5PFontAwesome4';
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
.h5p-question-try-again:before {
|
||||
content: "\F01E";
|
||||
}
|
||||
|
||||
.h5p-question-show-solution:before {
|
||||
content: "\F06E";
|
||||
}
|
||||
|
||||
.h5p-question-check-answer:before {
|
||||
content: "\F058";
|
||||
}
|
||||
|
||||
/* Remove outline for all elements having tabIndex="-1"*/
|
||||
.h5p-content [tabIndex="-1"] {
|
||||
outline: none;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Generated by IcoMoon</metadata>
|
||||
<defs>
|
||||
<font id="joubel" horiz-adv-x="1024">
|
||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||
<missing-glyph horiz-adv-x="1024" />
|
||||
<glyph unicode=" " horiz-adv-x="512" d="" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1015.937 644.199c10.751-33.596 16.126-69.207 16.126-105.491 0-232.483-231.139-421.291-516.031-421.291-38.971 0-188.136-26.205-296.315-46.362l-59.801-135.727c0 0 351.412 68.535 415.244 68.535 284.892 0 516.031 188.808 516.031 421.291-0.672 80.63-27.549 155.213-75.255 219.045z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1015.937 644.199c-57.113 181.417-259.36 315.801-499.906 315.801-284.892 0-516.031-188.808-516.031-421.291 0-117.585 59.129-223.748 154.541-300.346l-53.753-188.808c0 0 51.738 10.079 118.929 22.173 108.178 20.157 256.672 46.362 296.315 46.362 284.892 0 516.031 188.808 516.031 421.291 0 36.283-5.375 71.223-16.126 104.819z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1015.937 644.199c10.751-33.596 16.126-69.207 16.126-105.491 0-232.483-231.139-421.291-516.031-421.291-38.971 0-188.136-26.205-296.315-46.362l-59.801-135.727c0 0 351.412 68.535 415.244 68.535 284.892 0 516.031 188.808 516.031 421.291-0.672 80.63-27.549 155.213-75.255 219.045z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1015.937 644.199c-57.113 181.417-259.36 315.801-499.906 315.801-284.892 0-516.031-188.808-516.031-421.291 0-117.585 59.129-223.748 154.541-300.346l-53.753-188.808c0 0 51.738 10.079 118.929 22.173 108.178 20.157 256.672 46.362 296.315 46.362 284.892 0 516.031 188.808 516.031 421.291 0 36.283-5.375 71.223-16.126 104.819z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M692.073 626.058c0-14.11-2.016-26.877-6.047-38.971s-8.735-22.173-13.438-29.564c-4.703-7.391-12.094-15.454-20.829-22.845-9.407-7.391-16.798-13.438-22.173-16.798s-13.438-8.063-23.517-13.438c-10.751-6.047-19.486-14.11-26.205-24.861s-10.751-19.486-10.751-25.533c0-4.031-1.344-8.735-4.703-12.766s-6.719-6.047-10.751-6.047h-92.052c-4.031 0-7.391 2.688-10.079 7.391s-4.031 9.407-4.031 14.11v17.47c0 21.501 8.063 41.659 24.861 60.472s34.94 32.924 55.097 41.659c15.454 6.719 26.205 14.11 32.252 21.501 6.719 7.391 9.407 17.47 9.407 28.892 0 10.751-6.047 20.157-18.142 28.22s-25.533 12.094-41.659 12.094c-16.798 0-30.236-4.031-41.659-11.423-8.735-6.719-22.845-20.829-40.987-44.346-3.36-4.031-7.391-6.047-12.094-6.047-3.36 0-6.047 1.344-9.407 3.36l-61.816 49.050c-3.36 2.688-5.375 6.047-6.047 9.407-0.672 4.031 0 7.391 2.016 10.751 40.987 67.864 100.787 102.131 178.058 102.131 20.829 0 40.987-4.031 61.816-12.094s39.643-18.814 56.441-31.58c16.798-13.438 30.236-29.564 40.987-49.050 10.079-19.486 15.454-39.643 15.454-61.144zM570.457 395.591v-92.052c0-4.031-1.344-7.391-4.703-10.751s-6.719-4.703-10.751-4.703h-92.052c-4.031 0-7.391 1.344-10.751 4.703s-4.703 6.719-4.703 10.751v92.052c0 4.031 1.344 7.391 4.703 10.751s6.719 4.703 10.751 4.703h92.052c4.031 0 7.391-1.344 10.751-4.703 3.36-2.688 4.703-6.719 4.703-10.751z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1015.937 644.199c10.751-33.596 16.126-69.207 16.126-105.491 0-232.483-231.139-421.291-516.031-421.291-38.971 0-188.136-26.205-296.315-46.362l-59.801-135.727c0 0 351.412 68.535 415.244 68.535 284.892 0 516.031 188.808 516.031 421.291-0.672 80.63-27.549 155.213-75.255 219.045z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1030.719 622.698c6.719-14.782 12.766-30.236 18.142-45.69 10.751-33.596 16.126-68.535 16.126-104.819 0-232.483-231.139-421.291-516.031-421.291-39.643 0-188.136-26.205-296.315-46.362-26.205-4.703-49.722-8.735-68.535-12.766l-24.861-55.769c0 0 351.412 68.535 415.244 68.535 284.892 0 516.031 188.808 516.031 421.291 0 71.223-21.501 138.415-59.801 196.871z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1048.861 577.008c-4.703 15.454-10.751 30.908-18.142 45.69-74.583 157.9-262.047 270.11-481.764 270.11-284.892 0-516.031-188.808-516.031-421.291 0-117.585 59.129-223.748 154.541-300.346l-53.753-188.808c0 0 19.486 4.031 50.394 9.407 19.486 3.36 43.003 8.063 68.535 12.766 108.178 20.157 256.672 46.362 296.315 46.362 284.892 0 516.031 188.808 516.031 421.291 0 36.283-5.375 71.223-16.126 104.819z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M724.997 558.866c0-14.11-2.016-26.877-6.047-38.971s-8.735-22.173-13.438-29.564c-4.703-7.391-12.094-15.454-20.829-22.845-9.407-7.391-16.798-13.438-22.173-16.798s-13.438-8.063-23.517-13.438c-10.751-6.047-19.486-14.11-26.205-24.861s-10.751-19.486-10.751-25.533c0-4.031-1.344-8.735-4.703-12.766s-6.719-6.047-10.751-6.047h-92.052c-4.031 0-7.391 2.688-10.079 7.391s-4.031 9.407-4.031 14.11v17.47c0 21.501 8.063 41.659 24.861 60.472s34.94 32.924 55.097 41.659c15.454 6.719 26.205 14.11 32.252 21.501 6.719 7.391 9.407 17.47 9.407 28.892 0 10.751-6.047 20.157-18.142 28.22s-25.533 12.094-41.659 12.094c-16.798 0-30.236-4.031-41.659-11.423-8.735-6.719-22.845-20.829-40.987-44.346-3.36-4.031-7.391-6.047-12.094-6.047-3.36 0-6.047 1.344-9.407 3.36l-63.16 48.378c-3.36 2.688-5.375 6.047-6.047 9.407-0.672 4.031 0 7.391 2.016 10.751 40.987 67.864 100.787 102.131 178.058 102.131 20.829 0 40.987-4.031 61.816-12.094s39.643-18.814 56.441-31.58c16.798-13.438 30.236-29.564 40.987-49.050 11.423-18.814 16.798-38.971 16.798-60.472zM603.381 328.399v-92.052c0-4.031-1.344-7.391-4.703-10.751s-6.719-4.703-10.751-4.703h-92.052c-4.031 0-7.391 1.344-10.751 4.703s-4.703 6.719-4.703 10.751v92.052c0 4.031 1.344 7.391 4.703 10.751s6.719 4.703 10.751 4.703h92.052c4.031 0 7.391-1.344 10.751-4.703s4.703-6.719 4.703-10.751z" />
|
||||
<glyph unicode="" glyph-name="examples" horiz-adv-x="1421" d="M952.805 828.213c-71.195 0-137.846-18.178-196.923-56.047v-615.006c60.592 30.296 125.728 45.444 196.923 45.444 121.183 0 204.497-33.325 315.077-78.769l-78.769 654.391c-72.71 33.325-157.538 49.988-236.308 49.988zM474.13 828.213c-78.769 0-163.598-16.663-236.308-49.988l-78.769-654.391c110.58 45.444 193.893 78.769 315.077 78.769 74.225 0 139.361-15.148 202.982-48.473v613.491c-59.077 42.414-130.272 60.592-202.982 60.592zM116.639 858.509l-116.639-901.302c119.669-39.385 230.249 93.917 451.408 90.888 180.26-3.030 260.544-109.065 260.544-109.065s103.006 119.669 289.325 115.124c127.243-3.030 333.254-169.657 419.598-99.976l-113.609 902.817c0 0-190.864 103.006-296.899 101.491-154.509-4.544-289.325-63.621-289.325-63.621s-165.112 71.195-271.148 65.136c-186.32-13.633-333.254-101.491-333.254-101.491zM1204.26 52.639c-80.284 36.355-163.598 59.077-251.456 59.077-90.888 0-174.201-30.296-239.337-95.432-65.136 65.136-148.45 95.432-239.337 95.432-87.858 0-171.172-21.207-251.456-57.562-51.503-22.722-104.521-36.355-162.083-36.355h-3.030l99.976 814.959c90.888 51.503 202.982 81.799 309.018 81.799 86.343 0 175.716-18.178 248.426-68.166 72.71 49.988 162.083 68.166 248.426 68.166 106.036 0 216.615-28.781 309.018-81.799l99.976-814.959c-62.107-1.515-113.609 10.604-168.142 34.84z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1015.937 644.199c10.751-33.596 16.126-69.207 16.126-105.491 0-232.483-231.139-421.291-516.031-421.291-38.971 0-188.136-26.205-296.315-46.362l-59.801-135.727c0 0 351.412 68.535 415.244 68.535 284.892 0 516.031 188.808 516.031 421.291-0.672 80.63-27.549 155.213-75.255 219.045z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M633.617 361.995v-49.050c0-6.719-2.688-12.766-7.391-17.47s-10.751-7.391-17.47-7.391h-196.871c-6.719 0-12.766 2.688-17.47 7.391s-7.391 10.751-7.391 17.47v49.050c0 6.719 2.688 12.094 7.391 17.47 4.703 4.703 10.751 7.391 17.47 7.391h24.861v147.822h-24.861c-6.719 0-12.766 2.688-17.47 7.391s-7.391 10.751-7.391 17.47v49.050c0 6.719 2.688 12.094 7.391 17.47 4.703 4.703 10.751 7.391 17.47 7.391h147.822c6.719 0 12.094-2.688 17.47-7.391 4.703-4.703 7.391-10.751 7.391-17.47v-221.732h24.861c6.719 0 12.094-2.688 17.47-7.391 4.031-5.375 6.719-10.751 6.719-17.47zM583.895 804.787v-73.911c0-6.719-2.688-12.766-7.391-17.47s-10.751-7.391-17.47-7.391h-98.1c-6.719 0-12.766 2.688-17.47 7.391s-6.719 10.751-6.719 17.47v73.911c0 6.719 2.688 12.094 7.391 17.47 4.703 4.703 10.751 7.391 17.47 7.391h98.1c6.719 0 12.094-2.688 17.47-7.391 4.703-5.375 6.719-10.751 6.719-17.47z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M663.181 295.475v-49.050c0-6.719-2.688-12.766-7.391-17.47s-10.751-7.391-17.47-7.391h-196.871c-6.719 0-12.766 2.688-17.47 7.391s-7.391 10.751-7.391 17.47v49.050c0 6.719 2.688 12.094 7.391 17.47 4.703 4.703 10.751 7.391 17.47 7.391h24.861v147.822h-24.861c-6.719 0-12.766 2.688-17.47 7.391s-7.391 10.751-7.391 17.47v49.050c0 6.719 2.688 12.094 7.391 17.47 4.703 4.703 10.751 7.391 17.47 7.391h147.822c6.719 0 12.094-2.688 17.47-7.391s7.391-10.751 7.391-17.47v-221.732h24.189c6.719 0 12.094-2.688 17.47-7.391 4.703-5.375 7.391-10.751 7.391-17.47zM613.459 738.268v-73.911c0-6.719-2.688-12.766-7.391-17.47s-10.751-7.391-17.47-7.391h-98.1c-6.719 0-12.766 2.688-17.47 7.391s-7.391 10.751-7.391 17.47v73.911c0 6.719 2.688 12.094 7.391 17.47 4.703 4.703 10.751 7.391 17.47 7.391h98.1c6.719 0 12.094-2.688 17.47-7.391s7.391-10.751 7.391-17.47z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1021.312 636.136c9.407-18.814 17.47-37.627 24.189-57.785 10.751-34.268 16.126-69.207 16.126-104.819 0-232.483-231.139-421.291-516.031-421.291-39.643 0-188.136-26.205-296.315-46.362-24.189-4.031-46.362-8.063-64.504-12.094l-25.533-57.785c0 0 351.412 68.535 415.244 68.535 284.892 0 516.031 188.808 516.031 421.291 0 77.27-24.861 148.493-69.207 210.31z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1045.501 578.352c-6.047 20.157-14.11 38.971-24.189 57.785-77.942 151.181-262.047 258.016-475.717 258.016-284.892 0-516.031-188.808-516.031-421.291 0-117.585 59.129-224.42 154.541-300.346l-53.753-188.808c0 0 21.501 4.031 54.425 10.079 18.142 3.36 40.315 7.391 64.504 12.094 108.178 20.157 256.672 46.362 296.315 46.362 284.892 0 516.031 188.808 516.031 421.291 0 35.612-5.375 70.551-16.126 104.819z" />
|
||||
<glyph unicode="" glyph-name="tutorial" horiz-adv-x="1537" d="M1521.881 683.565l-747.565-234.821c-2.972 0-4.459 0-5.945 0s-4.459 0-5.945 0l-435.46 136.731c-38.642-29.724-65.393-104.035-69.852-193.208 25.266-14.862 41.614-41.614 41.614-72.824 0-29.724-14.862-56.476-38.642-71.338l38.642-288.325c0-5.945-1.486-11.89-5.945-16.348s-10.403-7.431-16.348-7.431h-127.814c-5.945 0-11.89 2.972-16.348 7.431s-5.945 10.403-5.945 16.348l38.642 288.325c-23.779 14.862-38.642 41.614-38.642 71.338 0 32.697 17.835 59.448 43.1 74.311 4.459 78.769 23.779 161.997 65.393 219.959l-219.959 69.852c-8.917 2.972-14.862 11.89-14.862 20.807s5.945 17.835 14.862 20.807l746.078 234.821c2.972 0 4.459 0 5.945 0s4.459 0 5.945 0l747.565-234.821c8.917-2.972 14.862-11.89 14.862-20.807s-4.459-17.835-13.376-20.807zM1194.914 276.343c5.945-93.631-191.721-170.914-426.543-170.914-234.821 1.486-432.488 77.283-426.543 170.914l11.89 211.042 383.443-120.383c10.403-2.972 20.807-4.459 32.697-4.459s20.807 1.486 32.697 4.459l383.443 120.383 8.917-211.042z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1015.937 644.199c-57.113 181.417-259.36 315.801-499.906 315.801-284.892 0-516.031-188.808-516.031-421.291 0-117.585 59.129-223.748 154.541-300.346l-53.753-188.808c0 0 51.738 10.079 118.929 22.173 108.178 20.157 256.672 46.362 296.315 46.362 284.892 0 516.031 188.808 516.031 421.291 0 36.283-5.375 71.223-16.126 104.819z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M692.073 626.058c0-14.11-2.016-26.877-6.047-38.971s-8.735-22.173-13.438-29.564c-4.703-7.391-12.094-15.454-20.829-22.845-9.407-7.391-16.798-13.438-22.173-16.798s-13.438-8.063-23.517-13.438c-10.751-6.047-19.486-14.11-26.205-24.861s-10.751-19.486-10.751-25.533c0-4.031-1.344-8.735-4.703-12.766s-6.719-6.047-10.751-6.047h-92.052c-4.031 0-7.391 2.688-10.079 7.391s-4.031 9.407-4.031 14.11v17.47c0 21.501 8.063 41.659 24.861 60.472s34.94 32.924 55.097 41.659c15.454 6.719 26.205 14.11 32.252 21.501 6.719 7.391 9.407 17.47 9.407 28.892 0 10.751-6.047 20.157-18.142 28.22s-25.533 12.094-41.659 12.094c-16.798 0-30.236-4.031-41.659-11.423-8.735-6.719-22.845-20.829-40.987-44.346-3.36-4.031-7.391-6.047-12.094-6.047-3.36 0-6.047 1.344-9.407 3.36l-61.816 49.050c-3.36 2.688-5.375 6.047-6.047 9.407-0.672 4.031 0 7.391 2.016 10.751 40.987 67.864 100.787 102.131 178.058 102.131 20.829 0 40.987-4.031 61.816-12.094s39.643-18.814 56.441-31.58c16.798-13.438 30.236-29.564 40.987-49.050 10.079-19.486 15.454-39.643 15.454-61.144zM570.457 395.591v-92.052c0-4.031-1.344-7.391-4.703-10.751s-6.719-4.703-10.751-4.703h-92.052c-4.031 0-7.391 1.344-10.751 4.703s-4.703 6.719-4.703 10.751v92.052c0 4.031 1.344 7.391 4.703 10.751s6.719 4.703 10.751 4.703h92.052c4.031 0 7.391-1.344 10.751-4.703 3.36-2.688 4.703-6.719 4.703-10.751z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M1015.937 644.199c-57.113 181.417-259.36 315.801-499.906 315.801-284.892 0-516.031-188.808-516.031-421.291 0-117.585 59.129-223.748 154.541-300.346l-53.753-188.808c0 0 51.738 10.079 118.929 22.173 108.178 20.157 256.672 46.362 296.315 46.362 284.892 0 516.031 188.808 516.031 421.291 0 36.283-5.375 71.223-16.126 104.819z" />
|
||||
<glyph unicode="" horiz-adv-x="1091" d="M633.617 361.995v-49.050c0-6.719-2.688-12.766-7.391-17.47s-10.751-7.391-17.47-7.391h-196.871c-6.719 0-12.766 2.688-17.47 7.391s-7.391 10.751-7.391 17.47v49.050c0 6.719 2.688 12.094 7.391 17.47 4.703 4.703 10.751 7.391 17.47 7.391h24.861v147.822h-24.861c-6.719 0-12.766 2.688-17.47 7.391s-7.391 10.751-7.391 17.47v49.050c0 6.719 2.688 12.094 7.391 17.47 4.703 4.703 10.751 7.391 17.47 7.391h147.822c6.719 0 12.094-2.688 17.47-7.391 4.703-4.703 7.391-10.751 7.391-17.47v-221.732h24.861c6.719 0 12.094-2.688 17.47-7.391 4.031-5.375 6.719-10.751 6.719-17.47zM583.895 804.787v-73.911c0-6.719-2.688-12.766-7.391-17.47s-10.751-7.391-17.47-7.391h-98.1c-6.719 0-12.766 2.688-17.47 7.391s-6.719 10.751-6.719 17.47v73.911c0 6.719 2.688 12.094 7.391 17.47 4.703 4.703 10.751 7.391 17.47 7.391h98.1c6.719 0 12.094-2.688 17.47-7.391 4.703-5.375 6.719-10.751 6.719-17.47z" />
|
||||
</font></defs></svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,93 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
/**
|
||||
* Class responsible for creating a help text dialog
|
||||
*/
|
||||
H5P.JoubelHelpTextDialog = (function ($) {
|
||||
|
||||
var numInstances = 0;
|
||||
/**
|
||||
* Display a pop-up containing a message.
|
||||
*
|
||||
* @param {H5P.jQuery} $container The container which message dialog will be appended to
|
||||
* @param {string} message The message
|
||||
* @param {string} closeButtonTitle The title for the close button
|
||||
* @return {H5P.jQuery}
|
||||
*/
|
||||
function JoubelHelpTextDialog(header, message, closeButtonTitle) {
|
||||
H5P.EventDispatcher.call(this);
|
||||
|
||||
var self = this;
|
||||
|
||||
numInstances++;
|
||||
var headerId = 'joubel-help-text-header-' + numInstances;
|
||||
var helpTextId = 'joubel-help-text-body-' + numInstances;
|
||||
|
||||
var $helpTextDialogBox = $('<div>', {
|
||||
'class': 'joubel-help-text-dialog-box',
|
||||
'role': 'dialog',
|
||||
'aria-labelledby': headerId,
|
||||
'aria-describedby': helpTextId
|
||||
});
|
||||
|
||||
$('<div>', {
|
||||
'class': 'joubel-help-text-dialog-background'
|
||||
}).appendTo($helpTextDialogBox);
|
||||
|
||||
var $helpTextDialogContainer = $('<div>', {
|
||||
'class': 'joubel-help-text-dialog-container'
|
||||
}).appendTo($helpTextDialogBox);
|
||||
|
||||
$('<div>', {
|
||||
'class': 'joubel-help-text-header',
|
||||
'id': headerId,
|
||||
'role': 'header',
|
||||
'html': header
|
||||
}).appendTo($helpTextDialogContainer);
|
||||
|
||||
$('<div>', {
|
||||
'class': 'joubel-help-text-body',
|
||||
'id': helpTextId,
|
||||
'html': message,
|
||||
'role': 'document',
|
||||
'tabindex': 0
|
||||
}).appendTo($helpTextDialogContainer);
|
||||
|
||||
var handleClose = function () {
|
||||
$helpTextDialogBox.remove();
|
||||
self.trigger('closed');
|
||||
};
|
||||
|
||||
var $closeButton = $('<div>', {
|
||||
'class': 'joubel-help-text-remove',
|
||||
'role': 'button',
|
||||
'title': closeButtonTitle,
|
||||
'tabindex': 1,
|
||||
'click': handleClose,
|
||||
'keydown': function (event) {
|
||||
// 32 - space, 13 - enter
|
||||
if ([32, 13].indexOf(event.which) !== -1) {
|
||||
event.preventDefault();
|
||||
handleClose();
|
||||
}
|
||||
}
|
||||
}).appendTo($helpTextDialogContainer);
|
||||
|
||||
/**
|
||||
* Get the DOM element
|
||||
* @return {HTMLElement}
|
||||
*/
|
||||
self.getElement = function () {
|
||||
return $helpTextDialogBox;
|
||||
};
|
||||
|
||||
self.focus = function () {
|
||||
$closeButton.focus();
|
||||
};
|
||||
}
|
||||
|
||||
JoubelHelpTextDialog.prototype = Object.create(H5P.EventDispatcher.prototype);
|
||||
JoubelHelpTextDialog.prototype.constructor = JoubelHelpTextDialog;
|
||||
|
||||
return JoubelHelpTextDialog;
|
||||
}(H5P.jQuery));
|
||||
@@ -0,0 +1,38 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
/**
|
||||
* Class responsible for creating auto-disappearing dialogs
|
||||
*/
|
||||
H5P.JoubelMessageDialog = (function ($) {
|
||||
|
||||
/**
|
||||
* Display a pop-up containing a message.
|
||||
*
|
||||
* @param {H5P.jQuery} $container The container which message dialog will be appended to
|
||||
* @param {string} message The message
|
||||
* @return {H5P.jQuery}
|
||||
*/
|
||||
function JoubelMessageDialog ($container, message) {
|
||||
var timeout;
|
||||
|
||||
var removeDialog = function () {
|
||||
$warning.remove();
|
||||
clearTimeout(timeout);
|
||||
$container.off('click.messageDialog');
|
||||
};
|
||||
|
||||
// Create warning popup:
|
||||
var $warning = $('<div/>', {
|
||||
'class': 'joubel-message-dialog',
|
||||
text: message
|
||||
}).appendTo($container);
|
||||
|
||||
// Remove after 3 seconds or if user clicks anywhere in $container:
|
||||
timeout = setTimeout(removeDialog, 3000);
|
||||
$container.on('click.messageDialog', removeDialog);
|
||||
|
||||
return $warning;
|
||||
}
|
||||
|
||||
return JoubelMessageDialog;
|
||||
})(H5P.jQuery);
|
||||
@@ -0,0 +1,159 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
/**
|
||||
* Class responsible for creating a circular progress bar
|
||||
*/
|
||||
|
||||
H5P.JoubelProgressCircle = (function ($) {
|
||||
|
||||
/**
|
||||
* Constructor for the Progress Circle
|
||||
*
|
||||
* @param {Number} number The amount of progress to display
|
||||
* @param {string} progressColor Color for the progress meter
|
||||
* @param {string} backgroundColor Color behind the progress meter
|
||||
*/
|
||||
function ProgressCircle(number, progressColor, fillColor, backgroundColor) {
|
||||
progressColor = progressColor || '#1a73d9';
|
||||
fillColor = fillColor || '#f0f0f0';
|
||||
backgroundColor = backgroundColor || '#ffffff';
|
||||
var progressColorRGB = this.hexToRgb(progressColor);
|
||||
|
||||
//Verify number
|
||||
try {
|
||||
number = Number(number);
|
||||
if (number === '') {
|
||||
throw 'is empty';
|
||||
}
|
||||
if (isNaN(number)) {
|
||||
throw 'is not a number';
|
||||
}
|
||||
} catch (e) {
|
||||
number = 'err';
|
||||
}
|
||||
|
||||
//Draw circle
|
||||
if (number > 100) {
|
||||
number = 100;
|
||||
}
|
||||
|
||||
// We can not use rgba, since they will stack on top of each other.
|
||||
// Instead we create the equivalent of the rgba color
|
||||
// and applies this to the activeborder and background color.
|
||||
var progressColorString = 'rgb(' + parseInt(progressColorRGB.r, 10) +
|
||||
',' + parseInt(progressColorRGB.g, 10) +
|
||||
',' + parseInt(progressColorRGB.b, 10) + ')';
|
||||
|
||||
// Circle wrapper
|
||||
var $wrapper = $('<div/>', {
|
||||
'class': "joubel-progress-circle-wrapper"
|
||||
});
|
||||
|
||||
//Active border indicates progress
|
||||
var $activeBorder = $('<div/>', {
|
||||
'class': "joubel-progress-circle-active-border"
|
||||
}).appendTo($wrapper);
|
||||
|
||||
//Background circle
|
||||
var $backgroundCircle = $('<div/>', {
|
||||
'class': "joubel-progress-circle-circle"
|
||||
}).appendTo($activeBorder);
|
||||
|
||||
//Progress text/number
|
||||
$('<span/>', {
|
||||
'text': number + '%',
|
||||
'class': "joubel-progress-circle-percentage"
|
||||
}).appendTo($backgroundCircle);
|
||||
|
||||
var deg = number * 3.6;
|
||||
if (deg <= 180) {
|
||||
$activeBorder.css('background-image',
|
||||
'linear-gradient(' + (90 + deg) + 'deg, transparent 50%, ' + fillColor + ' 50%),' +
|
||||
'linear-gradient(90deg, ' + fillColor + ' 50%, transparent 50%)')
|
||||
.css('border', '2px solid' + backgroundColor)
|
||||
.css('background-color', progressColorString);
|
||||
} else {
|
||||
$activeBorder.css('background-image',
|
||||
'linear-gradient(' + (deg - 90) + 'deg, transparent 50%, ' + progressColorString + ' 50%),' +
|
||||
'linear-gradient(90deg, ' + fillColor + ' 50%, transparent 50%)')
|
||||
.css('border', '2px solid' + backgroundColor)
|
||||
.css('background-color', progressColorString);
|
||||
}
|
||||
|
||||
this.$activeBorder = $activeBorder;
|
||||
this.$backgroundCircle = $backgroundCircle;
|
||||
this.$wrapper = $wrapper;
|
||||
|
||||
this.initResizeFunctionality();
|
||||
|
||||
return $wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes resize functionality for the progress circle
|
||||
*/
|
||||
ProgressCircle.prototype.initResizeFunctionality = function () {
|
||||
var self = this;
|
||||
|
||||
$(window).resize(function () {
|
||||
// Queue resize
|
||||
setTimeout(function () {
|
||||
self.resize();
|
||||
});
|
||||
});
|
||||
|
||||
// First resize
|
||||
setTimeout(function () {
|
||||
self.resize();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Resize function makes progress circle grow or shrink relative to parent container
|
||||
*/
|
||||
ProgressCircle.prototype.resize = function () {
|
||||
var $parent = this.$wrapper.parent();
|
||||
|
||||
if ($parent !== undefined && $parent) {
|
||||
|
||||
// Measurements
|
||||
var fontSize = parseInt($parent.css('font-size'), 10);
|
||||
|
||||
// Static sizes
|
||||
var fontSizeMultiplum = 3.75;
|
||||
var progressCircleWidthPx = parseInt((fontSize / 4.5), 10) % 2 === 0 ? parseInt((fontSize / 4.5), 10) + 4 : parseInt((fontSize / 4.5), 10) + 5;
|
||||
var progressCircleOffset = progressCircleWidthPx / 2;
|
||||
|
||||
var width = fontSize * fontSizeMultiplum;
|
||||
var height = fontSize * fontSizeMultiplum;
|
||||
this.$activeBorder.css({
|
||||
'width': width,
|
||||
'height': height
|
||||
});
|
||||
|
||||
this.$backgroundCircle.css({
|
||||
'width': width - progressCircleWidthPx,
|
||||
'height': height - progressCircleWidthPx,
|
||||
'top': progressCircleOffset,
|
||||
'left': progressCircleOffset
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hex to RGB conversion
|
||||
* @param hex
|
||||
* @returns {{r: Number, g: Number, b: Number}}
|
||||
*/
|
||||
ProgressCircle.prototype.hexToRgb = function (hex) {
|
||||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16)
|
||||
} : null;
|
||||
};
|
||||
|
||||
return ProgressCircle;
|
||||
|
||||
}(H5P.jQuery));
|
||||
@@ -0,0 +1,190 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
H5P.JoubelProgressbar = (function ($) {
|
||||
|
||||
/**
|
||||
* Joubel progressbar class
|
||||
* @method JoubelProgressbar
|
||||
* @constructor
|
||||
* @param {number} steps Number of steps
|
||||
* @param {Object} [options] Additional options
|
||||
* @param {boolean} [options.disableAria] Disable readspeaker assistance
|
||||
* @param {string} [options.progressText] A progress text for describing
|
||||
* current progress out of total progress for readspeakers.
|
||||
* e.g. "Slide :num of :total"
|
||||
*/
|
||||
function JoubelProgressbar(steps, options) {
|
||||
H5P.EventDispatcher.call(this);
|
||||
var self = this;
|
||||
this.options = $.extend({
|
||||
progressText: 'Slide :num of :total'
|
||||
}, options);
|
||||
this.currentStep = 0;
|
||||
this.steps = steps;
|
||||
|
||||
this.$progressbar = $('<div>', {
|
||||
'class': 'h5p-joubelui-progressbar',
|
||||
on: {
|
||||
click: function () {
|
||||
self.toggleTooltip();
|
||||
return false;
|
||||
},
|
||||
mouseenter: function () {
|
||||
self.showTooltip();
|
||||
},
|
||||
mouseleave: function () {
|
||||
setTimeout(function () {
|
||||
self.hideTooltip();
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.$background = $('<div>', {
|
||||
'class': 'h5p-joubelui-progressbar-background'
|
||||
}).appendTo(this.$progressbar);
|
||||
|
||||
$('body').click(function () {
|
||||
self.toggleTooltip(true);
|
||||
});
|
||||
}
|
||||
|
||||
JoubelProgressbar.prototype = Object.create(H5P.EventDispatcher.prototype);
|
||||
JoubelProgressbar.prototype.constructor = JoubelProgressbar;
|
||||
|
||||
/**
|
||||
* Display tooltip
|
||||
* @method showTooltip
|
||||
*/
|
||||
JoubelProgressbar.prototype.showTooltip = function () {
|
||||
var self = this;
|
||||
|
||||
if (this.currentStep === 0 || this.tooltip !== undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parentWidth = self.$progressbar.offset().left + self.$progressbar.width();
|
||||
|
||||
this.tooltip = new H5P.Drop({
|
||||
target: this.$background.get(0),
|
||||
content: this.currentStep + '/' + this.steps,
|
||||
classes: 'drop-theme-arrows-bounce h5p-joubelui-drop',
|
||||
position: 'top right',
|
||||
openOn: 'always',
|
||||
tetherOptions: {
|
||||
attachment: 'bottom center',
|
||||
targetAttachment: 'top right'
|
||||
}
|
||||
});
|
||||
this.tooltip.on('open', function () {
|
||||
var $drop = $(self.tooltip.drop);
|
||||
var left = $drop.position().left;
|
||||
var dropWidth = $drop.width();
|
||||
|
||||
// Need to handle drops getting outside of the progressbar:
|
||||
if (left < 0) {
|
||||
$drop.css({marginLeft: (-left) + 'px'});
|
||||
}
|
||||
else if (left + dropWidth > parentWidth) {
|
||||
$drop.css({marginLeft: (parentWidth - (left + dropWidth)) + 'px'});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
JoubelProgressbar.prototype.updateAria = function () {
|
||||
var self = this;
|
||||
if (this.options.disableAria) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.$currentStatus) {
|
||||
this.$currentStatus = $('<div>', {
|
||||
'class': 'h5p-joubelui-progressbar-slide-status-text',
|
||||
'aria-live': 'assertive'
|
||||
}).appendTo(this.$progressbar);
|
||||
}
|
||||
var interpolatedProgressText = self.options.progressText
|
||||
.replace(':num', self.currentStep)
|
||||
.replace(':total', self.steps);
|
||||
this.$currentStatus.html(interpolatedProgressText);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hides tooltip
|
||||
* @method hideTooltip
|
||||
*/
|
||||
JoubelProgressbar.prototype.hideTooltip = function () {
|
||||
if (this.tooltip !== undefined) {
|
||||
this.tooltip.remove();
|
||||
this.tooltip.destroy();
|
||||
this.tooltip = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggles tooltip-visibility
|
||||
* @method toggleTooltip
|
||||
* @param {boolean} [closeOnly] Don't show, only close if open
|
||||
*/
|
||||
JoubelProgressbar.prototype.toggleTooltip = function (closeOnly) {
|
||||
if (this.tooltip === undefined && !closeOnly) {
|
||||
this.showTooltip();
|
||||
}
|
||||
else if (this.tooltip !== undefined) {
|
||||
this.hideTooltip();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends to a container
|
||||
* @method appendTo
|
||||
* @param {H5P.jquery} $container
|
||||
*/
|
||||
JoubelProgressbar.prototype.appendTo = function ($container) {
|
||||
this.$progressbar.appendTo($container);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update progress
|
||||
* @method setProgress
|
||||
* @param {number} step
|
||||
*/
|
||||
JoubelProgressbar.prototype.setProgress = function (step) {
|
||||
// Check for valid value:
|
||||
if (step > this.steps || step < 0) {
|
||||
return;
|
||||
}
|
||||
this.currentStep = step;
|
||||
this.$background.css({
|
||||
width: ((this.currentStep/this.steps)*100) + '%'
|
||||
});
|
||||
|
||||
this.updateAria();
|
||||
};
|
||||
|
||||
/**
|
||||
* Increment progress with 1
|
||||
* @method next
|
||||
*/
|
||||
JoubelProgressbar.prototype.next = function () {
|
||||
this.setProgress(this.currentStep+1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset progressbar
|
||||
* @method reset
|
||||
*/
|
||||
JoubelProgressbar.prototype.reset = function () {
|
||||
this.setProgress(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if last step is reached
|
||||
* @method isLastStep
|
||||
* @return {Boolean}
|
||||
*/
|
||||
JoubelProgressbar.prototype.isLastStep = function () {
|
||||
return this.steps === this.currentStep;
|
||||
};
|
||||
|
||||
return JoubelProgressbar;
|
||||
})(H5P.jQuery);
|
||||
@@ -0,0 +1,225 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
/**
|
||||
* @module
|
||||
*/
|
||||
H5P.JoubelScoreBar = (function ($) {
|
||||
|
||||
/* Need to use an id for the star SVG since that is the only way to reference
|
||||
SVG filters */
|
||||
var idCounter = 0;
|
||||
|
||||
/**
|
||||
* Creates a score bar
|
||||
* @class H5P.JoubelScoreBar
|
||||
* @param {number} maxScore Maximum score
|
||||
* @param {string} [label] Makes it easier for readspeakers to identify the scorebar
|
||||
* @param {string} [helpText] Score explanation
|
||||
* @param {string} [scoreExplanationButtonLabel] Label for score explanation button
|
||||
*/
|
||||
function JoubelScoreBar(maxScore, label, helpText, scoreExplanationButtonLabel) {
|
||||
var self = this;
|
||||
|
||||
self.maxScore = maxScore;
|
||||
self.score = 0;
|
||||
idCounter++;
|
||||
|
||||
/**
|
||||
* @const {string}
|
||||
*/
|
||||
self.STAR_MARKUP = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 63.77 53.87" aria-hidden="true" focusable="false">' +
|
||||
'<title>star</title>' +
|
||||
'<filter id="h5p-joubelui-score-bar-star-inner-shadow-' + idCounter + '" x0="-50%" y0="-50%" width="200%" height="200%">' +
|
||||
'<feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur"></feGaussianBlur>' +
|
||||
'<feOffset dy="2" dx="4"></feOffset>' +
|
||||
'<feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowDiff"></feComposite>' +
|
||||
'<feFlood flood-color="#ffe95c" flood-opacity="1"></feFlood>' +
|
||||
'<feComposite in2="shadowDiff" operator="in"></feComposite>' +
|
||||
'<feComposite in2="SourceGraphic" operator="over" result="firstfilter"></feComposite>' +
|
||||
'<feGaussianBlur in="firstfilter" stdDeviation="3" result="blur2"></feGaussianBlur>' +
|
||||
'<feOffset dy="-2" dx="-4"></feOffset>' +
|
||||
'<feComposite in2="firstfilter" operator="arithmetic" k2="-1" k3="1" result="shadowDiff"></feComposite>' +
|
||||
'<feFlood flood-color="#ffe95c" flood-opacity="1"></feFlood>' +
|
||||
'<feComposite in2="shadowDiff" operator="in"></feComposite>' +
|
||||
'<feComposite in2="firstfilter" operator="over"></feComposite>' +
|
||||
'</filter>' +
|
||||
'<path class="h5p-joubelui-score-bar-star-shadow" d="M35.08,43.41V9.16H20.91v0L9.51,10.85,9,10.93C2.8,12.18,0,17,0,21.25a11.22,11.22,0,0,0,3,7.48l8.73,8.53-1.07,6.16Z"/>' +
|
||||
'<g>' +
|
||||
'<path class="h5p-joubelui-score-bar-star-border" d="M61.36,22.8,49.72,34.11l2.78,16a2.6,2.6,0,0,1,.05.64c0,.85-.37,1.6-1.33,1.6A2.74,2.74,0,0,1,49.94,52L35.58,44.41,21.22,52a2.93,2.93,0,0,1-1.28.37c-.91,0-1.33-.75-1.33-1.6,0-.21.05-.43.05-.64l2.78-16L9.8,22.8A2.57,2.57,0,0,1,9,21.25c0-1,1-1.33,1.81-1.49l16.07-2.35L34.09,2.83c.27-.59.85-1.33,1.55-1.33s1.28.69,1.55,1.33l7.21,14.57,16.07,2.35c.75.11,1.81.53,1.81,1.49A3.07,3.07,0,0,1,61.36,22.8Z"/>' +
|
||||
'<path class="h5p-joubelui-score-bar-star-fill" d="M61.36,22.8,49.72,34.11l2.78,16a2.6,2.6,0,0,1,.05.64c0,.85-.37,1.6-1.33,1.6A2.74,2.74,0,0,1,49.94,52L35.58,44.41,21.22,52a2.93,2.93,0,0,1-1.28.37c-.91,0-1.33-.75-1.33-1.6,0-.21.05-.43.05-.64l2.78-16L9.8,22.8A2.57,2.57,0,0,1,9,21.25c0-1,1-1.33,1.81-1.49l16.07-2.35L34.09,2.83c.27-.59.85-1.33,1.55-1.33s1.28.69,1.55,1.33l7.21,14.57,16.07,2.35c.75.11,1.81.53,1.81,1.49A3.07,3.07,0,0,1,61.36,22.8Z"/>' +
|
||||
'<path filter="url(#h5p-joubelui-score-bar-star-inner-shadow-' + idCounter + ')" class="h5p-joubelui-score-bar-star-fill-full-score" d="M61.36,22.8,49.72,34.11l2.78,16a2.6,2.6,0,0,1,.05.64c0,.85-.37,1.6-1.33,1.6A2.74,2.74,0,0,1,49.94,52L35.58,44.41,21.22,52a2.93,2.93,0,0,1-1.28.37c-.91,0-1.33-.75-1.33-1.6,0-.21.05-.43.05-.64l2.78-16L9.8,22.8A2.57,2.57,0,0,1,9,21.25c0-1,1-1.33,1.81-1.49l16.07-2.35L34.09,2.83c.27-.59.85-1.33,1.55-1.33s1.28.69,1.55,1.33l7.21,14.57,16.07,2.35c.75.11,1.81.53,1.81,1.49A3.07,3.07,0,0,1,61.36,22.8Z"/>' +
|
||||
'</g>' +
|
||||
'</svg>';
|
||||
|
||||
/**
|
||||
* @function appendTo
|
||||
* @memberOf H5P.JoubelScoreBar#
|
||||
* @param {H5P.jQuery} $wrapper Dom container
|
||||
*/
|
||||
self.appendTo = function ($wrapper) {
|
||||
self.$scoreBar.appendTo($wrapper);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the text representation of the scorebar .
|
||||
*
|
||||
* @private
|
||||
* @return {string}
|
||||
*/
|
||||
var createLabel = function (score) {
|
||||
if (!label) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return label.replace(':num', score).replace(':total', self.maxScore);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the html for this widget
|
||||
*
|
||||
* @method createHtml
|
||||
* @private
|
||||
*/
|
||||
var createHtml = function () {
|
||||
// Container div
|
||||
self.$scoreBar = $('<div>', {
|
||||
'class': 'h5p-joubelui-score-bar',
|
||||
});
|
||||
|
||||
var $visuals = $('<div>', {
|
||||
'class': 'h5p-joubelui-score-bar-visuals',
|
||||
appendTo: self.$scoreBar
|
||||
});
|
||||
|
||||
// The progress bar wrapper
|
||||
self.$progressWrapper = $('<div>', {
|
||||
'class': 'h5p-joubelui-score-bar-progress-wrapper',
|
||||
appendTo: $visuals
|
||||
});
|
||||
|
||||
self.$progress = $('<div>', {
|
||||
'class': 'h5p-joubelui-score-bar-progress',
|
||||
'html': createLabel(self.score),
|
||||
appendTo: self.$progressWrapper
|
||||
});
|
||||
|
||||
// The star
|
||||
$('<div>', {
|
||||
'class': 'h5p-joubelui-score-bar-star',
|
||||
html: self.STAR_MARKUP
|
||||
}).appendTo($visuals);
|
||||
|
||||
// The score container
|
||||
var $numerics = $('<div>', {
|
||||
'class': 'h5p-joubelui-score-numeric',
|
||||
appendTo: self.$scoreBar,
|
||||
'aria-hidden': true
|
||||
});
|
||||
|
||||
// The current score
|
||||
self.$scoreCounter = $('<span>', {
|
||||
'class': 'h5p-joubelui-score-number h5p-joubelui-score-number-counter',
|
||||
text: 0,
|
||||
appendTo: $numerics
|
||||
});
|
||||
|
||||
// The separator
|
||||
$('<span>', {
|
||||
'class': 'h5p-joubelui-score-number-separator',
|
||||
text: '/',
|
||||
appendTo: $numerics
|
||||
});
|
||||
|
||||
// Max score
|
||||
self.$maxScore = $('<span>', {
|
||||
'class': 'h5p-joubelui-score-number h5p-joubelui-score-max',
|
||||
text: self.maxScore,
|
||||
appendTo: $numerics
|
||||
});
|
||||
|
||||
if (helpText) {
|
||||
H5P.JoubelUI.createTip(helpText, {
|
||||
tipLabel: scoreExplanationButtonLabel ? scoreExplanationButtonLabel : helpText,
|
||||
helpIcon: true
|
||||
}).appendTo(self.$scoreBar);
|
||||
self.$scoreBar.addClass('h5p-score-bar-has-help');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the current score
|
||||
* @method setScore
|
||||
* @memberOf H5P.JoubelScoreBar#
|
||||
* @param {number} score
|
||||
*/
|
||||
self.setScore = function (score) {
|
||||
// Do nothing if score hasn't changed
|
||||
if (score === self.score) {
|
||||
return;
|
||||
}
|
||||
self.score = score > self.maxScore ? self.maxScore : score;
|
||||
self.updateVisuals();
|
||||
};
|
||||
|
||||
/**
|
||||
* Increment score
|
||||
* @method incrementScore
|
||||
* @memberOf H5P.JoubelScoreBar#
|
||||
* @param {number=} incrementBy Optional parameter, defaults to 1
|
||||
*/
|
||||
self.incrementScore = function (incrementBy) {
|
||||
self.setScore(self.score + (incrementBy || 1));
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the max score
|
||||
* @method setMaxScore
|
||||
* @memberOf H5P.JoubelScoreBar#
|
||||
* @param {number} maxScore The max score
|
||||
*/
|
||||
self.setMaxScore = function (maxScore) {
|
||||
self.maxScore = maxScore;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the progressbar visuals
|
||||
* @memberOf H5P.JoubelScoreBar#
|
||||
* @method updateVisuals
|
||||
*/
|
||||
self.updateVisuals = function () {
|
||||
self.$progress.html(createLabel(self.score));
|
||||
self.$scoreCounter.text(self.score);
|
||||
self.$maxScore.text(self.maxScore);
|
||||
|
||||
setTimeout(function () {
|
||||
// Start the progressbar animation
|
||||
self.$progress.css({
|
||||
width: ((self.score / self.maxScore) * 100) + '%'
|
||||
});
|
||||
|
||||
H5P.Transition.onTransitionEnd(self.$progress, function () {
|
||||
// If fullscore fill the star and start the animation
|
||||
self.$scoreBar.toggleClass('h5p-joubelui-score-bar-full-score', self.score === self.maxScore);
|
||||
self.$scoreBar.toggleClass('h5p-joubelui-score-bar-animation-active', self.score === self.maxScore);
|
||||
|
||||
// Only allow the star animation to run once
|
||||
self.$scoreBar.one("animationend", function() {
|
||||
self.$scoreBar.removeClass("h5p-joubelui-score-bar-animation-active");
|
||||
});
|
||||
}, 600);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes all classes
|
||||
* @method reset
|
||||
*/
|
||||
self.reset = function () {
|
||||
self.$scoreBar.removeClass('h5p-joubelui-score-bar-full-score');
|
||||
};
|
||||
|
||||
createHtml();
|
||||
}
|
||||
|
||||
return JoubelScoreBar;
|
||||
})(H5P.jQuery);
|
||||
@@ -0,0 +1,32 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
H5P.SimpleRoundedButton = (function ($) {
|
||||
|
||||
/**
|
||||
* Creates a new tip
|
||||
*/
|
||||
function SimpleRoundedButton(text) {
|
||||
|
||||
var $simpleRoundedButton = $('<div>', {
|
||||
'class': 'joubel-simple-rounded-button',
|
||||
'title': text,
|
||||
'role': 'button',
|
||||
'tabindex': '0'
|
||||
}).keydown(function (e) {
|
||||
// 32 - space, 13 - enter
|
||||
if ([32, 13].indexOf(e.which) !== -1) {
|
||||
$(this).click();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
$('<span>', {
|
||||
'class': 'joubel-simple-rounded-button-text',
|
||||
'html': text
|
||||
}).appendTo($simpleRoundedButton);
|
||||
|
||||
return $simpleRoundedButton;
|
||||
}
|
||||
|
||||
return SimpleRoundedButton;
|
||||
}(H5P.jQuery));
|
||||
@@ -0,0 +1,96 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
H5P.JoubelSlider = (function ($) {
|
||||
|
||||
/**
|
||||
* Creates a new Slider
|
||||
*
|
||||
* @param {object} [params] Additional parameters
|
||||
*/
|
||||
function JoubelSlider(params) {
|
||||
H5P.EventDispatcher.call(this);
|
||||
|
||||
this.$slider = $('<div>', $.extend({
|
||||
'class': 'h5p-joubel-ui-slider'
|
||||
}, params));
|
||||
|
||||
this.$slides = [];
|
||||
this.currentIndex = 0;
|
||||
this.numSlides = 0;
|
||||
}
|
||||
JoubelSlider.prototype = Object.create(H5P.EventDispatcher.prototype);
|
||||
JoubelSlider.prototype.constructor = JoubelSlider;
|
||||
|
||||
JoubelSlider.prototype.addSlide = function ($content) {
|
||||
$content.addClass('h5p-joubel-ui-slide').css({
|
||||
'left': (this.numSlides*100) + '%'
|
||||
});
|
||||
this.$slider.append($content);
|
||||
this.$slides.push($content);
|
||||
|
||||
this.numSlides++;
|
||||
|
||||
if(this.numSlides === 1) {
|
||||
$content.addClass('current');
|
||||
}
|
||||
};
|
||||
|
||||
JoubelSlider.prototype.attach = function ($container) {
|
||||
$container.append(this.$slider);
|
||||
};
|
||||
|
||||
JoubelSlider.prototype.move = function (index) {
|
||||
var self = this;
|
||||
|
||||
if(index === 0) {
|
||||
self.trigger('first-slide');
|
||||
}
|
||||
if(index+1 === self.numSlides) {
|
||||
self.trigger('last-slide');
|
||||
}
|
||||
self.trigger('move');
|
||||
|
||||
var $previousSlide = self.$slides[this.currentIndex];
|
||||
H5P.Transition.onTransitionEnd(this.$slider, function () {
|
||||
$previousSlide.removeClass('current');
|
||||
self.trigger('moved');
|
||||
});
|
||||
this.$slides[index].addClass('current');
|
||||
|
||||
var translateX = 'translateX(' + (-index*100) + '%)';
|
||||
this.$slider.css({
|
||||
'-webkit-transform': translateX,
|
||||
'-moz-transform': translateX,
|
||||
'-ms-transform': translateX,
|
||||
'transform': translateX
|
||||
});
|
||||
|
||||
this.currentIndex = index;
|
||||
};
|
||||
|
||||
JoubelSlider.prototype.remove = function () {
|
||||
this.$slider.remove();
|
||||
};
|
||||
|
||||
JoubelSlider.prototype.next = function () {
|
||||
if(this.currentIndex+1 >= this.numSlides) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.move(this.currentIndex+1);
|
||||
};
|
||||
|
||||
JoubelSlider.prototype.previous = function () {
|
||||
this.move(this.currentIndex-1);
|
||||
};
|
||||
|
||||
JoubelSlider.prototype.first = function () {
|
||||
this.move(0);
|
||||
};
|
||||
|
||||
JoubelSlider.prototype.last = function () {
|
||||
this.move(this.numSlides-1);
|
||||
};
|
||||
|
||||
return JoubelSlider;
|
||||
})(H5P.jQuery);
|
||||
@@ -0,0 +1,356 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
/**
|
||||
* Class responsible for creating speech bubbles
|
||||
*/
|
||||
H5P.JoubelSpeechBubble = (function ($) {
|
||||
|
||||
var $currentSpeechBubble;
|
||||
var $currentContainer;
|
||||
var $tail;
|
||||
var $innerTail;
|
||||
var removeSpeechBubbleTimeout;
|
||||
var currentMaxWidth;
|
||||
|
||||
var DEFAULT_MAX_WIDTH = 400;
|
||||
|
||||
var iDevice = navigator.userAgent.match(/iPod|iPhone|iPad/g) ? true : false;
|
||||
|
||||
/**
|
||||
* Creates a new speech bubble
|
||||
*
|
||||
* @param {H5P.jQuery} $container The speaking object
|
||||
* @param {string} text The text to display
|
||||
* @param {number} maxWidth The maximum width of the bubble
|
||||
* @return {H5P.JoubelSpeechBubble}
|
||||
*/
|
||||
function JoubelSpeechBubble($container, text, maxWidth) {
|
||||
maxWidth = maxWidth || DEFAULT_MAX_WIDTH;
|
||||
currentMaxWidth = maxWidth;
|
||||
$currentContainer = $container;
|
||||
|
||||
this.isCurrent = function ($tip) {
|
||||
return $tip.is($currentContainer);
|
||||
};
|
||||
|
||||
this.remove = function () {
|
||||
remove();
|
||||
};
|
||||
|
||||
var fadeOutSpeechBubble = function ($speechBubble) {
|
||||
if (!$speechBubble) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop removing bubble
|
||||
clearTimeout(removeSpeechBubbleTimeout);
|
||||
|
||||
$speechBubble.removeClass('show');
|
||||
setTimeout(function () {
|
||||
if ($speechBubble) {
|
||||
$speechBubble.remove();
|
||||
$speechBubble = undefined;
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
||||
if ($currentSpeechBubble !== undefined) {
|
||||
remove();
|
||||
}
|
||||
|
||||
var $h5pContainer = getH5PContainer($container);
|
||||
|
||||
// Make sure we fade out old speech bubble
|
||||
fadeOutSpeechBubble($currentSpeechBubble);
|
||||
|
||||
// Create bubble
|
||||
$tail = $('<div class="joubel-speech-bubble-tail"></div>');
|
||||
$innerTail = $('<div class="joubel-speech-bubble-inner-tail"></div>');
|
||||
var $innerBubble = $(
|
||||
'<div class="joubel-speech-bubble-inner">' +
|
||||
'<div class="joubel-speech-bubble-text">' + text + '</div>' +
|
||||
'</div>'
|
||||
).prepend($innerTail);
|
||||
|
||||
$currentSpeechBubble = $(
|
||||
'<div class="joubel-speech-bubble" aria-live="assertive">'
|
||||
).append([$tail, $innerBubble])
|
||||
.appendTo($h5pContainer);
|
||||
|
||||
// Show speech bubble with transition
|
||||
setTimeout(function () {
|
||||
$currentSpeechBubble.addClass('show');
|
||||
}, 0);
|
||||
|
||||
position($currentSpeechBubble, $currentContainer, maxWidth, $tail, $innerTail);
|
||||
|
||||
// Handle click to close
|
||||
H5P.$body.on('mousedown.speechBubble', handleOutsideClick);
|
||||
|
||||
// Handle window resizing
|
||||
H5P.$window.on('resize', '', handleResize);
|
||||
|
||||
// Handle clicks when inside IV which blocks bubbling.
|
||||
$container.parents('.h5p-dialog')
|
||||
.on('mousedown.speechBubble', handleOutsideClick);
|
||||
|
||||
if (iDevice) {
|
||||
H5P.$body.css('cursor', 'pointer');
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// Remove speechbubble if it belongs to a dom element that is about to be hidden
|
||||
H5P.externalDispatcher.on('domHidden', function (event) {
|
||||
if ($currentSpeechBubble !== undefined && event.data.$dom.find($currentContainer).length !== 0) {
|
||||
remove();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the closest h5p container for the given DOM element.
|
||||
*
|
||||
* @param {object} $container jquery element
|
||||
* @return {object} the h5p container (jquery element)
|
||||
*/
|
||||
function getH5PContainer($container) {
|
||||
var $h5pContainer = $container.closest('.h5p-frame');
|
||||
|
||||
// Check closest h5p frame first, then check for container in case there is no frame.
|
||||
if (!$h5pContainer.length) {
|
||||
$h5pContainer = $container.closest('.h5p-container');
|
||||
}
|
||||
|
||||
return $h5pContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler that is called when the window is resized.
|
||||
*/
|
||||
function handleResize() {
|
||||
position($currentSpeechBubble, $currentContainer, currentMaxWidth, $tail, $innerTail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Repositions the speech bubble according to the position of the container.
|
||||
*
|
||||
* @param {object} $currentSpeechbubble the speech bubble that should be positioned
|
||||
* @param {object} $container the container to which the speech bubble should point
|
||||
* @param {number} maxWidth the maximum width of the speech bubble
|
||||
* @param {object} $tail the tail (the triangle that points to the referenced container)
|
||||
* @param {object} $innerTail the inner tail (the triangle that points to the referenced container)
|
||||
*/
|
||||
function position($currentSpeechBubble, $container, maxWidth, $tail, $innerTail) {
|
||||
var $h5pContainer = getH5PContainer($container);
|
||||
|
||||
// Calculate offset between the button and the h5p frame
|
||||
var offset = getOffsetBetween($h5pContainer, $container);
|
||||
|
||||
var direction = (offset.bottom > offset.top ? 'bottom' : 'top');
|
||||
var tipWidth = offset.outerWidth * 0.9; // Var needs to be renamed to make sense
|
||||
var bubbleWidth = tipWidth > maxWidth ? maxWidth : tipWidth;
|
||||
|
||||
var bubblePosition = getBubblePosition(bubbleWidth, offset);
|
||||
var tailPosition = getTailPosition(bubbleWidth, bubblePosition, offset, $container.width());
|
||||
// Need to set font-size, since element is appended to body.
|
||||
// Using same font-size as parent. In that way it will grow accordingly
|
||||
// when resizing
|
||||
var fontSize = 16;//parseFloat($parent.css('font-size'));
|
||||
|
||||
// Set width and position of speech bubble
|
||||
$currentSpeechBubble.css(bubbleCSS(
|
||||
direction,
|
||||
bubbleWidth,
|
||||
bubblePosition,
|
||||
fontSize
|
||||
));
|
||||
|
||||
var preparedTailCSS = tailCSS(direction, tailPosition);
|
||||
$tail.css(preparedTailCSS);
|
||||
$innerTail.css(preparedTailCSS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function for removing the speechbubble
|
||||
*/
|
||||
var remove = function () {
|
||||
H5P.$body.off('mousedown.speechBubble');
|
||||
H5P.$window.off('resize', '', handleResize);
|
||||
$currentContainer.parents('.h5p-dialog').off('mousedown.speechBubble');
|
||||
if (iDevice) {
|
||||
H5P.$body.css('cursor', '');
|
||||
}
|
||||
if ($currentSpeechBubble !== undefined) {
|
||||
// Apply transition, then remove speech bubble
|
||||
$currentSpeechBubble.removeClass('show');
|
||||
|
||||
// Make sure we remove any old timeout before reassignment
|
||||
clearTimeout(removeSpeechBubbleTimeout);
|
||||
removeSpeechBubbleTimeout = setTimeout(function () {
|
||||
$currentSpeechBubble.remove();
|
||||
$currentSpeechBubble = undefined;
|
||||
}, 500);
|
||||
}
|
||||
// Don't return false here. If the user e.g. clicks a button when the bubble is visible,
|
||||
// we want the bubble to disapear AND the button to receive the event
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the speech bubble and container reference
|
||||
*/
|
||||
function handleOutsideClick(event) {
|
||||
if (event.target === $currentContainer[0]) {
|
||||
return; // Button clicks are not outside clicks
|
||||
}
|
||||
|
||||
remove();
|
||||
// There is no current container when a container isn't clicked
|
||||
$currentContainer = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate position for speech bubble
|
||||
*
|
||||
* @param {number} bubbleWidth The width of the speech bubble
|
||||
* @param {object} offset
|
||||
* @return {object} Return position for the speech bubble
|
||||
*/
|
||||
function getBubblePosition(bubbleWidth, offset) {
|
||||
var bubblePosition = {};
|
||||
|
||||
var tailOffset = 9;
|
||||
var widthOffset = bubbleWidth / 2;
|
||||
|
||||
// Calculate top position
|
||||
bubblePosition.top = offset.top + offset.innerHeight;
|
||||
|
||||
// Calculate bottom position
|
||||
bubblePosition.bottom = offset.bottom + offset.innerHeight + tailOffset;
|
||||
|
||||
// Calculate left position
|
||||
if (offset.left < widthOffset) {
|
||||
bubblePosition.left = 3;
|
||||
}
|
||||
else if ((offset.left + widthOffset) > offset.outerWidth) {
|
||||
bubblePosition.left = offset.outerWidth - bubbleWidth - 3;
|
||||
}
|
||||
else {
|
||||
bubblePosition.left = offset.left - widthOffset + (offset.innerWidth / 2);
|
||||
}
|
||||
|
||||
return bubblePosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate position for speech bubble tail
|
||||
*
|
||||
* @param {number} bubbleWidth The width of the speech bubble
|
||||
* @param {object} bubblePosition Speech bubble position
|
||||
* @param {object} offset
|
||||
* @param {number} iconWidth The width of the tip icon
|
||||
* @return {object} Return position for the tail
|
||||
*/
|
||||
function getTailPosition(bubbleWidth, bubblePosition, offset, iconWidth) {
|
||||
var tailPosition = {};
|
||||
// Magic numbers. Tuned by hand so that the tail fits visually within
|
||||
// the bounds of the speech bubble.
|
||||
var leftBoundary = 9;
|
||||
var rightBoundary = bubbleWidth - 20;
|
||||
|
||||
tailPosition.left = offset.left - bubblePosition.left + (iconWidth / 2) - 6;
|
||||
if (tailPosition.left < leftBoundary) {
|
||||
tailPosition.left = leftBoundary;
|
||||
}
|
||||
if (tailPosition.left > rightBoundary) {
|
||||
tailPosition.left = rightBoundary;
|
||||
}
|
||||
|
||||
tailPosition.top = -6;
|
||||
tailPosition.bottom = -6;
|
||||
|
||||
return tailPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return bubble CSS for the desired growth direction
|
||||
*
|
||||
* @param {string} direction The direction the speech bubble will grow
|
||||
* @param {number} width The width of the speech bubble
|
||||
* @param {object} position Speech bubble position
|
||||
* @param {number} fontSize The size of the bubbles font
|
||||
* @return {object} Return CSS
|
||||
*/
|
||||
function bubbleCSS(direction, width, position, fontSize) {
|
||||
if (direction === 'top') {
|
||||
return {
|
||||
width: width + 'px',
|
||||
bottom: position.bottom + 'px',
|
||||
left: position.left + 'px',
|
||||
fontSize: fontSize + 'px',
|
||||
top: ''
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
width: width + 'px',
|
||||
top: position.top + 'px',
|
||||
left: position.left + 'px',
|
||||
fontSize: fontSize + 'px',
|
||||
bottom: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return tail CSS for the desired growth direction
|
||||
*
|
||||
* @param {string} direction The direction the speech bubble will grow
|
||||
* @param {object} position Tail position
|
||||
* @return {object} Return CSS
|
||||
*/
|
||||
function tailCSS(direction, position) {
|
||||
if (direction === 'top') {
|
||||
return {
|
||||
bottom: position.bottom + 'px',
|
||||
left: position.left + 'px',
|
||||
top: ''
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
top: position.top + 'px',
|
||||
left: position.left + 'px',
|
||||
bottom: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the offset between an element inside a container and the
|
||||
* container. Only works if all the edges of the inner element are inside the
|
||||
* outer element.
|
||||
* Width/height of the elements is included as a convenience.
|
||||
*
|
||||
* @param {H5P.jQuery} $outer
|
||||
* @param {H5P.jQuery} $inner
|
||||
* @return {object} Position offset
|
||||
*/
|
||||
function getOffsetBetween($outer, $inner) {
|
||||
var outer = $outer[0].getBoundingClientRect();
|
||||
var inner = $inner[0].getBoundingClientRect();
|
||||
|
||||
return {
|
||||
top: inner.top - outer.top,
|
||||
right: outer.right - inner.right,
|
||||
bottom: outer.bottom - inner.bottom,
|
||||
left: inner.left - outer.left,
|
||||
innerWidth: inner.width,
|
||||
innerHeight: inner.height,
|
||||
outerWidth: outer.width,
|
||||
outerHeight: outer.height
|
||||
};
|
||||
}
|
||||
|
||||
return JoubelSpeechBubble;
|
||||
})(H5P.jQuery);
|
||||
@@ -0,0 +1,19 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
H5P.JoubelThrobber = (function ($) {
|
||||
|
||||
/**
|
||||
* Creates a new tip
|
||||
*/
|
||||
function JoubelThrobber() {
|
||||
|
||||
// h5p-throbber css is described in core
|
||||
var $throbber = $('<div/>', {
|
||||
'class': 'h5p-throbber'
|
||||
});
|
||||
|
||||
return $throbber;
|
||||
}
|
||||
|
||||
return JoubelThrobber;
|
||||
}(H5P.jQuery));
|
||||
@@ -0,0 +1,106 @@
|
||||
H5P.JoubelTip = (function ($) {
|
||||
var $conv = $('<div/>');
|
||||
|
||||
/**
|
||||
* Creates a new tip element.
|
||||
*
|
||||
* NOTE that this may look like a class but it doesn't behave like one.
|
||||
* It returns a jQuery object.
|
||||
*
|
||||
* @param {string} tipHtml The text to display in the popup
|
||||
* @param {Object} [behaviour] Options
|
||||
* @param {string} [behaviour.tipLabel] Set to use a custom label for the tip button (you want this for good A11Y)
|
||||
* @param {boolean} [behaviour.helpIcon] Set to 'true' to Add help-icon classname to Tip button (changes the icon)
|
||||
* @param {boolean} [behaviour.showSpeechBubble] Set to 'false' to disable functionality (you may this in the editor)
|
||||
* @param {boolean} [behaviour.tabcontrol] Set to 'true' if you plan on controlling the tabindex in the parent (tabindex="-1")
|
||||
* @return {H5P.jQuery|undefined} Tip button jQuery element or 'undefined' if invalid tip
|
||||
*/
|
||||
function JoubelTip(tipHtml, behaviour) {
|
||||
|
||||
// Keep track of the popup that appears when you click the Tip button
|
||||
var speechBubble;
|
||||
|
||||
// Parse tip html to determine text
|
||||
var tipText = $conv.html(tipHtml).text().trim();
|
||||
if (tipText === '') {
|
||||
return; // The tip has no textual content, i.e. it's invalid.
|
||||
}
|
||||
|
||||
// Set default behaviour
|
||||
behaviour = $.extend({
|
||||
tipLabel: tipText,
|
||||
helpIcon: false,
|
||||
showSpeechBubble: true,
|
||||
tabcontrol: false
|
||||
}, behaviour);
|
||||
|
||||
// Create Tip button
|
||||
var $tipButton = $('<div/>', {
|
||||
class: 'joubel-tip-container' + (behaviour.showSpeechBubble ? '' : ' be-quiet'),
|
||||
title: behaviour.tipLabel,
|
||||
'aria-label': behaviour.tipLabel,
|
||||
'aria-expanded': false,
|
||||
role: 'button',
|
||||
tabindex: (behaviour.tabcontrol ? -1 : 0),
|
||||
click: function (event) {
|
||||
// Toggle show/hide popup
|
||||
toggleSpeechBubble();
|
||||
event.preventDefault();
|
||||
},
|
||||
keydown: function (event) {
|
||||
if (event.which === 32 || event.which === 13) { // Space & enter key
|
||||
// Toggle show/hide popup
|
||||
toggleSpeechBubble();
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
else { // Any other key
|
||||
// Toggle hide popup
|
||||
toggleSpeechBubble(false);
|
||||
}
|
||||
},
|
||||
// Add markup to render icon
|
||||
html: '<span class="joubel-icon-tip-normal ' + (behaviour.helpIcon ? ' help-icon': '') + '">' +
|
||||
'<span class="h5p-icon-shadow"></span>' +
|
||||
'<span class="h5p-icon-speech-bubble"></span>' +
|
||||
'<span class="h5p-icon-info"></span>' +
|
||||
'</span>'
|
||||
// IMPORTANT: All of the markup elements must have 'pointer-events: none;'
|
||||
});
|
||||
|
||||
const $tipAnnouncer = $('<div>', {
|
||||
'class': 'hidden-but-read',
|
||||
'aria-live': 'polite',
|
||||
appendTo: $tipButton,
|
||||
});
|
||||
|
||||
/**
|
||||
* Tip button interaction handler.
|
||||
* Toggle show or hide the speech bubble popup when interacting with the
|
||||
* Tip button.
|
||||
*
|
||||
* @private
|
||||
* @param {boolean} [force] 'true' shows and 'false' hides.
|
||||
*/
|
||||
var toggleSpeechBubble = function (force) {
|
||||
if (speechBubble !== undefined && speechBubble.isCurrent($tipButton)) {
|
||||
// Hide current popup
|
||||
speechBubble.remove();
|
||||
speechBubble = undefined;
|
||||
|
||||
$tipButton.attr('aria-expanded', false);
|
||||
$tipAnnouncer.html('');
|
||||
}
|
||||
else if (force !== false && behaviour.showSpeechBubble) {
|
||||
// Create and show new popup
|
||||
speechBubble = H5P.JoubelSpeechBubble($tipButton, tipHtml);
|
||||
$tipButton.attr('aria-expanded', true);
|
||||
$tipAnnouncer.html(tipHtml);
|
||||
}
|
||||
};
|
||||
|
||||
return $tipButton;
|
||||
}
|
||||
|
||||
return JoubelTip;
|
||||
})(H5P.jQuery);
|
||||
@@ -0,0 +1,183 @@
|
||||
var H5P = H5P || {};
|
||||
|
||||
/**
|
||||
* H5P Joubel UI library.
|
||||
*
|
||||
* This is a utility library, which does not implement attach. I.e, it has to bee actively used by
|
||||
* other libraries
|
||||
* @module
|
||||
*/
|
||||
H5P.JoubelUI = (function ($) {
|
||||
|
||||
/**
|
||||
* The internal object to return
|
||||
* @class H5P.JoubelUI
|
||||
* @static
|
||||
*/
|
||||
function JoubelUI() {}
|
||||
|
||||
/* Public static functions */
|
||||
|
||||
/**
|
||||
* Create a tip icon
|
||||
* @method H5P.JoubelUI.createTip
|
||||
* @param {string} text The textual tip
|
||||
* @param {Object} params Parameters
|
||||
* @return {H5P.JoubelTip}
|
||||
*/
|
||||
JoubelUI.createTip = function (text, params) {
|
||||
return new H5P.JoubelTip(text, params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create message dialog
|
||||
* @method H5P.JoubelUI.createMessageDialog
|
||||
* @param {H5P.jQuery} $container The dom container
|
||||
* @param {string} message The message
|
||||
* @return {H5P.JoubelMessageDialog}
|
||||
*/
|
||||
JoubelUI.createMessageDialog = function ($container, message) {
|
||||
return new H5P.JoubelMessageDialog($container, message);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create help text dialog
|
||||
* @method H5P.JoubelUI.createHelpTextDialog
|
||||
* @param {string} header The textual header
|
||||
* @param {string} message The textual message
|
||||
* @param {string} closeButtonTitle The title for the close button
|
||||
* @return {H5P.JoubelHelpTextDialog}
|
||||
*/
|
||||
JoubelUI.createHelpTextDialog = function (header, message, closeButtonTitle) {
|
||||
return new H5P.JoubelHelpTextDialog(header, message, closeButtonTitle);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create progress circle
|
||||
* @method H5P.JoubelUI.createProgressCircle
|
||||
* @param {number} number The progress (0 to 100)
|
||||
* @param {string} progressColor The progress color in hex value
|
||||
* @param {string} fillColor The fill color in hex value
|
||||
* @param {string} backgroundColor The background color in hex value
|
||||
* @return {H5P.JoubelProgressCircle}
|
||||
*/
|
||||
JoubelUI.createProgressCircle = function (number, progressColor, fillColor, backgroundColor) {
|
||||
return new H5P.JoubelProgressCircle(number, progressColor, fillColor, backgroundColor);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create throbber for loading
|
||||
* @method H5P.JoubelUI.createThrobber
|
||||
* @return {H5P.JoubelThrobber}
|
||||
*/
|
||||
JoubelUI.createThrobber = function () {
|
||||
return new H5P.JoubelThrobber();
|
||||
};
|
||||
|
||||
/**
|
||||
* Create simple rounded button
|
||||
* @method H5P.JoubelUI.createSimpleRoundedButton
|
||||
* @param {string} text The button label
|
||||
* @return {H5P.SimpleRoundedButton}
|
||||
*/
|
||||
JoubelUI.createSimpleRoundedButton = function (text) {
|
||||
return new H5P.SimpleRoundedButton(text);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Slider
|
||||
* @method H5P.JoubelUI.createSlider
|
||||
* @param {Object} [params] Parameters
|
||||
* @return {H5P.JoubelSlider}
|
||||
*/
|
||||
JoubelUI.createSlider = function (params) {
|
||||
return new H5P.JoubelSlider(params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Score Bar
|
||||
* @method H5P.JoubelUI.createScoreBar
|
||||
* @param {number=} maxScore The maximum score
|
||||
* @param {string} [label] Makes it easier for readspeakers to identify the scorebar
|
||||
* @return {H5P.JoubelScoreBar}
|
||||
*/
|
||||
JoubelUI.createScoreBar = function (maxScore, label, helpText, scoreExplanationButtonLabel) {
|
||||
return new H5P.JoubelScoreBar(maxScore, label, helpText, scoreExplanationButtonLabel);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Progressbar
|
||||
* @method H5P.JoubelUI.createProgressbar
|
||||
* @param {number=} numSteps The total numer of steps
|
||||
* @param {Object} [options] Additional options
|
||||
* @param {boolean} [options.disableAria] Disable readspeaker assistance
|
||||
* @param {string} [options.progressText] A progress text for describing
|
||||
* current progress out of total progress for readspeakers.
|
||||
* e.g. "Slide :num of :total"
|
||||
* @return {H5P.JoubelProgressbar}
|
||||
*/
|
||||
JoubelUI.createProgressbar = function (numSteps, options) {
|
||||
return new H5P.JoubelProgressbar(numSteps, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create standard Joubel button
|
||||
*
|
||||
* @method H5P.JoubelUI.createButton
|
||||
* @param {object} params
|
||||
* May hold any properties allowed by jQuery. If href is set, an A tag
|
||||
* is used, if not a button tag is used.
|
||||
* @return {H5P.jQuery} The jquery element created
|
||||
*/
|
||||
JoubelUI.createButton = function(params) {
|
||||
var type = 'button';
|
||||
if (params.href) {
|
||||
type = 'a';
|
||||
}
|
||||
else {
|
||||
params.type = 'button';
|
||||
}
|
||||
if (params.class) {
|
||||
params.class += ' h5p-joubelui-button';
|
||||
}
|
||||
else {
|
||||
params.class = 'h5p-joubelui-button';
|
||||
}
|
||||
return $('<' + type + '/>', params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Fix for iframe scoll bug in IOS. When focusing an element that doesn't have
|
||||
* focus support by default the iframe will scroll the parent frame so that
|
||||
* the focused element is out of view. This varies dependening on the elements
|
||||
* of the parent frame.
|
||||
*/
|
||||
if (H5P.isFramed && !H5P.hasiOSiframeScrollFix &&
|
||||
/iPad|iPhone|iPod/.test(navigator.userAgent)) {
|
||||
H5P.hasiOSiframeScrollFix = true;
|
||||
|
||||
// Keep track of original focus function
|
||||
var focus = HTMLElement.prototype.focus;
|
||||
|
||||
// Override the original focus
|
||||
HTMLElement.prototype.focus = function () {
|
||||
// Only focus the element if it supports it natively
|
||||
if ( (this instanceof HTMLAnchorElement ||
|
||||
this instanceof HTMLInputElement ||
|
||||
this instanceof HTMLSelectElement ||
|
||||
this instanceof HTMLTextAreaElement ||
|
||||
this instanceof HTMLButtonElement ||
|
||||
this instanceof HTMLIFrameElement ||
|
||||
this instanceof HTMLAreaElement) && // HTMLAreaElement isn't supported by Safari yet.
|
||||
!this.getAttribute('role')) { // Focus breaks if a different role has been set
|
||||
// In theory this.isContentEditable should be able to recieve focus,
|
||||
// but it didn't work when tested.
|
||||
|
||||
// Trigger the original focus with the proper context
|
||||
focus.call(this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return JoubelUI;
|
||||
})(H5P.jQuery);
|
||||
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"title": "Joubel UI",
|
||||
"contentType": "Utility",
|
||||
"description": "UI utility library",
|
||||
"majorVersion": 1,
|
||||
"minorVersion": 3,
|
||||
"patchVersion": 9,
|
||||
"runnable": 0,
|
||||
"coreApi": {
|
||||
"majorVersion": 1,
|
||||
"minorVersion": 3
|
||||
},
|
||||
"machineName": "H5P.JoubelUI",
|
||||
"author": "Joubel",
|
||||
"preloadedJs": [
|
||||
{
|
||||
"path": "js/joubel-help-dialog.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-message-dialog.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-progress-circle.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-simple-rounded-button.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-speech-bubble.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-throbber.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-tip.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-slider.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-score-bar.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-progressbar.js"
|
||||
},
|
||||
{
|
||||
"path": "js/joubel-ui.js"
|
||||
}
|
||||
],
|
||||
"preloadedCss": [
|
||||
{
|
||||
"path": "css/joubel-help-dialog.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-message-dialog.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-progress-circle.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-simple-rounded-button.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-speech-bubble.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-tip.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-slider.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-score-bar.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-progressbar.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-ui.css"
|
||||
},
|
||||
{
|
||||
"path": "css/joubel-icon.css"
|
||||
}
|
||||
],
|
||||
"preloadedDependencies": [
|
||||
{
|
||||
"machineName": "FontAwesome",
|
||||
"majorVersion": 4,
|
||||
"minorVersion": 5
|
||||
},
|
||||
{
|
||||
"machineName": "H5P.Transition",
|
||||
"majorVersion": 1,
|
||||
"minorVersion": 0
|
||||
},
|
||||
{
|
||||
"machineName": "Drop",
|
||||
"majorVersion": 1,
|
||||
"minorVersion": 0
|
||||
},
|
||||
{
|
||||
"machineName": "H5P.FontIcons",
|
||||
"majorVersion": 1,
|
||||
"minorVersion": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user