Custom list picker
How do I make an custom list picker?
What is a custom list picker? How do you make a custom list picker? This script and codes were developed by Anthony Pothin on 17 January 2023, Tuesday.
Custom list picker - Script Codes HTML Codes
<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>custom list picker</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
</head>
<body> <!-- dependancies -->
<!-- gesture list -->
<link rel="import" href="https://codepen.io/Thorien/pen/VLWzWR.html" />
<!-- easing -->
<link rel="import" href="https://codepen.io/Thorien/pen/f0e61caa5742e9d488421d33a5bf7dd2.html" />
<!-- custom scroll -->
<link rel="import" href="https://codepen.io/Thorien/pen/xGgMwV.html" />
<template id="c-list-picker"> <style scoped="scoped"> :host{ position: relative; flex-shrink: 0; flex-basis: 0; display: flex; flex-direction: column; justify-content: stretch; } c-scroll { flex: 1 1 0; cursor: pointer; text-align: center; -moz-user-select: -moz-none; -webkit-user-select: none; -khtml-user-select: none; -o-user-select: none; user-select: none; } #selection{ position: absolute; width: 100%; background-color: rgba(250, 0, 0, 0.5); } /* surcharge */ c-list-picker { position: relative; flex-shrink: 0; flex-basis: 0; display: flex; flex-direction: column; justify-content: stretch; } </style> <div id="selection"></div> <c-scroll hidescrollbar> <div class="padding" id="paddingtop"></div> <div class="padding" id="paddingbottom"></div> </c-scroll>
</template>
<script> var HTMLCustomListPickerElement = (function() { var parentDoc = (document._currentScript || document.currentScript).ownerDocument; // fonctions privées var onScrollEnd = function(event) { console.warn('onScrollEnd', event); var customListPicker = event.currentTarget.parentNode.host; var scroll = event.currentTarget; // récupérer hauteur d'un élément var itemHeight = customListPicker.shadowRoot.querySelector('c-scroll div:not(.wrapper):not(.padding)').clientHeight; // récupérer hauteur totale var visibleHeight = customListPicker.shadowRoot.querySelector('c-scroll').clientHeight; // calculer padding var verticalPadding = (visibleHeight - itemHeight) / 2; // récupérer scrollTop var scrollTop = customListPicker.shadowRoot.querySelector('c-scroll').scrollTop; offsetTopTarget = scrollTop + verticalPadding + (itemHeight / 2); console.error('scrollTop', scrollTop, 'verticalPadding', verticalPadding, '(itemHeight / 2)', (itemHeight / 2), 'offsetTopTarget', offsetTopTarget); // parcourir les div var divList = customListPicker.shadowRoot.querySelectorAll('c-scroll div:not(.wrapper):not(.padding)'); var selectedDiv; for (var i=0, iMax=divList.length; i<iMax; i++) { if ((offsetTopTarget - divList.item(i).offsetTop) / 2 <= itemHeight / 2) { selectedDiv = divList.item(i); customListPicker.select(selectedDiv.value); break; } } if (!selectedDiv && customListPicker.value) { customListPicker.select(customListPicker.value); } }; var onResize = function(event) { clearTimeout(this.resizeTimeoutID); var customListPicker = this; this.resizeTimeoutID = setTimeout(function() { delete customListPicker.resizeTimeoutID; customListPicker.resize(); }, 100); } // objet custom return document.registerElement('c-list-picker', { prototype: Object.create(HTMLElement.prototype, { // constructeur createdCallback: { value: function() { // création shadow root this.createShadowRoot(); // ajout contenu depuis le template var cloneTemplate = document.importNode(parentDoc.querySelector('template#c-list-picker').content, true); this.shadowRoot.appendChild(cloneTemplate); // propriétés custom avec stockage caché var _value = null; Object.defineProperty(this, 'value', { configurable: false, enumerable: false, get: function() { //console.info('HTMLCustomListPickerElement.value.get()'); return _value; }, set: function(value) { //console.info('HTMLCustomListPickerElement.value.set()'); var oldValue = _value; _value = (value === null || value === '' ? null : value); Object.getNotifier(this).notify({ type: 'update', name: 'value', oldValue: oldValue }); } }); // ajout event interaction // propriétés custom avec stockage caché // ajout event propriété Object.observe(this, function(changes) { //console.info('HTMLCustomListPickerElement.onchange()'); changes.forEach(function(change) { // change === {name (nom propriété), object (l'objet observé), type (add, update, delete), oldValue} //console.info('Object.observe', change.object, change.name, 'qui valait', change.oldValue, 'vaut désormais', change.object[change.name]); // stuff switch (change.name) { default: break; } }); }); // initialisation this.init(); } }, // propriétés custom name: { get: function() { //console.info('HTMLCustomListPickerElement.name.get()'); return this.getAttribute('name'); }, set: function(value) { //console.info('HTMLCustomListPickerElement.name.set()'); var oldValue = this.getAttribute('name'); this.setAttribute('name', value); Object.getNotifier(this).notify({ type: 'update', name: 'name', oldValue: oldValue }); } }, min: { get: function() { //console.info('HTMLCustomListPickerElement.min.get()'); return (this.hasAttribute('min') && !isNaN(this.getAttribute('min')) ? parseFloat(this.getAttribute('min')) : null); }, set: function(value) { //console.info('HTMLCustomListPickerElement.min.set()'); var oldValue = this.getAttribute('min'); this.setAttribute('min', value); Object.getNotifier(this).notify({ type: 'update', name: 'min', oldValue: oldValue }); } }, max: { get: function() { //console.info('HTMLCustomListPickerElement.max.get()'); return (this.hasAttribute('max') && !isNaN(this.getAttribute('max')) ? parseFloat(this.getAttribute('max')) : null); }, set: function(value) { //console.info('HTMLCustomListPickerElement.max.set()'); var oldValue = this.getAttribute('max'); this.setAttribute('max', value); Object.getNotifier(this).notify({ type: 'update', name: 'max', oldValue: oldValue }); } }, step: { get: function() { //console.info('HTMLCustomListPickerElement.step.get()'); return (this.hasAttribute('step') && !isNaN(this.getAttribute('step')) ? parseFloat(this.getAttribute('step')) : null); }, set: function(value) { //console.info('HTMLCustomListPickerElement.step.set()'); var oldValue = this.getAttribute('step'); this.setAttribute('step', value); Object.getNotifier(this).notify({ type: 'update', name: 'step', oldValue: oldValue }); } }, reverse: { get: function() { //console.info('HTMLCustomListPickerElement.reverse.get()'); return this.hasAttribute('reverse'); }, set: function(value) { //console.info('HTMLCustomListPickerElement.reverse.set()'); var oldValue = this.hasAttribute('reverse'); if (value) { this.setAttribute('reverse', 'reverse'); } else { this.removeAttribute('reverse'); } Object.getNotifier(this).notify({ type: 'update', name: 'reverse', oldValue: oldValue }); } }, // méthodes custom clear: { value: function() { var scroll = this.shadowRoot.querySelector('c-scroll'); var div = scroll.querySelector('div:not(.wrapper):not(.padding)'); while (div) { scroll.removeChild(div); div = scroll.querySelector('div:not(.wrapper):not(.padding)'); } } }, init: { value: function() { //console.info('HTMLCustomListPickerElement.init()'); if (this.min === null || this.max === null) { return; } var scroll = this.shadowRoot.querySelector('c-scroll'); // supprimer précédents éléments this.clear(); // créer nouveaux éléments var step = (this.step && this.step !== 0 ? this.step : 1); var reverse = this.reverse; for (var i=this.min, iMax=this.max; i<=iMax; i += step) { div = document.createElement('div'); div.textContent = i; div.value = i; div.id = 'lp'+i; if (!reverse) { //scroll.appendChild(div); scroll.insertBefore(div, scroll.querySelector('#paddingbottom')); } else { //scroll.insertBefore(div, scroll.firstElementChild); scroll.insertBefore(div, scroll.querySelector('#paddingtop').nextElementSibling); } } this.resize(); } }, select: { value: function(value) { //console.error('HTMLCustomListPickerElement.select()', value); // trouver la div if (value === null) { return; } var target = this.shadowRoot.querySelector('#lp'+value); if (!target) { //console.error('unfound value',value) target = this.shadowRoot.querySelector('#lp'+ this.max); if(!target) { //console.error('HTMLCustomListPickerElement.select() => unfound value',value, 'or',(value - 1)); this.value = null; return; } } // repositionner le scroll top var scroll = this.shadowRoot.querySelector('c-scroll'); // récupérer hauteur d'un élément var itemHeight = this.shadowRoot.querySelector('c-scroll div:not(.wrapper):not(.padding)').clientHeight; // récupérer hauteur totale var visibleHeight = this.shadowRoot.querySelector('c-scroll').clientHeight; // calculer padding var verticalPadding = (visibleHeight - itemHeight) / 2; var delta = target.offsetTop - (scroll.scrollTop + verticalPadding); var targetScrollTop = scroll.scrollTop + delta; if (targetScrollTop !== scroll.scrollTop) { var previousScrollTop = scroll.scrollTop; var intervalID, timeoutID, pastTime = 0, currentTime = 0, interval = 10, duration = 100; var onInterval = function() { currentTime += interval; var ratio = easing.easeOutBounce(currentTime / duration); scroll.scrollTop = previousScrollTop + (delta * ratio); } var onTimeout = function() { clearInterval(intervalID); clearTimeout(timeoutID); scroll.scrollTop = previousScrollTop + delta; } intervalID = setInterval(onInterval, interval); timeoutID = setTimeout(onTimeout, duration); } // affecter nouvelle valeur this.value = target.value; } }, resize: { value: function(value) { // passer padding à 0 /*this.shadowRoot.querySelector('c-scroll').style.paddingTop = null; this.shadowRoot.querySelector('c-scroll').style.paddingBottom = null;*/ this.shadowRoot.querySelector('#paddingtop').style.height = null; this.shadowRoot.querySelector('#paddingbottom').style.height = null; var itemHeight = this.shadowRoot.querySelector('c-scroll div:not(.wrapper):not(.padding)').clientHeight; // récupérer hauteur totale var visibleHeight = this.shadowRoot.querySelector('c-scroll').clientHeight; // calculer padding var verticalPadding = (visibleHeight - itemHeight) / 2; // affecter padding /*this.shadowRoot.querySelector('c-scroll').style.paddingTop = verticalPadding + 'px'; this.shadowRoot.querySelector('c-scroll').style.paddingBottom = verticalPadding + 'px';*/ this.shadowRoot.querySelector('#paddingtop').style.height = verticalPadding + 'px'; this.shadowRoot.querySelector('#paddingbottom').style.height = verticalPadding + 'px'; // repositionner la boite de sélection var selectionBox = this.shadowRoot.querySelector('#selection'); selectionBox.style.height = itemHeight + 'px'; selectionBox.style.top = verticalPadding + 'px'; this.select(this.value); } }, // méthode exécuté à chaque insertion de l'élément custom attachedCallback: { value: function() { //console.info('HTMLCustomListPickerElement.attachedCallback()'); // methode bindée this.onResize = onResize.bind(this); // ajout des events this.shadowRoot.querySelector('c-scroll').addEventListener('c-scrollEnd', onScrollEnd, true); window.addEventListener('resize', this.onResize, true); } }, // méthode exécuté à chaque détachement de l'élément custom detachedCallback: { value: function() { //console.info('HTMLCustomListPickerElement.detachedCallback()'); // retrait des events this.shadowRoot.querySelector('c-scroll').removeEventListener('c-scrollEnd', onScrollEnd, true); window.removeEventListener('resize', this.onResize, true); // methode bindée delete this.onResize; } }, // méthode exécuté quand un attribut est modifié attributeChangedCallback: { value: function(attrName, oldValue, newValue) { //console.info('HTMLCustomListPickerElement.attributeChangedCallback()'); //console.info('attributeChangedCallback', this, attrName, 'qui valait', oldValue, 'vaut désormais', newValue); switch (attrName) { case 'min': case 'max': case 'step': this.init(); break; } } } }) }); })();
</script> <script src="js/index.js"></script>
</body>
</html>
Custom list picker - Script Codes JS Codes
var onScrollEnd = function(event) { console.warn('onScrollEnd', event); var customListPicker = event.currentTarget.parentNode.host; var scroll = event.currentTarget; // trouver la balise // récupérer hauteur d'un élément var itemHeight = customListPicker.shadowRoot.querySelector('c-scroll div:not(.wrapper)').clientHeight; // récupérer hauteur totale var visibleHeight = customListPicker.shadowRoot.querySelector('c-scroll').clientHeight; // calculer padding var verticalPadding = (visibleHeight - itemHeight) / 2; // récupérer scrollTop var scrollTop = customListPicker.shadowRoot.querySelector('c-scroll').scrollTop; offsetTopTarget = scrollTop + verticalPadding + (itemHeight / 2); // parcourir les div var divList = customListPicker.shadowRoot.querySelectorAll('c-scroll div:not(.wrapper)'); var selectedDiv; for (var i=0, iMax=divList.length; i<iMax; i++) { if ((offsetTopTarget - divList.item(i).offsetTop) / 2 <= itemHeight / 2) { } } // la repositionner // enregistrer la nouvelle valeur }
Developer | Anthony Pothin |
Username | Thorien |
Uploaded | January 17, 2023 |
Rating | 3 |
Size | 5,009 Kb |
Views | 10,120 |
Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!
Name | Size |
Responsive slide | 2,400 Kb |
Form - datetime picker | 6,482 Kb |
Form - form | 3,487 Kb |
A Pen by Anthony Pothin | 4,034 Kb |
Form - checkbox | 3,829 Kb |
Form - select | 10,146 Kb |
Test moment.js | 1,546 Kb |
Resizable flexible box | 3,381 Kb |
Magic table | 8,674 Kb |
Demo component | 2,725 Kb |
Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!
Name | Username | Size |
A vuejs widget | Chrgl86 | 2,869 Kb |
Simple Buttons | Haydenmills | 1,750 Kb |
Sass random color animation | Jotavejv | 4,827 Kb |
Apex Calculator | Michaelwnelson | 2,370 Kb |
Magnus 3 | ARocketfish | 7,944 Kb |
FCC_Twitch.tv | MitchES | 3,466 Kb |
Faces SVG animation | ScavengerFrontend | 2,957 Kb |
Apple website | Jds317 | 1,835 Kb |
Drawing a Terminal with CSS | Lachlanjc | 3,185 Kb |
RRC wrapSwitch | Pshrmn | 2,922 Kb |
Surf anonymously, prevent hackers from acquiring your IP address, send anonymous email, and encrypt your Internet connection. High speed, ultra secure, and easy to use. Instant setup. Hide Your IP Now!