I'm adapting an example found here on StackOverflow for replacing the "select" component on IE7 that does not support some nice CSS layout.
The example lacks a scrollbar, so I added a div with a fixed size so the scrollbars would appear and the component would be almost complete.
My problems:
1 - On IE7 (IE9 compatibility mode) the scrollbars do not appear. Any fix for this?
2 - How do I do to the "div" to just be positioned on that location but stay in front of the other components, instead of occupying its full size?
My code/html on jsfiddle:
http://jsfiddle.net/mbarni/nTYWA/
(run it as "no wrap (head)")
Inline code/html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<style type="text/css">
body {
font: 80% 'Quicksand-Regular', Verdana, Geneva, sans-serif;
}
select {
display: block;
margin: 0 0 10px;
width: 300px;
}
select.replaced {
width: 1px;
position: absolute;
left: -999em;
}
ul.selectReplacement {
background: #10194B;
margin: 0 0 10px;
padding: 0;
height: 1.65em;
width: 300px;
position: relative;
z-index: 1000;
}
ul.selectFocused {
background: #10194B;
}
ul.selectReplacement li {
background: #09C;
color: #fff;
cursor: pointer;
display: none;
font-size: 11px;
line-height: 1.7em;
list-style: none;
margin: 0;
padding: 1px 12px;
width: 276px;
}
ul.selectOpen li {
display: block;
}
ul.selectReplacement li.selected {
background: #10194B;
border-bottom: 1px solid #fff;
color: #fff;
display: block;
}
ul.selectOpen li.selected {
background: #10194B;
border: 0;
display: block;
}
ul.selectOpen li:hover,
ul.selectOpen li.hover,
ul.selectOpen li.selected:hover {
background: #10194B;
color: #fff;
}
div.scroll {
overflow-y: auto;
overflow-x: hidden;
height: 100px;
width: 300px;
}
</style>
<script type="text/javascript">
function selectReplacement(obj) {
obj.className += ' replaced';
var ul = document.createElement('ul');
ul.className = 'selectReplacement';
var div = document.createElement('div');
div.className = 'scroll';
div.appendChild(ul);
var opts = obj.options;
var selectedOpt = (!obj.selectedIndex) ? 0 : obj.selectedIndex;
for (var i=0; i<opts.length; i++) {
var li = document.createElement('li');
var txt = document.createTextNode(opts[i].text);
li.appendChild(txt);
li.selIndex = i;
li.selectID = obj.id;
li.onclick = function() {
selectMe(this);
};
if (i == selectedOpt) {
li.className = 'selected';
li.onclick = function() {
this.parentNode.className += ' selectOpen';
this.onclick = function() {
selectMe(this);
};
};
}
if (window.attachEvent) {
li.onmouseover = function() {
this.className += ' hover';
};
li.onmouseout = function() {
this.className =
this.className.replace(new RegExp(" hover\\b"), '');
};
}
ul.appendChild(li);
}
obj.onfocus = function() {
ul.className += ' selectFocused';
};
obj.onblur = function() {
ul.className = 'selectReplacement';
};
obj.onchange = function() {
var idx = this.selectedIndex;
selectMe(ul.childNodes[idx]);
};
obj.onkeypress = obj.onchange;
obj.parentNode.insertBefore(div,obj);
}
function selectMe(obj) {
var lis = obj.parentNode.getElementsByTagName('li');
for (var i=0; i<lis.length; i++) {
if (lis[i] != obj) {
lis[i].className='';
lis[i].onclick = function() {
selectMe(this);
};
} else {
setVal(obj.selectID, obj.selIndex);
obj.className='selected';
obj.parentNode.className =
obj.parentNode.className.replace(new RegExp(" selectOpen\\b"), '');
obj.onclick = function() {
obj.parentNode.className += ' selectOpen';
this.onclick = function() {
selectMe(this);
};
};
}
}
}
function setVal(objID,val) {
var obj = document.getElementById(objID);
obj.selectedIndex = val;
}
function setForm() {
var s = document.getElementsByTagName('select');
for (var i=0; i<s.length; i++) {
selectReplacement(s[i]);
}
}
window.onload = function() {
(document.all && !window.print) ? null : setForm();
};
</script>
</head>
<body>
<select id="unidade">
<option value="001">TEST 1</option>
<option selected value="002">TEST 2</option>
<option value="003">TEST 3</option>
<option value="004">TEST 4</option>
<option value="005">TEST 5</option>
<option value="006">TEST 6</option>
<option value="007">TEST 7</option>
<option value="008">TEST 8</option>
</select>
</body>
</html>
You've run into the IE7 scrolling div bug.
Remove position: relative from ul.selectReplacement and everything works. Already tested in jsfiddle in IE9's IE7 Browser Mode.
If you find that you need the position: relative on the ul elements, attach position: relative to the containing div (div.scroll)and that also fixes things (relevant jsfiddle). Just striping position relative didn't seem to break anything in either chrome or IE7 mode, but if you need the ul elements to not use the static model and don't need the div to use the static, the second method works fine too in both cases.
As to the second question, you can position: relative the div.scroll and then wrap it in a height: 1.5em div as seen in this jsfiddle. The wrapping div can have positioning and z-indexing added to it as needed: note that if you need interior elements to appear higher than other siblings to the wrapper div, you will need z-indexing on the wrapper due to an IE bug relating to z-indexing on child elements versus elements sibling to an ancestor. Works in IE7 mode and in chrome.
(Note that if you want to have this be an inline element, you can display: inline-block it with the usual caveats--appropriate jsfiddle here and IE7 fix hack with zoom and *display:inline version here)
Edit:
Inline version with fix for text below by having the div switch between two different heights: jsfiddle. Note that this will require some playing with the heights/line heights of the ul and li elements to avoid slight displacements in height from open to close, but the basic concept is there, albeit in an inelegant way ("better" would be to simply change the div's height attribute, or isolate the height in an additional class and only swap that class). Note that the selected element height had to be reduced and padding removed to be able to compress the div down to essentially a single line height. Reducing heights on certain elements further will allow further compression of the scroll div without ending up with scrollbars even in the closed state, if needed.
Related
I have this simple collapsible menu on www.keokuk.com
I would like for the previous menu to close when you click on the next one.
this is the javascript:
<script>
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function () {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
</script>
I worked on a solution on your website.
But it appears you set max-height manually in an other javascript function so you can just do the same thing in the commented line.
document.querySelectorAll('.collapsible').forEach(el => {
el.addEventListener('click', (e) => {
document.querySelectorAll('.collapsible').forEach(e => {
e.classList.remove('active');
e.nextSibling.nextElementSibling.style.maxHeight = "0px";
});
e.target.classList.toggle('active');
e.target.nextSibling.nextElementSibling.style.maxHeight =
`${el.nextSibling.nextElementSibling.scrollHeight}px`;
});
});
Details are commented in example
// Collect all .switch into an array
const switches = [...document.querySelectorAll(".switch")];
// Bind each .switch to the click event
switches.forEach(s => s.addEventListener("click", openClose));
// Event handler passes Event Object as default
function openClose(event) {
// Reference the tag proceeding clicked tag
const content = this.nextElementSibling;
// Get the height of content
let maxHt = content.scrollHeight + 'px';
// Find the index position of clicked tag
let index = switches.indexOf(this);
// The clicked tag will toggle .active class
this.classList.toggle('active');
// Remove .active class from all .switch
switches.forEach((btn, idx) => {
/*
If current index does NOT equal index of
clicked tag...
...remove .active
*/
if (idx != index) {
btn.classList.remove('active');
}
});
/*
If clicked has .active class...
...set style property of max-height using CSS variables
*/
if (this.classList.contains('active')) {
content.style.setProperty('--maxH', maxHt + 'px');
} else {
content.style.setProperty('--maxH', '0px');
}
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box
}
:root {
font: 300 1.5ch/1.2 'Segoe UI';
--maxH: 0px;
}
body {
width: 100%;
min-height: 200%;
padding: 15px;
}
header {
width: max-content;
margin: 10px 0 0;
padding: 5px 10px;
border: 3px ridge black;
border-radius: 4px;
background: #aaa;
cursor: pointer;
}
section {
position: relative;
max-height: var(--maxH);
margin: 0;
padding: 5px 10px;
border: 3px ridge black;
border-radius: 4px;
background: #ddd;
opacity: 0;
pointer-events: none;
}
.active+section {
z-index: 1;
opacity: 1.0;
}
<header class='switch'>Read more...</header>
<section>
<p>Merchandise Morty, your only purpose in life is to buy & consume merchandise and you did it, you went into a store an actual honest to god store and you bought something, you didn't ask questions or raise ethical complaints you just looked into
the bleeding jaws of capitalism and said 'yes daddy please' and I'm so proud of you, I only wish you could have bought more, I love buying things so much Morty. Morty, you know outer space is up right? Are you kidding? I'm hoping I can get to both
of them, Rick! And there's no evidence that a Latino student did it.</p>
</section>
<header class='switch'>Read more...</header>
<section>
<p>Oh, I'm sorry Morty, are you the scientist or are you the kid who wanted to get laid? Why don't you ask the smartest people in the universe, Jerry? Oh yeah you can't. They blew up. Looossseeerrrrr. I am not putting my father in a home! He just came
back into my life, and you want to, grab him and, stuff him under a mattress like last month's Victoria's Secret?!
</p>
</section>
I'm trying to implement an Infinity scroll.
But not a window object, the target is a child div with a scroller.
Is there a way to examine the current height of a child div with JavaScript?
For example, I would like to request an event when the scroll touches at the end.
This is my template code.
<div
style="overflow-y: scroll; height:500px;"
class="scroll-content"
#scroll="onScroll"
>
Here is an example:
var listElm = document.querySelector('#infinite-list');
// Add items.
var nextItem = 1;
var loadMore = function() {
for (var i = 0; i < 10; i++) {
var item = document.createElement('li');
item.innerText = 'Item ' + nextItem++;
listElm.appendChild(item);
}
}
// Detect when scrolled to bottom.
listElm.addEventListener('scroll', function() {
if (listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight) {
loadMore();
}
});
// Initially load some items.
loadMore();
#infinite-list {
/* We need to limit the height and show a scrollbar */
width: 200px;
height: 100px;
overflow: auto;
/* Optional, only to check that it works with margin/padding */
margin: 30px;
padding: 20px;
border: 10px solid black;
}
/* Optional eye candy below: */
li {
padding: 10px;
list-style-type: none;
}
li:hover {
background: #ccc;
}
<ul id='infinite-list'>
</ul>
The following function returns, whether the user has scrolled to the bottom of a certain element:
function scrollEnd(el) {
return (el.scrollTop + el.offsetHeight >= el.scrollHeight);
}
If you add this to a scroll event listener:
element.addEventListener('scroll', () => {
if (scrollEnd(element)) {
// the user reached the end
}
})
I tried this on a textarea, should work with anything, though.
I've made a menu that reveals a drop down menu when you click or touch it. At least that's what happens when you select the word 'Menu2' but unfortunately it's not what happens when you select the words 'Menu3'.
On Menu3, for some reason my code is not recognising the selection of the anchor element and then as a consequence the id of that anchor element is not being passed to the functions which will make the sub-menu appear and disappear.
The strangest thing is that when I replace the 'else if' statement with an 'if' statement the menu under 'Menu2' will appear when I select 'Menu3'!
The thing I took from this was that the querySelectorAll method and the For loop are working. It remains a mystery me why the third menu choice can't be selected.
My question is can anyone work why the menu below 'Menu3' is not opening and closing?
The listeners in the javascript code are activated when the window is loaded.
var timeout = 500;
var closetimer = 0;
var ddmenuitem = 0;
function listen(elem, evnt, func) {
if (elem.addEventListener) { //W3C DOMS.
elem.addEventListener(evnt, func, false);
} else if (elem.attachEvent) { //IE DOM 7
var r = elem.attachEvent("on" + evnt, func);
return r;
}
}
function attachListeners() {
var selectors = document.querySelectorAll("a#a2, a#a3");
for (var i = 0; i < selectors.length; i++) {
selectors[i].addEventListener("focus", function(event) {
var id_of_clicked_element = event.target.id
});
if (id_of_clicked_element = 'a2') {
var touch_div = document.getElementById(id_of_clicked_element);
// return false;
} else if (id_of_clicked_element = 'a3') {
touch_div = document.getElementById(id_of_clicked_element);
//return false;
}
}
listen(touch_div, 'touchstart', function(event) {
// get new layer and show it
event.preventDefault();
mopen(id_of_clicked_element);
}, false);
listen(touch_div, 'mouseover', function(event) {
// get new layer and show it
mopen(id_of_clicked_element);
}, false);
listen(touch_div, 'click', function(event) {
// get new layer and show it
mopen(id_of_clicked_element);
}, false);
}
function m1View() {
var y = document.getElementById('m1');
if (y.style.visibility === 'hidden') {
y.style.visibility = 'visible';
} else {
y.style.visibility = 'hidden';
}
}
function m2View() {
var z = document.getElementById('m2');
if (z.style.visibility === 'hidden') {
z.style.visibility = 'visible';
} else {
z.style.visibility = 'hidden';
}
}
// open hidden layer
function mopen(x) { // get new layer and show it
var openmenu = x;
if (openmenu = 'a2') {
m1View();
} else if (openmenu = 'a3') {
m2View();
}
}
window.onload = attachListeners;
#ddm {
margin: 0;
padding: 0;
z-index: 30
}
#ddm li {
margin: 0;
padding: 0;
list-style: none;
float: left;
font: bold 14px arial
}
#ddm li a {
display: block;
margin: 0 0 0 0;
padding: 12px 17px;
width: 130px;
background: #CC0066;
color: #FFF;
text-align: center;
text-decoration: none
}
#ddm li a:hover {
background: #CC0066
}
#ddm div {
position: absolute;
visibility: hidden;
margin: 0;
padding: 0;
background: #EAEBD8;
border: 1px solid #5970B2
}
#ddm div a {
position: relative;
display: block;
margin: 0;
padding: 5px 10px;
width: 130px;
white-space: nowrap;
text-align: left;
text-decoration: none;
background: #EAEBD8;
color: #5C124A;
font: 13px arial;
border: 1px solid #CC0066
}
#ddm div a:hover {
background: #CC0066;
color: #FFF
}
<ul id="ddm">
<li>Menu1</li>
<li>
Menu2
<div id="m1">
Dropdown 1.1
Dropdown 1.2
Dropdown 1.3
Dropdown 1.4
Dropdown 1.5
Dropdown 1.6
</div>
</li>
<li>
Menu3
<div id="m2">
Menu4
</div>
</li>
<li>Menu5</li>
<li>Menu6</li>
</ul>
<div style="clear:both"></div>
A JSfiddle can be found here: https://jsfiddle.net/Webfeet/z9x6Ly6k/27/
Thank you for any help anyone can provide.
NewWeb
I'd suggest a couple of things. First, like Leo Li suggested, I think you may have overcomplicated this a little. For instance, you could replace your attachListeners function with something like this:
function attachListeners() {
var selectors = document.querySelectorAll("a#a2, a#a3");
for (var i = 0; i < selectors.length; i++) {
selectors[i].addEventListener('touchstart', function(event){
event.preventDefault();
mopen(event.target.id);
}, false);
selectors[i].addEventListener('mouseover', function(event){
event.preventDefault();
mopen(event.target.id);
}, false);
selectors[i].addEventListener('click', function(event){
event.preventDefault();
mopen(event.target.id);
}, false);
}
}
But, besides that, one of the biggest problems is in the mopen() function. Instead of checking the value being passed in for x, you're reassigning it. Just switch the equals signs with triple equals, like this:
if (openmenu === 'a2') {
m1View();
} else if (openmenu === 'a3') {
m2View();
}
It's still probably not quite what you're looking for but here's a fork of your JSfiddle with my changes - https://jsfiddle.net/n90ryvfd/
Hope that helps!
I need to customize a md-select so that the option list acts more like a traditional select. The options should show up below the select element instead of hovering over top of the element. Does anyone know of something like this that exists, or how to accomplish this?
This applies to Material for Angular 2+
Use disableOptionCentering option, such as:
<mat-select disableOptionCentering>
<mat-option *ngFor="let movie of movies" [value]="movie.value">
{{ movie.viewValue }}
</mat-option>
</mat-select>
Here you go - CodePen
Use the md-container-class attribute. From the docs:
Markup
<div ng-controller="AppCtrl" class="md-padding" ng-cloak="" ng-app="MyApp">
<md-input-container>
<label>Favorite Number</label>
<md-select ng-model="myModel" md-container-class="mySelect">
<md-option ng-value="myVal" ng-repeat="myVal in values">{{myVal.val}}</md-option>
</md-select>
</md-input-container>
</div>
CSS
.mySelect md-select-menu {
margin-top: 45px;
}
JS
(function () {
'use strict';
angular
.module('MyApp',['ngMaterial', 'ngMessages', 'material.svgAssetsCache'])
.controller('AppCtrl', function($scope) {
$scope.required = "required";
$scope.values = [
{val:1, des: 'One'},
{val:2, des: 'Two'}
];
});
})();
Hi maybe try something like this:
$('.dropdown-button2').dropdown({
inDuration: 300,
outDuration: 225,
constrain_width: false, // Does not change width of dropdown to that of the activator
hover: true, // Activate on hover
gutter: ($('.dropdown-content').width()*3)/2.5 + 5, // Spacing from edge
belowOrigin: false, // Displays dropdown below the button
alignment: 'left' // Displays dropdown with edge aligned to the left of button
}
);
https://jsfiddle.net/fb0c6b5b/
One post seems have the same issue: How can I make the submenu in the MaterializeCSS dropdown?
To people who has cdk-overlay (cdk-panel) with md-select.
Suppose that you use Angular 2, Typescript, Pug and Material Design Lite (MDL) in working environment.
Function which styles md-select works on click.
Javascript (TypeScript) in component
#Component({
selector: ..,
templateUrl: ..,
styleUrl: ..,
// For re-calculating on resize
host: { '(window:resize)': 'onResize()' }
})
export class MyComponent {
//Function to style md-select BEGIN
public styleSelectDropdown(event) {
var bodyRect = document.body.getBoundingClientRect();
let dropdown = document.getElementsByClassName("cdk-overlay-pane") as HTMLCollectionOf<HTMLElement>;
if (dropdown.length > 0) {
for(var i = 0; i < dropdown.length; i++) {
dropdown[i].style.top = "auto";
dropdown[i].style.bottom = "auto";
dropdown[i].style.left = "auto";
}
for(var i = 0; i < dropdown.length; i++) {
if (dropdown[i].innerHTML != "") {
var getDropdownId = dropdown[i].id;
document.getElementById(getDropdownId).classList.add('pane-styleSelectDropdown');
}
}
}
let target = event.currentTarget;
let selectLine = target.getElementsByClassName("mat-select-underline") as HTMLCollectionOf<HTMLElement>;
if (selectLine.length > 0) {
var selectLineRect = selectLine[0].getBoundingClientRect();
}
let targetPanel = target.getElementsByClassName("mat-select-content") as HTMLCollectionOf<HTMLElement>;
if (targetPanel.length > 0) {
var selectLineRect = selectLine[0].getBoundingClientRect();
}
if (dropdown.length > 0) {
for(var i = 0; i < dropdown.length; i++) {
dropdown[i].style.top = selectLineRect.top + "px";
dropdown[i].style.bottom = 0 + "px";
dropdown[i].style.left = selectLineRect.left + "px";
}
}
var windowHeight = window.outerHeight;
if (targetPanel.length > 0) {
targetPanel[0].style.maxHeight = window.outerHeight - selectLineRect.top + "px";
}
}
public onResize() {
this.styleSelectDropdown(event);
}
//Function to style md-select END
}
HTML (Pug)
.form-container
div.styleSelectDropdown((click)="styleSelectDropdown($event)")
md-select.form-group(md-container-class="my-container", id = '...',
md-option(....)
CSS which overrides Material Design Lite (MDL) css
.pane-styleSelectDropdown .mat-select-panel {
border: none;
min-width: initial !important;
box-shadow: none !important;
border-top: 2px #3f51b5 solid !important;
position: relative;
overflow: visible !important;
}
.pane-styleSelectDropdown .mat-select-panel::before {
content: "";
position: absolute;
top: -17px;
right: 0;
display: block;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #3f51b5;
margin: 0 4px;
z-index: 1000;
}
.pane-styleSelectDropdown .mat-select-content {
border: 1px solid #e0e0e0;
box-shadow: 0 2px 1px #e0e0e0;
position: relative;
}
#media screen and (max-height: 568px) {
.pane-styleSelectDropdown .mat-select-content {
overflow-y: scroll;
}
}
.pane-styleSelectDropdown.cdk-overlay-pane {
top: 0;
bottom: 0;
left: 0;
overflow: hidden;
padding-bottom: 5px;
z-index: 10000;
}
.pane-styleSelectDropdown .mat-select-panel .mat-option.mat-selected:not(.mat-option-multiple),
.pane-styleSelectDropdown .mat-option:focus:not(.mat-option-disabled),
.pane-styleSelectDropdown .mat-option:hover:not(.mat-option-disabled) {
background: #fff !important;
}
.pane-styleSelectDropdown .mat-option {
line-height: 36px;
height: 36px;
font-size: 14px;
}
So this turned out to be something I had to do with Javascript and setTimeout, as ugly as the solution is. You can't effectively do this with CSS only as material design uses javascript positioning of the drop down. As a result I had to attach a function to the popup opening inside there I set a 200ms timeout that calculates the desired position of the drop down on the screen and moves it there. I also attached a function in the controller to a window resize event so it will move with a resize.
Ultimately you have to use a timeout to get material design time to do it's javascript based move of the popover and then move it yourself. I also uses a trick to hide it while the moving is taking place so the user doesn't see the jump. That's the description of what I had to do just in case someone else attempts similar.
You must override "top" of the CSS class ".md-select-menu-container".
To do so, you have to use the attribute md-container-class like:
md-container-class="dropDown"
inside the md-select tag. then you just have to create a custom css for the class declared:
.md-select-menu-container.dropDown{
top: 147px !important;
}
!important is the key here! top is the value you want... in this case 147px.
here's a CodePen
MY code below lets me take an HTML selection and provide a more user friendly image clickable version. When an image is clicked, it selects the proper value in a hidden selection filed in the DOM.
I just need help in adjusting my code below to work on a selection that is on the page multiple times.
If it is on the page 10 times, I need to run this code 10 times.
I am not sure how to target each one separately though
Preview
HTML Selection gets turned into clickable Images like this below. The JavaScript reads the HTML Selection filed already on the page and clones it and replaces each value with images. It then hides the original selection field. When an image is clicked on, and appears selected, it is using JavaScript to select that value in the real hidden selector as well!...
Live Demo
http://jsfiddle.net/jasondavis/ov1a4apc/
JavaScript
jQuery(document).ready(function($) {
if ($('#page_template').length) {
//$('#page_template').hide().after('<div id="page_template_visual"></div>');
$('#page_template').after('<div id="page_template_visual"></div>');
$('#page_template option').each(function() {
var classname = $(this).val().replace('.php', '');
if ($(this).is("[selected]")) {
classname = classname + ' selected';
}
$('#page_template_visual').append('<small></small>' + $(this).text() + '');
});
if (!$('#page_template option[selected]').length) {
$('#page_template_visual a:first-child').addClass('selected');
}
$('#page_template_visual a').on('click', function() {
$('#page_template_visual a').removeClass('selected');
theValue = $(this).addClass('selected').attr('href');
$("#page_template").val(theValue).attr('selected', true);
return false;
});
}
});
HTML Select
<select name="page_template" id="page_template" selected="selected">
<option value="default">Default Template</option>
<option value="custom-archives.php">Archives Template</option>
<option value="wpi/pdf_quote_bold.php">Bold</option>
<option value="SOONcontact.php">Contact</option>
<option value="page-invoice.php">Invoice</option>
<option value="wpi/pdf_quote_modern.php">Modern</option>
<option value="wpi/pdf_quote.php">Traditional</option>
</select>
CSS
#page_template{
/* display: none; */
}
#page_template_visual {
margin: 0 -10px;
}
#page_template_visual a {
display: inline-block;
width: 129px;
height: 100px;
margin: 0 5px 5px;
text-align: center;
color: #333333;
font-weight: bold;
text-decoration: none;
background: url('http://i.imgur.com/7S9yzTY.png') no-repeat left top;
}
#page_template_visual a small {
height: 64px;
width: 119px;
display: inline-block;
margin: 5px 5px 5px 5px;
}
/* You can define images for the options here based on the classnames */
#page_template_visual a.template-both-sidebar-page {background-position: right -100px;}
#page_template_visual a.template-left-sidebar-page {background-position: right top;}
#page_template_visual a.template-right-sidebar-page {background-position: left -100px;}
#page_template_visual a.selected {
color: #559a08;
text-shadow: 1px 1px 0px #fff;
}
#page_template_visual a.selected small {
background: rgba(106,189,15,0.1) url('http://i.imgur.com/P0E1jmh.png') no-repeat center;
}
First, you need to change the page_template and page_template_visual ids to classes (in the HTML, JavaScript & CSS).
Then loop through all the elements with the page_template class, like this:
jQuery(document).ready(function($) {
$('.page_template').each(function() {
var $select = $(this);
// Keep a reference to this element so you can use it below.
var $visual = $('<div class="page_template_visual"></div>');
$select.after($visual);
$select.find('option').each(function() {
var $option = $(this);
var classname = $option.val().replace('.php', '');
if ($option.is("[selected]")) {
classname = classname + ' selected';
}
$visual.append('<small></small>' + $option.text() + '');
});
if (!$select.find('option[selected]').length) {
$visual.find('a:first-child').addClass('selected');
}
// The next line could have been:
// $visual.find('a').on('click', function() {
// But instead it uses event delegation, so only one
// event handler is registered, instead of one for each <a>.
$visual.on('click', 'a', function() {
$visual.find('a').removeClass('selected');
var value = $(this).addClass('selected').attr('href');
$select.val(value);
return false; // You don't need this, unless you really don't want the click event to bubble up.
});
});
});
jsfiddle