<div class="star-rating" data-item-id="XXXX" data-endpoint="/api/rating-useful.json" data-average-rating="2.4" data-rating-type="useful">
<form class="star-rating__form" action="">
<fieldset class="star-rating__fieldset">
<legend class="star-rating__legend label">Nützliches Thema?</legend>
<div class="star-rating__inner">
<div class="star-rating__stars">
<input class="star-rating__input" type="radio" id="XXXX-1" name="rating" value="1" />
<label class="star-rating__label" for="XXXX-1" title="ein Stern"><span class="u-hidden-visually">1 Stern</span></label>
<input class="star-rating__input" type="radio" id="XXXX-2" name="rating" value="2" />
<label class="star-rating__label" for="XXXX-2" title="zwei Sterne"><span class="u-hidden-visually">2 Sterne</span></label>
<input class="star-rating__input" type="radio" id="XXXX-3" name="rating" value="3" />
<label class="star-rating__label" for="XXXX-3" title="drei Sterne"><span class="u-hidden-visually">3 Sterne</span></label>
<input class="star-rating__input" type="radio" id="XXXX-4" name="rating" value="4" />
<label class="star-rating__label" for="XXXX-4" title="vier Sterne"><span class="u-hidden-visually">4 Sterne</span></label>
<input class="star-rating__input" type="radio" id="XXXX-5" name="rating" value="5" />
<label class="star-rating__label" for="XXXX-5" title="fünf Sterne"><span class="u-hidden-visually">5 Sterne</span></label>
</div><span class="star-rating__count"><span class="u-hidden-visually">Abgegebene Bewertungen</span><span>(12)</span></span>
</div>
<input class="star-rating__submit" type="submit" />
</fieldset>
</form>
</div>
.star-rating(data-item-id=id, data-endpoint=endpoint, data-average-rating=avgRating, data-rating-type=ratingType)
form.star-rating__form(action='')
fieldset.star-rating__fieldset
legend.star-rating__legend.label #{title}
.star-rating__inner
.star-rating__stars
input.star-rating__input(type='radio', id=`${id}-1`, name='rating', value='1')
label.star-rating__label(for=`${id}-1`, title='ein Stern')
span.u-hidden-visually 1 Stern
input.star-rating__input(type='radio', id=`${id}-2`, name='rating', value='2')
label.star-rating__label(for=`${id}-2`, title='zwei Sterne')
span.u-hidden-visually 2 Sterne
input.star-rating__input(type='radio', id=`${id}-3`, name='rating', value='3')
label.star-rating__label(for=`${id}-3`, title='drei Sterne')
span.u-hidden-visually 3 Sterne
input.star-rating__input(type='radio', id=`${id}-4`, name='rating', value='4')
label.star-rating__label(for=`${id}-4`, title='vier Sterne')
span.u-hidden-visually 4 Sterne
input.star-rating__input(type='radio', id=`${id}-5`, name='rating', value='5')
label.star-rating__label(for=`${id}-5`, title='fünf Sterne')
span.u-hidden-visually 5 Sterne
span.star-rating__count
span.u-hidden-visually Abgegebene Bewertungen
span (#{count})
input.star-rating__submit(type='submit')
{
"id": "XXXX",
"title": "Nützliches Thema?",
"endpoint": "/api/rating-useful.json",
"avgRating": 2.4,
"ratingType": "useful",
"count": 12
}
import h from 'hyperscript';
import showTooltip from '../tooltip/tooltip';
const LockState = {
NO_LOCK: null,
LOCKED: 'locked',
UNLOCKED: 'unlocked',
};
const createValuesById = $inputs => (
Array.from($inputs).reduce(
(result, $input) => Object.assign(result, {
[$input.id]: $input.value,
}),
{},
)
);
export default class StarForm {
constructor(element, submitForm) {
this.$element = element;
this.submitForm = submitForm;
this.$fieldset = element.querySelector('.star-rating__fieldset');
this.$count = element.querySelector('.star-rating__count');
this.$starsWrapper = element.querySelector('.star-rating__stars');
this.$inputs = element.querySelectorAll('.star-rating__input');
this.$labels = element.querySelectorAll('.star-rating__label');
this.$form = element.querySelector('.star-rating__form');
this.lockState = LockState.NO_LOCK;
this.id = element.dataset.itemId;
this.avgRating = Math.round(Number(element.dataset.averageRating));
this.ratingType = element.dataset.ratingType;
this.endpoint = element.dataset.endpoint;
this.localStorageId = `${this.id}-${this.ratingType}`;
this.value = this.getStorage();
this.valuesById = createValuesById(this.$inputs);
this.removeUnlockedTooltip = null;
this.init();
this.initMediaListener();
}
getStorage() {
return window.localStorage.getItem(this.localStorageId) || null;
}
setStorage(rating) {
window.localStorage.setItem(this.localStorageId, rating);
}
setLockState(lockState) {
this.lockState = lockState;
this.$element.dataset.lockState = lockState;
}
setDisabled() {
this.disabled = true;
this.$inputs.forEach($input => $input.setAttribute('disabled', 'disabled'));
}
getValueByLabel($label) {
const id = $label.getAttribute('for');
return this.valuesById[id];
}
fillStars(rating) {
this.$labels.forEach(($label, index) => {
if (index + 1 <= rating) {
$label.classList.add('star-rating__label--filled');
return;
}
$label.classList.remove('star-rating__label--filled');
});
}
handleCatcherClick() {
if (this.lockState !== LockState.LOCKED) {
return;
}
this.removeUnlockedTooltip = showTooltip(this.$fieldset, {
text: 'Bitte Bewertung abgeben',
color: 'blue-light',
});
this.setLockState(LockState.UNLOCKED);
}
handleInputChange(event) {
const number = event.target.value;
this.fillStars(number);
}
handleLabelClick(event) {
if (this.disabled) {
showTooltip(this.$fieldset, {
text: 'Bewertung bereits abgegeben!',
timeout: 3000,
});
return;
}
this.value = this.getValueByLabel(event.target);
this.handleFormSubmit();
}
handleLabelMouseEnter(event) {
if (this.disabled) {
return;
}
const value = this.getValueByLabel(event.target);
this.$element.classList.add('star-rating--hovered');
this.fillStars(Number(value));
}
handleLabelMouseLeave() {
this.$element.classList.remove('star-rating--hovered');
this.fillStars(this.avgRating);
}
handleFormSubmit() {
const rating = Number(this.value);
this.setDisabled();
this.setStorage(rating);
this.setLockState(LockState.NO_LOCK);
if (typeof this.removeUnlockedTooltip === 'function') {
this.removeUnlockedTooltip();
}
showTooltip(this.$fieldset, {
text: 'Danke für Ihre Bewertung!',
timeout: 3000,
});
this.submitForm(this.id, rating, this.ratingType, this.endpoint, (data) => {
this.$count.textContent = `(${data.count})`;
this.avgRating = Math.round(data.averagerating);
this.fillStars(this.avgRating);
});
}
// Setup an extra unlock step for small viewports. We assume that small
// viewports are touch devices and therefore can't visualize the hover state.
initMediaListener() {
const smallMediaTest = window.matchMedia('(max-width: 1024px)');
const listener = (query) => {
const lockState = query.matches && !this.disabled
? LockState.LOCKED
: LockState.NO_LOCK;
this.setLockState(lockState);
};
smallMediaTest.addListener(listener);
listener(smallMediaTest);
}
init() {
if (this.value) {
this.setDisabled();
}
this.fillStars(this.avgRating);
this.$starsWrapper.appendChild(
h('div.star-rating__catcher', {
onclick: () => this.handleCatcherClick(),
}),
);
this.$form.addEventListener('submit', (event) => {
event.preventDefault();
this.handleFormSubmit();
});
this.$inputs.forEach(($input) => {
$input.addEventListener('change', event => this.handleInputChange(event));
});
this.$labels.forEach(($label) => {
$label.addEventListener('click', event => this.handleLabelClick(event));
$label.addEventListener('mouseenter', event => this.handleLabelMouseEnter(event));
$label.addEventListener('mouseleave', event => this.handleLabelMouseLeave(event));
});
}
}
import $ from 'jquery';
import StarForm from './StarForm';
function handleFormSubmit(articlepage, rating, ratingtype, url, success) {
$.ajax({
type: 'POST',
url,
data: {
ratingtype,
articlepage,
rating,
},
success,
});
}
document.querySelectorAll('.star-rating').forEach(($starRating) => {
// eslint-disable-next-line
new StarForm($starRating, handleFormSubmit);
});
@mixin star-rating-svg($color, $filled: false) {
$fill: if($filled, $color, 'transparent');
background-image: svg-url('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><path fill="#{$fill}" fill-rule="evenodd" stroke="#{$color}" stroke-width="12" d="M155.2 190.6L144.7 126l45-46.1-62.2-9.5L100 11.8 72.5 70.4l-62.1 9.5 45 46-10.6 64.7 55.2-30.5 55.2 30.5z"/></svg>');
}
.star-rating__input {
opacity: 0;
position: absolute;
z-index: -1;
}
.star-rating__input:disabled + .star-rating__label {
&:hover {
cursor: default;
}
}
.star-rating__label {
@include star-rating-svg($color-blue-light);
background-size: 2.5rem 2.5rem;
display: inline-block;
height: 2.5rem;
margin-right: 0.4rem;
outline: 0;
width: 2.5rem;
&:hover {
cursor: pointer;
}
}
.star-rating__label--filled {
@include star-rating-svg($color-blue-light, true);
}
[data-lock-state='unlocked'] .star-rating__label {
@include star-rating-svg($color-blue-light);
}
@include mq($from: 1025px) {
.star-rating--hovered .star-rating__label {
@include star-rating-svg($color-red);
}
.star-rating--hovered .star-rating__label--filled {
@include star-rating-svg($color-red, true);
}
}
.star-rating__label--outline {
outline: 1px dotted #ccc;
}
.star-rating__input:focus + .star-rating__label {
outline: 1px dotted #ccc;
}
.star-rating__inner {
display: flex;
}
.star-rating__stars {
position: relative;
}
.star-rating__catcher {
display: none;
[data-lock-state='locked'] & {
bottom: 0;
display: block;
left: 0;
position: absolute;
right: 0;
top: 0;
}
}
.star-rating__count {
color: $color-blue-light;
display: inline-block;
font-weight: bold;
line-height: 2.5rem;
margin-left: 0.4rem;
vertical-align: top;
}
.star-rating__submit {
display: none;
}
.star-rating__fieldset {
border: 0;
margin: 0;
padding: 0;
position: relative;
}
There are no notes for this item.