Last active
July 3, 2018 11:48
-
-
Save moritzjacobs/7a8d8de0e700bcd2aafce06a18ea5286 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
($ => { | |
/** | |
* jQuery.selectToggler | |
* | |
* replaces a <select><option>… structure with a simple toggle structure | |
* | |
* $("select.foobar").selectToggler(function(el){ | |
* el.addClass("foobar-toggler"); | |
* el.find("> *").addClass("foobar-toggles"); | |
* }) | |
* | |
* @version 1.0.0 | |
* @param {function} a callback function to put the output through | |
* @return {jQuery} this for chaining | |
*/ | |
$.fn.selectToggler = function(renderFn = false) { | |
let wrapped = []; | |
this.toArray().forEach(el => { | |
const instance = new jQuerySelectToggler(el, renderFn); | |
if (instance !== false) { | |
wrapped.push(instance); | |
} | |
}); | |
let ret = $(); | |
$.each(wrapped, (i, o) => { | |
ret = ret.add(o) | |
}); | |
return ret; | |
}; | |
/** | |
* plugin class | |
*/ | |
class jQuerySelectToggler { | |
/** | |
* constructor | |
* @param {HTMLElement} el the <select> element | |
* @param {object} options options | |
* @return {jQuery} the created wrapper for chaining | |
*/ | |
constructor(el, renderFn = false) { | |
// fields | |
this.el = el; | |
this.renderFn = renderFn; | |
this.$el = $(el); | |
// error handling | |
if ($(el).length < 1) { | |
return false; | |
} | |
if (el.nodeName.toLowerCase() !== "select") { | |
return false; | |
} | |
if (this.$el.hasClass("select-toggler-hidden")) { | |
return false; | |
} | |
if (typeof this.renderFn !== "function") { | |
this.renderFn = x => x; | |
} | |
this.init(); | |
return this.wrapper; | |
} | |
/** | |
* Init function | |
* @return {void} | |
*/ | |
init() { | |
this.wrapper = this.insertNextTo(); | |
this.hide(); | |
this.observe(); | |
} | |
/** | |
* hide the select dropdown | |
* @return {void} | |
*/ | |
hide() { | |
this.$el.addClass("select-toggler-hidden"); | |
this.$el.hide(); | |
} | |
/** | |
* insert the created UI next to the select element | |
* @return {void} | |
*/ | |
insertNextTo() { | |
const wrapper = $("<span/>"); | |
wrapper.addClass("select-toggler-wrapper"); | |
$(this.el).after(wrapper); | |
return wrapper; | |
} | |
/** | |
* convert select>option structure to obj structure | |
* @return {object} all options | |
*/ | |
parseOptions() { | |
const options = this.$el.find("> *"); | |
const selectedValue = this.$el.val(); | |
let parsed = []; | |
options.each((i, option) => { | |
const value = $(option).attr("value"); | |
const selected = value === selectedValue; | |
const label = $(option).html(); | |
parsed.push({ value, label, selected }); | |
}); | |
return parsed; | |
} | |
/** | |
* create single toggle element | |
* @param {object} o toggle options | |
* @return {jQuery} single toggle element | |
*/ | |
makeToggle(o) { | |
const toggle = $("<span/>"); | |
toggle.addClass("select-toggler-item"); | |
toggle | |
.attr("data-jqst-value", o.value) | |
.addClass(o.selected === true ? "is-selected" : "not-selected") | |
.html(o.label) | |
.click(e => { | |
e.preventDefault(); | |
this.select(toggle); | |
}); | |
return toggle; | |
} | |
/** | |
* (re-)render all the toggles | |
* @return {[type]} [description] | |
*/ | |
makeToggles() { | |
// remove old toggles | |
if (this.toggles !== undefined) { | |
this.toggles.remove(); | |
} | |
// new toggles | |
this.toggles = $("<span class='select-toggler-items'/>").appendTo(this.wrapper); | |
// helper class | |
if (this.$el.val().length <= 0) { | |
this.toggles.addClass("is-none-selected"); | |
} | |
const options = this.parseOptions(this.el); | |
options.forEach(o => { | |
this.makeToggle(o).appendTo(this.toggles); | |
}); | |
// run through custom render function, if there is one | |
const rendered = this.renderFn(this.wrapper); | |
this.wrapper.replaceWith(rendered); | |
} | |
/** | |
* select dropwdion item by toggle item | |
* @param {jQuery} item the selected item | |
* @return {void} | |
*/ | |
select(item) { | |
this.el.value = $(item).attr("data-jqst-value"); | |
this.$el.change(); | |
this.toggles.find("*").removeClass("is-selected"); | |
item.addClass("is-selected"); | |
} | |
/** | |
* Add mutation observer | |
* @return {void} | |
*/ | |
observe() { | |
const observer = new MutationObserver(() => { | |
// if anything changes, rerender! | |
this.makeToggles(); | |
}); | |
observer.observe(this.el, { attributes: true, childList: true }); | |
} | |
} | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
jQuery.selectToggler
jQuery plugin to replace a
<select><option>…
structure with a simple toggle structure while maintaing all event handling.