Hacked By AnonymousFox
/*!
* DropKick 2.0.2
*
* Highly customizable <select> lists
* https://github.com/robdel12/DropKick
*
*/
(function( $, window, document, undefined ) {
window.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( navigator.userAgent );
window.isIframe = (window.parent != window.self && location.host === parent.location.host);
var
// Cache of DK Objects
dkCache = {},
dkIndex = 0,
// The Dropkick Object
Dropkick = function( sel, opts ) {
var i;
// Prevent DK on mobile
if ( window.isMobile && !opts.mobile ) {
return false;
}
// Safety if `Dropkick` is called without `new`
if ( this === window ) {
return new Dropkick( sel, opts );
}
if ( typeof sel === "string" && sel[0] === "#" ) {
sel = document.getElementById( sel.substr( 1 ) );
}
// Check if select has already been DK'd and return the DK Object
if ( i = sel.getAttribute( "data-dkcacheid" ) ) {
_.extend( dkCache[ i ].data.settings, opts );
return dkCache[ i ];
}
if ( sel.nodeName === "SELECT" ) {
return this.init( sel, opts );
}
},
noop = function() {},
// DK default options
defaults = {
// Called once after the DK element is inserted into the DOM
initialize: noop,
// Called every time the select changes value
change: noop,
// Called every time the DK element is opened
open: noop,
// Called every time the DK element is closed
close: noop,
// Search method; "strict", "partial", or "fuzzy"
search: "strict"
},
// Common Utilities
_ = {
hasClass: function( elem, classname ) {
var reg = new RegExp( "(^|\\s+)" + classname + "(\\s+|$)" );
return elem && reg.test( elem.className );
},
addClass: function( elem, classname ) {
if( elem && !_.hasClass( elem, classname ) ) {
elem.className += " " + classname;
}
},
removeClass: function( elem, classname ) {
var reg = new RegExp( "(^|\\s+)" + classname + "(\\s+|$)" );
elem && ( elem.className = elem.className.replace( reg, " " ) );
},
toggleClass: function( elem, classname ) {
var fn = _.hasClass( elem, classname ) ? "remove" : "add";
_[ fn + "Class" ]( elem, classname );
},
// Shallow object extend
extend: function( obj ) {
Array.prototype.slice.call( arguments, 1 ).forEach( function( source ) {
if ( source ) for ( var prop in source ) obj[ prop ] = source[ prop ];
});
return obj;
},
// Returns the top and left offset of an element
offset: function( elem ) {
var box = elem.getBoundingClientRect() || { top: 0, left: 0 },
docElem = document.documentElement;
return {
top: box.top + window.pageYOffset - docElem.clientTop,
left: box.left + window.pageXOffset - docElem.clientLeft
};
},
// Returns the top and left position of an element relative to an ancestor
position: function( elem, relative ) {
var pos = { top: 0, left: 0 };
while ( elem !== relative ) {
pos.top += elem.offsetTop;
pos.left += elem.offsetLeft;
elem = elem.parentNode;
}
return pos;
},
// Returns the closest ancestor element of the child or false if not found
closest: function( child, ancestor ) {
while ( child ) {
if ( child === ancestor ) return child;
child = child.parentNode;
}
return false;
},
// Creates a DOM node with the specified attributes
create: function( name, attrs ) {
var a, node = document.createElement( name );
if ( !attrs ) attrs = {};
for ( a in attrs ) {
if ( attrs.hasOwnProperty( a ) ) {
if ( a == "innerHTML" ) {
node.innerHTML = attrs[ a ];
} else {
node.setAttribute( a, attrs[ a ] );
}
}
}
return node;
}
};
// Extends the DK objects's Prototype
Dropkick.prototype = {
// Emulate some of HTMLSelectElement's methods
/**
* Adds an element to the select
* @param {Node} elem HTMLOptionElement
* @param {Node/Integer} before HTMLOptionElement/Index of Element
*/
add: function( elem, before ) {
var text, option, i;
if ( typeof elem === "string" ) {
text = elem;
elem = document.createElement("option");
elem.text = text;
}
if ( elem.nodeName === "OPTION" ) {
option = _.create( "li", {
"class": "dk-option",
"data-value": elem.value,
"innerHTML": elem.text,
"role": "option",
"aria-selected": "false",
"id": "dk" + this.data.cacheID + "-" + ( elem.id || elem.value.replace( " ", "-" ) )
});
_.addClass( option, elem.className );
this.length += 1;
if ( elem.disabled ) {
_.addClass( option, "dk-option-disabled" );
option.setAttribute( "aria-disabled", "true" );
}
this.data.select.add( elem, before );
if ( typeof before === "number" ) {
before = this.item( before );
}
if ( this.options.indexOf( before ) > -1 ) {
before.parentNode.insertBefore( option, before );
} else {
this.data.elem.lastChild.appendChild( option );
}
option.addEventListener( "mouseover", this );
i = this.options.indexOf( before );
this.options.splice( i, 0, option );
if ( elem.selected ) {
this.select( i );
}
}
},
/**
* Selects an option in the lists at the desired index
* (negative numbers select from the end)
* @param {Integer} index Index of element (positive or negative)
* @return {Node} The DK option from the list, or null if not found
*/
item: function( index ) {
index = index < 0 ? this.options.length + index : index;
return this.options[ index ] || null;
},
/**
* Removes an element at the given index
* @param {Integer} index Index of element (positive or negative)
*/
remove: function( index ) {
var dkOption = this.item( index );
dkOption.parentNode.removeChild( dkOption );
this.options.splice( index, 1 );
this.data.select.remove( index );
this.select( this.data.select.selectedIndex );
this.length -= 1;
},
/**
* Initializes the DK Object
* @param {Node} sel [description]
* @param {Object} opts Options to override defaults
* @return {Object} The DK Object
*/
init: function( sel, opts ) {
var i,
dk = Dropkick.build( sel, "dk" + dkIndex );
// Set some data on the DK Object
this.data = {};
this.data.select = sel;
this.data.elem = dk.elem;
this.data.settings = _.extend({}, defaults, opts );
// Emulate some of HTMLSelectElement's properties
this.disabled = sel.disabled;
this.form = sel.form;
this.length = sel.length;
this.multiple = sel.multiple;
this.options = dk.options.slice( 0 );
this.selectedIndex = sel.selectedIndex;
this.selectedOptions = dk.selected.slice( 0 );
this.value = sel.value;
// Insert the DK element before the original select
sel.parentNode.insertBefore( this.data.elem, sel );
// Bind events
this.data.elem.addEventListener( "click", this );
this.data.elem.addEventListener( "keydown", this );
this.data.elem.addEventListener( "keypress", this );
if ( this.form ) {
this.form.addEventListener( "reset", this );
}
if ( !this.multiple ) {
for ( i = 0; i < this.options.length; i++ ) {
this.options[ i ].addEventListener( "mouseover", this );
}
}
if ( dkIndex === 0 ) {
document.addEventListener( "click", Dropkick.onDocClick );
if ( window.isIframe ){
parent.document.addEventListener( "click", Dropkick.onDocClick );
}
}
// Add the DK Object to the cache
this.data.cacheID = dkIndex;
sel.setAttribute( "data-dkCacheId", this.data.cacheID );
dkCache[ this.data.cacheID ] = this;
// Call the optional initialize function
this.data.settings.initialize.call( this );
// Increment the index
dkIndex += 1;
return this;
},
/**
* Closes the DK dropdown
*/
close: function() {
var dk = this.data.elem;
if ( !this.isOpen || this.multiple ) {
return false;
}
for ( i = 0; i < this.options.length; i++ ) {
_.removeClass( this.options[ i ], "dk-option-highlight" );
}
dk.lastChild.setAttribute( "aria-expanded", "false" );
_.removeClass( dk.lastChild, "dk-select-options-highlight" );
_.removeClass( dk, "dk-select-open-(up|down)" );
this.isOpen = false;
this.data.settings.close.call( this );
},
/**
* Opens the DK dropdown
*/
open: function() {
var dropHeight, above, below,
dk = this.data.elem,
dkOptsList = dk.lastChild,
dkTop = _.offset( dk ).top - window.scrollY,
dkBottom = window.innerHeight - ( dkTop + dk.offsetHeight );
if ( this.isOpen || this.multiple ) return false;
dkOptsList.style.display = "block";
dropHeight = dkOptsList.offsetHeight;
dkOptsList.style.display = "";
above = dkTop > dropHeight;
below = dkBottom > dropHeight;
direction = above && !below ? "-up" : "-down";
this.isOpen = true;
_.addClass( dk, "dk-select-open" + direction );
dkOptsList.setAttribute( "aria-expanded", "true" );
this._scrollTo( this.options.length - 1 );
this._scrollTo( this.selectedIndex );
this.data.settings.open.call( this );
},
/**
* Disables or enables an option or the entire Dropkick
* @param {Node/Integer} elem The element or index to disable
* @param {Boolean} disabled Value of disabled
*/
disable: function( elem, disabled ) {
var disabledClass = "dk-option-disabled";
if ( arguments.length == 0 || typeof elem === "boolean" ) {
disabled = elem === undefined ? true : false;
elem = this.data.elem;
disabledClass = "dk-select-disabled";
this.disabled = disabled;
}
if ( disabled == undefined ) {
disabled = true;
}
if ( typeof elem === "number" ) {
elem = this.item( elem );
}
_[ disabled ? "addClass" : "removeClass" ]( elem, disabledClass );
},
/**
* Selects an option from the list
* @param {Node/Integer/String} elem The element, index, or value to select
* @param {Boolean} disabled Selects disabled options
* @return {Node} The selected element
*/
select: function( elem, disabled ) {
var i, index, option, combobox,
select = this.data.select;
if ( typeof elem === "number" ) {
elem = this.item( elem );
}
if ( typeof elem === "string" ) {
for ( i = 0; i < this.length; i++ ) {
if ( this.options[ i ].getAttribute( "data-value" ) == elem ) {
elem = this.options[ i ];
} else {
return false;
}
}
}
if ( !disabled && _.hasClass( elem, "dk-option-disabled" ) ) return false;
if ( _.hasClass( elem, "dk-option" ) ) {
index = this.options.indexOf( elem );
option = select.options[ index ];
if ( this.multiple ) {
_.toggleClass( elem, "dk-option-selected" );
option.selected = !option.selected;
if ( _.hasClass( elem, "dk-option-selected" ) ) {
elem.setAttribute( "aria-selected", "true" );
this.selectedOptions.push( elem );
} else {
elem.setAttribute( "aria-selected", "false" );
index = this.selectedOptions.indexOf( elem );
this.selectedOptions.splice( index, 1 );
}
} else {
combobox = this.data.elem.firstChild;
if ( this.selectedOptions.length ) {
_.removeClass( this.selectedOptions[0], "dk-option-selected" );
this.selectedOptions[0].setAttribute( "aria-selected", "false" );
}
_.addClass( elem, "dk-option-selected" );
elem.setAttribute( "aria-selected", "true" );
combobox.setAttribute( "aria-activedescendant", elem.id );
combobox.innerHTML = option.text;
this.selectedOptions[0] = elem;
option.selected = true;
}
this.selectedIndex = select.selectedIndex;
this.value = select.value;
this.data.settings.change.call( this );
return elem;
}
},
/**
* Selects a single option from the list
* @param {Node/Integer} elem The element or index to select
* @param {Boolean} disabled Selects disabled options
* @return {Node} The selected element
*/
selectOne: function( elem, disabled ) {
this.reset( true );
this._scrollTo( elem );
return this.select( elem, disabled );
},
/**
* Finds all options who's text matches a pattern (strict, partial, or fuzzy)
* @param {String} string The string to search for
* @param {Integer} mode How to search; "strict", "partial", or "fuzzy"
* @return {Array/Boolean} An Array of matched elements
*/
search: function( pattern, mode ) {
var i, tokens, str, tIndex, sIndex, cScore, tScore, reg,
options = this.data.select.options,
matches = [];
if ( !pattern ) return this.options;
// Fix Mode
mode = mode ? mode.toLowerCase() : "strict";
mode = mode == "fuzzy" ? 2 : mode == "partial" ? 1 : 0;
reg = new RegExp( ( mode ? "" : "^" ) + pattern, "i" );
for ( i = 0; i < options.length; i++ ) {
str = options[ i ].text.toLowerCase();
// Fuzzy
if ( mode == 2 ) {
tokens = pattern.toLowerCase().split("");
tIndex = sIndex = cScore = tScore = 0;
while ( sIndex < str.length ) {
if ( str[ sIndex ] === tokens[ tIndex ] ) {
cScore += 1 + cScore;
tIndex++;
} else {
cScore = 0;
}
tScore += cScore;
sIndex++;
}
if ( tIndex == tokens.length ) {
matches.push({ e: this.options[ i ], s: tScore, i: i });
}
// Partial or Strict (Default)
} else {
reg.test( str ) && matches.push( this.options[ i ] );
}
}
// Sort fuzzy results
if ( mode == 2 ) {
matches = matches.sort( function ( a, b ) {
return ( b.s - a.s ) || a.i - b.i;
}).reduce( function ( p, o ) {
p[ p.length ] = o.e;
return p;
}, [] );
}
return matches;
},
/**
* Resets the DK and select element
* @param {Boolean} clear Defaults to first option if True
*/
reset: function( clear ) {
var i,
select = this.data.select;
this.selectedOptions.length = 0;
for ( i = 0; i < select.options.length; i++ ) {
select.options[ i ].selected = false;
_.removeClass( this.options[ i ], "dk-option-selected" );
this.options[ i ].setAttribute( "aria-selected", "false" );
if ( !clear && select.options[ i ].defaultSelected ) {
this.select( i, true );
}
}
if ( !this.selectedOptions.length && !this.multiple ) {
this.select( 0, true );
}
},
/**
* Rebuilds the DK Object
* (use if HTMLSelectElement has changed)
*/
refresh: function() {
this.dispose().init( this.data.select, this.data.settings );
},
/**
* Removes the DK Object from the cache and the element from the DOM
*/
dispose: function() {
delete dkCache[ this.data.cachID ];
this.data.elem.parentNode.removeChild( this.data.elem );
this.data.select.removeAttribute( "data-dkCacheId" );
return this;
},
// Private Methods
handleEvent: function( event ) {
if ( this.disabled ) return;
switch ( event.type ) {
case "click":
this._delegate( event );
break;
case "keydown":
this._keyHandler( event );
break;
case "keypress":
this._searchOptions( event );
break;
case "mouseover":
this._highlight( event );
break;
case "reset":
this.reset();
break;
}
},
_delegate: function( event ) {
var selection, index, firstIndex, lastIndex,
target = event.target;
if ( _.hasClass( target, "dk-option-disabled" ) ) {
return false;
}
if ( !this.multiple ) {
this[ this.isOpen ? "close" : "open" ]();
if ( _.hasClass( target, "dk-option" ) ) this.select( target );
} else {
if ( _.hasClass( target, "dk-option" ) ) {
selection = window.getSelection();
if ( selection.type == "Range" ) selection.collapseToStart();
if ( event.shiftKey ) {
firstIndex = this.options.indexOf( this.selectedOptions[0] );
lastIndex = this.options.indexOf( this.selectedOptions[ this.selectedOptions.length - 1 ] );
index = this.options.indexOf( target );
if ( index > firstIndex && index < lastIndex ) index = firstIndex;
if ( index > lastIndex && lastIndex > firstIndex ) lastIndex = firstIndex;
this.reset( true );
if ( lastIndex > index ) {
while ( index < lastIndex + 1 ) this.select( index++ );
} else {
while ( index > lastIndex - 1 ) this.select( index-- );
}
} else if ( event.ctrlKey || event.metaKey ) {
this.select( target );
} else {
this.reset( true );
this.select( target );
}
}
}
},
_highlight: function( event ) {
var i, option = event.target;
if ( !this.multiple ) {
for ( i = 0; i < this.options.length; i++ ) {
_.removeClass( this.options[ i ], "dk-option-highlight" );
}
_.addClass( this.data.elem.lastChild, "dk-select-options-highlight" );
_.addClass( option, "dk-option-highlight" );
}
},
_keyHandler: function( event ) {
var lastSelected,
selected = this.selectedOptions,
options = this.options,
i = 1,
keys = {
tab: 9,
enter: 13,
esc: 27,
space: 32,
up: 38,
down: 40
};
switch ( event.keyCode ) {
case keys.up:
i = -1;
// deliberate fallthrough
case keys.down:
event.preventDefault();
lastSelected = selected[ selected.length - 1 ];
i = options.indexOf( lastSelected ) + i;
if ( i > options.length - 1 ) {
i = options.length - 1;
} else if ( i < 0 ) {
i = 0;
}
if ( !this.data.select.options[ i ].disabled ) {
this.reset( true );
this.select( i );
this._scrollTo( i );
}
break;
case keys.space:
if ( !this.isOpen ) {
event.preventDefault();
this.open();
break;
}
// deliberate fallthrough
case keys.tab:
case keys.enter:
for ( i = 0; i < options.length; i++ ) {
if ( _.hasClass( options[ i ], "dk-option-highlight" ) ) {
this.select( i );
}
}
// deliberate fallthrough
case keys.esc:
if ( this.isOpen ) {
event.preventDefault();
this.close();
}
break;
}
},
_searchOptions: function( event ) {
var results,
self = this,
keyChar = String.fromCharCode( event.keyCode || event.which ),
waitToReset = function() {
if ( self.data.searchTimeout ) {
clearTimeout( self.data.searchTimeout );
}
self.data.searchTimeout = setTimeout(function() {
self.data.searchString = "";
}, 1000 );
};
if ( this.data.searchString === undefined ) {
this.data.searchString = "";
}
waitToReset();
this.data.searchString += keyChar;
results = this.search( this.data.searchString, this.data.settings.search );
if ( results.length ) {
if ( !_.hasClass( results[0], "dk-option-disabled" ) ) {
this.selectOne( results[0] );
}
}
},
_scrollTo: function( option ) {
var optPos, optTop, optBottom,
dkOpts = this.data.elem.lastChild;
if ( !this.isOpen && !this.multiple ) {
return false;
}
if ( typeof option === "number" ) {
option = this.item( option );
}
optPos = _.position( option, dkOpts ).top;
optTop = optPos - dkOpts.scrollTop;
optBottom = optTop + option.offsetHeight;
if ( optBottom > dkOpts.offsetHeight ) {
optPos += option.offsetHeight;
dkOpts.scrollTop = optPos - dkOpts.offsetHeight;
} else if ( optTop < 0 ) {
dkOpts.scrollTop = optPos;
}
}
};
// Static Methods
/**
* Builds the Dropkick element from a select element
* @param {Node} sel The HTMLSelectElement
* @return {Object} An object containing the new DK element and it's options
*/
Dropkick.build = function( sel, idpre ) {
var optList, i,
options = [],
ret = {
elem: null,
options: [],
selected: []
},
addOption = function ( node ) {
var option, optgroup, optgroupList, i,
children = [];
switch ( node.nodeName ) {
case "OPTION":
option = _.create( "li", {
"class": "dk-option",
"data-value": node.value,
"innerHTML": node.text,
"role": "option",
"aria-selected": "false",
"id": idpre + "-" + ( node.id || node.value.replace( " ", "-" ) )
});
_.addClass( option, node.className );
if ( node.disabled ) {
_.addClass( option, "dk-option-disabled" );
option.setAttribute( "aria-disabled", "true" );
}
if ( node.selected ) {
_.addClass( option, "dk-option-selected" );
option.setAttribute( "aria-selected", "true" );
ret.selected.push( option );
}
ret.options.push( this.appendChild( option ) );
break;
case "OPTGROUP":
optgroup = _.create( "li", { "class": "dk-optgroup" });
if ( node.label ) {
optgroup.appendChild( _.create( "div", {
"class": "dk-optgroup-label",
"innerHTML": node.label
}));
}
optgroupList = _.create( "ul", {
"class": "dk-optgroup-options",
});
for ( i = node.children.length; i--; children.unshift( node.children[ i ] ) );
children.forEach( addOption, optgroupList );
this.appendChild( optgroup ).appendChild( optgroupList );
break;
}
};
ret.elem = _.create( "div", {
"class": "dk-select" + ( sel.multiple ? "-multi" : "" )
});
optList = _.create( "ul", {
"class": "dk-select-options",
"id": idpre + "-listbox",
"role": "listbox"
});
sel.disabled && _.addClass( ret.elem, "dk-select-disabled" );
ret.elem.id = idpre + ( sel.id ? "-" + sel.id : "" );
_.addClass( ret.elem, sel.className );
if ( !sel.multiple ) {
ret.elem.appendChild( _.create( "div", {
"class": "dk-selected",
"tabindex": sel.tabindex || 0,
"innerHTML": sel.options[ sel.selectedIndex ].text,
"id": idpre + "-combobox",
"aria-live": "assertive",
"aria-owns": optList.id,
"role": "combobox"
}));
optList.setAttribute( "aria-expanded", "false" );
} else {
ret.elem.setAttribute( "tabindex", sel.getAttribute( "tabindex" ) || "0" );
optList.setAttribute( "aria-multiselectable", "true" );
}
for ( i = sel.children.length; i--; options.unshift( sel.children[ i ] ) );
options.forEach( addOption, ret.elem.appendChild( optList ) );
return ret;
};
/**
* Focus DK Element when corresponding label is clicked; close all other DK's
*/
Dropkick.onDocClick = function( event ) {
var t, tId, i;
if ( t = document.getElementById( event.target.htmlFor ) ) {
if ( ( tId = t.getAttribute( "data-dkcacheid" ) ) !== null ) {
dkCache[ tId ].data.elem.focus();
}
}
for ( i in dkCache ) {
if ( !_.closest( event.target, dkCache[ i ].data.elem ) ) {
dkCache[ i ].disabled || dkCache[ i ].close();
}
}
};
/**
* Without this part taken from Dropkick v1, we have issues with scrolling element list in live editor in fancybox in chrome (but not in Firefox).
*/
// Prevents window scroll when scrolling through dk_options, simulating native behaviour
var wheelSupport = 'onwheel' in window ? 'wheel' : // Modern browsers support "wheel"
'onmousewheel' in document ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
"MouseScrollEvent" in window ? 'DOMMouseScroll MozMousePixelScroll' : // legacy non-standard event for older Firefox
false // lacks support
;
wheelSupport && $(document).on(wheelSupport, '.dk_options_inner', function(event) {
var delta = event.originalEvent.wheelDelta || -event.originalEvent.deltaY || -event.originalEvent.detail; // Gets scroll ammount
if (msie) { this.scrollTop -= Math.round(delta/10); return false; } // Normalize IE behaviour
return (delta > 0 && this.scrollTop <= 0 ) || (delta < 0 && this.scrollTop >= this.scrollHeight - this.offsetHeight ) ? false : true; // Finally cancels page scroll when nedded
});
// Expose Dropkick Globally
window.Dropkick = Dropkick;
})( opjq, window, document );
opjq.fn.dropkick = function () {
var args = Array.prototype.slice.call( arguments );
return opjq( this ).each(function() {
if ( !args[0] || typeof args[0] === 'object' ) {
new Dropkick( this, args[0] || {} );
} else if ( typeof args[0] === 'string' ) {
Dropkick.prototype[ args[0] ].apply( new Dropkick( this ), args.slice( 1 ) );
}
});
};
Hacked By AnonymousFox1.0, Coded By AnonymousFox