game/js/wSelect.js
2022-06-07 00:30:34 +03:00

383 lines
14 KiB
JavaScript

(function($) {
/*****************************************************************
* Select
*****************************************************************/
function Select(el, options) {
this.$el = $(el);
this.id = Math.random();
this.options = options;
this.multiple = this.$el.prop('multiple');
this.activeOpt = null;
this.widthSet = false;
this.generate();
}
Select.prototype = {
generate: function() {
if (!this.$select) {
var _self = this;
this.$select = $('<div class="wSelect"><div class="wSelect-arrow"></div></div>');
this.$optionsHolder = $('<div class="wSelect-options-holder"></div>');
this.$options = $('<div class="wSelect-options"></div>');
// ie 7 fix to get proper zIndex on select dropdowns
if(!$.support.placeholder) {
this.$select.css('zIndex', 100 - this.$el.index());
}
var click = function(e) {
e.stopPropagation();
$('select').each(function() {
var wSelect = $(this).data('wSelect');
if (wSelect && wSelect.id !== _self.id) {
if (!wSelect.multiple) { wSelect.$optionsHolder.hide(); }
wSelect.onBlur();
}
});
if (!_self.multiple) { _self.onClick(e); }
_self.$el.focus();
};
if (this.multiple) {
this.$select.addClass('wSelect-multiple');
this.$optionsHolder.click(click);
}
else {
this.$selected = $('<div class="wSelect-selected"></div>');
this.$select.append(this.$selected);
this.$select.click(click);
this.$optionsHolder.click(function(e) {
e.stopPropagation();
_self.$el.focus();
});
}
this.$select.hover(
function(){ _self.onFocus('hover'); },
function(){ _self.onBlur('hover'); }
);
this.$el.addClass('wSelect-el')
.change(function() { _self.change(); })
.focus(function() { _self.onFocus(); })
.keydown(function(e) { _self.keydown(e); })
.keyup(function(e) { _self.keyup(e); });
$(document).click(function() {
if (!_self.multiple) { _self.$optionsHolder.hide(); }
_self.onBlur();
});
this.widthSet = this.$select.width() > 0;
this.setTheme(this.options.theme);
this.setSize(this.options.size);
this.reset();
this.$optionsHolder.append(this.$options);
this.$select.append(this.$optionsHolder);
this.$el.after(this.$select);//.hide();
}
return this.$select;
},
reset: function() {
var _self = this;
this.$options.children().remove();
this.$el.children().each(function() {
var option = new Option(this, _self);
$.data(this, 'wSelect-option', option);
_self.$options.append(option.generate());
});
this.$options.children().removeClass('wSelect-option-last').last().addClass('wSelect-option-last');
this.setSize(this.options.size);
},
change: function() {
this.$options.children().removeClass('wSelect-option-selected wSelect-option-active');
this.$el.children(':selected').each(function() {
$(this).data('wSelect-option').select();
});
},
keydown: function(e) {
// tab
if (e.keyCode === 9) {
this.$optionsHolder.hide();
this.onBlur();
}
},
keyup: function(e) {
// enter
if (e.keyCode === 13) {
this.$optionsHolder.hide();
}
// left, up, right, down
else if (e.keyCode >= 37 && e.keyCode <= 40) {
this.change();
var $option = this.$options.find('.wSelect-option-selected:last'),
scrollTop = this.$options.scrollTop(),
top = $option.position().top + scrollTop,
optionsHeight = this.$options.height(),
optionHeight = $option.outerHeight(true);
if (top - scrollTop < 0) {
this.$options.scrollTop(top);
}
else if (top + optionHeight - scrollTop > optionsHeight) {
this.$options.scrollTop(top - optionsHeight + optionHeight);
}
}
},
onClick: function(e) {
// find best fit for dropdowns (top or bottom)
if (!this.$optionsHolder.is(':visible')) {
var top = this.$select.offset().top - $(window).scrollTop(),
optionsHeight = this.$optionsHolder.outerHeight(),
topDiff = top - optionsHeight,
botDiff = $(window).height() - (top + this.$select.outerHeight() + optionsHeight + 5), // 5 is just for some bottom screen padding
newTop = (botDiff > 0 || botDiff > topDiff) ? this.$select.height() : -optionsHeight;
this.$optionsHolder.css('top', newTop);
}
this.$optionsHolder.toggle();
},
onFocus: function(className) {
className = className || 'active';
if (this.options.highlight) {
this.$select.addClass(`wSelect-${className}`);
}
},
onBlur: function(className) {
className = className || 'active';
if (this.options.highlight) {
this.$select.removeClass(`wSelect-${className}`);
}
},
setTheme: function(theme) {
this.$select.attr('class', this.$select.attr('class').replace(/wSelect-theme-.+\s|wSelect-theme-.+$/, ''));
this.$select.addClass(`wSelect-theme-${theme}`);
},
setSize: function(size) {
var $option = this.$options.children(':first').clone().css({position:'absolute', left:-10000}),
numOptions = this.$el.children().length,
height;
$('body').append($option);
height = $option.outerHeight(true);
$option.remove();
if (!this.multiple && size > numOptions) {
size = numOptions;
}
this.$options.height(height * size - 1);
}
};
/*****************************************************************
* Option
*****************************************************************/
function Option(el, wSelect) {
this.$el = $(el);
this.wSelect = wSelect;
}
Option.prototype = {
generate: function() {
var _self = this;
if (!this.$option) {
var icon = this.$el.attr('data-icon');
this.$option = $('<div class="wSelect-option"></div>');
this.$value = $('<div class="wSelect-option-value"></div>');
this.$option.append(this.$value);
if (typeof icon === 'string') {
this.$value.addClass('wSelect-option-icon');
this.$value.css('backgroundImage', `url(${icon})`);
}
}
if (this.$el.prop('selected')) this.select();
if (this.$el.prop('disabled')) {
this.$option.addClass('wSelect-option-disabled');
}
else {
this.$option.removeClass('wSelect-option-disabled');
this.$option.unbind('click').click(function(e){ _self.onClick(e); });
}
this.$value.html(this.$el.html()); // in case html has changed we always set it here
this.setWidth();
return this.$option;
},
select: function() {
if (!this.wSelect.activeOpt) {
this.wSelect.activeOpt = this;
}
if (!this.wSelect.multiple) {
var icon = this.$el.attr('data-icon');
if (typeof icon === 'string') {
this.wSelect.$selected.addClass('wSelect-option-icon');
this.wSelect.$selected.css('backgroundImage', `url(${icon})`);
}
else {
this.wSelect.$selected.removeClass('wSelect-option-icon');
this.wSelect.$selected.css('backgroundImage', '');
}
//if(!this.wSelect.focus) { this.wSelect.$optionsHolder.hide(); }
this.wSelect.$selected.html(this.$el.html());
}
this.$option.addClass('wSelect-option-selected');
},
onClick: function(e) {
var selVal = null;
if (this.wSelect.multiple && (e.ctrlKey || e.shiftKey) ) {
if (e.ctrlKey || !this.wSelect.activeOpt) {
selVal = this.wSelect.$el.val() || [];
var optVal = this.$el.val(),
arrayPos = $.inArray(optVal, selVal);
if (arrayPos === -1) {
selVal.push(this.$el.val());
this.wSelect.activeOpt = this; // only set active when "selecting"
}
else selVal.splice(arrayPos, 1);
}
// don't set active here as the shift+click only highlights from active option
else if (e.shiftKey) {
var indexActive = this.wSelect.activeOpt.$el.index(),
indexCurrent = this.$el.index(),
indexStart = 0,
indexEnd = 0,
$option = null;
if (indexCurrent > indexActive) {
indexStart = indexActive;
indexEnd = indexCurrent;
} else {
indexStart = indexCurrent;
indexEnd = indexActive;
}
selVal = [];
for (var i=indexStart; i<=indexEnd; i++) {
$option = this.wSelect.$el.children(`:eq(${i})`);
if ($option.is(':not(:disabled)')) {
selVal.push($option.val());
}
}
}
}
else {
selVal = this.$el.val();
this.wSelect.$optionsHolder.hide();
this.wSelect.activeOpt = this;
}
this.wSelect.$el.val(selVal).change();
},
// help us set the proper widths based on given values (this way so we can add options on the fly one at a time)
setWidth: function() {
if (this.wSelect.multiple || this.wSelect.widthSet) { return true; }
this.$option.hide().appendTo('body');
var optionWidth = this.$option.width();
if (optionWidth > this.wSelect.$select.width()) {
this.wSelect.$select.width(optionWidth);
}
this.$option.detach().show();
}
};
/*****************************************************************
* fn.wSelect
*****************************************************************/
$.support.placeholder = 'placeholder' in document.createElement('input');
$.fn.wSelect = function(options, value) {
if (typeof options === 'string') {
var values = [];
var elements = this.each(function() {
var wSelect = $(this).data('wSelect');
if (wSelect) {
var func = (value ? 'set' : 'get') + options.charAt(0).toUpperCase() + options.substring(1).toLowerCase();
if (wSelect[options]) {
wSelect[options].apply(wSelect, [value]);
} else if (value) {
if (wSelect[func]) { wSelect[func].apply(wSelect, [value]); }
if (wSelect.options[options]) { wSelect.options[options] = value; }
} else {
if(wSelect[func]) { values.push(wSelect[func].apply(wSelect, [value])); }
else if (wSelect.options[options]) { values.push(wSelect.options[options]); }
else { values.push(null); }
}
}
});
if (values.length === 1) { return values[0]; }
else if (values.length > 0) { return values; }
else { return elements; }
}
options = $.extend({}, $.fn.wSelect.defaults, options);
function get(el) {
var wSelect = $.data(el, 'wSelect');
if (!wSelect) {
var _options = jQuery.extend(true, {}, options);
_options.size = $(el).prop('size') || _options.size;
wSelect = new Select(el, _options);
$.data(el, 'wSelect', wSelect);
}
return wSelect;
}
return this.each(function() { get(this); });
};
$.fn.wSelect.defaults = {
theme: 'classic', // theme
size: '4', // default number of options to display (overwrite with `size` attr on `select` element)
highlight: true // highlight fields when selected
};
})(jQuery);