Merge branch 'dedicated-radio' into 'master'

Dedicated radio button JS util

See merge request !159
This commit is contained in:
Felix Hamann 2019-03-03 21:30:27 +01:00
commit b225e6a5ba
15 changed files with 258 additions and 165 deletions

View File

@ -87,6 +87,7 @@ CourseRegisterToTip: Anmeldung darf auch unbegrenzt offen bleiben
CourseDeregisterUntilTip: Abmeldung darf auch unbegrenzt erlaubt bleiben CourseDeregisterUntilTip: Abmeldung darf auch unbegrenzt erlaubt bleiben
CourseFilterSearch: Volltext-Suche CourseFilterSearch: Volltext-Suche
CourseFilterRegistered: Registriert CourseFilterRegistered: Registriert
CourseFilterNone: Egal
CourseDeleteQuestion: Wollen Sie den unten aufgeführten Kurs wirklich löschen? CourseDeleteQuestion: Wollen Sie den unten aufgeführten Kurs wirklich löschen?
CourseDeleted: Kurs gelöscht CourseDeleted: Kurs gelöscht
CourseUserNote: Notiz CourseUserNote: Notiz

View File

@ -1035,9 +1035,11 @@ siteLayout' headingOverride widget = do
addStylesheet $ StaticR css_utils_asyncForm_scss addStylesheet $ StaticR css_utils_asyncForm_scss
addStylesheet $ StaticR css_utils_asyncTable_scss addStylesheet $ StaticR css_utils_asyncTable_scss
addStylesheet $ StaticR css_utils_asyncTableFilter_scss addStylesheet $ StaticR css_utils_asyncTableFilter_scss
addStylesheet $ StaticR css_utils_checkbox_scss
addStylesheet $ StaticR css_utils_form_scss addStylesheet $ StaticR css_utils_form_scss
addStylesheet $ StaticR css_utils_inputs_scss addStylesheet $ StaticR css_utils_inputs_scss
addStylesheet $ StaticR css_utils_modal_scss addStylesheet $ StaticR css_utils_modal_scss
addStylesheet $ StaticR css_utils_radio_scss
addStylesheet $ StaticR css_utils_showHide_scss addStylesheet $ StaticR css_utils_showHide_scss
addStylesheet $ StaticR css_utils_tabber_scss addStylesheet $ StaticR css_utils_tabber_scss
addStylesheet $ StaticR css_utils_tooltip_scss addStylesheet $ StaticR css_utils_tooltip_scss

View File

