1/*! RateIt | v1.0.18 / 12/22/2013 | https://rateit.codeplex.com/license 2 http://rateit.codeplex.com | Twitter: @gjunge 3*/ 4(function ($) { 5 $.rateit = { 6 aria : { 7 resetLabel: 'reset rating', 8 ratingLabel: 'rating' 9 } 10 } 11 12 $.fn.rateit = function (p1, p2) { 13 //quick way out. 14 var index = 1; 15 var options = {}; var mode = 'init'; 16 var capitaliseFirstLetter = function (string) { 17 return string.charAt(0).toUpperCase() + string.substr(1); 18 }; 19 20 if (this.length == 0) return this; 21 22 23 var tp1 = $.type(p1); 24 if (tp1 == 'object' || p1 === undefined || p1 == null) { 25 options = $.extend({}, $.fn.rateit.defaults, p1); //wants to init new rateit plugin(s). 26 } 27 else if (tp1 == 'string' && p1 !== 'reset' && p2 === undefined) { 28 return this.data('rateit' + capitaliseFirstLetter(p1)); //wants to get a value. 29 } 30 else if (tp1 == 'string') { 31 mode = 'setvalue' 32 } 33 34 return this.each(function () { 35 var item = $(this); 36 37 38 //shorten all the item.data('rateit-XXX'), will save space in closure compiler, will be like item.data('XXX') will become x('XXX') 39 var itemdata = function (key, value) { 40 41 if (value != null) { 42 //update aria values 43 var ariakey = 'aria-value' + ((key == 'value') ? 'now' : key); 44 var range = item.find('.rateit-range'); 45 if (range.attr(ariakey) != undefined) { 46 range.attr(ariakey, value); 47 } 48 49 } 50 51 arguments[0] = 'rateit' + capitaliseFirstLetter(key); 52 return item.data.apply(item, arguments); ////Fix for WI: 523 53 }; 54 55 //handle programmatic reset 56 if (p1 == 'reset') { 57 var setup = itemdata('init'); //get initial value 58 for (var prop in setup) { 59 item.data(prop, setup[prop]); 60 } 61 62 if (itemdata('backingfld')) { //reset also backingfield 63 var fld = $(itemdata('backingfld')); 64 fld.val(itemdata('value')); 65 if (fld[0].min) fld[0].min = itemdata('min'); 66 if (fld[0].max) fld[0].max = itemdata('max'); 67 if (fld[0].step) fld[0].step = itemdata('step'); 68 } 69 item.trigger('reset'); 70 } 71 72 //add the rate it class. 73 if (!item.hasClass('rateit')) item.addClass('rateit'); 74 75 var ltr = item.css('direction') != 'rtl'; 76 77 // set value mode 78 if (mode == 'setvalue') { 79 if (!itemdata('init')) throw 'Can\'t set value before init'; 80 81 82 //if readonly now and it wasn't readonly, remove the eventhandlers. 83 if (p1 == 'readonly' && p2 == true && !itemdata('readonly')) { 84 item.find('.rateit-range').unbind(); 85 itemdata('wired', false); 86 } 87 //when we receive a null value, reset the score to its min value. 88 if (p1 == 'value') 89 p2 = (p2 == null) ? itemdata('min') : Math.max(itemdata('min'), Math.min(itemdata('max'), p2)); 90 if (itemdata('backingfld')) { 91 //if we have a backing field, check which fields we should update. 92 //In case of input[type=range], although we did read its attributes even in browsers that don't support it (using fld.attr()) 93 //we only update it in browser that support it (&& fld[0].min only works in supporting browsers), not only does it save us from checking if it is range input type, it also is unnecessary. 94 var fld = $(itemdata('backingfld')); 95 if (p1 == 'value') fld.val(p2); 96 if (p1 == 'min' && fld[0].min) fld[0].min = p2; 97 if (p1 == 'max' && fld[0].max) fld[0].max = p2; 98 if (p1 == 'step' && fld[0].step) fld[0].step = p2; 99 } 100 101 itemdata(p1, p2); 102 } 103 104 //init rateit plugin 105 if (!itemdata('init')) { 106 107 //get our values, either from the data-* html5 attribute or from the options. 108 itemdata('min', isNaN(itemdata('min')) ? options.min : itemdata('min')); 109 itemdata('max', isNaN(itemdata('max')) ? options.max : itemdata('max')); 110 itemdata('step', itemdata('step') || options.step); 111 itemdata('readonly', itemdata('readonly') !== undefined ? itemdata('readonly') : options.readonly); 112 itemdata('resetable', itemdata('resetable') !== undefined ? itemdata('resetable') : options.resetable); 113 itemdata('backingfld', itemdata('backingfld') || options.backingfld); 114 itemdata('starwidth', itemdata('starwidth') || options.starwidth); 115 itemdata('starheight', itemdata('starheight') || options.starheight); 116 itemdata('value', Math.max(itemdata('min'), Math.min(itemdata('max'), (!isNaN(itemdata('value')) ? itemdata('value') : (!isNaN(options.value) ? options.value : options.min) )))); 117 itemdata('ispreset', itemdata('ispreset') !== undefined ? itemdata('ispreset') : options.ispreset);
118 //are we LTR or RTL? 119 120 if (itemdata('backingfld')) { 121 //if we have a backing field, hide it, and get its value, and override defaults if range. 122 var fld = $(itemdata('backingfld')); 123 itemdata('value', fld.hide().val()); 124 125 if (fld.attr('disabled') || fld.attr('readonly')) 126 itemdata('readonly', true); //http://rateit.codeplex.com/discussions/362055 , if a backing field is disabled or readonly at instantiation, make rateit readonly. 127 128 129 if (fld[0].nodeName == 'INPUT') { 130 if (fld[0].type == 'range' || fld[0].type == 'text') { //in browsers not support the range type, it defaults to text 131 132 itemdata('min', parseInt(fld.attr('min')) || itemdata('min')); //if we would have done fld[0].min it wouldn't have worked in browsers not supporting the range type. 133 itemdata('max', parseInt(fld.attr('max')) || itemdata('max')); 134 itemdata('step', parseInt(fld.attr('step')) || itemdata('step')); 135 } 136 } 137 if (fld[0].nodeName == 'SELECT' && fld[0].options.length > 1) { 138 itemdata('min', Number(fld[0].options[0].value)); 139 itemdata('max', Number(fld[0].options[fld[0].length - 1].value)); 140 itemdata('step', Number(fld[0].options[1].value) - Number(fld[0].options[0].value)); 141 } 142 } 143 144 //Create the necessary tags. For ARIA purposes we need to give the items an ID. So we use an internal index to create unique ids 145 var element = item[0].nodeName == 'DIV' ? 'div' : 'span'; 146 index++; 147 var html = '<button id="rateit-reset-{{index}}" data-role="none" class="rateit-reset" aria-label="' + $.rateit.aria.resetLabel + '" aria-controls="rateit-range-{{index}}"></button><{{element}} id="rateit-range-{{index}}" class="rateit-range" tabindex="0" role="slider" aria-label="' + $.rateit.aria.ratingLabel + '" aria-owns="rateit-reset-{{index}}" aria-valuemin="' + itemdata('min') + '" aria-valuemax="' + itemdata('max') + '" aria-valuenow="' + itemdata('value') + '"><{{element}} class="rateit-selected" style="height:' + itemdata('starheight') + 'px"></{{element}}><{{element}} class="rateit-hover" style="height:' + itemdata('starheight') + 'px"></{{element}}></{{element}}>'; 148 item.append(html.replace(/{{index}}/gi, index).replace(/{{element}}/gi, element)); 149 150 //if we are in RTL mode, we have to change the float of the "reset button" 151 if (!ltr) { 152 item.find('.rateit-reset').css('float', 'right'); 153 item.find('.rateit-selected').addClass('rateit-selected-rtl'); 154 item.find('.rateit-hover').addClass('rateit-hover-rtl'); 155 } 156 157 itemdata('init', JSON.parse(JSON.stringify(item.data()))); //cheap way to create a clone 158 } 159 //resize the height of all elements, 160 item.find('.rateit-selected, .rateit-hover').height(itemdata('starheight')); 161 162 //set the range element to fit all the stars. 163 var range = item.find('.rateit-range'); 164 range.width(itemdata('starwidth') * (itemdata('max') - itemdata('min'))).height(itemdata('starheight')); 165 166 167 //add/remove the preset class 168 var presetclass = 'rateit-preset' + ((ltr) ? '' : '-rtl'); 169 if (itemdata('ispreset')) 170 item.find('.rateit-selected').addClass(presetclass); 171 else 172 item.find('.rateit-selected').removeClass(presetclass); 173 174 //set the value if we have it. 175 if (itemdata('value') != null) { 176 var score = (itemdata('value') - itemdata('min')) * itemdata('starwidth'); 177 item.find('.rateit-selected').width(score); 178 } 179 180 //setup the reset button 181 var resetbtn = item.find('.rateit-reset'); 182 if (resetbtn.data('wired') !== true) { 183 resetbtn.bind('click', function (e) { 184 e.preventDefault(); 185 resetbtn.blur(); 186 item.rateit('value', null); 187 item.trigger('reset'); 188 }).data('wired', true); 189 190 } 191 192 //this function calculates the score based on the current position of the mouse. 193 var calcRawScore = function (element, event) { 194 var pageX = (event.changedTouches) ? event.changedTouches[0].pageX : event.pageX; 195 196 var offsetx = pageX - $(element).offset().left;
197 if (!ltr) offsetx = range.width() - offsetx; 198 if (offsetx > range.width()) offsetx = range.width(); 199 if (offsetx < 0) offsetx = 0; 200 201 return score = Math.ceil(offsetx / itemdata('starwidth') * (1 / itemdata('step'))); 202 }; 203 204 //sets the hover element based on the score. 205 var setHover = function (score) { 206 var w = score * itemdata('starwidth') * itemdata('step'); 207 var h = range.find('.rateit-hover'); 208 if (h.data('width') != w) { 209 range.find('.rateit-selected').hide(); 210 h.width(w).show().data('width', w); 211 var data = [(score * itemdata('step')) + itemdata('min')]; 212 item.trigger('hover', data).trigger('over', data); 213 } 214 }; 215 216 var setSelection = function (value) { 217 itemdata('value', value); 218 if (itemdata('backingfld')) { 219 $(itemdata('backingfld')).val(value); 220 } 221 if (itemdata('ispreset')) { //if it was a preset value, unset that. 222 range.find('.rateit-selected').removeClass(presetclass); 223 itemdata('ispreset', false); 224 } 225 range.find('.rateit-hover').hide(); 226 range.find('.rateit-selected').width(value * itemdata('starwidth') - (itemdata('min') * itemdata('starwidth'))).show(); 227 item.trigger('hover', [null]).trigger('over', [null]).trigger('rated', [value]); 228 }; 229 230 if (!itemdata('readonly')) { 231 //if we are not read only, add all the events 232 233 //if we have a reset button, set the event handler. 234 if (!itemdata('resetable')) 235 resetbtn.hide(); 236 237 //when the mouse goes over the range element, we set the "hover" stars. 238 if (!itemdata('wired')) { 239 range.bind('touchmove touchend', touchHandler); //bind touch events 240 range.mousemove(function (e) { 241 var score = calcRawScore(this, e); 242 setHover(score); 243 }); 244 //when the mouse leaves the range, we have to hide the hover stars, and show the current value. 245 range.mouseleave(function (e) { 246 range.find('.rateit-hover').hide().width(0).data('width', ''); 247 item.trigger('hover', [null]).trigger('over', [null]); 248 range.find('.rateit-selected').show(); 249 }); 250 //when we click on the range, we have to set the value, hide the hover. 251 range.mouseup(function (e) { 252 var score = calcRawScore(this, e); 253 var value = (score * itemdata('step')) + itemdata('min'); 254 setSelection(value); 255 range.blur(); 256 }); 257 258 //support key nav 259 range.keyup( function (e) { 260 if (e.which == 38 || e.which == (ltr ? 39 : 37)) { 261 setSelection(Math.min(itemdata('value') + itemdata('step'), itemdata('max'))); 262 } 263 if (e.which == 40 || e.which == (ltr ? 37 : 39)) { 264 setSelection(Math.max(itemdata('value') - itemdata('step'), itemdata('min'))); 265 } 266 }); 267 268 itemdata('wired', true); 269 } 270 if (itemdata('resetable')) { 271 resetbtn.show(); 272 } 273 } 274 else { 275 resetbtn.hide(); 276 } 277 278 range.attr('aria-readonly', itemdata('readonly')); 279 }); 280 }; 281 282 //touch converter http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/ 283 function touchHandler(event) { 284 285 var touches = event.originalEvent.changedTouches, 286 first = touches[0], 287 type = ""; 288 switch (event.type) { 289 case "touchmove": type = "mousemove"; break; 290 case "touchend": type = "mouseup"; break; 291 default: return; 292 } 293 294 var simulatedEvent = document.createEvent("MouseEvent"); 295 simulatedEvent.initMouseEvent(type, true, true, window, 1, 296 first.screenX, first.screenY, 297 first.clientX, first.clientY, false, 298 false, false, false, 0/*left*/, null); 299 300 first.target.dispatchEvent(simulatedEvent); 301 event.preventDefault(); 302 }; 303 304 //some default values. 305 $.fn.rateit.defaults = { min: 0, max: 5, step: 0.5, starwidth: 16, starheight: 16, readonly: false, resetable: true, ispreset: false}; 306 307 //invoke it on all .rateit elements. This could be removed if not wanted. 308 $(function () { $('div.rateit, span.rateit').rateit(); }); 309 310})(jQuery);
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.