1/*! 2 * JavaScript Custom Forms : Radio Module 3 * 4 * Copyright 2014-2015 PSD2HTML - http://psd2html.com/jcf 5 * Released under the MIT license (LICENSE.txt) 6 * 7 * Version: 1.2.3 8 */ 9 10(function(jcf) { 11 12jcf.addModule(function($) { 13 'use strict'; 14 15 return { 16 name: 'Radio', 17 selector: 'input[type="radio"]', 18 options: { 19 wrapNative: true, 20 checkedClass: 'jcf-checked', 21 uncheckedClass: 'jcf-unchecked', 22 labelActiveClass: 'jcf-label-active', 23 fakeStructure: '<span class="jcf-radio"><span></span></span>' 24 }, 25 matchElement: function(element) { 26 return element.is(':radio'); 27 }, 28 init: function() { 29 this.initStructure(); 30 this.attachEvents(); 31 this.refresh(); 32 }, 33 initStructure: function() { 34 // prepare structure 35 this.doc = $(document); 36 this.realElement = $(this.options.element); 37 this.fakeElement = $(this.options.fakeStructure).insertAfter(this.realElement); 38 this.labelElement = this.getLabelFor(); 39 40 if (this.options.wrapNative) { 41 // wrap native radio inside fake block 42 this.realElement.prependTo(this.fakeElement).css({ 43 position: 'absolute', 44 opacity: 0 45 }); 46 } else { 47 // just hide native radio 48 this.realElement.addClass(this.options.hiddenClass); 49 } 50 }, 51 attachEvents: function() { 52 // add event handlers 53 this.realElement.on({ 54 focus: this.onFocus, 55 click: this.onRealClick 56 }); 57 this.fakeElement.on('click', this.onFakeClick); 58 this.fakeElement.on('jcf-pointerdown', this.onPress); 59 }, 60 onRealClick: function(e) { 61 // redraw current radio and its group (setTimeout handles click that might be prevented) 62 var self = this; 63 this.savedEventObject = e; 64 setTimeout(function() { 65 self.refreshRadioGroup(); 66 }, 0); 67 }, 68 onFakeClick: function(e) { 69 // skip event if clicked on real element inside wrapper 70 if (this.options.wrapNative && this.realElement.is(e.target)) { 71 return; 72 } 73 74 // toggle checked class 75 if (!this.realElement.is(':disabled')) { 76 delete this.savedEventObject; 77 this.currentActiveRadio = this.getCurrentActiveRadio(); 78 this.stateChecked = this.realElement.prop('checked'); 79 this.realElement.prop('checked', true); 80 this.fireNativeEvent(this.realElement, 'click'); 81 if (this.savedEventObject && this.savedEventObject.isDefaultPrevented()) { 82 this.realElement.prop('checked', this.stateChecked); 83 this.currentActiveRadio.prop('checked', true); 84 } else { 85 this.fireNativeEvent(this.realElement, 'change'); 86 } 87 delete this.savedEventObject; 88 } 89 }, 90 onFocus: function() { 91 if (!this.pressedFlag || !this.focusedFlag) { 92 this.focusedFlag = true; 93 this.fakeElement.addClass(this.options.focusClass); 94 this.realElement.on('blur', this.onBlur); 95 } 96 }, 97 onBlur: function() { 98 if (!this.pressedFlag) { 99 this.focusedFlag = false; 100 this.fakeElement.removeClass(this.options.focusClass); 101 this.realElement.off('blur', this.onBlur); 102 } 103 }, 104 onPress: function(e) { 105 if (!this.focusedFlag && e.pointerType === 'mouse') { 106 this.realElement.focus(); 107 } 108 this.pressedFlag = true; 109 this.fakeElement.addClass(this.options.pressedClass); 110 this.doc.on('jcf-pointerup', this.onRelease); 111 }, 112 onRelease: function(e) { 113 if (this.focusedFlag && e.pointerType === 'mouse') { 114 this.realElement.focus(); 115 } 116 this.pressedFlag = false; 117 this.fakeElement.removeClass(this.options.pressedClass); 118 this.doc.off('jcf-pointerup', this.onRelease); 119 }, 120 getCurrentActiveRadio: function() { 121 return this.getRadioGroup(this.realElement).filter(':checked'); 122 }, 123 getRadioGroup: function(radio) { 124 // find radio group for specified radio button 125 var name = radio.attr('name'), 126 parentForm = radio.parents('form'); 127 128 if (name) { 129 if (parentForm.length) { 130 return parentForm.find('input[name="' + name + '"]'); 131 } else { 132 return $('input[name="' + name + '"]:not(form input)'); 133 } 134 } else { 135 return radio; 136 } 137 }, 138 getLabelFor: function() { 139 var parentLabel = this.realElement.closest('label'), 140 elementId = this.realElement.prop('id'); 141 142 if (!parentLabel.length && elementId) { 143 parentLabel = $('label[for="' + elementId + '"]'); 144 } 145 return parentLabel.length ? parentLabel : null; 146 }, 147 refreshRadioGroup: function() { 148 // redraw current radio and its group 149 this.getRadioGroup(this.realElement).each(function() { 150 jcf.refresh(this); 151 }); 152 }, 153 refresh: function() { 154 // redraw current radio button 155 var isChecked = this.realElement.is(':checked'), 156 isDisabled = this.realElement.is(':disabled'); 157 158 this.fakeElement.toggleClass(this.options.checkedClass, isChecked) 159 .toggleClass(this.options.uncheckedClass, !isChecked) 160 .toggleClass(this.options.disabledClass, isDisabled); 161 162 if (this.labelElement) { 163 this.labelElement.toggleClass(this.options.labelActiveClass, isChecked); 164 } 165 }, 166 destroy: function() { 167 // restore structure 168 if (this.options.wrapNative) { 169 this.realElement.insertBefore(this.fakeElement).css({ 170 position: '', 171 width: '', 172 height: '', 173 opacity: '', 174 margin: '' 175 }); 176 } else { 177 this.realElement.removeClass(this.options.hiddenClass); 178 } 179 180 // removing element will also remove its event handlers 181 this.fakeElement.off('jcf-pointerdown', this.onPress); 182 this.fakeElement.remove(); 183 184 // remove other event handlers 185 this.doc.off('jcf-pointerup', this.onRelease); 186 this.realElement.off({ 187 blur: this.onBlur, 188 focus: this.onFocus, 189 click: this.onRealClick 190 }); 191 } 192 }; 193}); 194 195}(jcf));
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.