@ -57,7 +57,7 @@
padding-left: 10px; padding-left: 10px;
&.js-show-hide__toggle::before { &.js-show-hide__toggle::before {
top: 25px; z-index: 1;
} }
} }
} }
@ -103,7 +103,6 @@
&::before { &::before {
left: auto; left: auto;
right: 20px; right: 20px;
top: 30px;
color: var(--color-font); color: var(--color-font);
} }
} }
@ -314,6 +313,10 @@
word-break: break-all; word-break: break-all;
background-color: var(--color-dark); background-color: var(--color-dark);
color: var(--color-lightwhite); color: var(--color-lightwhite);
&:hover {
background-color: var(--color-dark);
}
} }
.asidenav__link-shorthand { .asidenav__link-shorthand {

View File

@ -0,0 +1,74 @@
/* CUSTOM CHECKBOXES */
/* Completely replaces legacy checkbox */
.checkbox {
position: relative;
display: inline-block;
[type="checkbox"] {
position: fixed;
top: -1px;
left: -1px;
width: 1px;
height: 1px;
overflow: hidden;
}
label {
display: block;
height: 24px;
width: 24px;
background-color: #f3f3f3;
box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05);
border: 2px solid var(--color-primary);
border-radius: 4px;
color: white;
cursor: pointer;
}
label::before,
label::after {
position: absolute;
display: block;
top: 12px;
left: 8px;
height: 2px;
width: 8px;
background-color: var(--color-font);
}
:checked + label {
background-color: var(--color-primary);
}
[type="checkbox"]:focus + label {
border-color: #3273dc;
box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
outline: 0;
}
:checked + label::before,
:checked + label::after {
content: '';
}
:checked + label::before {
background-color: white;
transform: rotate(45deg);
left: 4px;
}
:checked + label::after {
background-color: white;
transform: rotate(-45deg);
top: 11px;
width: 13px;
}
[disabled] + label {
pointer-events: none;
border: none;
opacity: 0.6;
filter: grayscale(1);
}
}

View File

@ -183,130 +183,6 @@ option {
} }
} }
/* CUSTOM LEGACY CHECKBOX AND RADIO BOXES */
input[type="checkbox"] {
position: relative;
height: 20px;
width: 20px;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
}
input[type="checkbox"]::before {
content: '';
position: absolute;
width: 20px;
height: 20px;
background-color: var(--color-lighter);
display: flex;
align-items: center;
justify-content: center;
border-radius: 2px;
}
input[type="checkbox"]:checked::before {
background-color: var(--color-light);
}
input[type="checkbox"]:checked::after {
content: '';
position: absolute;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
}
/* CUSTOM CHECKBOXES AND RADIO BOXES */
/* Completely replaces legacy checkbox and radiobox */
.checkbox,
.radio {
position: relative;
display: inline-block;
[type="checkbox"],
[type="radio"] {
position: fixed;
top: -1px;
left: -1px;
width: 1px;
height: 1px;
overflow: hidden;
}
label {
display: block;
height: 24px;
width: 24px;
background-color: #f3f3f3;
box-shadow: inset 0 1px 2px 1px rgba(50, 50, 50, 0.05);
border: 2px solid var(--color-primary);
border-radius: 4px;
color: white;
cursor: pointer;
}
label::before,
label::after {
position: absolute;
display: block;
top: 12px;
left: 8px;
height: 2px;
width: 8px;
background-color: var(--color-font);
}
:checked + label {
background-color: var(--color-primary);
}
[type="checkbox"]:focus + label,
[type="radio"]:focus + label {
border-color: #3273dc;
box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
outline: 0;
}
:checked + label::before,
:checked + label::after {
content: '';
}
:checked + label::before {
background-color: white;
transform: rotate(45deg);
left: 4px;
}
:checked + label::after {
background-color: white;
transform: rotate(-45deg);
top: 11px;
width: 13px;
}
[disabled] + label {
pointer-events: none;
border: none;
opacity: 0.6;
filter: grayscale(1);
}
}
.radio::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
right: 2px;
bottom: 2px;
border-radius: 4px;
border: 2px solid white;
z-index: -1;
}
/* CUSTOM FILE INPUT */ /* CUSTOM FILE INPUT */
.file-input__label { .file-input__label {
cursor: pointer; cursor: pointer;

View File

@ -0,0 +1,76 @@
/* CUSTOM RADIO BOXES */
/* Completely replaces native radiobox */
.radio-group {
display: flex;
}
.radio-group__option {
min-width: 30px;
}
.radio {
position: relative;
display: inline-block;
[type="radio"] {
position: fixed;
top: -1px;
left: -1px;
width: 1px;
height: 1px;
overflow: hidden;
}
label {
display: block;
height: 34px;
min-width: 42px;
line-height: 34px;
text-align: center;
padding: 0 7px;
background-color: #f3f3f3;
box-shadow: inset 2px 1px 2px 1px rgba(50, 50, 50, 0.05);
color: var(--color-font);
cursor: pointer;
}
:checked + label {
background-color: #818181;
color: var(--color-lightwhite);
box-shadow: inset -2px -1px 2px 1px rgba(255, 255, 255, 0.15);
}
:focus + label {
border-color: #3273dc;
box-shadow: 0 0 0.125em 0 rgba(50,115,220,0.8);
outline: 0;
}
[disabled] + label {
pointer-events: none;
border: none;
opacity: 0.6;
filter: grayscale(1);
}
}
.radio:first-child {
label {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
}
.radio:last-child {
label {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
}
@media (max-width: 768px) {
.radio + .radio {
margin-left: 10px;
}
}

View File

@ -1,22 +1,30 @@
$show-hide-toggle-size: 6px;
.js-show-hide__toggle { .js-show-hide__toggle {
position: relative; position: relative;
cursor: pointer; cursor: pointer;
padding: 3px 7px;
&:hover {
background-color: var(--color-grey-lighter);
cursor: pointer;
}
} }
.js-show-hide__toggle::before { .js-show-hide__toggle::before {
content: ''; content: '';
position: absolute; position: absolute;
width: 0; width: $show-hide-toggle-size;
height: 0; height: $show-hide-toggle-size;
left: -28px; left: -15px;
top: 6px; top: 12px - $show-hide-toggle-size / 2;
color: var(--color-primary); color: var(--color-primary);
border-right: 8px solid transparent; border-right: 2px solid currentColor;
border-top: 8px solid transparent; border-top: 2px solid currentColor;
border-left: 8px solid transparent;
border-bottom: 8px solid currentColor;
transition: transform .2s ease; transition: transform .2s ease;
transform-origin: 8px 12px; transform-origin: ($show-hide-toggle-size / 2);
transform: translateY($show-hide-toggle-size) rotate(-45deg);
} }
.js-show-hide__target { .js-show-hide__target {
@ -26,7 +34,7 @@
.js-show-hide--collapsed { .js-show-hide--collapsed {
.js-show-hide__toggle::before { .js-show-hide__toggle::before {
transform: rotate(180deg); transform: translateY($show-hide-toggle-size / 3) rotate(135deg);
} }
.js-show-hide__target { .js-show-hide__target {

View File

@ -51,6 +51,9 @@
// check all // check all
utilInstances.push(window.utils.setup('checkAll', wrapper)); utilInstances.push(window.utils.setup('checkAll', wrapper));
// showhide
utilInstances.push(window.utils.setup('showHide', wrapper));
// filter // filter
var filterForm = wrapper.querySelector('.' + TABLE_FILTER_FORM_CLASS); var filterForm = wrapper.querySelector('.' + TABLE_FILTER_FORM_CLASS);
if (filterForm) { if (filterForm) {

View File

@ -82,7 +82,7 @@
checkAllCheckbox.setAttribute('id', getCheckboxId()); checkAllCheckbox.setAttribute('id', getCheckboxId());
th.innerHTML = ''; th.innerHTML = '';
th.insertBefore(checkAllCheckbox, null); th.insertBefore(checkAllCheckbox, null);
utilInstances.push(window.utils.setup('checkboxRadio', checkAllCheckbox)); utilInstances.push(window.utils.setup('checkbox', checkAllCheckbox));
checkAllCheckbox.addEventListener('input', onCheckAllCheckboxInput); checkAllCheckbox.addEventListener('input', onCheckAllCheckboxInput);
setupCheckboxListeners(); setupCheckboxListeners();

View File

@ -13,10 +13,16 @@
var utilInstances = []; var utilInstances = [];
// checkboxes / radios // checkboxes
var checkboxes = Array.from(wrapper.querySelectorAll('input[type="checkbox"], input[type="radio"]')); var checkboxes = Array.from(wrapper.querySelectorAll('input[type="checkbox"]'));
checkboxes.filter(isNotInitialized).forEach(function(checkbox) { checkboxes.filter(isNotInitialized).forEach(function(checkbox) {
utilInstances.push(window.utils.setup('checkboxRadio', checkbox)); utilInstances.push(window.utils.setup('checkbox', checkbox));
});
// radios
var radios = Array.from(wrapper.querySelectorAll('input[type="radio"]'));
radios.filter(isNotInitialized).forEach(function(radio) {
utilInstances.push(window.utils.setup('radio', radio));
}); });
// file-uploads // file-uploads
@ -167,17 +173,15 @@
}; };
} }
// turns native checkboxes and radio buttons into custom ones // turns native checkboxes into custom ones
window.utils.checkboxRadio = function(input) { window.utils.checkbox = function(input) {
var type = input.getAttribute('type'); if (!input.parentElement.classList.contains('checkbox')) {
if (!input.parentElement.classList.contains(type)) {
var parentEl = input.parentElement; var parentEl = input.parentElement;
var siblingEl = input.nextElementSibling; var siblingEl = input.nextElementSibling;
var wrapperEl = document.createElement('div'); var wrapperEl = document.createElement('div');
var labelEl = document.createElement('label'); var labelEl = document.createElement('label');
wrapperEl.classList.add(type); wrapperEl.classList.add('checkbox');
labelEl.setAttribute('for', input.id); labelEl.setAttribute('for', input.id);
wrapperEl.appendChild(input); wrapperEl.appendChild(input);
wrapperEl.appendChild(labelEl); wrapperEl.appendChild(labelEl);
@ -195,4 +199,27 @@
}; };
} }
// turns native radio buttons into custom ones
window.utils.radio = function(input) {
if (!input.parentElement.classList.contains('radio')) {
var parentEl = input.parentElement;
var siblingEl = input.nextElementSibling;
var wrapperEl = document.createElement('div');
wrapperEl.classList.add('radio');
wrapperEl.appendChild(input);
if (siblingEl && siblingEl.matches('label')) {
wrapperEl.appendChild(siblingEl);
}
input.classList.add(JS_INITIALIZED_CLASS);
parentEl.appendChild(wrapperEl);
}
return {
destroy: function() {},
};
}
})(); })();

View File

@ -3,7 +3,12 @@
window.utils = window.utils || {}; window.utils = window.utils || {};
var JS_INITIALIZED_CLASS = 'js-show-hide-initialized';
var LOCAL_STORAGE_SHOW_HIDE = 'SHOW_HIDE'; var LOCAL_STORAGE_SHOW_HIDE = 'SHOW_HIDE';
var SHOW_HIDE_TOGGLE_CLASS = 'js-show-hide__toggle';
var SHOW_HIDE_COLLAPSED_CLASS = 'js-show-hide--collapsed';
var SHOW_HIDE_TARGET_CLASS = 'js-show-hide__target';
/** /**
* div * div
* div.js-show-hide__toggle * div.js-show-hide__toggle
@ -12,9 +17,12 @@
* content here * content here
*/ */
window.utils.showHide = function(wrapper, options) { window.utils.showHide = function(wrapper, options) {
options = options || {};
function addEventHandler(el) { function addEventHandler(el) {
el.addEventListener('click', function elClickListener() { el.addEventListener('click', function elClickListener() {
var newState = el.parentElement.classList.toggle('js-show-hide--collapsed'); var newState = el.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS);
updateLSState(el.dataset.shIndex || null, newState); updateLSState(el.dataset.shIndex || null, newState);
}); });
} }
@ -23,32 +31,41 @@
if (!index) { if (!index) {
return false; return false;
} }
var lsData = fromLocalStorage(); var lsData = getLocalStorageData();
lsData[index] = state; lsData[index] = state;
window.localStorage.setItem(LOCAL_STORAGE_SHOW_HIDE, JSON.stringify(lsData)); window.localStorage.setItem(LOCAL_STORAGE_SHOW_HIDE, JSON.stringify(lsData));
} }
function collapsedStateInLocalStorage(index) { function collapsedStateInLocalStorage(index) {
return fromLocalStorage()[index] || null; var lsState = getLocalStorageData();
return lsState[index];
} }
function fromLocalStorage() { function getLocalStorageData() {
return JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_SHOW_HIDE)) || {}; return JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_SHOW_HIDE)) || {};
} }
Array Array
.from(wrapper.querySelectorAll('.js-show-hide__toggle')) .from(wrapper.querySelectorAll('.' + SHOW_HIDE_TOGGLE_CLASS))
.forEach(function(el) { .forEach(function(el) {
if (el.classList.contains(JS_INITIALIZED_CLASS)) {
return false;
}
var index = el.dataset.shIndex || null; var index = el.dataset.shIndex || null;
el.parentElement.classList.toggle( var isCollapsed = el.dataset.collapsed === 'true';
'js-show-hide--collapsed', var lsCollapsedState = collapsedStateInLocalStorage(index);
collapsedStateInLocalStorage(index) || el.dataset.collapsed === 'true' if (typeof lsCollapsedState !== 'undefined') {
); isCollapsed = lsCollapsedState;
}
el.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS, isCollapsed);
Array.from(el.parentElement.children).forEach(function(el) { Array.from(el.parentElement.children).forEach(function(el) {
if (!el.classList.contains('js-show-hide__toggle')) { if (!el.classList.contains('' + SHOW_HIDE_TOGGLE_CLASS)) {
el.classList.add('js-show-hide__target'); el.classList.add(SHOW_HIDE_TARGET_CLASS);
} }
}); });
el.classList.add(JS_INITIALIZED_CLASS);
addEventHandler(el); addEventHandler(el);
}); });

