Custom selectbox (jScrollPane) werkt niet op iOS
Ik maak op mijn website veel gebruik van customised selectboxen via de jquery-plugin "jScrollPane" van Kelvin Luck (zie http://jscrollpane.kelvinluck.com/).
Dit werkt allemaal prima op de desktop. Echter, op de iPad (en iPhone) werken deze customized selectboxen niet. Meer precies: op de iPad (en iPhone) worden de selectboxen wel gecustomized weergegeven, maar wanneer er op gedrukt wordt met je vinger dan opent de selectbox (selectList) niet.
Een voorbeeld op mijn site van deze selectbox(en) die wel werkt op desktop en niet op de iPad of iPhone:
http://www.devoetbalscout.nl/club.php?clubID=1&menu=statistieken
Hier zijn drie selectboxen: de seizoens-selectbox, competitie-selectbox en het onderwerp-selectbox.
Ik heb zelf al een hoop gezocht op internet en geprobeerd, maar krijg het niet werkend op de iPad. Wat het allemaal extra lastig maakt is dat ik de pagina niet kan inspecteren op de iPad.
Weet iemand wat hier verkeerd gaat op mijn website? En hoe ik dit op kan lossen?
Met vriendelijke groet,
Jo
Gewijzigd op 06/02/2018 11:58:54 door Jo Immanuel
http://jscrollpane.kelvinluck.com/known_issues.html
Quote:
In Webkit browsers CSS must be included before Javascript
For jScrollPane to work correctly in Webkit based browsers (e.g. Safari, Chrome, iOS and Android) then the CSS must be included above your javascript includes. Otherwise jScrollPane can't correctly measure the size of the item you are applying jScrollPane to. See all of the example or theme pages for a reference as to the correct ordering of items in your <head>.
For jScrollPane to work correctly in Webkit based browsers (e.g. Safari, Chrome, iOS and Android) then the CSS must be included above your javascript includes. Otherwise jScrollPane can't correctly measure the size of the item you are applying jScrollPane to. See all of the example or theme pages for a reference as to the correct ordering of items in your <head>.
Ik heb geen idee of je dit ook al geprobeerd hebt?
Gewijzigd op 06/02/2018 12:09:37 door - Ariën -
Volgens mij wel:
ik heb op mijn pagina eerst in de <head>:
<link rel="stylesheet" type="text/css" href="customselectbox/jquery.jscrollpane.css" />
<link rel="stylesheet" type="text/css" href="customselectbox/customSelectBox.css" rel="NOFOLLOW"/>
<link rel="stylesheet" type="text/css" href="Templates/CSS/jquery.mCustomScrollbar.css"/>
Dan de <body>, en aan het eind van de body de <scripts>:
<script src="customselectbox/jScrollPane.js"></script>
<script src="customselectbox/jquery.mousewheel.js"></script>
<script src="customselectbox/SelectBox.js"></script>
Toevoeging op 06/02/2018 12:22:54:
Toevoeging:
De content waar de selectboxen in staan worden wel geladen met een ajax-post-request. Dus eerst wordt de linkerkant van de pagina geladen en op het einde worden dan (afhankelijk van de meegegeven variabelen in de URL) het middengedeelte en de rechterkant geladen (waar hier de selectboxen in staan).
Misschien dat dit het probleem veroorzaakt?
MIHTool Basic - Web Debugger van Gaolu Li
https://itunes.apple.com/nl/app/mihtool-basic-web-debugger/id584739126?mt=8
Als voorbeeld neem ik de selectbox op de volgende pagina van mijn website: http://www.devoetbalscout.nl/competitiezoeken.php
Dit is wat er gebeurd:
A: Desktop:
Als ik de geparsde html-code van de selectbox genaamd "zoekmanier" inspecteer op de desktop, dan krijg ik initieel het volgende:
Code (php)
1
2
3
4
5
2
3
4
5
<div class="customSelect custom" id="select-zoekmanier" style="width: 280px; z-index: 100;">
<select id="zoekmanier" class="custom"> ... met hierin de options & css: display="none" ... </select>
<div class="selectValueWrap"> ... met selected value ... </div>
<div class="selectList"> ... de lijst met options ... </div>
</div>
<select id="zoekmanier" class="custom"> ... met hierin de options & css: display="none" ... </select>
<div class="selectValueWrap"> ... met selected value ... </div>
<div class="selectList"> ... de lijst met options ... </div>
</div>
Na klikken op de selectbox wordt de html-code:
Code (php)
1
2
3
4
5
2
3
4
5
<div class="customSelect custom select-open" id="select-zoekmanier" style="width: 280px; z-index: 101;">
<select id="zoekmanier" class="custom"> ... met hierin de options & css: display="none" ... </select>
<div class="selectValueWrap"> ... met selected value ... </div>
<div class="selectList"> ... de lijst met options ... </div>
</div>
<select id="zoekmanier" class="custom"> ... met hierin de options & css: display="none" ... </select>
<div class="selectValueWrap"> ... met selected value ... </div>
<div class="selectList"> ... de lijst met options ... </div>
</div>
Kortom: de class "select-open" wordt toegevoegd aan de buitenste div en de z-index van deze div wordt verhoogd van 100 naar 101. Gevolg is dat de selectList zichtbaar wordt.
B: iPad:
Als ik de geparsde html-code van de selectbox genaamd "zoekmanier" inspecteer op de iPad, dan krijg ik initieel het volgende:
Code (php)
1
2
3
4
5
2
3
4
5
<div class="customSelect custom use-default" id="select-zoekmanier" style="width: 280px; z-index: 100;">
<select id="zoekmanier" class="custom"> ... met hierin de options & css: display="none" ... </select>
<div class="selectValueWrap"> ... met selected value ... </div>
<div class="selectList"> ... de lijst met options ... </div>
</div>
<select id="zoekmanier" class="custom"> ... met hierin de options & css: display="none" ... </select>
<div class="selectValueWrap"> ... met selected value ... </div>
<div class="selectList"> ... de lijst met options ... </div>
</div>
Na drukken op de selectbox verandert de html-code op de iPad niet en de class "select-open" wordt ook niet toegevoegd. De selectList is dus ook niet zichtbaar. Het enige dat er gebeurd is dat de selectbox heel kort grijs wordt en daarna weer terug verandert.
Iemand een idee wat hier mis gaat en hoe ik dit kan oplossen?
Toevoeging op 06/02/2018 20:08:01:
Extra info:
De HTML-code van de selectbox:
Code (php)
1
2
3
4
5
2
3
4
5
<select id="zoekmanier" class="custom">
<option value="normaal" default="default" selected="selected">normaal zoeken</option>
<option value="normaal">normaal zoeken</option>
<option value="uitgebreid">uitgebreid zoeken</option>
</select>
<option value="normaal" default="default" selected="selected">normaal zoeken</option>
<option value="normaal">normaal zoeken</option>
<option value="uitgebreid">uitgebreid zoeken</option>
</select>
De customselect wordt 'geactiveerd' met volgende code:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
$(document).ready(function(){
$("select#zoekmanier.custom").each(function() {
var sb = new SelectBox({
selectbox: $(this),
height: 290,
width: 280,
changeCallback: function(val) {
var manier = val;
.. etc ...
}
});
});
});
$("select#zoekmanier.custom").each(function() {
var sb = new SelectBox({
selectbox: $(this),
height: 290,
width: 280,
changeCallback: function(val) {
var manier = val;
.. etc ...
}
});
});
});
Verder denk ik onderstaand bestandje van belang is (en vraag ik me af of ik scrollpane.js eigenlijk wel gebruik... ) aangezien daar de "select-open" class wordt toegevoegd.
(zie http://www.roblaplaca.com/docs/custom-selectbox/ )
"SelectBox.js"
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
/**
* @classDescription Custom selectbox with the option to use jScrollPane
* for a custom scrollbar. Hides the original selectbox off
* screen so that it will still get picked up as a form element.
*
* @version 1.1.0
*
* @author Rob LaPlaca - [email protected]
* @date 04/05/2010
* @lastUpdate 03/09/2014
* @dependency jScrollPane.js optional
* jquery.mousewheel.js optional
*
* @param {DOMElement} options.selectbox the selectbox that is being customized, REQUIRED (default undefined)
* @param {Boolean} options.customScrollbar whether or not to use jScrollPane to restyle system scrollbar (default false)
* @param {Number} options.zIndex The default z-index of the selectbox. (default 100)
* @param {Function} options.changeCallback Function that gets executed on change of the selectbox (default empty function)
* @param {Function} options.manager Optional reference to a class that manages all instances of the selectbox
* @param {Object} options.scrollOptions jScrollPane options, refer to jscrollpane documentation for possible options
* http://www.kelvinluck.com/assets/jquery/jScrollPane/scripts/jScrollPane.js
*/
(function($){
window.SelectBoxManager = function(options){
var sbs = [],
self = this;
$(document).click(function(e) {
if($(e.target).parents(".customSelect").size() === 0) {
self.close();
}
});
this.add = function(sb) {
sbs.push(sb);
};
this.close = function() {
$(sbs).each(function() {
this.close();
});
};
};
var sb_manager = new SelectBoxManager();
window.SelectBox = function(options){
var self = this,
cfg = $.extend(true, {
manager: sb_manager,
customScrollbar: true,
zIndex: 100,
changeCallback: function(val) { },
truncate: function(str) {return str;},
scrollOptions: {}
}, options);
var $customSelect, $selectedValue, $selectValueWrap, $selectList, $dl, $options,
FOCUSED_CLASS = "focused",
SELECTED_CLASS = "selected",
SELECT_OPEN_CLASS = "select-open",
DISABLED_CLASS = "disabled",
HOVERED_CLASS = "hovered",
_useDefaultBehavior = false,
_isOpen = false,
_isEnabled = true,
_isFocused = false,
_selectedValue = "";
/**
* @constructor
*/
function init() {
// TODO: don't use userAgent matching to detect defaulting to device specific behavior
_useDefaultBehavior = navigator.userAgent.match(/iPad|iPhone|Android|IEMobile|BlackBerry/i) ? true : false;
if( _useDefaultBehavior ) {
cfg.selectbox.addClass("use-default");
}
var selectId = "",
selectedClass = cfg.selectbox.attr("class");
if(typeof cfg.selectbox.attr("id") !== "undefined") {
selectId = 'id="select-'+cfg.selectbox.attr("id")+'"';
}
cfg.selectbox.wrap('<div class="customSelect '+selectedClass+'" '+selectId+' />');
$customSelect = cfg.selectbox.parents(".customSelect");
$options = cfg.selectbox.find("option");
var selectListHTML = ['<div class="selectList"><div class="selectListOuterWrap"><div class="selectListInnerWrap"><div class="selectListTop"></div><dl>'];
selectListHTML.push(_renderOptions());
selectListHTML.push('</dl><div class="selectListBottom"></div></div></div></div>');
$customSelect.append('<div class="selectValueWrap"><div class="selectedValue">'+_selectedValue+'</div> <span class="caret"><img src="images/Icoontjes/selectarrowdown.jpg" class="arrowselectbox"></span></div>' + selectListHTML.join(""));
$dl = $customSelect.find("dl");
$selectedValue = $customSelect.find(".selectedValue");
$selectValueWrap = $customSelect.find(".selectValueWrap");
$selectList = $customSelect.find(".selectList");
$customSelect.width(cfg.width);
$dl.width(cfg.width - 2);
_bindEvents();
sb_manager.add(self);
}
/**
* @private
*/
function _bindEvents() {
$selectValueWrap.click(function() {
if(_isOpen) {
cfg.selectbox.focus();
self.close();
} else if(_isEnabled) {
if( _useDefaultBehavior ) {
cfg.selectbox.focus();
} else {
self.open();
//NIEUW:
$(".itm-0").remove();
//if ( $(".itm-0").parents.parents("#main-nav").length == 1 ) {
// // YES, the child element is inside the parent
//} else {
// // NO, it is not inside
//}
}
}
});
// delegated events
$dl.click(function(e) {
var $target = $(e.target);
if($target.is("dd") || $target.parents("dd")) {
if(e.target.tagName.toLowerCase() != "dd") {
$target = $target.parents("dd");
}
if(!$target.hasClass(DISABLED_CLASS) && $target.get(0)) {
self.jumpToIndex($target.get(0).className.split(" ")[0].split("-")[1]);
self.close();
if( ! _useDefaultBehavior ) {
cfg.selectbox.focus();
}
}
}
});
cfg.selectbox.focus(function(e) {
_isFocused = true;
$customSelect.addClass(FOCUSED_CLASS);
}).blur(function(e){
_isFocused = false;
$customSelect.removeClass(FOCUSED_CLASS);
});
if( _useDefaultBehavior ) {
cfg.selectbox.change(function(e) {
_updateValue( $(this).find("option:selected").html() );
});
}
cfg.selectbox.keyup(function(e){
self.close();
$options.each(function(i, itm){
if(itm.selected) {
self.jumpToIndex(i);
return false;
}
});
});
_bindHover();
}
/**
* @private
*/
function _bindHover() {
var $dds = $(".customSelect dd");
$dds.off("mouseover");
$dds.off("mouseout");
$dds.on("mouseover", function(e) {
var $target = $(e.target);
if(e.target.tagName.toLowerCase() != "dd") {
$target = $target.parents("dd");
}
$target.addClass(HOVERED_CLASS);
});
$dds.on("mouseout", function(e) {
var $target = $(e.target);
if(e.target.tagName.toLowerCase() != "dd") {
$target = $target.parents("dd");
}
$target.removeClass(HOVERED_CLASS);
});
}
/**
* @param {String} val
* @private
*/
function _updateValue(val) {
if($selectedValue.html() != val) {
$selectedValue.html(_truncate(val));
cfg.changeCallback(cfg.selectbox.val());
}
}
/**
* @returns {String} HTML generated after processing options
* @private
*/
function _renderOptions() {
var optionHTML = [];
$options.each(function(i, itm) {
var $this = $(this),
optgroup = $this.parents('optgroup'),
addlOptClasses = "",
iconMarkup = "";
// render optgroups if present in original select
if (optgroup.length > 0 && $this.prev().length === 0){
optionHTML.push('<dt>'+optgroup.attr('label')+'</dt>');
}
// if option has a classname add that to custom select as well
if(itm.className !== "") {
$(itm.className.split(" ")).each(function() {
iconMarkup += '<span class="' + this + '"></span>';
});
}
// add selected class to whatever option is currently active
if(itm.selected && !itm.disabled) {
_selectedValue = iconMarkup + _truncate($(itm).html());
addlOptClasses = " " + SELECTED_CLASS;
}
// Check for disabled options
if( itm.disabled ) {
addlOptClasses += " " + DISABLED_CLASS;
}
optionHTML.push('<dd class="itm-'+i+' ' + addlOptClasses + '">' + iconMarkup + itm.innerHTML + '</dd>');
});
if($selectedValue && $selectedValue.get(0) !== null) {
$selectedValue.html(_selectedValue);
}
return optionHTML.join("");
}
/**
* @private
*/
function _setupScrollbar() {
$dl.css("height","auto");
if(cfg.height && $dl.height() > cfg.height) {
$dl.css("height", cfg.height);
if(cfg.customScrollbar) {
self.scrollpane = $dl.jScrollPane($.extend({
contentWidth: 200
}, cfg.scrollOptions));
} else {
$dl.addClass("defaultScrollbar");
}
} else {
$dl.css({overflow: "hidden"});
}
}
/**
* @param {String} str
* @returns truncated display string
* @private
*/
function _truncate(str) {
var arr = str.split("</span>");
var valToTrunc = arr[arr.length - 1];
arr[arr.length - 1] = "";
var spans = arr.join("</SPAN>");
return spans + cfg.truncate(valToTrunc);
}
/**
* @public
*/
this.sync = function() {
$options = cfg.selectbox.find("option");
$dl.html(_renderOptions());
_bindHover();
_setupScrollbar();
};
/**
* @public
*/
this.disable = function() {
_isEnabled = false;
$customSelect.addClass(DISABLED_CLASS);
cfg.selectbox.attr("disabled", "disabled");
};
/**
* @public
*/
this.enable = function() {
_isEnabled = true;
$customSelect.removeClass(DISABLED_CLASS);
cfg.selectbox.removeAttr("disabled");
};
/**
* @public
*/
this.close = function() {
$customSelect.removeClass(SELECT_OPEN_CLASS);
$customSelect.css({"z-index": cfg.zIndex});
_isOpen = false;
};
/**
* @public
*/
this.open = function() {
_setupScrollbar();
if(cfg.manager) {
cfg.manager.close();
}
$customSelect.addClass(SELECT_OPEN_CLASS);
if(self.scrollpane) {
self.scrollpane.data('jsp').scrollToY($customSelect.find(".selected").position().top);
}
$customSelect.css({"z-index": cfg.zIndex + 1});
_isOpen = true;
};
/**
* @param {Number} index
* @public
*/
this.jumpToIndex = function(index) {
cfg.selectbox.get(0).selectedIndex = index;
$customSelect.find(".selected").removeClass(SELECTED_CLASS);
$customSelect.find(".itm-" + index).addClass(SELECTED_CLASS);
_updateValue($customSelect.find(".itm-" + index).html());
};
/**
* @param {String} value
* @returns {Number} index of the value
* @public
*/
this.jumpToValue = function(value) {
var index = -1;
$options.each(function(i) {
if (this.innerHTML==value){
index = i;
return false;
}
});
if (index!=-1){
self.jumpToIndex(index);
}
return index;
};
init();
};
})(jQuery);
Toevoeging op 07/02/2018 10:49:25:
Dit issue kan gesloten worden...
Gisterennacht een hoop gezocht en nu blijkt dat bij deze versie (SelectBox.js v1.1) van Rob LaPlaca het niet openen van selectboxen op iOS een known problem is.
(zie: https://github.com/roblaplaca/jQuery-Custom-Selectbox/issues/12 )
Rob LaPlaca heeft hier zelf het issue geclassificeerd als major bug en er is sinds 2014 geen nieuwere versie uitgekomen. Opvallend is dat bij versie 1.0 de selectboxen wel werken op de iPad (dit kun je testen door de volgende pagina te openen op de iPad: http://www.roblaplaca.com/docs/custom-selectbox/ .
Dus ik heb gezocht naar versie 1.0 en een beetje een mix document gemaakt van 1.0 en 1.1 en nnu werken de selectboxen zowel op de desktop als op de iPad.
Mocht iemand met hetzelfde probleem zitten, dit is de code van mijn mix-bestandje:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
/**
* @classDescription Custom selectbox with the option to use jScrollPane
* for a custom scrollbar. Hides the original selectbox off
* screen so that it will still get picked up as a form element.
*
* @version 1.0.0 - let op: aangepast met enkele elementen van v1.1.0
*
* @author Rob LaPlaca - [email protected] - let op: aangepast met enkele elementen van v1.1.0
* @date 04/05/2010
* @lastUpdate 07/02/2018
* @dependency jScrollPane.js optional
* jquery.mousewheel.js optional
*
* @param {DOMElement} options.selectbox the selectbox that is being customized, REQUIRED (default undefined)
* @param {Boolean} options.customScrollbar whether or not to use jScrollPane to restyle system scrollbar (default false)
* @param {Number} options.zIndex The default z-index of the selectbox. (default 100)
* @param {Function} options.changeCallback Function that gets executed on change of the selectbox (default empty function)
* @param {Function} options.manager Optional reference to a class that manages all instances of the selectbox
* @param {Object} options.scrollOptions jScrollPane options, refer to jscrollpane documentation for possible options
* http://www.kelvinluck.com/assets/jquery/jScrollPane/scripts/jScrollPane.js
*/
(function($){
/*
// v1.0:
var undefined;
$.SelectBoxManager = function(options){
var sbs = [],
self = this;
$(document).click(function(e) {
if($(e.target).parents(".customSelect").get(0) == null) {
self.close();
}
});
this.add = function(sb) {
sbs.push(sb);
};
this.close = function() {
$(sbs).each(function() {
this.close();
});
};
};
*/
/*
// v1.verder:
window.SelectBoxManager = function(options){
var sbs = [],
self = this;
$(document).click(function(e) {
if($(e.target).parents(".customSelect").size() === 0) {
self.close();
}
});
this.add = function(sb) {
sbs.push(sb);
};
this.close = function() {
$(sbs).each(function() {
this.close();
});
};
};
*/
// /*
// mix:
window.SelectBoxManager = function(options){
var sbs = [],
self = this;
$(document).click(function(e) {
if($(e.target).parents(".customSelect").get(0) == null) {
self.close();
}
});
this.add = function(sb) {
sbs.push(sb);
};
this.close = function() {
$(sbs).each(function() {
this.close();
});
};
};
// */
/* // v1.0:
$.SelectBox = function(options){
var self = this,
cfg = $.extend(true, {
customScrollbar: false,
zIndex: 100,
changeCallback: function(val) { },
truncate: function(str) {return str;},
scrollOptions: {}
}, options);
var $customSelect, $selectedValue, $selectValueWrap, $selectList, $dl, $options,
_isOpen = false,
_isEnabled = true,
_isFocused = false,
_selectedValue = "";
*/
/*
// v1.verder:
var sb_manager = new SelectBoxManager();
window.SelectBox = function(options){
var self = this,
cfg = $.extend(true, {
manager: sb_manager,
customScrollbar: true,
zIndex: 100,
changeCallback: function(val) { },
truncate: function(str) {return str;},
scrollOptions: {}
}, options);
var $customSelect, $selectedValue, $selectValueWrap, $selectList, $dl, $options,
FOCUSED_CLASS = "focused",
SELECTED_CLASS = "selected",
SELECT_OPEN_CLASS = "select-open",
DISABLED_CLASS = "disabled",
HOVERED_CLASS = "hovered",
_useDefaultBehavior = false,
_isOpen = false,
_isEnabled = true,
_isFocused = false,
_selectedValue = "";
*/
// /*
// mix:
var sb_manager = new SelectBoxManager();
window.SelectBox = function(options){
var self = this,
cfg = $.extend(true, {
customScrollbar: false,
zIndex: 100,
changeCallback: function(val) { },
truncate: function(str) {return str;},
scrollOptions: {}
}, options);
var $customSelect, $selectedValue, $selectValueWrap, $selectList, $dl, $options,
_isOpen = false,
_isEnabled = true,
_isFocused = false,
_selectedValue = "";
// */
// versie 1.0:
function init(){
var selectId = "";
if(cfg.selectbox.attr("id") != "") {
selectId = 'id="select-'+cfg.selectbox.attr("id")+'"';
}
cfg.selectbox.wrap('<div class="customSelect" '+selectId+' />');
$customSelect = cfg.selectbox.parents(".customSelect");
$options = cfg.selectbox.find("option");
var selectListHTML = ['<div class="selectList"><div class="selectListOuterWrap"><div class="selectListInnerWrap"><div class="selectListTop"></div><dl>'];
selectListHTML.push(_renderOptions());
selectListHTML.push('</dl><div class="selectListBottom"></div></div></div></div>');
$customSelect.append('<div class="selectValueWrap"><div class="selectedValue">'+_selectedValue+'</div></div>' + selectListHTML.join(""));
$dl = $customSelect.find("dl");
$selectedValue = $customSelect.find(".selectedValue");
$selectValueWrap = $customSelect.find(".selectValueWrap");
$selectList = $customSelect.find(".selectList");
$customSelect.width(cfg.width);
$dl.width(cfg.width);
_bindEvents();
}
// versie 1.0:
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
* start:private
* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
function _bindEvents() {
$selectValueWrap.click(function() {
if(_isOpen) {
cfg.selectbox.focus();
self.close();
} else if(_isEnabled) {
self.open();
}
});
// delegated events
$dl.click(function(e) {
var $target = $(e.target);
if($target.is("dd") || $target.parents("dd")) {
if(e.target.tagName.toLowerCase() != "dd") {
$target = $target.parents("dd");
}
if($target.get(0)) {
self.jumpToIndex($target.get(0).className.split(" ")[0].split("-")[1]);
self.close();
cfg.selectbox.focus();
}
}
});
cfg.selectbox.focus(function(e){
_isFocused = true;
$customSelect.addClass("focused");
}).blur(function(e){
_isFocused = false;
$customSelect.removeClass("focused");
});
cfg.selectbox.keyup(function(e){
self.close();
$options.each(function(i, itm){
if(itm.selected) {
self.jumpToIndex(i);
return false;
}
});
});
_bindHover();
}
/*
// versie 1.0:
function _bindHover() {
var $dds = $(".customSelect dd");
$dds.die("mouseover");
$dds.die("mouseout");
$dds.live("mouseover", function(e) {
var $target = $(e.target);
if(e.target.tagName.toLowerCase() != "dd") {
$target = $target.parents("dd");
}
$target.addClass("hovered");
});
$dds.live("mouseout", function(e) {
var $target = $(e.target);
if(e.target.tagName.toLowerCase() != "dd") {
$target = $target.parents("dd");
}
$target.removeClass("hovered");
});
}
*/
// versie 1.1:
function _bindHover() {
var $dds = $(".customSelect dd");
$dds.off("mouseover");
$dds.off("mouseout");
$dds.on("mouseover", function(e) {
var $target = $(e.target);
if(e.target.tagName.toLowerCase() != "dd") {
$target = $target.parents("dd");
}
$target.addClass(HOVERED_CLASS);
});
$dds.on("mouseout", function(e) {
var $target = $(e.target);
if(e.target.tagName.toLowerCase() != "dd") {
$target = $target.parents("dd");
}
$target.removeClass(HOVERED_CLASS);
});
}
// versie 1.0:
function _updateValue(val) {
if($selectedValue.html() != val) {
$selectedValue.html(_truncate(val));
cfg.changeCallback(cfg.selectbox.val());
}
}
// versie 1.0:
function _renderOptions() {
var optionHTML = [];
$options.each(function(i, itm) {
var $this = $(this);
var optgroup = $this.parents('optgroup');
if (optgroup.length > 0 && $this.prev().length === 0){
optionHTML.push('<dt>'+optgroup.attr('label')+'</dt>');
}
var iconMarkup = "";
if(itm.className != "") {
$(itm.className.split(" ")).each(function() {
iconMarkup += '<span class="' + this + '"></span>';
});
}
if(itm.selected) {
_selectedValue = iconMarkup + _truncate($(itm).html());
optionHTML.push('<dd class="itm-'+i+' selected">' + iconMarkup + itm.innerHTML + '</dd>');
} else {
optionHTML.push('<dd class="itm-'+i+'">' + iconMarkup + itm.innerHTML + '</dd>');
}
});
if($selectedValue && $selectedValue.get(0) != null) {
$selectedValue.html(_selectedValue);
}
return optionHTML.join("");
}
// versie 1.0:
function _setupScrollbar() {
$dl.css("height","auto");
if(cfg.height && $dl.height() > cfg.height) {
$dl.css("height", cfg.height);
if(cfg.customScrollbar) {
self.scrollpane = $dl.jScrollPane($.extend({tabIndex: -1, scrollbarMargin: 0}, cfg.scrollOptions));
} else {
$dl.addClass("defaultScrollbar");
}
} else {
$dl.css({overflow: "hidden"});
}
}
// versie 1.0:
function _truncate(str) {
var arr = str.split("</span>");
var valToTrunc = arr[arr.length - 1];
arr[arr.length - 1] = "";
var spans = arr.join("</SPAN>");
return spans + cfg.truncate(valToTrunc);
}
// end:private
// versie 1.0:
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
* start:public
* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
this.sync = function() {
$options = cfg.selectbox.find("option");
$dl.html(_renderOptions());
$dl.jScrollPaneRemove();
_bindHover();
_setupScrollbar();
};
this.disable = function() {
_isEnabled = false;
$customSelect.addClass("disabled");
cfg.selectbox.attr("disabled", "disabled");
};
this.enable = function() {
_isEnabled = true;
$customSelect.removeClass("disabled");
cfg.selectbox.removeAttr("disabled");
};
this.close = function() {
$customSelect.removeClass("select-open");
$customSelect.css({"z-index": cfg.zIndex});
_isOpen = false;
};
this.open = function() {
_setupScrollbar();
if(cfg.manager) {
cfg.manager.close();
}
$customSelect.addClass("select-open");
if(self.scrollpane) {
self.scrollpane[0].scrollTo($customSelect.find(".selected").position().top);
}
$customSelect.css({"z-index": cfg.zIndex + 1});
_isOpen = true;
};
this.jumpToIndex = function(index) {
cfg.selectbox.get(0).selectedIndex = index;
$customSelect.find(".selected").removeClass("selected");
$customSelect.find(".itm-" + index).addClass("selected");
_updateValue($customSelect.find(".itm-" + index).html());
};
this.jumpToValue = function(value) {
var index = -1;
$options.each(function(i){
if (this.innerHTML==value){
index = i;
return false;
}
});
if (index!=-1){
self.jumpToIndex(index);
}
return index;
};
// end:public
init();
};
})(jQuery);
Gewijzigd op 07/02/2018 10:50:15 door Jo Immanuel