1(function($) { 2 var trailingSlash = $('html').attr('data-trailing-slash'), 3 idCounter = 0; 4 window.user_trailingslashit = function (value) { 5 value = (value || '').toString(); 6 if(trailingSlash && value.match('\/$') != '/') value += trailingSlash; 7 return value; 8 }; 9 10 $(document).ready(function() { 11 var $body = $('body') 12 ,touched = false 13 ,detectMouse = function(event){ 14 if(event.type == 'touchstart') touched = true; 15 else if(!touched && event.type == 'mousemove') fpClientUtil.device.usingMouse = true; 16 $body.off('touchstart mousemove', detectMouse); 17 }; 18 $body.on('touchstart mousemove', detectMouse); 19 }); 20 21 window.fpClientUtil = { 22 //expects YYYY-MM-DD 23 formatDate: function(value) { 24 var temp = (value || '').toString().split(' ')[0].split('-'); 25 return temp[1] + '/' + temp[2] + '/' + temp[0]; 26 } 27 ,msie: function() { 28 if(this._msie != null) return this._msie; 29 var ua = window.navigator.userAgent 30 ,index = ua.indexOf('MSIE '); 31 this._msie = index >= 0 ? parseInt(ua.substring(index + 5, ua.indexOf('.', index)), 10) : 0; 32 if(!this._msie && 'ActiveXObject' in window) this._msie = 11; 33 return this._msie; 34 } 35 ,getStringValue: function(value) { 36 return value != null ? value.toString() : ''; 37 } 38 ,startsWith: function(value, prefix, ignoreCase) { 39 value = this.getStringValue(value); 40 prefix = this.getStringValue(prefix); 41 if(ignoreCase) { 42 value = value.toLowerCase(); 43 prefix = prefix.toLowerCase(); 44 } 45 return value.indexOf(prefix) === 0; 46 } 47 ,endsWith: function(value, suffix, ignoreCase) { 48 value = this.getStringValue(value); 49 suffix = this.getStringValue(suffix); 50 if(ignoreCase) { 51 value = value.toLowerCase(); 52 suffix = suffix.toLowerCase(); 53 } 54 return value.match(suffix+"$") == suffix; 55 } 56 ,contains: function(value, suffix, ignoreCase) { 57 value = this.getStringValue(value); 58 suffix = this.getStringValue(suffix); 59 if(ignoreCase) { 60 value = value.toLowerCase(); 61 suffix = suffix.toLowerCase(); 62 } 63 return value.indexOf(suffix) >= 0; 64 } 65 ,eq: function(value1, value2, ignoreCase) { 66 value1 = this.getStringValue(value1); 67 value2 = this.getStringValue(value2); 68 if(ignoreCase) { 69 value1 = value1.toLowerCase(); 70 value2 = value2.toLowerCase(); 71 } 72 return value1 === value2; 73 } 74 ,concatUrlHashParam: function(url, paramName, paramValue) { 75 if(url && paramName) { 76 const urlParts = url.split(`${paramName}=`); 77 if(urlParts.length > 1) { 78 url = urlParts[0] + (urlParts[1].indexOf('&') !== -1 ? urlParts[1].split('&')[1] : ''); 79 } 80 const hashBang = '#!/?', 81 hashIndex = url.indexOf(hashBang); 82 if(paramValue) { 83 if(hashIndex === -1) { 84 url += hashBang; 85 } 86 if(url.split(hashBang)[1]) { 87 url += '&'; 88 } 89 url = `${url}${paramName}=${paramValue}`; 90 } 91 else if(hashIndex + hashBang.length === url.length){ 92 url = url.replace(hashBang, ''); 93 } 94 } 95 return url; 96 } 97 ,device: { 98 hasTouch: 'ontouchstart' in document.documentElement 99 ,usingMouse: false 100 }, 101 uniqueId: function uniqueId(prefix) { 102 const id = ++idCounter + ''; 103 return prefix ? prefix + id : id; 104 }, 105 isNumeric: function(value) { 106 return !isNaN(parseFloat(value)) && isFinite(value); 107 }, 108 sort: function(array, key, desc) { 109 if(!($.isArray(array) && array.length > 1)) return array; 110 key = (key && typeof(array[0]) === 'object') ? key : null; 111 const self = this; 112 array.sort(function(a, b) { 113 return self.sortHelper(a, b, key, desc); 114 }); 115 return array; 116 }, 117 sortHelper: function(a, b, key, desc) { 118 if(key) { 119 a = a[key]; 120 b = b[key]; 121 } 122 123 a = a || 0; 124 b = b || 0; 125 126 if(typeof(a) === 'string') { 127 a = this.isNumeric(a) ? parseFloat(a) : a.toLowerCase(); 128 } 129 if(typeof(b) === 'string') { 130 b = this.isNumeric(b) ? parseFloat(b) : b.toLowerCase(); 131 } 132 133 if(a instanceof Date && b instanceof Date) { 134 return desc ? b - a : a - b; 135 } 136 137 if(desc) return (a == b) ? 0 : (b > a) ? 1 : -1; 138 return (a == b) ? 0 : (a > b) ? 1 : -1; 139 }, 140 /*** 141 Copyright 2013 Teun Duynstee 142 https://github.com/Teun/thenBy.js/tree/master 143 */ 144 sortFirstBy: (function() { 145 function identity(v){return v;} 146 147 function ignoreCase(v){return typeof(v)==="string" ? v.toLowerCase() : v;} 148 149 function makeCompareFunction(f, opt){ 150 opt = typeof(opt)==="number" ? {direction:opt} : opt||{}; 151 if(typeof(f)!="function"){ 152 var prop = f; 153 // make unary function 154 f = function(v1){return !!v1[prop] ? v1[prop] : "";} 155 } 156 if(f.length === 1) { 157 // f is a unary function mapping a single item to its sort score 158 var uf = f; 159 var preprocess = opt.ignoreCase?ignoreCase:identity; 160 f = function(v1,v2) {return preprocess(uf(v1)) < preprocess(uf(v2)) ? -1 : preprocess(uf(v1)) > preprocess(uf(v2)) ? 1 : 0;} 161 } 162 if(opt.direction === -1)return function(v1,v2){return -f(v1,v2)}; 163 return f; 164 } 165 166 /* adds a secondary compare function to the target function (`this` context)
167 which is applied in case the first one returns 0 (equal) 168 returns a new compare function, which has a `thenBy` method as well */ 169 function tb(func, opt) { 170 var x = typeof(this) == "function" ? this : false; 171 var y = makeCompareFunction(func, opt); 172 var f = x ? function(a, b) { 173 return x(a,b) || y(a,b); 174 } 175 : y; 176 f.thenBy = tb; 177 return f; 178 } 179 return tb; 180 })(), 181 getMobilePhoneHtml: function(value) { 182 if(typeof(value) === 'string' && !/<a\s.*?href=["']tel:/gim.test(value)) { 183 const matchPhone = /(\+?(\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4})|(\+?(\d{1})?\d{10})/g, 184 matchNumeric = /\d+/g; 185 value = value.replace(matchPhone, function(match) { 186 matchNumeric.lastIndex = 0; 187 const phoneNumber = match.match(matchNumeric).join(''), 188 phone = match; 189 return `<a href="tel:${phoneNumber}">${phone}</a>`; 190 }); 191 } 192 return value; 193 } 194 }; 195 196 $.fn.dropdown = function(options) { 197 function dropdown($element, options){ 198 this.$element = $($element); 199 if(this.$element.data('dropdown')) this.$element.data('dropdown').destroy(); 200 if($.isFunction(options)) options = {onchange: options}; 201 this.options = $.extend({onchange: $.noop}, options); 202 var me = this 203 ,$menu = me.$element.find('> .dropdown-menu'); 204 205 this.__close = function(event) { 206 me.close(0); 207 }; 208 this.__onKeyup = function(event) { 209 me.onKeyup(event); 210 }; 211 212 var $combined = this.$element.add($menu) 213 .on('click', function(event) { 214 event.preventDefault(); 215 event.stopImmediatePropagation(); 216 if(!me.$list.length) return; 217 218 clearTimeout(me.closeTimerId); 219 me.$element.toggleClass('is-dropdown-open'); 220 if(me.$element.hasClass('is-dropdown-open')) { 221 $(document.body).addClass('is-dropdown-open'); 222 $(document) 223 .trigger('close.dropdown.sd') 224 .off('click', me.__close).on('click', me.__close) 225 .off('keyup', me.__onKeyup).on('keyup', me.__onKeyup) 226 .off('close.dropdown.sd', me.__close).on('close.dropdown.sd', me.__close); 227 var borderWidth = parseInt(me.$element.css('border-left-width'), 10) 228 ,offset = me.$element.offset() 229 ,css = {} 230 ,$item = me.__getSelected() 231 ,windowWidth = $(window).width(); 232 233 $menu.removeClass('right'); 234 var width = $menu.outerWidth() 235 ,left = offset.left + borderWidth * 0.5; 236 if(left + width > windowWidth) $menu.addClass('right'); 237 238 if($item.length) { 239 var $list = $item.closest('.dropdown-list'); 240 $list.scrollTop($item.position().top + $list.scrollTop() - ($list.parent().height() - $item.height()) * 0.5); 241 } 242 } 243 else me.close(0); 244 }) 245 .on('click', '.dropdown-list > li a', function(event) { 246 event.preventDefault(); 247 me.__setSelected($(this)); 248 }) 249 .on('mouseover', function(event) { 250 if(!fpClientUtil.device.usingMouse) return; 251 if(event.target == $menu[0]) return; 252 253 clearTimeout(me.closeTimerId); 254 }) 255 .on('mouseout', function(event) { 256 if(!fpClientUtil.device.usingMouse) return; 257 me.close(); 258 }); 259 260 this.$list = $menu.find('.dropdown-list > li a'); 261 262 var value = fpClientUtil.getStringValue(this.getValue()); 263 if(!value.length) { 264 value = this.$element.find('> input[type="hidden"]').first().val(); 265 if(value) this.setValue(value, true); 266 else this.__setSelected(this.$list.filter('[data-selected="true"]'), true); 267 } 268 269 this.$element.data('dropdown', this); 270 } 271 272 dropdown.prototype.onChange = function() { 273 this.options.onchange.call(this.$element[0], this.value); 274 };
275 //keyup is called in the contect of the document 276 dropdown.prototype.onKeyup = function(event) { 277 event.preventDefault(); 278 event.stopImmediatePropagation(); 279 280 var util = fpClientUtil 281 ,$item 282 ,$key; 283 if (event.key !== undefined) { 284 // ff supports key 285 $key = event.key; 286 } 287 else if (event.keyCode !== undefined) { 288 // Chrome supports keycode 289 $key = String.fromCharCode(event.keyCode); 290 } 291 292 if((/[a-z0-9]/i).test($key)) { 293 var me = this.$element.data('dropdown'); 294 me.$list.each(function() { 295 $item = $(this); 296 if(fpClientUtil.startsWith($item.text(), $key, true)) { 297 me.__setSelected($item); 298 var $list = $item.closest('.dropdown-list'); 299 $list.scrollTop($item.position().top + $list.scrollTop() - ($list.parent().height() - $item.height()) * 0.5); 300 return false; 301 } 302 }); 303 } 304 }; 305 dropdown.prototype.getValue = function() { 306 return this.value; 307 }; 308 dropdown.prototype.setValue = function(value) { 309 var me = this 310 ,util = fpClientUtil; 311 value = util.getStringValue(value); 312 if(value.length) { 313 var $this 314 ,thisValue; 315 this.$list.each(function() { 316 $this = $(this); 317 thisValue = $this.attr('data-value') || $this.text(); 318 if(util.eq(thisValue, value, true)) { 319 me.__setSelected($this, true); 320 return false; 321 } 322 }); 323 } 324 else me.__setSelected(null, true); 325 }; 326 dropdown.prototype.__getSelected = function() { 327 return this.$list.filter('.is-selected'); 328 }; 329 dropdown.prototype.__setSelected = function($item, isInit) { 330 var text 331 ,selectedValue; 332 if($item) { 333 if(typeof($item) === 'string') text = selectedValue = $item; 334 else if($item && $item.jquery && $item.length) { 335 var prevItem; 336 text = $item.html(); 337 selectedValue = fpClientUtil.getStringValue($item.attr('data-value')); 338 this.$list.each(function() { 339 var $this = $(this).removeClass('is-selected'); 340 if($this.attr('data-selected')) { 341 $this.removeAttr('data-selected'); 342 prevItem = $this[0]; 343 } 344 }); 345 $item.addClass('is-selected').attr('data-selected', true); 346 selectedValue = selectedValue.length > 0 ? selectedValue : text; 347 } 348 } 349 if(!text) text = selectedValue = fpClientUtil.getStringValue(this.$element.attr('data-default')); 350 this.$element.find('> .dropdown-value .value').html(text); 351 352 if(this.$element.attr('data-default') != selectedValue) this.$element.addClass('has-value'); 353 else { 354 selectedValue = ''; 355 this.$element.removeClass('has-value'); 356 } 357 this.$element.find('> input[type="hidden"]').val(selectedValue); 358 this.value = selectedValue; 359 if(!isInit && (!$item || ($item && $item[0] != prevItem))) this.onChange(); 360 }; 361 dropdown.prototype.close = function(ms) { 362 ms = (ms != null ? ms : 100); 363 var me = this; 364 clearTimeout(me.closeTimerId); 365 if(ms) me.closeTimerId = setTimeout(close, ms); 366 else close(); 367 368 function close() { 369 $(document.body).removeClass('is-dropdown-open'); 370 $(document) 371 .off('click', me.__close) 372 .off('keyup', me.__onKeyup) 373 .off('close.dropdown.sd', this.__close); 374 me.$element.removeClass('is-dropdown-open'); 375 } 376 }; 377 dropdown.prototype.destroy = function() { 378 this.close(0); 379 //this.setValue(); 380 this.$list.off(); 381 $(document) 382 .off('click', this.__close) 383 .off('keyup', this.__onKeyup) 384 .off('close.dropdown.sd', this.__close); 385 var $menu = this.$element.find('> .dropdown-menu'); 386 this.$element.add($menu).off(); 387 this.$element.removeData('dropdown'); 388 }; 389 390 return this.each(function() { 391 var $this = $(this); 392 if($this.data('dropdown')) $this.data('dropdown').destroy(); 393 $this.data('dropdown', new dropdown($this, options)); 394 }); 395 }; 396 397 398 $.urlParam = function(name){ 399 var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href); 400 return results && results[1]; 401 }; 402 403 $.fn.cleanWhitespace = function() { 404 textNodes = this.contents().filter( 405 function() { return (this.nodeType == 3 && !/\S/.test(this.nodeValue)); }) 406 .remove(); 407 return this; 408 }; 409 410 $.fn.outerHTML = function() { 411 var el = this[0]; 412 if(el && el.outerHTML) return el.outerHTML; 413 var $p = $('<p>').append(this.eq(0).clone()) 414 ,html = $p.html(); 415 $p.remove(); 416 return html; 417 }; 418})(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.