View File

@ -8,6 +8,7 @@
--color-lightwhite: #fcfffa; --color-lightwhite: #fcfffa;
--color-grey: #B1B5C0; --color-grey: #B1B5C0;
--color-grey-light: #efefef; --color-grey-light: #efefef;
--color-grey-lighter: #f5f5f5;
--color-grey-medium: #9A989E; --color-grey-medium: #9A989E;
--color-font: #34303a; --color-font: #34303a;
--color-fontsec: #5b5861; --color-fontsec: #5b5861;

View File

@ -1,8 +1,9 @@
$newline never $newline never
<section> <div .table-filter>
<form .table-filter-form method=GET action=#{filterAction} enctype=#{filterEnctype}> <h3 .js-show-hide__toggle data-sh-index=table-filter data-collapsed=true>Filter
^{filterWgdt} <div>
<button type=submit data-autosubmit> <form .table-filter-form method=GET action=#{filterAction} enctype=#{filterEnctype}>
^{btnLabel BtnSubmit} ^{filterWgdt}
<section> <button type=submit data-autosubmit>
^{scrolltable} ^{btnLabel BtnSubmit}
^{scrolltable}

View File

@ -0,0 +1,4 @@
.table-filter {
border-bottom: 1px solid #d3d3d3;
margin-bottom: 13px;
}

View File

@ -3,7 +3,7 @@ $newline never
$if not isReq $if not isReq
<div .radio> <div .radio>
<input id=#{theId}-none *{attrs} type=radio name=#{name} value=none checked> <input id=#{theId}-none *{attrs} type=radio name=#{name} value=none checked>
<label for=#{theId}-none>_{MsgSelectNone} <label for=#{theId}-none>_{MsgCourseFilterNone}
<div .radio> <div .radio>
<input id=#{theId}-yes *{attrs} type=radio name=#{name} value=yes :showVal id val:checked> <input id=#{theId}-yes *{attrs} type=radio name=#{name} value=yes :showVal id val:checked>