1 2; /* Start:"a:4:{s:4:"full";s:26:"/js/jcf.js?151707261813686";s:6:"source";s:10:"/js/jcf.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/ 3/*! 4 * JavaScript Custom Forms 5 * 6 * Copyright 2014-2016 PSD2HTML - http://psd2html.com/jcf 7 * Released under the MIT license (LICENSE.txt) 8 * 9 * Version: 1.2.3 10 */ 11;(function(root, factory) { 12 'use strict'; 13 if (typeof define === 'function' && define.amd) { 14 define(['jquery'], factory); 15 } else if (typeof exports === 'object') { 16 module.exports = factory(require('jquery')); 17 } else { 18 root.jcf = factory(jQuery); 19 } 20}(this, function($) { 21 'use strict'; 22 23 // define version 24 var version = '1.2.3'; 25 26 // private variables 27 var customInstances = []; 28 29 // default global options 30 var commonOptions = { 31 optionsKey: 'jcf', 32 dataKey: 'jcf-instance', 33 rtlClass: 'jcf-rtl', 34 focusClass: 'jcf-focus', 35 pressedClass: 'jcf-pressed', 36 disabledClass: 'jcf-disabled', 37 hiddenClass: 'jcf-hidden', 38 resetAppearanceClass: 'jcf-reset-appearance', 39 unselectableClass: 'jcf-unselectable' 40 }; 41 42 // detect device type 43 var isTouchDevice = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch, 44 isWinPhoneDevice = /Windows Phone/.test(navigator.userAgent); 45 commonOptions.isMobileDevice = !!(isTouchDevice || isWinPhoneDevice); 46 47 // create global stylesheet if custom forms are used 48 var createStyleSheet = function() { 49 var styleTag = $('<style>').appendTo('head'), 50 styleSheet = styleTag.prop('sheet') || styleTag.prop('styleSheet'); 51 52 // crossbrowser style handling 53 var addCSSRule = function(selector, rules, index) { 54 index = index || 0; 55 if (styleSheet.insertRule) { 56 styleSheet.insertRule(selector + '{' + rules + '}', index); 57 } else { 58 styleSheet.addRule(selector, rules, index); 59 } 60 }; 61 62 // add special rules 63 addCSSRule('.' + commonOptions.hiddenClass, 'position:absolute !important;left:-9999px !important;height:1px !important;width:1px !important;margin:0 !important;border-width:0 !important;-webkit-appearance:none;-moz-appearance:none;appearance:none'); 64 addCSSRule('.' + commonOptions.rtlClass + ' .' + commonOptions.hiddenClass, 'right:-9999px !important; left: auto !important'); 65 addCSSRule('.' + commonOptions.unselectableClass, '-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: rgba(0,0,0,0);'); 66 addCSSRule('.' + commonOptions.resetAppearanceClass, 'background: none; border: none; -webkit-appearance: none; appearance: none; opacity: 0; filter: alpha(opacity=0);'); 67 68 // detect rtl pages 69 var html = $('html'), body = $('body'); 70 if (html.css('direction') === 'rtl' || body.css('direction') === 'rtl') { 71 html.addClass(commonOptions.rtlClass); 72 } 73 74 // handle form reset event 75 html.on('reset', function() { 76 setTimeout(function() { 77 api.refreshAll(); 78 }, 0); 79 }); 80 81 // mark stylesheet as created 82 commonOptions.styleSheetCreated = true; 83 }; 84 85 // simplified pointer events handler 86 (function() { 87 var pointerEventsSupported = navigator.pointerEnabled || navigator.msPointerEnabled, 88 touchEventsSupported = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch, 89 eventList, eventMap = {}, eventPrefix = 'jcf-'; 90 91 // detect events to attach 92 if (pointerEventsSupported) { 93 eventList = { 94 pointerover: navigator.pointerEnabled ? 'pointerover' : 'MSPointerOver', 95 pointerdown: navigator.pointerEnabled ? 'pointerdown' : 'MSPointerDown', 96 pointermove: navigator.pointerEnabled ? 'pointermove' : 'MSPointerMove', 97 pointerup: navigator.pointerEnabled ? 'pointerup' : 'MSPointerUp' 98 }; 99 } else { 100 eventList = { 101 pointerover: 'mouseover', 102 pointerdown: 'mousedown' + (touchEventsSupported ? ' touchstart' : ''), 103 pointermove: 'mousemove' + (touchEventsSupported ? ' touchmove' : ''), 104 pointerup: 'mouseup' + (touchEventsSupported ? ' touchend' : '') 105 }; 106 } 107 108 // create event map 109 $.each(eventList, function(targetEventName, fakeEventList) { 110 $.each(fakeEventList.split(' '), function(index, fakeEventName) { 111 eventMap[fakeEventName] = targetEventName; 112 }); 113 }); 114 115 // jQuery event hooks 116 $.each(eventList, function(eventName, eventHandlers) { 117 eventHandlers = eventHandlers.split(' '); 118 $.event.special[eventPrefix + eventName] = { 119 setup: function() { 120 var self = this; 121 $.each(eventHandlers, function(index, fallbackEvent) { 122 if (self.addEventListener) self.addEventListener(fallbackEvent, fixEvent, false); 123 else self['on' + fallbackEvent] = fixEvent; 124 }); 125 }, 126 teardown: function() { 127 var self = this; 128 $.each(eventHandlers, function(index, fallbackEvent) { 129 if (self.addEventListener) self.removeEventListener(fallbackEvent, fixEvent, false); 130 else self['on' + fallbackEvent] = null; 131 }); 132 } 133 }; 134 }); 135 136 // check that mouse event are not simulated by mobile browsers 137 var lastTouch = null; 138 var mouseEventSimulated = function(e) { 139 var dx = Math.abs(e.pageX - lastTouch.x), 140 dy = Math.abs(e.pageY - lastTouch.y), 141 rangeDistance = 25; 142 143 if (dx <= rangeDistance && dy <= rangeDistance) { 144 return true; 145 } 146 }; 147 148 // normalize event 149 var fixEvent = function(e) { 150 var origEvent = e || window.event, 151 touchEventData = null, 152 targetEventName = eventMap[origEvent.type]; 153 154 e = $.event.fix(origEvent); 155 e.type = eventPrefix + targetEventName; 156 157 if (origEvent.pointerType) { 158 switch (origEvent.pointerType) { 159 case 2: e.pointerType = 'touch'; break; 160 case 3: e.pointerType = 'pen'; break; 161 case 4: e.pointerType = 'mouse'; break; 162 default: e.pointerType = origEvent.pointerType; 163 } 164 } else { 165 e.pointerType = origEvent.type.substr(0, 5); // "mouse" or "touch" word length 166 } 167 168 if (!e.pageX && !e.pageY) { 169 touchEventData = origEvent.changedTouches ? origEvent.changedTouches[0] : origEvent; 170 e.pageX = touchEventData.pageX; 171 e.pageY = touchEventData.pageY; 172 } 173 174 if (origEvent.type === 'touchend') { 175 lastTouch = { x: e.pageX, y: e.pageY }; 176 } 177 if (e.pointerType === 'mouse' && lastTouch && mouseEventSimulated(e)) { 178 return; 179 } else { 180 return ($.event.dispatch || $.event.handle).call(this, e); 181 } 182 }; 183 }()); 184 185 // custom mousewheel/trackpad handler 186 (function() { 187 var wheelEvents = ('onwheel' in document || document.documentMode >= 9 ? 'wheel' : 'mousewheel DOMMouseScroll').split(' '), 188 shimEventName = 'jcf-mousewheel'; 189 190 $.event.special[shimEventName] = { 191 setup: function() { 192 var self = this; 193 $.each(wheelEvents, function(index, fallbackEvent) { 194 if (self.addEventListener) self.addEventListener(fallbackEvent, fixEvent, false); 195 else self['on' + fallbackEvent] = fixEvent; 196 }); 197 }, 198 teardown: function() { 199 var self = this; 200 $.each(wheelEvents, function(index, fallbackEvent) { 201 if (self.addEventListener) self.removeEventListener(fallbackEvent, fixEvent, false); 202 else self['on' + fallbackEvent] = null; 203 }); 204 } 205 }; 206 207 var fixEvent = function(e) { 208 var origEvent = e || window.event; 209 e = $.event.fix(origEvent); 210 e.type = shimEventName; 211 212 // old wheel events handler 213 if ('detail' in origEvent) { e.deltaY = -origEvent.detail; } 214 if ('wheelDelta' in origEvent) { e.deltaY = -origEvent.wheelDelta; } 215 if ('wheelDeltaY' in origEvent) { e.deltaY = -origEvent.wheelDeltaY; } 216 if ('wheelDeltaX' in origEvent) { e.deltaX = -origEvent.wheelDeltaX; } 217 218 // modern wheel event handler 219 if ('deltaY' in origEvent) { 220 e.deltaY = origEvent.deltaY; 221 } 222 if ('deltaX' in origEvent) { 223 e.deltaX = origEvent.deltaX; 224 } 225 226 // handle deltaMode for mouse wheel 227 e.delta = e.deltaY || e.deltaX; 228 if (origEvent.deltaMode === 1) { 229 var lineHeight = 16; 230 e.delta *= lineHeight; 231 e.deltaY *= lineHeight; 232 e.deltaX *= lineHeight; 233 } 234 235 return ($.event.dispatch || $.event.handle).call(this, e); 236 }; 237 }()); 238 239 // extra module methods 240 var moduleMixin = { 241 // provide function for firing native events 242 fireNativeEvent: function(elements, eventName) { 243 $(elements).each(function() { 244 var element = this, eventObject; 245 if (element.dispatchEvent) { 246 eventObject = document.createEvent('HTMLEvents'); 247 eventObject.initEvent(eventName, true, true); 248 element.dispatchEvent(eventObject); 249 } else if (document.createEventObject) { 250 eventObject = document.createEventObject(); 251 eventObject.target = element; 252 element.fireEvent('on' + eventName, eventObject); 253 } 254 }); 255 }, 256 // bind event handlers for module instance (functions beggining with "on") 257 bindHandlers: function() { 258 var self = this; 259 $.each(self, function(propName, propValue) { 260 if (propName.indexOf('on') === 0 && $.isFunction(propValue)) { 261 // dont use $.proxy here because it doesn't create unique handler 262 self[propName] = function() { 263 return propValue.apply(self, arguments); 264 }; 265 } 266 }); 267 } 268 }; 269 270 // public API 271 var api = { 272 version: version, 273 modules: {}, 274 getOptions: function() { 275 return $.extend({}, commonOptions); 276 }, 277 setOptions: function(moduleName, moduleOptions) { 278 if (arguments.length > 1) { 279 // set module options 280 if (this.modules[moduleName]) { 281 $.extend(this.modules[moduleName].prototype.options, moduleOptions); 282 } 283 } else { 284 // set common options 285 $.extend(commonOptions, moduleName); 286 } 287 }, 288 addModule: function(proto) { 289 // proto is factory function 290 if ($.isFunction(proto)) { 291 proto = proto($, window); 292 } 293 294 // add module to list 295 var Module = function(options) { 296 // save instance to collection 297 if (!options.element.data(commonOptions.dataKey)) { 298 options.element.data(commonOptions.dataKey, this); 299 } 300 customInstances.push(this); 301 302 // save options 303 this.options = $.extend({}, commonOptions, this.options, getInlineOptions(options.element), options); 304 305 // bind event handlers to instance 306 this.bindHandlers(); 307 308 // call constructor 309 this.init.apply(this, arguments); 310 }; 311 312 // parse options from HTML attribute 313 var getInlineOptions = function(element) { 314 var dataOptions = element.data(commonOptions.optionsKey), 315 attrOptions = element.attr(commonOptions.optionsKey); 316 317 if (dataOptions) { 318 return dataOptions; 319 } else if (attrOptions) { 320 try { 321 return $.parseJSON(attrOptions); 322 } catch (e) { 323 // ignore invalid attributes 324 } 325 } 326 }; 327 328 // set proto as prototype for new module 329 Module.prototype = proto; 330 331 // add mixin methods to module proto 332 $.extend(proto, moduleMixin); 333 if (proto.plugins) { 334 $.each(proto.plugins, function(pluginName, plugin) { 335 $.extend(plugin.prototype, moduleMixin); 336 }); 337 } 338 339 // override destroy method 340 var originalDestroy = Module.prototype.destroy; 341 Module.prototype.destroy = function() { 342 this.options.element.removeData(this.options.dataKey); 343 344 for (var i = customInstances.length - 1; i >= 0; i--) { 345 if (customInstances[i] === this) { 346 customInstances.splice(i, 1); 347 break; 348 } 349 } 350 351 if (originalDestroy) { 352 originalDestroy.apply(this, arguments); 353 } 354 }; 355 356 // save module to list 357 this.modules[proto.name] = Module; 358 }, 359 getInstance: function(element) { 360 return $(element).data(commonOptions.dataKey); 361 }, 362 replace: function(elements, moduleName, customOptions) { 363 var self = this, 364 instance; 365 366 if (!commonOptions.styleSheetCreated) { 367 createStyleSheet(); 368 } 369 370 $(elements).each(function() { 371 var moduleOptions, 372 element = $(this); 373 374 instance = element.data(commonOptions.dataKey); 375 if (instance) { 376 instance.refresh(); 377 } else { 378 if (!moduleName) { 379 $.each(self.modules, function(currentModuleName, module) { 380 if (module.prototype.matchElement.call(module.prototype, element)) { 381 moduleName = currentModuleName; 382 return false;
383 } 384 }); 385 } 386 if (moduleName) { 387 moduleOptions = $.extend({ element: element }, customOptions); 388 instance = new self.modules[moduleName](moduleOptions); 389 } 390 } 391 }); 392 return instance; 393 }, 394 refresh: function(elements) { 395 $(elements).each(function() { 396 var instance = $(this).data(commonOptions.dataKey); 397 if (instance) { 398 instance.refresh(); 399 } 400 }); 401 }, 402 destroy: function(elements) { 403 $(elements).each(function() { 404 var instance = $(this).data(commonOptions.dataKey); 405 if (instance) { 406 instance.destroy(); 407 } 408 }); 409 }, 410 replaceAll: function(context) { 411 var self = this; 412 $.each(this.modules, function(moduleName, module) { 413 $(module.prototype.selector, context).each(function() { 414 if (this.className.indexOf('jcf-ignore') < 0) { 415 self.replace(this, moduleName); 416 } 417 }); 418 }); 419 }, 420 refreshAll: function(context) { 421 if (context) { 422 $.each(this.modules, function(moduleName, module) { 423 $(module.prototype.selector, context).each(function() { 424 var instance = $(this).data(commonOptions.dataKey); 425 if (instance) { 426 instance.refresh(); 427 } 428 }); 429 }); 430 } else { 431 for (var i = customInstances.length - 1; i >= 0; i--) { 432 customInstances[i].refresh(); 433 } 434 } 435 }, 436 destroyAll: function(context) { 437 if (context) { 438 $.each(this.modules, function(moduleName, module) { 439 $(module.prototype.selector, context).each(function(index, element) { 440 var instance = $(element).data(commonOptions.dataKey); 441 if (instance) { 442 instance.destroy(); 443 } 444 }); 445 }); 446 } else { 447 while (customInstances.length) { 448 customInstances[0].destroy(); 449 } 450 } 451 } 452 }; 453 454 // we need to make JCF available globally if we're in AMD environment 455 if (typeof define === 'function' && define.amd) { 456 window.jcf = api; 457 } 458 459 return api; 460})); 461 462/* End */ 463; 464; /* Start:"a:4:{s:4:"full";s:33:"/js/jcf.select.js?173657735230423";s:6:"source";s:17:"/js/jcf.select.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/ 465/*! 466 * JavaScript Custom Forms : Select Module 467 * 468 * Copyright 2014-2016 PSD2HTML - http://psd2html.com/jcf 469 * Released under the MIT license (LICENSE.txt) 470 * 471 * Version: 1.2.3 472 */ 473 474(function(jcf) { 475 476jcf.addModule(function($, window) { 477 'use strict'; 478 479 var module = { 480 name: 'Select', 481 selector: 'select', 482 options: { 483 element: null, 484 multipleCompactStyle: false 485 }, 486 plugins: { 487 ListBox: ListBox, 488 ComboBox: ComboBox, 489 SelectList: SelectList 490 }, 491 matchElement: function(element) { 492 return element.is('select'); 493 }, 494 init: function() { 495 this.element = $(this.options.element); 496 this.createInstance(); 497 }, 498 isListBox: function() { 499 return this.element.is('[size]:not([jcf-size]), [multiple]'); 500 }, 501 createInstance: function() { 502 if (this.instance) { 503 this.instance.destroy(); 504 } 505 506 if (this.isListBox() && !this.options.multipleCompactStyle && this.options.isMobileDevice && this.options.wrapNativeOnMobile) { 507 this.options.multipleCompactStyle = true; 508 } 509 510 // workaround for iOS issue with multiple selects and autoselection of first option 511 if (this.options.isMobileDevice && this.options.multipleCompactStyle && this.options.wrapNativeOnMobile && !this.element.children('optgroup:first-child').length) { 512 $('<optgroup disabled hidden></optgroup>').prependTo(this.element); 513 } 514 515 if (this.isListBox() && !this.options.multipleCompactStyle) { 516 this.instance = new ListBox(this.options); 517 } else { 518 this.instance = new ComboBox(this.options); 519 } 520 }, 521 refresh: function() { 522 var typeMismatch = (this.isListBox() && this.instance instanceof ComboBox) || 523 (!this.isListBox() && this.instance instanceof ListBox); 524 525 if (typeMismatch) { 526 this.createInstance(); 527 } else { 528 this.instance.refresh(); 529 } 530 }, 531 destroy: function() { 532 this.instance.destroy(); 533 } 534 }; 535 536 // combobox module 537 function ComboBox(options) { 538 this.options = $.extend({ 539 wrapNative: true, 540 wrapNativeOnMobile: true, 541 fakeDropInBody: true, 542 useCustomScroll: true, 543 flipDropToFit: true, 544 maxVisibleItems: 10, 545 fakeAreaStructure: '<span class="jcf-select"><span class="jcf-select-text"></span><span class="jcf-select-opener"></span></span>', 546 fakeDropStructure: '<div class="jcf-select-drop"><div class="jcf-select-drop-content"></div></div>', 547 optionClassPrefix: 'jcf-option-', 548 selectClassPrefix: 'jcf-select-', 549 dropContentSelector: '.jcf-select-drop-content', 550 selectTextSelector: '.jcf-select-text', 551 dropActiveClass: 'jcf-drop-active', 552 flipDropClass: 'jcf-drop-flipped' 553 }, options); 554 this.init(); 555 } 556 $.extend(ComboBox.prototype, { 557 init: function() { 558 this.initStructure(); 559 this.bindHandlers(); 560 this.attachEvents(); 561 this.refresh(); 562 }, 563 initStructure: function() { 564 // prepare structure 565 this.win = $(window); 566 this.doc = $(document); 567 this.realElement = $(this.options.element); 568 this.fakeElement = $(this.options.fakeAreaStructure).insertAfter(this.realElement); 569 this.selectTextContainer = this.fakeElement.find(this.options.selectTextSelector); 570 this.selectText = $('<span></span>').appendTo(this.selectTextContainer); 571 makeUnselectable(this.fakeElement); 572 573 // copy classes from original select
574 this.fakeElement.addClass(getPrefixedClasses(this.realElement.prop('className'), this.options.selectClassPrefix)); 575 576 // handle compact multiple style 577 if (this.realElement.prop('multiple')) { 578 this.fakeElement.addClass('jcf-compact-multiple'); 579 } 580 581 // detect device type and dropdown behavior 582 if (this.options.isMobileDevice && this.options.wrapNativeOnMobile && !this.options.wrapNative) { 583 this.options.wrapNative = true; 584 } 585 586 if (this.options.wrapNative) { 587 // wrap native select inside fake block 588 this.realElement.prependTo(this.fakeElement).css({ 589 position: 'absolute', 590 height: '100%', 591 width: '100%' 592 }).addClass(this.options.resetAppearanceClass); 593 } else { 594 // just hide native select 595 this.realElement.addClass(this.options.hiddenClass); 596 this.fakeElement.attr('title', this.realElement.attr('title')); 597 this.fakeDropTarget = this.options.fakeDropInBody ? $('body') : this.fakeElement; 598 } 599 }, 600 attachEvents: function() { 601 // delayed refresh handler 602 var self = this; 603 this.delayedRefresh = function() { 604 setTimeout(function() { 605 self.refresh(); 606 if (self.list) { 607 self.list.refresh(); 608 self.list.scrollToActiveOption(); 609 } 610 }, 1); 611 }; 612 613 // native dropdown event handlers 614 if (this.options.wrapNative) { 615 this.realElement.on({ 616 focus: this.onFocus, 617 change: this.onChange, 618 click: this.onChange, 619 keydown: this.delayedRefresh 620 }); 621 } else { 622 // custom dropdown event handlers 623 this.realElement.on({ 624 focus: this.onFocus, 625 change: this.onChange, 626 keydown: this.onKeyDown 627 }); 628 this.fakeElement.on({ 629 'jcf-pointerdown': this.onSelectAreaPress 630 }); 631 } 632 }, 633 onKeyDown: function(e) { 634 if (e.which === 13) { 635 this.toggleDropdown(); 636 } else if (this.dropActive) { 637 this.delayedRefresh(); 638 } 639 }, 640 onChange: function() { 641 this.refresh(); 642 }, 643 onFocus: function() { 644 if (!this.pressedFlag || !this.focusedFlag) { 645 this.fakeElement.addClass(this.options.focusClass); 646 this.realElement.on('blur', this.onBlur); 647 this.toggleListMode(true); 648 this.focusedFlag = true; 649 } 650 }, 651 onBlur: function() { 652 if (!this.pressedFlag) { 653 this.fakeElement.removeClass(this.options.focusClass); 654 this.realElement.off('blur', this.onBlur); 655 this.toggleListMode(false); 656 this.focusedFlag = false; 657 } 658 }, 659 onResize: function() { 660 if (this.dropActive) { 661 this.hideDropdown(); 662 } 663 }, 664 onSelectDropPress: function() { 665 this.pressedFlag = true; 666 }, 667 onSelectDropRelease: function(e, pointerEvent) { 668 this.pressedFlag = false; 669 if (pointerEvent.pointerType === 'mouse') { 670 this.realElement.focus(); 671 } 672 }, 673 onSelectAreaPress: function(e) { 674 // skip click if drop inside fake element or real select is disabled 675 var dropClickedInsideFakeElement = !this.options.fakeDropInBody && $(e.target).closest(this.dropdown).length; 676 if (dropClickedInsideFakeElement || e.button > 1 || this.realElement.is(':disabled')) { 677 return; 678 } 679 680 // toggle dropdown visibility 681 this.selectOpenedByEvent = e.pointerType; 682 this.toggleDropdown(); 683 684 // misc handlers 685 if (!this.focusedFlag) { 686 if (e.pointerType === 'mouse') { 687 this.realElement.focus(); 688 } else { 689 this.onFocus(e); 690 } 691 } 692 this.pressedFlag = true; 693 this.fakeElement.addClass(this.options.pressedClass); 694 this.doc.on('jcf-pointerup', this.onSelectAreaRelease); 695 }, 696 onSelectAreaRelease: function(e) { 697 if (this.focusedFlag && e.pointerType === 'mouse') { 698 this.realElement.focus(); 699 } 700 this.pressedFlag = false; 701 this.fakeElement.removeClass(this.options.pressedClass); 702 this.doc.off('jcf-pointerup', this.onSelectAreaRelease); 703 }, 704 onOutsideClick: function(e) { 705 var target = $(e.target), 706 clickedInsideSelect = target.closest(this.fakeElement).length || target.closest(this.dropdown).length; 707 708 if (!clickedInsideSelect) { 709 this.hideDropdown(); 710 } 711 }, 712 onSelect: function() { 713 this.refresh(); 714 715 if (this.realElement.prop('multiple')) { 716 this.repositionDropdown(); 717 } else { 718 this.hideDropdown(); 719 } 720 721 this.fireNativeEvent(this.realElement, 'change'); 722 }, 723 toggleListMode: function(state) { 724 if (!this.options.wrapNative) { 725 if (state) { 726 // temporary change select to list to avoid appearing of native dropdown 727 this.realElement.attr({ 728 size: 4, 729 'jcf-size': '' 730 }); 731 } else { 732 // restore select from list mode to dropdown select 733 if (!this.options.wrapNative) { 734 this.realElement.removeAttr('size jcf-size'); 735 } 736 } 737 } 738 }, 739 createDropdown: function() { 740 // destroy previous dropdown if needed 741 if (this.dropdown) { 742 this.list.destroy(); 743 this.dropdown.remove(); 744 } 745 746 // create new drop container 747 this.dropdown = $(this.options.fakeDropStructure).appendTo(this.fakeDropTarget);
748 this.dropdown.addClass(getPrefixedClasses(this.realElement.prop('className'), this.options.selectClassPrefix)); 749 makeUnselectable(this.dropdown); 750 751 // handle compact multiple style 752 if (this.realElement.prop('multiple')) { 753 this.dropdown.addClass('jcf-compact-multiple'); 754 } 755 756 // set initial styles for dropdown in body 757 if (this.options.fakeDropInBody) { 758 this.dropdown.css({ 759 position: 'absolute', 760 top: -9999 761 }); 762 } 763 764 // create new select list instance 765 this.list = new SelectList({ 766 useHoverClass: true, 767 handleResize: false, 768 alwaysPreventMouseWheel: true, 769 maxVisibleItems: this.options.maxVisibleItems, 770 useCustomScroll: this.options.useCustomScroll, 771 holder: this.dropdown.find(this.options.dropContentSelector), 772 multipleSelectWithoutKey: this.realElement.prop('multiple'), 773 element: this.realElement 774 }); 775 $(this.list).on({ 776 select: this.onSelect, 777 press: this.onSelectDropPress, 778 release: this.onSelectDropRelease 779 }); 780 }, 781 repositionDropdown: function() { 782 var selectOffset = this.fakeElement.offset(), 783 fakeElementBounds = this.fakeElement[0].getBoundingClientRect(), 784 selectWidth = fakeElementBounds.width || fakeElementBounds.right - fakeElementBounds.left, 785 selectHeight = this.fakeElement.outerHeight(), 786 dropHeight = this.dropdown.css('width', selectWidth).outerHeight(), 787 winScrollTop = this.win.scrollTop(), 788 winHeight = this.win.height(), 789 calcTop, calcLeft, bodyOffset, needFlipDrop = false; 790 791 // check flip drop position 792 if (selectOffset.top + selectHeight + dropHeight > winScrollTop + winHeight && selectOffset.top - dropHeight > winScrollTop) { 793 needFlipDrop = true; 794 } 795 796 if (this.options.fakeDropInBody) { 797 bodyOffset = this.fakeDropTarget.css('position') !== 'static' ? this.fakeDropTarget.offset().top : 0; 798 if (this.options.flipDropToFit && needFlipDrop) { 799 // calculate flipped dropdown position 800 calcLeft = selectOffset.left; 801 calcTop = selectOffset.top - dropHeight - bodyOffset; 802 } else { 803 // calculate default drop position 804 calcLeft = selectOffset.left; 805 calcTop = selectOffset.top + selectHeight - bodyOffset; 806 } 807 808 // update drop styles 809 this.dropdown.css({ 810 width: selectWidth, 811 left: calcLeft, 812 top: calcTop 813 }); 814 } 815 816 // refresh flipped class 817 this.dropdown.add(this.fakeElement).toggleClass(this.options.flipDropClass, this.options.flipDropToFit && needFlipDrop); 818 }, 819 showDropdown: function() { 820 // do not show empty custom dropdown 821 if (!this.realElement.prop('options').length) { 822 return; 823 } 824 825 // create options list if not created 826 if (!this.dropdown) { 827 this.createDropdown(); 828 } 829 830 // show dropdown 831 this.dropActive = true; 832 this.dropdown.appendTo(this.fakeDropTarget); 833 this.fakeElement.addClass(this.options.dropActiveClass); 834 this.refreshSelectedText(); 835 this.repositionDropdown(); 836 this.list.setScrollTop(this.savedScrollTop); 837 this.list.refresh(); 838 839 // add temporary event handlers 840 this.win.on('resize', this.onResize); 841 this.doc.on('jcf-pointerdown', this.onOutsideClick); 842 }, 843 hideDropdown: function() { 844 if (this.dropdown) { 845 this.savedScrollTop = this.list.getScrollTop(); 846 this.fakeElement.removeClass(this.options.dropActiveClass + ' ' + this.options.flipDropClass); 847 this.dropdown.removeClass(this.options.flipDropClass).detach(); 848 this.doc.off('jcf-pointerdown', this.onOutsideClick); 849 this.win.off('resize', this.onResize); 850 this.dropActive = false; 851 if (this.selectOpenedByEvent === 'touch') { 852 this.onBlur(); 853 } 854 } 855 }, 856 toggleDropdown: function() { 857 if (this.dropActive) { 858 this.hideDropdown(); 859 } else { 860 this.showDropdown(); 861 } 862 }, 863 refreshSelectedText: function() { 864 // redraw selected area 865 var selectedIndex = this.realElement.prop('selectedIndex'), 866 selectedOption = this.realElement.prop('options')[selectedIndex], 867 selectedOptionImage = selectedOption ? selectedOption.getAttribute('data-image') : null, 868 selectedOptionText = '', 869 selectedOptionClasses, 870 self = this; 871 872 if (this.realElement.prop('multiple')) { 873 $.each(this.realElement.prop('options'), function(index, option) { 874 if (option.selected) {
875 selectedOptionText += (selectedOptionText ? ', ' : '') + option.innerHTML; 876 } 877 }); 878 if (!selectedOptionText) { 879 selectedOptionText = self.realElement.attr('placeholder') || ''; 880 } 881 this.selectText.removeAttr('class').html(selectedOptionText); 882 } else if (!selectedOption) { 883 if (this.selectImage) { 884 this.selectImage.hide(); 885 } 886 this.selectText.removeAttr('class').empty(); 887 } else if (this.currentSelectedText !== selectedOption.innerHTML || this.currentSelectedImage !== selectedOptionImage) { 888 selectedOptionClasses = getPrefixedClasses(selectedOption.className, this.options.optionClassPrefix); 889 this.selectText.attr('class', selectedOptionClasses).html(selectedOption.innerHTML); 890 891 if (selectedOptionImage) { 892 if (!this.selectImage) { 893 this.selectImage = $('<img>').prependTo(this.selectTextContainer).hide(); 894 } 895 this.selectImage.attr('src', selectedOptionImage).show(); 896 } else if (this.selectImage) { 897 this.selectImage.hide(); 898 } 899 900 this.currentSelectedText = selectedOption.innerHTML; 901 this.currentSelectedImage = selectedOptionImage; 902 } 903 }, 904 refresh: function() { 905 // refresh fake select visibility 906 if (this.realElement.prop('style').display === 'none') { 907 this.fakeElement.hide(); 908 } else { 909 this.fakeElement.show(); 910 } 911 912 // refresh selected text 913 this.refreshSelectedText(); 914 915 // handle disabled state 916 this.fakeElement.toggleClass(this.options.disabledClass, this.realElement.is(':disabled')); 917 }, 918 destroy: function() { 919 // restore structure 920 if (this.options.wrapNative) { 921 this.realElement.insertBefore(this.fakeElement).css({ 922 position: '', 923 height: '', 924 width: '' 925 }).removeClass(this.options.resetAppearanceClass); 926 } else { 927 this.realElement.removeClass(this.options.hiddenClass); 928 if (this.realElement.is('[jcf-size]')) { 929 this.realElement.removeAttr('size jcf-size'); 930 } 931 } 932 933 // removing element will also remove its event handlers 934 this.fakeElement.remove(); 935 936 // remove other event handlers 937 this.doc.off('jcf-pointerup', this.onSelectAreaRelease); 938 this.realElement.off({ 939 focus: this.onFocus 940 }); 941 } 942 }); 943 944 // listbox module 945 function ListBox(options) { 946 this.options = $.extend({ 947 wrapNative: true, 948 useCustomScroll: true, 949 fakeStructure: '<span class="jcf-list-box"><span class="jcf-list-wrapper"></span></span>', 950 selectClassPrefix: 'jcf-select-', 951 listHolder: '.jcf-list-wrapper' 952 }, options); 953 this.init(); 954 } 955 $.extend(ListBox.prototype, { 956 init: function() { 957 this.bindHandlers(); 958 this.initStructure(); 959 this.attachEvents(); 960 }, 961 initStructure: function() { 962 this.realElement = $(this.options.element); 963 this.fakeElement = $(this.options.fakeStructure).insertAfter(this.realElement); 964 this.listHolder = this.fakeElement.find(this.options.listHolder); 965 makeUnselectable(this.fakeElement); 966 967 // copy classes from original select 968 this.fakeElement.addClass(getPrefixedClasses(this.realElement.prop('className'), this.options.selectClassPrefix)); 969 this.realElement.addClass(this.options.hiddenClass); 970 971 this.list = new SelectList({ 972 useCustomScroll: this.options.useCustomScroll, 973 holder: this.listHolder, 974 selectOnClick: false, 975 element: this.realElement 976 }); 977 }, 978 attachEvents: function() { 979 // delayed refresh handler 980 var self = this; 981 this.delayedRefresh = function(e) { 982 if (e && (e.which === 16 || e.ctrlKey || e.metaKey || e.altKey)) { 983 // ignore modifier keys 984 return; 985 } else { 986 clearTimeout(self.refreshTimer); 987 self.refreshTimer = setTimeout(function() { 988 self.refresh(); 989 self.list.scrollToActiveOption(); 990 }, 1); 991 } 992 }; 993 994 // other event handlers 995 this.realElement.on({ 996 focus: this.onFocus, 997 click: this.delayedRefresh, 998 keydown: this.delayedRefresh 999 }); 1000 1001 // select list event handlers 1002 $(this.list).on({ 1003 select: this.onSelect, 1004 press: this.onFakeOptionsPress, 1005 release: this.onFakeOptionsRelease 1006 }); 1007 }, 1008 onFakeOptionsPress: function(e, pointerEvent) { 1009 this.pressedFlag = true; 1010 if (pointerEvent.pointerType === 'mouse') { 1011 this.realElement.focus(); 1012 } 1013 }, 1014 onFakeOptionsRelease: function(e, pointerEvent) { 1015 this.pressedFlag = false;
1016 if (pointerEvent.pointerType === 'mouse') { 1017 this.realElement.focus(); 1018 } 1019 }, 1020 onSelect: function() { 1021 this.fireNativeEvent(this.realElement, 'change'); 1022 this.fireNativeEvent(this.realElement, 'click'); 1023 }, 1024 onFocus: function() { 1025 if (!this.pressedFlag || !this.focusedFlag) { 1026 this.fakeElement.addClass(this.options.focusClass); 1027 this.realElement.on('blur', this.onBlur); 1028 this.focusedFlag = true; 1029 } 1030 }, 1031 onBlur: function() { 1032 if (!this.pressedFlag) { 1033 this.fakeElement.removeClass(this.options.focusClass); 1034 this.realElement.off('blur', this.onBlur); 1035 this.focusedFlag = false; 1036 } 1037 }, 1038 refresh: function() { 1039 this.fakeElement.toggleClass(this.options.disabledClass, this.realElement.is(':disabled')); 1040 this.list.refresh(); 1041 }, 1042 destroy: function() { 1043 this.list.destroy(); 1044 this.realElement.insertBefore(this.fakeElement).removeClass(this.options.hiddenClass); 1045 this.fakeElement.remove(); 1046 } 1047 }); 1048 1049 // options list module 1050 function SelectList(options) { 1051 this.options = $.extend({ 1052 holder: null, 1053 maxVisibleItems: 10, 1054 selectOnClick: true, 1055 useHoverClass: false, 1056 useCustomScroll: false, 1057 handleResize: true, 1058 multipleSelectWithoutKey: false, 1059 alwaysPreventMouseWheel: false, 1060 indexAttribute: 'data-index', 1061 cloneClassPrefix: 'jcf-option-', 1062 containerStructure: '<span class="jcf-list"><span class="jcf-list-content"></span></span>', 1063 containerSelector: '.jcf-list-content', 1064 captionClass: 'jcf-optgroup-caption', 1065 disabledClass: 'jcf-disabled', 1066 optionClass: 'jcf-option', 1067 groupClass: 'jcf-optgroup', 1068 hoverClass: 'jcf-hover', 1069 selectedClass: 'jcf-selected', 1070 scrollClass: 'jcf-scroll-active' 1071 }, options); 1072 this.init(); 1073 } 1074 $.extend(SelectList.prototype, { 1075 init: function() { 1076 this.initStructure(); 1077 this.refreshSelectedClass(); 1078 this.attachEvents(); 1079 }, 1080 initStructure: function() { 1081 this.element = $(this.options.element); 1082 this.indexSelector = '[' + this.options.indexAttribute + ']'; 1083 this.container = $(this.options.containerStructure).appendTo(this.options.holder); 1084 this.listHolder = this.container.find(this.options.containerSelector); 1085 this.lastClickedIndex = this.element.prop('selectedIndex'); 1086 this.rebuildList(); 1087 1088 // save current selection in multiple select 1089 if (this.element.prop('multiple')) { 1090 this.previousSelection = this.getSelectedOptionsIndexes(); 1091 } 1092 }, 1093 attachEvents: function() { 1094 this.bindHandlers(); 1095 this.listHolder.on('jcf-pointerdown', this.indexSelector, this.onItemPress); 1096 this.listHolder.on('jcf-pointerdown', this.onPress); 1097 1098 if (this.options.useHoverClass) { 1099 this.listHolder.on('jcf-pointerover', this.indexSelector, this.onHoverItem); 1100 } 1101 }, 1102 onPress: function(e) { 1103 $(this).trigger('press', e); 1104 this.listHolder.on('jcf-pointerup', this.onRelease); 1105 }, 1106 onRelease: function(e) { 1107 $(this).trigger('release', e); 1108 this.listHolder.off('jcf-pointerup', this.onRelease); 1109 }, 1110 onHoverItem: function(e) { 1111 var hoverIndex = parseFloat(e.currentTarget.getAttribute(this.options.indexAttribute)); 1112 this.fakeOptions.removeClass(this.options.hoverClass).eq(hoverIndex).addClass(this.options.hoverClass); 1113 }, 1114 onItemPress: function(e) { 1115 if (e.pointerType === 'touch' || this.options.selectOnClick) { 1116 // select option after "click" 1117 this.tmpListOffsetTop = this.list.offset().top; 1118 this.listHolder.on('jcf-pointerup', this.indexSelector, this.onItemRelease); 1119 } else { 1120 // select option immediately 1121 this.onSelectItem(e); 1122 } 1123 }, 1124 onItemRelease: function(e) { 1125 // remove event handlers and temporary data 1126 this.listHolder.off('jcf-pointerup', this.indexSelector, this.onItemRelease); 1127 1128 // simulate item selection 1129 if (this.tmpListOffsetTop === this.list.offset().top) { 1130 this.listHolder.on('click', this.indexSelector, { savedPointerType: e.pointerType }, this.onSelectItem); 1131 } 1132 delete this.tmpListOffsetTop; 1133 }, 1134 onSelectItem: function(e) { 1135 var clickedIndex = parseFloat(e.currentTarget.getAttribute(this.options.indexAttribute)), 1136 pointerType = e.data && e.data.savedPointerType || e.pointerType || 'mouse', 1137 range; 1138 1139 // remove click event handler 1140 this.listHolder.off('click', this.indexSelector, this.onSelectItem); 1141 1142 // ignore clicks on disabled options 1143 if (e.button > 1 || this.realOptions[clickedIndex].disabled) { 1144 return; 1145 } 1146 1147 if (this.element.prop('multiple')) { 1148 if (e.metaKey || e.ctrlKey || pointerType === 'touch' || this.options.multipleSelectWithoutKey) { 1149 // if CTRL/CMD pressed or touch devices - toggle selected option 1150 this.realOptions[clickedIndex].selected = !this.realOptions[clickedIndex].selected; 1151 } else if (e.shiftKey) { 1152 // if SHIFT pressed - update selection 1153 range = [this.lastClickedIndex, clickedIndex].sort(function(a, b) { 1154 return a - b; 1155 }); 1156 this.realOptions.each(function(index, option) { 1157 option.selected = (index >= range[0] && index <= range[1]); 1158 }); 1159 } else { 1160 // set single selected index 1161 this.element.prop('selectedIndex', clickedIndex); 1162 } 1163 } else { 1164 this.element.prop('selectedIndex', clickedIndex); 1165 } 1166 1167 // save last clicked option 1168 if (!e.shiftKey) { 1169 this.lastClickedIndex = clickedIndex; 1170 } 1171 1172 // refresh classes 1173 this.refreshSelectedClass(); 1174 1175 // scroll to active item in desktop browsers 1176 if (pointerType === 'mouse') { 1177 this.scrollToActiveOption(); 1178 } 1179 1180 // make callback when item selected 1181 $(this).trigger('select'); 1182 }, 1183 rebuildList: function() { 1184 // rebuild options 1185 var self = this, 1186 rootElement = this.element[0]; 1187 1188 // recursively create fake options 1189 this.storedSelectHTML = rootElement.innerHTML; 1190 this.optionIndex = 0; 1191 this.list = $(this.createOptionsList(rootElement)); 1192 this.listHolder.empty().append(this.list); 1193 this.realOptions = this.element.find('option'); 1194 this.fakeOptions = this.list.find(this.indexSelector); 1195 this.fakeListItems = this.list.find('.' + this.options.captionClass + ',' + this.indexSelector); 1196 delete this.optionIndex; 1197 1198 // detect max visible items 1199 var maxCount = this.options.maxVisibleItems, 1200 sizeValue = this.element.prop('size'); 1201 if (sizeValue > 1 && !this.element.is('[jcf-size]')) { 1202 maxCount = sizeValue; 1203 } 1204 1205 // handle scrollbar 1206 var needScrollBar = this.fakeOptions.length > maxCount; 1207 this.container.toggleClass(this.options.scrollClass, needScrollBar); 1208 if (needScrollBar) { 1209 // change max-height 1210 this.listHolder.css({ 1211 maxHeight: this.getOverflowHeight(maxCount), 1212 overflow: 'auto' 1213 }); 1214 1215 if (this.options.useCustomScroll && jcf.modules.Scrollable) { 1216 // add custom scrollbar if specified in options 1217 jcf.replace(this.listHolder, 'Scrollable', { 1218 handleResize: this.options.handleResize, 1219 alwaysPreventMouseWheel: this.options.alwaysPreventMouseWheel 1220 }); 1221 return; 1222 } 1223 } 1224 1225 // disable edge wheel scrolling 1226 if (this.options.alwaysPreventMouseWheel) { 1227 this.preventWheelHandler = function(e) { 1228 var currentScrollTop = self.listHolder.scrollTop(), 1229 maxScrollTop = self.listHolder.prop('scrollHeight') - self.listHolder.innerHe
1229ight(); 1230 1231 // check edge cases 1232 if ((currentScrollTop <= 0 && e.deltaY < 0) || (currentScrollTop >= maxScrollTop && e.deltaY > 0)) { 1233 e.preventDefault(); 1234 } 1235 }; 1236 this.listHolder.on('jcf-mousewheel', this.preventWheelHandler); 1237 } 1238 }, 1239 refreshSelectedClass: function() { 1240 var self = this, 1241 selectedItem, 1242 isMultiple = this.element.prop('multiple'), 1243 selectedIndex = this.element.prop('selectedIndex'); 1244 1245 if (isMultiple) { 1246 this.realOptions.each(function(index, option) { 1247 self.fakeOptions.eq(index).toggleClass(self.options.selectedClass, !!option.selected); 1248 }); 1249 } else { 1250 this.fakeOptions.removeClass(this.options.selectedClass + ' ' + this.options.hoverClass); 1251 selectedItem = this.fakeOptions.eq(selectedIndex).addClass(this.options.selectedClass); 1252 if (this.options.useHoverClass) { 1253 selectedItem.addClass(this.options.hoverClass); 1254 } 1255 } 1256 }, 1257 scrollToActiveOption: function() { 1258 // scroll to target option 1259 var targetOffset = this.getActiveOptionOffset(); 1260 if (typeof targetOffset === 'number') { 1261 this.listHolder.prop('scrollTop', targetOffset); 1262 } 1263 }, 1264 getSelectedOptionsIndexes: function() { 1265 var selection = []; 1266 this.realOptions.each(function(index, option) { 1267 if (option.selected) { 1268 selection.push(index); 1269 } 1270 }); 1271 return selection; 1272 }, 1273 getChangedSelectedIndex: function() { 1274 var selectedIndex = this.element.prop('selectedIndex'), 1275 self = this, 1276 found = false, 1277 targetIndex = null; 1278 1279 if (this.element.prop('multiple')) { 1280 // multiple selects handling 1281 this.currentSelection = this.getSelectedOptionsIndexes(); 1282 $.each(this.currentSelection, function(index, optionIndex) { 1283 if (!found && self.previousSelection.indexOf(optionIndex) < 0) { 1284 if (index === 0) { 1285 found = true; 1286 } 1287 targetIndex = optionIndex; 1288 } 1289 }); 1290 this.previousSelection = this.currentSelection; 1291 return targetIndex; 1292 } else { 1293 // single choice selects handling 1294 return selectedIndex; 1295 } 1296 }, 1297 getActiveOptionOffset: function() { 1298 // calc values 1299 var currentIndex = this.getChangedSelectedIndex(); 1300 1301 // selection was not changed 1302 if (currentIndex === null) { 1303 return; 1304 } 1305 1306 // find option and scroll to it if needed 1307 var dropHeight = this.listHolder.height(), 1308 dropScrollTop = this.listHolder.prop('scrollTop'), 1309 fakeOption = this.fakeOptions.eq(currentIndex), 1310 fakeOptionOffset = fakeOption.offset().top - this.list.offset().top, 1311 fakeOptionHeight = fakeOption.innerHeight(); 1312 1313 // scroll list 1314 if (fakeOptionOffset + fakeOptionHeight >= dropScrollTop + dropHeight) { 1315 // scroll down (always scroll to option) 1316 return fakeOptionOffset - dropHeight + fakeOptionHeight; 1317 } else if (fakeOptionOffset < dropScrollTop) { 1318 // scroll up to option 1319 return fakeOptionOffset; 1320 } 1321 }, 1322 getOverflowHeight: function(sizeValue) { 1323 var item = this.fakeListItems.eq(sizeValue - 1), 1324 listOffset = this.list.offset().top, 1325 itemOffset = item.offset().top, 1326 itemHeight = item.innerHeight(); 1327 1328 return itemOffset + itemHeight - listOffset; 1329 }, 1330 getScrollTop: function() { 1331 return this.listHolder.scrollTop(); 1332 }, 1333 setScrollTop: function(value) { 1334 this.listHolder.scrollTop(value); 1335 }, 1336 createOption: function(option) { 1337 var newOption = document.createElement('span'); 1338 newOption.className = this.options.optionClass; 1339 newOption.innerHTML = option.innerHTML; 1340 newOption.setAttribute(this.options.indexAttribute, this.optionIndex++); 1341 1342 var optionImage, optionImageSrc = option.getAttribute('data-image'); 1343 if (optionImageSrc) { 1344 optionImage = document.createElement('img'); 1345 optionImage.src = optionImageSrc; 1346 newOption.insertBefore(optionImage, newOption.childNodes[0]); 1347 } 1348 if (option.disabled) { 1349 newOption.className += ' ' + this.options.disabledClass; 1350 } 1351 if (option.className) { 1352 newOption.className += ' ' + getPrefixedClasses(option.className, this.options.cloneClassPrefix); 1353 } 1354 return newOption; 1355 }, 1356 createOptGroup: function(optgroup) { 1357 var optGroupContainer = document.createElement('span'), 1358 optGroupName = optgroup.getAttribute('label'), 1359 optGroupCaption, optGroupList; 1360 1361 // create caption 1362 optGroupCaption = document.createElement('span'); 1363 optGroupCaption.className = this.options.captionClass; 1364 optGroupCaption.innerHTML = optGroupName; 1365 optGroupContainer.appendChild(optGroupCaption); 1366 1367 // create list of options 1368 if (optgroup.children.length) { 1369 optGroupList = this.createOptionsList(optgroup); 1370 optGroupContainer.appendChild(optGroupList); 1371 } 1372 1373 optGroupContainer.className = this.options.groupClass; 1374 return optGroupContainer; 1375 }, 1376 createOptionContainer: function() { 1377 var optionContainer = document.createElement('li'); 1378 return optionContainer; 1379 }, 1380 createOptionsList: function(container) { 1381 var self = this, 1382 list = document.createElement('ul'); 1383 1384 $.each(container.children, function(index, currentNode) { 1385 var item = self.createOptionContainer(currentNode), 1386 newNode; 1387 1388 switch (currentNode.tagName.toLowerCase()) { 1389 case 'option': newNode = self.createOption(currentNode); break; 1390 case 'optgroup': newNode = self.createOptGroup(currentNode); break; 1391 } 1392 list.appendChild(item).appendChild(newNode); 1393 }); 1394 return list; 1395 }, 1396 refresh: function() { 1397 // check for select innerHTML changes 1398 if (this.storedSelectHTML !== this.element.prop('innerHTML')) { 1399 this.rebuildList(); 1400 } 1401 1402 // refresh custom scrollbar 1403 var scrollInstance = jcf.getInstance(this.listHolder); 1404 if (scrollInstance) { 1405 scrollInstance.refresh(); 1406 } 1407 1408 // refresh selectes classes 1409 this.refreshSelectedClass(); 1410 }, 1411 destroy: function() { 1412 this.listHolder.off('jcf-mousewheel', this.preventWheelHandler); 1413 this.listHolder.off('jcf-pointerdown', this.indexSelector, this.onSelectItem); 1414 this.listHolder.off('jcf-pointerover', this.indexSelector, this.onHoverItem); 1415 this.listHolder.off('jcf-pointerdown', this.onPress); 1416 } 1417 }); 1418 1419 // helper functions
1420 var getPrefixedClasses = function(className, prefixToAdd) { 1421 return className ? className.replace(/[\s]*([\S]+)+[\s]*/gi, prefixToAdd + '$1 ') : ''; 1422 }; 1423 var makeUnselectable = (function() { 1424 var unselectableClass = jcf.getOptions().unselectableClass; 1425 function preventHandler(e) { 1426 e.preventDefault(); 1427 } 1428 return function(node) { 1429 node.addClass(unselectableClass).on('selectstart', preventHandler); 1430 }; 1431 }()); 1432 1433 return module; 1434}); 1435 1436}(jcf)); 1437 1438/* End */ 1439; 1440; /* Start:"a:4:{s:4:"full";s:27:"/js/select.js?1736859260257";s:6:"source";s:13:"/js/select.js";s:3:"min";s:0:"";s:3:"map";s:0:"";}"*/ 1441$(document).ready(function () { 1442 $('.modal-wrap').find('select').each(function () { 1443 $(this).attr('data-jcf', '{"wrapNative": true}') 1444 }); 1445 1446 jcf.setOptions('Select', { 1447 wrapNative: false, 1448 wrapNativeOnMobile: true 1449 }); 1450 1451 jcf.replaceAll(); 1452}); 1453 1454/* End */ 1455;; /* /js/jcf.js?151707261813686*/ 1456; /* /js/jcf.select.js?173657735230423*/ 1457; /* /js/select.js?1736859260257*/
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.