rework show-hide js utility

This commit is contained in:
Felix Hamann 2019-04-04 22:57:53 +02:00
parent ff59d0a412
commit 5e71e8c9e6
9 changed files with 125 additions and 102 deletions

View File

@ -55,10 +55,6 @@
.asidenav__box-title { .asidenav__box-title {
font-size: 18px; font-size: 18px;
padding-left: 10px; padding-left: 10px;
&.js-show-hide__toggle::before {
z-index: 1;
}
} }
} }
} }
@ -94,18 +90,9 @@
margin-top: 30px; margin-top: 30px;
background-color: transparent; background-color: transparent;
transition: all .2s ease; transition: all .2s ease;
padding: 30px 13px 10px; padding: 10px 13px;
margin: 0; margin: 0;
border-bottom: 1px solid var(--color-grey); border-bottom: 1px solid var(--color-grey);
&.js-show-hide__toggle {
&::before {
left: auto;
right: 20px;
color: var(--color-font);
}
}
} }
/* LOGO */ /* LOGO */
@ -361,9 +348,5 @@
background-color: var(--color-lightwhite); background-color: var(--color-lightwhite);
} }
} }
.js-show-hide__toggle::before {
content: none;
}
} }
} }

View File

@ -1,10 +1,9 @@
$show-hide-toggle-size: 6px; $show-hide-toggle-size: 6px;
.js-show-hide__toggle { .show-hide__toggle {
position: relative; position: relative;
cursor: pointer; cursor: pointer;
padding: 3px 7px;
&:hover { &:hover {
background-color: var(--color-grey-lighter); background-color: var(--color-grey-lighter);
@ -12,32 +11,33 @@ $show-hide-toggle-size: 6px;
} }
} }
.js-show-hide__toggle::before { .show-hide__toggle::before {
content: ''; content: '';
position: absolute; position: absolute;
width: $show-hide-toggle-size; width: $show-hide-toggle-size;
height: $show-hide-toggle-size; height: $show-hide-toggle-size;
left: -15px; left: -15px;
top: 12px - $show-hide-toggle-size / 2; top: 50%;
color: var(--color-primary); color: var(--color-primary);
border-right: 2px solid currentColor; border-right: 2px solid currentColor;
border-top: 2px solid currentColor; border-top: 2px solid currentColor;
transition: transform .2s ease; transition: transform .2s ease;
transform-origin: ($show-hide-toggle-size / 2); transform: translateY(-50%) rotate(-45deg);
transform: translateY($show-hide-toggle-size) rotate(-45deg);
} }
.js-show-hide__target { .show-hide__toggle--right::before {
transition: all .2s ease; left: auto;
right: 20px;
color: var(--color-font);
} }
.js-show-hide--collapsed { .show-hide--collapsed {
.js-show-hide__toggle::before { .show-hide__toggle::before {
transform: translateY($show-hide-toggle-size / 3) rotate(135deg); transform: translateY(-50%) rotate(135deg);
} }
.js-show-hide__target { :not(.show-hide__toggle) {
display: block; display: block;
height: 0; height: 0;
margin: 0; margin: 0;

View File

@ -2,6 +2,20 @@
'use strict'; 'use strict';
window.utils = window.utils || {}; window.utils = window.utils || {};
// ########################
// TODO: make use of selector
// or think of a different way to dynamically initialize widgets
// with selectors with specific ids like #modal-hident69
//
// Idee:
// Alles wegschmeißen zu dynamischen IDs. Util init rein über Selector '[uw-...]'
// bedarf Änderung in Templates.
// Ausserdem müssen sich Utils bei Event 'util-setup-ready' registrieren als Util
// utils.setup wird dann überflüssig, bzw. wird zu einer Registry / Controller
// der die utils bei DomCOntentLoaded intialisiert.
//
// ########################
var SELECTOR = '[uw-modal]';
var JS_INITIALIZED_CLASS = 'js-modal-initialized'; var JS_INITIALIZED_CLASS = 'js-modal-initialized';
var MODAL_OPEN_CLASS = 'modal--open'; var MODAL_OPEN_CLASS = 'modal--open';
@ -17,7 +31,7 @@
var OVERLAY_OPEN_CLASS = 'modal__overlay--open'; var OVERLAY_OPEN_CLASS = 'modal__overlay--open';
var CLOSER_CLASS = 'modal__closer'; var CLOSER_CLASS = 'modal__closer';
window.utils.modal = function(modalElement, options) { window.utils.modal = function(scope, options) {
if (!modalElement || modalElement.classList.contains(JS_INITIALIZED_CLASS)) { if (!modalElement || modalElement.classList.contains(JS_INITIALIZED_CLASS)) {
return; return;

View File

@ -55,7 +55,14 @@
const elements = _findUtilElements(util, scope); const elements = _findUtilElements(util, scope);
elements.forEach(function(element) { elements.forEach(function(element) {
var utilInstance = util.setup(element); var utilInstance = null;
try {
utilInstance = util.setup(element);
} catch(err) {
console.warn('Error while trying to initialize a utility!', { util , element, err });
}
if (utilInstance) { if (utilInstance) {
activeUtilInstances.push(utilInstance); activeUtilInstances.push(utilInstance);
} }

View File

@ -1,98 +1,113 @@
(function() { (function() {
'use strict'; 'use strict';
var UTIL_NAME = 'showHide'; var SHOW_HIDE_UTIL_NAME = 'showHide';
var UTIL_SELECTOR = '[uw-show-hide]'; var SHOW_HIDE_UTIL_SELECTOR = '[uw-show-hide]';
var JS_INITIALIZED_CLASS = 'js-show-hide-initialized'; var SHOW_HIDE_LOCAL_STORAGE_KEY = 'SHOW_HIDE';
var LOCAL_STORAGE_SHOW_HIDE = 'SHOW_HIDE'; var SHOW_HIDE_INITIALIZED_CLASS = 'show-hide--initialized';
var SHOW_HIDE_COLLAPSED_CLASS = 'js-show-hide--collapsed'; var SHOW_HIDE_COLLAPSED_CLASS = 'show-hide--collapsed';
var SHOW_HIDE_TARGET_CLASS = 'js-show-hide__target'; var SHOW_HIDE_TOGGLE_CLASS = 'show-hide__toggle';
var SHOW_HIDE_TOGGLE_RIGHT_CLASS = 'show-hide__toggle--right';
/** /**
*
* ShowHide Utility
*
* Attribute: uw-show-hide
*
* Params: (all optional)
* data-show-hide-id: string
* If this param is given the state of the utility will be persisted in the clients local storage.
* data-show-hide-collapsed: boolean property
* If this param is present the ShowHide utility will be collapsed. This value will be overruled by any value stored in the LocalStorage.
* data-show-hide-align: 'right'
* Where to put the arrow that marks the element as a ShowHide toggle. Left of toggle by default.
*
* Example usage:
* <div> * <div>
* <div uw-show-hide> * <div uw-show-hide>Click me
* [toggle here] * <div>This will be toggled
* <div> * <div>This will be toggled as well
* [content here]
*/ */
var util = function(element) { var showHideUtil = function(element) {
function _init() { var showHideId;
function init() {
if (!element) { if (!element) {
throw new Error('ShowHide utility cannot be setup without an element!'); throw new Error('ShowHide utility cannot be setup without an element!');
} }
if (element.classList.contains(JS_INITIALIZED_CLASS)) { if (element.classList.contains(SHOW_HIDE_INITIALIZED_CLASS)) {
return false; throw new Error('ShowHide utility already initialized!');
} }
_addEventHandler(); // register click listener
addClickListener();
// param showHideId
if (element.dataset.showHideId) {
showHideId = element.dataset.showHideId;
}
// param showHideCollapsed
var collapsed = false;
if (element.dataset.showHideCollapsed !== undefined) {
collapsed = true;
}
if (showHideId) {
var localStorageCollapsed = getLocalStorage()[showHideId];
if (typeof localStorageCollapsed !== 'undefined') {
collapsed = localStorageCollapsed;
}
}
element.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS, collapsed);
// param showHideAlign
var alignment = element.dataset.showHideAlign;
if (alignment === 'right') {
element.classList.add(SHOW_HIDE_TOGGLE_RIGHT_CLASS);
}
// mark as initialized
element.classList.add(SHOW_HIDE_INITIALIZED_CLASS, SHOW_HIDE_TOGGLE_CLASS);
return {
name: SHOW_HIDE_UTIL_NAME,
element: element,
destroy: function() {},
};
} }
function _addEventHandler() { function addClickListener() {
element.addEventListener('click', function clickListener() { element.addEventListener('click', function clickListener() {
console.log('showhide clicked');
var newState = element.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS); var newState = element.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS);
_updateLSState(element.dataset.shIndex || null, newState);
if (showHideId) {
setLocalStorage(showHideId, newState);
}
}); });
} }
function _updateLSState(index, state) { function setLocalStorage(id, state) {
if (!index) { var lsData = getLocalStorage();
return false; lsData[id] = state;
} window.localStorage.setItem(SHOW_HIDE_LOCAL_STORAGE_KEY, JSON.stringify(lsData));
var lsData = _getLocalStorageData();
lsData[index] = state;
window.localStorage.setItem(LOCAL_STORAGE_SHOW_HIDE, JSON.stringify(lsData));
} }
// function _getCollapsedLSState(index) { function getLocalStorage() {
// var lsState = _getLocalStorageData(); return JSON.parse(window.localStorage.getItem(SHOW_HIDE_LOCAL_STORAGE_KEY)) || {};
// return lsState[index];
// }
function _getLocalStorageData() {
return JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_SHOW_HIDE)) || {};
} }
// var showHides = Array.from(scope.querySelectorAll(UTIL_SELECTOR)); return init();
// showHides.forEach(function(el) {
// if (el.classList.contains(JS_INITIALIZED_CLASS)) {
// return false;
// }
// var index = el.dataset.shIndex || null;
// var isCollapsed = el.dataset.collapsed === 'true';
// var lsCollapsedState = _getCollapsedLSState(index);
// if (typeof lsCollapsedState !== 'undefined') {
// isCollapsed = lsCollapsedState;
// }
// el.parentElement.classList.toggle(SHOW_HIDE_COLLAPSED_CLASS, isCollapsed);
// Array.from(el.parentElement.children).forEach(function(el) {
// if (!el.matches(UTIL_SELECTOR)) {
// el.classList.add(SHOW_HIDE_TARGET_CLASS);
// }
// });
// el.classList.add(JS_INITIALIZED_CLASS);
// _addEventHandler(el);
// });
_init();
return {
name: UTIL_NAME,
element: element,
destroy: function() {},
};
}; };
if (UtilRegistry) { if (UtilRegistry) {
UtilRegistry.register({ UtilRegistry.register({
name: UTIL_NAME, name: SHOW_HIDE_UTIL_NAME,
selector: UTIL_SELECTOR, selector: SHOW_HIDE_UTIL_SELECTOR,
setup: util setup: showHideUtil
}); });
} }

View File

@ -6,7 +6,7 @@
Der Handler sollte jeweils aktuelle Beispiele für alle möglichen Funktionalitäten enthalten, so dass man immer weiß, wo man nachschlagen kann. Der Handler sollte jeweils aktuelle Beispiele für alle möglichen Funktionalitäten enthalten, so dass man immer weiß, wo man nachschlagen kann.
<section> <section>
<h2 .js-show-hide__toggle>Teilweise funktionierende Abschnitte <h2 uw-show-hide>Teilweise funktionierende Abschnitte
<ul> <ul>
<li .list-group-item> <li .list-group-item>

View File

@ -1,6 +1,6 @@
$newline never $newline never
<div .table-filter> <div .table-filter>
<h3 .js-show-hide__toggle data-sh-index=table-filter data-collapsed=true>Filter <h3 .table-filter__toggle uw-show-hide data-show-hide-id=table-filter data-show-hide-collapsed>Filter
<div> <div>
^{filterForm} ^{filterForm}
^{scrolltable} ^{scrolltable}

View File

@ -1,3 +1,7 @@
.table-filter { .table-filter {
margin-bottom: 13px; margin-bottom: 13px;
} }
.table-filter__toggle {
padding: 3px 7px;
}

View File

@ -7,10 +7,10 @@ $newline never
<div .asidenav> <div .asidenav>
$forall tid <- favouriteTerms $forall tid <- favouriteTerms
<div .asidenav__box.js-show-hide> <div .asidenav__box>
<h3 .asidenav__box-title.js-show-hide__toggle data-sh-index="#{termToText tid}"> <h3 .asidenav__box-title uw-show-hide data-show-hide-id="#{termToText tid}" data-show-hide-align=right>
_{ShortTermIdentifier tid} _{ShortTermIdentifier tid}
<ul .asidenav__list.js-show-hide__target.list--iconless> <ul .asidenav__list.list--iconless>
$forall (Course{courseShorthand, courseName}, courseRoute, pageActions) <- favouriteTerm tid $forall (Course{courseShorthand, courseName}, courseRoute, pageActions) <- favouriteTerm tid
<li .asidenav__list-item :highlight courseRoute:.asidenav__list-item--active> <li .asidenav__list-item :highlight courseRoute:.asidenav__list-item--active>
<a .asidenav__link-wrapper href=@{courseRoute}> <a .asidenav__link-wrapper href=@{courseRoute}>