@sncf/bootstrap-sncf.metier
Version:
SNCF frontend framework
222 lines (176 loc) • 5.45 kB
JavaScript
/* eslint-disable */
/*
* Stretchy: Form element autosizing, the way it should be.
* by Lea Verou http://lea.verou.me
* MIT license
*/
(function() {
if (!self.Element) {
return; // super old browser
}
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || null;
}
if (!Element.prototype.matches) {
return;
}
function $$(expr, con) {
return expr instanceof Node || expr instanceof Window? [expr] :
[].slice.call(typeof expr == "string"? (con || document).querySelectorAll(expr) : expr || []);
}
var _ = self.Stretchy = {
selectors: {
base: '.stretchy',
filter: "*"
},
// Script element this was included with, if any
script: document.currentScript || $$("script").pop(),
// Autosize one element. The core of Stretchy.
resize: function(element) {
if (!_.resizes(element)) {
return;
}
var cs = getComputedStyle(element);
var offset = 0;
var empty;
if (!element.value && element.placeholder) {
empty = true;
element.value = element.placeholder;
}
var type = element.nodeName.toLowerCase();
if (type == "textarea") {
element.style.height = "0";
if (cs.boxSizing == "border-box") {
offset = element.offsetHeight;
}
else if (cs.boxSizing == "content-box") {
offset = -element.clientHeight + parseFloat(cs.minHeight);
}
element.style.height = element.scrollHeight + "px";
}
else if(type == "input") {
// First test that it is actually visible, otherwise all measurements are off
element.style.width = "1000px";
if (element.offsetWidth) {
element.style.width = "0";
if (cs.boxSizing == "border-box") {
offset = element.offsetWidth;
}
else if (cs.boxSizing == "padding-box") {
offset = element.clientWidth;
}
else if (cs.boxSizing == "content-box") {
offset = parseFloat(cs.minWidth);
}
var width = Math.max(offset, element.scrollWidth - element.clientWidth);
element.style.width = width + "px";
// To bulletproof, we will set scrollLeft to a
// huge number, and read that back to see what it was clipped to
// and increment width by that much, iteratively
for (var i=0; i<10; i++) { // max iterations
element.scrollLeft = 1e+10;
if (element.scrollLeft == 0) {
break;
}
width += element.scrollLeft;
element.style.width = width + "px";
}
}
else {
// Element is invisible, just set to something reasonable
element.style.width = element.value.length + 1 + "ch";
}
}
else if (type == "select") {
var selectedIndex = element.selectedIndex > 0? element.selectedIndex : 0;
// Need to use dummy element to measure :(
var option = document.createElement("_");
option.textContent = element.options[selectedIndex].textContent;
element.parentNode.insertBefore(option, element.nextSibling);
// The name of the appearance property, as it might be prefixed
var appearance;
for (var property in cs) {
var value = cs[property];
if (!/^(width|webkitLogicalWidth|length)$/.test(property) && typeof value == "string") {
//console.log(property, option.offsetWidth, cs[property]);
option.style[property] = value;
if (/appearance$/i.test(property)) {
appearance = property;
}
}
}
option.style.width = "";
if (option.offsetWidth > 0) {
element.style.width = option.offsetWidth + "px";
if (!cs[appearance] || cs[appearance] !== "none") {
// Account for arrow
element.style.width = "calc(" + element.style.width + " + 2em)";
}
}
option.parentNode.removeChild(option);
option = null;
}
if (empty) {
element.value = "";
}
},
// Autosize multiple elements
resizeAll: function(elements) {
$$(elements || _.selectors.base).forEach(function (element) {
_.resize(element);
});
},
active: true,
// Will stretchy do anything for this element?
resizes: function(element) {
return element &&
element.parentNode &&
element.matches &&
element.matches(_.selectors.base) &&
element.matches(_.selectors.filter);
},
init: function(){
_.selectors.filter = _.script.getAttribute("data-filter") ||
($$("[data-stretchy-filter]").pop() || document.body).getAttribute("data-stretchy-filter") || Stretchy.selectors.filter || "*";
_.resizeAll();
},
$$: $$
};
// Autosize all elements once the DOM is loaded
// DOM already loaded?
if (document.readyState !== "loading") {
_.init();
}
else {
// Wait for it
document.addEventListener("DOMContentLoaded", _.init);
}
window.addEventListener("load", function(){
_.resizeAll();
});
// Listen for changes
var listener = function(evt) {
if (_.active) {
_.resize(evt.target);
}
};
document.documentElement.addEventListener("input", listener);
// Firefox fires a change event instead of an input event
document.documentElement.addEventListener("change", listener);
// Listen for new elements
if (self.MutationObserver) {
(new MutationObserver(function(mutations) {
if (_.active) {
mutations.forEach(function(mutation) {
if (mutation.type == "childList") {
Stretchy.resizeAll(mutation.addedNodes);
}
});
}
})).observe(document.documentElement, {
childList: true,
subtree: true
});
}
})();
/* eslint-enable */