1/*! 2 * is.js 0.9.0 3 * Author: Aras Atasaygin 4 */ 5 6// AMD with global, Node, or global 7;(function(root, factory) { // eslint-disable-line no-extra-semi 8 if (typeof define === 'function' && define.amd) { 9 // AMD. Register as an anonymous module. 10 define(function() { 11 // Also create a global in case some scripts 12 // that are loaded still are looking for 13 // a global even when an AMD loader is in use. 14 return (root.is = factory()); 15 }); 16 } else if (typeof exports === 'object') { 17 // Node. Does not work with strict CommonJS, but 18 // only CommonJS-like enviroments that support module.exports, 19 // like Node. 20 module.exports = factory(); 21 } else { 22 // Browser globals (root is self) 23 root.is = factory(); 24 } 25}(this, function() { 26 27 // Baseline 28 /* -------------------------------------------------------------------------- */ 29 30 // define 'is' object and current version 31 var is = {}; 32 is.VERSION = '0.8.0'; 33 34 // define interfaces 35 is.not = {}; 36 is.all = {}; 37 is.any = {}; 38 39 // cache some methods to call later on 40 var toString = Object.prototype.toString; 41 var slice = Array.prototype.slice; 42 var hasOwnProperty = Object.prototype.hasOwnProperty; 43 44 // helper function which reverses the sense of predicate result 45 function not(func) { 46 return function() { 47 return !func.apply(null, slice.call(arguments)); 48 }; 49 } 50 51 // helper function which call predicate function per parameter and return true if all pass 52 function all(func) { 53 return function() { 54 var params = getParams(arguments); 55 var length = params.length; 56 for (var i = 0; i < length; i++) { 57 if (!func.call(null, params[i])) { 58 return false; 59 } 60 } 61 return true; 62 }; 63 } 64 65 // helper function which call predicate function per parameter and return true if any pass 66 function any(func) { 67 return function() { 68 var params = getParams(arguments); 69 var length = params.length; 70 for (var i = 0; i < length; i++) { 71 if (func.call(null, params[i])) { 72 return true; 73 } 74 } 75 return false; 76 }; 77 } 78 79 // build a 'comparator' object for various comparison checks 80 var comparator = { 81 '<': function(a, b) { return a < b; }, 82 '<=': function(a, b) { return a <= b; }, 83 '>': function(a, b) { return a > b; }, 84 '>=': function(a, b) { return a >= b; } 85 } 86 87 // helper function which compares a version to a range 88 function compareVersion(version, range) { 89 var string = (range + ''); 90 var n = +(string.match(/\d+/) || NaN); 91 var op = string.match(/^[<>]=?|/)[0]; 92 return comparator[op] ? comparator[op](version, n) : (version == n || n !== n); 93 } 94 95 // helper function which extracts params from arguments 96 function getParams(args) { 97 var params = slice.call(args); 98 var length = params.length; 99 if (length === 1 && is.array(params[0])) { // support array 100 params = params[0]; 101 } 102 return params; 103 } 104 105 // Type checks 106 /* -------------------------------------------------------------------------- */ 107 108 // is a given value Arguments? 109 is.arguments = function(value) { // fallback check is for IE 110 return toString.call(value) === '[object Arguments]' || 111 (value != null && typeof value === 'object' && 'callee' in value); 112 }; 113 114 // is a given value Array? 115 is.array = Array.isArray || function(value) { // check native isArray first 116 return toString.call(value) === '[object Array]'; 117 }; 118 119 // is a given value Boolean? 120 is.boolean = function(value) { 121 return value === true || value === false || toString.call(value) === '[object Boolean]'; 122 }; 123 124 // is a given value Char? 125 is.char = function(value) { 126 return is.string(value) && value.length === 1; 127 }; 128 129 // is a given value Date Object? 130 is.date = function(value) { 131 return toString.call(value) === '[object Date]'; 132 }; 133 134 // is a given object a DOM node? 135 is.domNode = function(object) { 136 return is.object(object) && object.nodeType > 0; 137 }; 138 139 // is a given value Error object? 140 is.error = function(value) { 141 return toString.call(value) === '[object Error]'; 142 }; 143 144 // is a given value function? 145 is['function'] = function(value) { // fallback check is for IE 146 return toString.call(value) === '[object Function]' || typeof value === 'function'; 147 }; 148 149 // is given value a pure JSON object? 150 is.json = function(value) { 151 return toString.call(value) === '[object Object]'; 152 }; 153 154 // is a given value NaN? 155 is.nan = function(value) { // NaN is number :) Also it is the only value which does not equal itself 156 return value !== value; 157 }; 158 159 // is a given value null? 160 is['null'] = function(value) { 161 return value === null; 162 }; 163 164 // is a given value number? 165 is.number = function(value) { 166 return is.not.nan(value) && toString.call(value) === '[object Number]'; 167 }; 168 169 // is a given value object? 170 is.object = function(value) { 171 return Object(value) === value; 172 }; 173 174 // is a given value RegExp? 175 is.regexp = function(value) { 176 return toString.call(value) === '[object RegExp]'; 177 }; 178 179 // are given values same type? 180 // prevent NaN, Number same type check 181 is.sameType = function(value, other) { 182 var tag = toString.call(value); 183 if (tag !== toString.call(other)) { 184 return false;
185 } 186 if (tag === '[object Number]') { 187 return !is.any.nan(value, other) || is.all.nan(value, other); 188 } 189 return true; 190 }; 191 // sameType method does not support 'all' and 'any' interfaces 192 is.sameType.api = ['not']; 193 194 // is a given value String? 195 is.string = function(value) { 196 return toString.call(value) === '[object String]'; 197 }; 198 199 // is a given value undefined? 200 is.undefined = function(value) { 201 return value === void 0; 202 }; 203 204 // is a given value window? 205 // setInterval method is only available for window object 206 is.windowObject = function(value) { 207 return value != null && typeof value === 'object' && 'setInterval' in value; 208 }; 209 210 // Presence checks 211 /* -------------------------------------------------------------------------- */ 212 213 //is a given value empty? Objects, arrays, strings 214 is.empty = function(value) { 215 if (is.object(value)) { 216 var length = Object.getOwnPropertyNames(value).length; 217 if (length === 0 || (length === 1 && is.array(value)) || 218 (length === 2 && is.arguments(value))) { 219 return true; 220 } 221 return false; 222 } 223 return value === ''; 224 }; 225 226 // is a given value existy? 227 is.existy = function(value) { 228 return value != null; 229 }; 230 231 // is a given value falsy? 232 is.falsy = function(value) { 233 return !value; 234 }; 235 236 // is a given value truthy? 237 is.truthy = not(is.falsy); 238 239 // Arithmetic checks 240 /* -------------------------------------------------------------------------- */ 241 242 // is a given number above minimum parameter? 243 is.above = function(n, min) { 244 return is.all.number(n, min) && n > min; 245 }; 246 // above method does not support 'all' and 'any' interfaces 247 is.above.api = ['not']; 248 249 // is a given number decimal? 250 is.decimal = function(n) { 251 return is.number(n) && n % 1 !== 0; 252 }; 253 254 // are given values equal? supports numbers, strings, regexes, booleans 255 // TODO: Add object and array support 256 is.equal = function(value, other) { 257 // check 0 and -0 equity with Infinity and -Infinity 258 if (is.all.number(value, other)) { 259 return value === other && 1 / value === 1 / other; 260 } 261 // check regexes as strings too 262 if (is.all.string(value, other) || is.all.regexp(value, other)) { 263 return '' + value === '' + other; 264 } 265 if (is.all.boolean(value, other)) { 266 return value === other; 267 } 268 return false; 269 }; 270 // equal method does not support 'all' and 'any' interfaces 271 is.equal.api = ['not']; 272 273 // is a given number even? 274 is.even = function(n) { 275 return is.number(n) && n % 2 === 0; 276 }; 277 278 // is a given number finite? 279 is.finite = isFinite || function(n) { 280 return is.not.infinite(n) && is.not.nan(n); 281 }; 282 283 // is a given number infinite? 284 is.infinite = function(n) { 285 return n === Infinity || n === -Infinity; 286 }; 287 288 // is a given number integer? 289 is.integer = function(n) { 290 return is.number(n) && n % 1 === 0; 291 }; 292 293 // is a given number negative? 294 is.negative = function(n) { 295 return is.number(n) && n < 0; 296 }; 297 298 // is a given number odd? 299 is.odd = function(n) { 300 return is.number(n) && n % 2 === 1; 301 }; 302 303 // is a given number positive? 304 is.positive = function(n) { 305 return is.number(n) && n > 0; 306 }; 307 308 // is a given number above maximum parameter? 309 is.under = function(n, max) { 310 return is.all.number(n, max) && n < max; 311 }; 312 // least method does not support 'all' and 'any' interfaces 313 is.under.api = ['not']; 314 315 // is a given number within minimum and maximum parameters? 316 is.within = function(n, min, max) { 317 return is.all.number(n, min, max) && n > min && n < max; 318 }; 319 // within method does not support 'all' and 'any' interfaces 320 is.within.api = ['not']; 321 322 // Regexp checks 323 /* -------------------------------------------------------------------------- */ 324 // Steven Levithan, Jan Goyvaerts: Regular Expressions Cookbook 325 // Scott Gonzalez: Email address validation 326 327 // dateString match m/d/yy and mm/dd/yyyy, allowing any combination of one or tw
327o digits for the day and month, and two or four digits for the year 328 // eppPhone match extensible provisioning protocol format 329 // nanpPhone match north american number plan format 330 // time match hours, minutes, and seconds, 24-hour clock 331 var regexes = { 332 affirmative: /^(?:1|t(?:rue)?|y(?:es)?|ok(?:ay)?)$/, 333 alphaNumeric: /^[A-Za-z0-9]+$/, 334 caPostalCode: /^(?!.*[DFIOQU])[A-VXY][0-9][A-Z]\s?[0-9][A-Z][0-9]$/, 335 creditCard: /^(?:(4[0-9]{12}(?:[0-9]{3})?)|(5[1-5][0-9]{14})|(6(?:011|5[0-9]{2})[0-9]{12})|(3[47][0-9]{13})|(3(?:0[0-5]|[68][0-9])[0-9]{11})|((?:2131|1800|35[0-9]{3})[0-9]{11}))$/, 336 dateString: /^(1[0-2]|0?[1-9])([\/-])(3[01]|[12][0-9]|0?[1-9])(?:\2)(?:[0-9]{2})?[0-9]{2}$/, 337 email: /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i, // eslint-disable-line no-control-regex 338 eppPhone: /^\+[0-9]{1,3}\.[0-9]{4,14}(?:x.+)?$/, 339 hexadecimal: /^(?:0x)?[0-9a-fA-F]+$/, 340 hexColor: /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/, 341 ipv4: /^(?:(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/, 342 ipv6: /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i, 343 nanpPhone: /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/, 344 socialSecurityNumber: /^(?!000|666)[0-8][0-9]{2}-?(?!00)[0-9]{2}-?(?!0000)[0-9]{4}$/, 345 timeString: /^(2[0-3]|[01]?[0-9]):([0-5]?[0-9]):([0-5]?[0-9])$/, 346 ukPostCode: /^[A-Z]{1,2}[0-9RCHNQ][0-9A-Z]?\s?[0-9][ABD-HJLNP-UW-Z]{2}$|^[A-Z]{2}-?[0-9]{4}$/, 347 url: /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/i, 348 usZipCode: /^[0-9]{5}(?:-[0-9]{4})?$/ 349 }; 350 351 function regexpCheck(regexp, regexes) { 352 is[regexp] = function(value) { 353 return regexes[regexp].test(value); 354 }; 355 } 356 357 // create regexp checks methods from 'regexes' object 358 for (var regexp in regexes) { 359 if (regexes.hasOwnProperty(regexp)) { 360 regexpCheck(regexp, regexes); 361 } 362 } 363 364 // simplify IP checks by calling the regex helpers for IPv4 and IPv6 365 is.ip = function(value) { 366 return is.ipv4(value) || is.ipv6(value); 367 }; 368 369 // String checks 370 /* -------------------------------------------------------------------------- */ 371 372 // is a given string or sentence capitalized? 373 is.capitalized = function(string) { 374 if (is.not.string(string)) { 375 return false; 376 } 377 var words = string.split(' '); 378 for (var i = 0; i < words.length; i++) { 379 var word = words[i]; 380 if (word.length) { 381 var chr = word.charAt(0); 382 if (chr !== chr.toUpperCase()) { 383 return false; 384 } 385 } 386 } 387 return true; 388 }; 389 390 // is string end with a given target parameter? 391 is.endWith = function(string, target) { 392 if (is.not.string(string)) { 393 return false;
394 } 395 target += ''; 396 var position = string.length - target.length; 397 return position >= 0 && string.indexOf(target, position) === position; 398 }; 399 // endWith method does not support 'all' and 'any' interfaces 400 is.endWith.api = ['not']; 401 402 // is a given string include parameter target? 403 is.include = function(string, target) { 404 return string.indexOf(target) > -1; 405 }; 406 // include method does not support 'all' and 'any' interfaces 407 is.include.api = ['not']; 408 409 // is a given string all lowercase? 410 is.lowerCase = function(string) { 411 return is.string(string) && string === string.toLowerCase(); 412 }; 413 414 // is a given string palindrome? 415 is.palindrome = function(string) { 416 if (is.not.string(string)) { 417 return false; 418 } 419 string = string.replace(/[^a-zA-Z0-9]+/g, '').toLowerCase(); 420 var length = string.length - 1; 421 for (var i = 0, half = Math.floor(length / 2); i <= half; i++) { 422 if (string.charAt(i) !== string.charAt(length - i)) { 423 return false; 424 } 425 } 426 return true; 427 }; 428 429 // is a given value space? 430 // horizantal tab: 9, line feed: 10, vertical tab: 11, form feed: 12, carriage return: 13, space: 32 431 is.space = function(value) { 432 if (is.not.char(value)) { 433 return false; 434 } 435 var charCode = value.charCodeAt(0); 436 return (charCode > 8 && charCode < 14) || charCode === 32; 437 }; 438 439 // is string start with a given target parameter? 440 is.startWith = function(string, target) { 441 return is.string(string) && string.indexOf(target) === 0; 442 }; 443 // startWith method does not support 'all' and 'any' interfaces 444 is.startWith.api = ['not']; 445 446 // is a given string all uppercase? 447 is.upperCase = function(string) { 448 return is.string(string) && string === string.toUpperCase(); 449 }; 450 451 // Time checks 452 /* -------------------------------------------------------------------------- */ 453 454 var days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; 455 var months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december']; 456 457 // is a given dates day equal given day parameter? 458 is.day = function(date, day) { 459 return is.date(date) && day.toLowerCase() === days[date.getDay()]; 460 }; 461 // day method does not support 'all' and 'any' interfaces 462 is.day.api = ['not']; 463 464 // is a given date in daylight saving time? 465 is.dayLightSavingTime = function(date) { 466 var january = new Date(date.getFullYear(), 0, 1); 467 var july = new Date(date.getFullYear(), 6, 1); 468 var stdTimezoneOffset = Math.max(january.getTimezoneOffset(), july.getTimezoneOffset()); 469 return date.getTimezoneOffset() < stdTimezoneOffset; 470 }; 471 472 // is a given date future? 473 is.future = function(date) { 474 var now = new Date(); 475 return is.date(date) && date.getTime() > now.getTime(); 476 }; 477 478 // is date within given range? 479 is.inDateRange = function(date, start, end) { 480 if (is.not.date(date) || is.not.date(start) || is.not.date(end)) { 481 return false; 482 } 483 var stamp = date.getTime(); 484 return stamp > start.getTime() && stamp < end.getTime(); 485 }; 486 // inDateRange method does not support 'all' and 'any' interfaces 487 is.inDateRange.api = ['not']; 488 489 // is a given date in last month range? 490 is.inLastMonth = function(date) { 491 return is.inDateRange(date, new Date(new Date().setMonth(new Date().getMonth() - 1)), new Date()); 492 }; 493 494 // is a given date in last week range? 495 is.inLastWeek = function(date) { 496 return is.inDateRange(date, new Date(new Date().setDate(new Date().getDate() - 7)), new Date()); 497 }; 498 499 // is a given date in last year range? 500 is.inLastYear = function(date) { 501 return is.inDateRange(date, new Date(new Date().setFullYear(new Date().getFullYear() - 1)), new Date()); 502 }; 503 504 // is a given date in next month range? 505 is.inNextMonth = function(date) { 506 return is.inDateRange(date, new Date(), new Date(new Date().setMonth(new Date().getMonth() + 1))); 507 }; 508 509 // is a given date in next week range? 510 is.inNextWeek = function(date) { 511 return is.inDateRange(date, new Date(), new Date(new Date().setDate(new Date().getDate() + 7))); 512 }; 513 514 // is a given date in next year range? 515 is.inNextYear = function(date) { 516 return is.inDateRange(date, new Date(), new Date(new Date().setFullYear(new Date().getFullYear() + 1))); 517 }; 518 519 // is the given year a leap year? 520 is.leapYear = function(year) { 521 return is.number(year) && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0); 522 }; 523 524 // is a given dates month equal given month parameter? 525 is.month = function(date, month) { 526 return is.date(date) && month.toLowerCase() === months[date.getMonth()]; 527 }; 528 // month method does not support 'all' and 'any' interfaces 529 is.month.api = ['not']; 530 531 // is a given date past? 532 is.past = function(date) { 533 var now = new Date(); 534 return is.date(date) && date.getTime() < now.getTime(); 535 }; 536 537 // is a given date in the parameter quarter? 538 is.quarterOfYear = function(date, quarter) { 539 return is.date(date) && is.number(quarter) && quarter === Math.floor((date.getMonth() + 3) / 3); 540 }; 541 // quarterOfYear method does not support 'all' and 'any' interfaces 542 is.quarterOfYear.api = ['not']; 543 544 // is a given date indicate today? 545 is.today = function(date) { 546 var now = new Date(); 547 var todayString = now.toDateString(); 548 return is.date(date) && date.toDateString() === todayString; 549 }; 550 551 // is a given date indicate tomorrow? 552 is.tomorrow = function(date) { 553 var now = new Date(); 554 var tomorrowString = new Date(now.setDate(now.getDate() + 1)).toDateString(); 555 return is.date(date) && date.toDateString() === tomorrowString; 556 }; 557 558 // is a given date weekend? 559 // 6: Saturday, 0: Sunday 560 is.weekend = function(date) { 561 return is.date(date) && (date.getDay() === 6 || date.getDay() === 0); 562 }; 563 564 // is a given date weekday? 565 is.weekday = not(is.weekend); 566 567 // is a given dates year equal given year parameter? 568 is.year = function(date, year) { 569 return is.date(date) && is.number(year) && year === date.getFullYear(); 570 }; 571 // year method does not support 'all' and 'any' interfaces 572 is.year.api = ['not']; 573 574 // is a given date indicate yesterday? 575 is.yesterday = function(date) { 576 var now = new Date(); 577 var yesterdayString = new Date(now.setDate(now.getDate() - 1)).toDateString(); 578 return is.date(date) && date.toDateString() === yesterdayString; 579 }; 580 581 // Environment checks 582 /* -------------------------------------------------------------------------- */ 583 584 var freeGlobal = is.windowObject(typeof global == 'object' && global) && global; 585 var freeSelf = is.windowObject(typeof self == 'object' && self) && self; 586 var thisGlobal = is.windowObject(typeof this == 'object' && this) && this; 587 var root = freeGlobal || freeSelf || thisGlobal || Function('return this')(); 588 589 var document = freeSelf && freeSelf.document; 590 var previousIs = root.is; 591 592 // store navigator properties to use later 593 var navigator = freeSelf && freeSelf.navigator; 594 var appVersion = (navigator && navigator.appVersion || '').toLowerCase(); 595 var userAgent = (navigator && navigator.userAgent || '').toLowerCase(); 596 var vendor = (navigator && navigator.vendor || '').toLowerCase(); 597 598 // is current device android? 599 is.android = function() { 600 return /android/.test(userAgent); 601 }; 602 // android method does not support 'all' and 'any' interfaces 603 is.android.api = ['not']; 604
605 // is current device android phone? 606 is.androidPhone = function() { 607 return /android/.test(userAgent) && /mobile/.test(userAgent); 608 }; 609 // androidPhone method does not support 'all' and 'any' interfaces 610 is.androidPhone.api = ['not']; 611 612 // is current device android tablet? 613 is.androidTablet = function() { 614 return /android/.test(userAgent) && !/mobile/.test(userAgent); 615 }; 616 // androidTablet method does not support 'all' and 'any' interfaces 617 is.androidTablet.api = ['not']; 618 619 // is current device blackberry? 620 is.blackberry = function() { 621 return /blackberry/.test(userAgent) || /bb10/.test(userAgent); 622 }; 623 // blackberry method does not support 'all' and 'any' interfaces 624 is.blackberry.api = ['not']; 625 626 // is current browser chrome? 627 // parameter is optional 628 is.chrome = function(range) { 629 var match = /google inc/.test(vendor) ? userAgent.match(/(?:chrome|crios)\/(\d+)/) : null; 630 return match !== null && compareVersion(match[1], range); 631 }; 632 // chrome method does not support 'all' and 'any' interfaces 633 is.chrome.api = ['not']; 634 635 // is current device desktop? 636 is.desktop = function() { 637 return is.not.mobile() && is.not.tablet(); 638 }; 639 // desktop method does not support 'all' and 'any' interfaces 640 is.desktop.api = ['not']; 641 642 // is current browser edge? 643 // parameter is optional 644 is.edge = function(range) { 645 var match = userAgent.match(/edge\/(\d+)/); 646 return match !== null && compareVersion(match[1], range); 647 }; 648 // edge method does not support 'all' and 'any' interfaces 649 is.edge.api = ['not']; 650 651 // is current browser firefox? 652 // parameter is optional 653 is.firefox = function(range) { 654 var match = userAgent.match(/(?:firefox|fxios)\/(\d+)/); 655 return match !== null && compareVersion(match[1], range); 656 }; 657 // firefox method does not support 'all' and 'any' interfaces 658 is.firefox.api = ['not']; 659 660 // is current browser internet explorer? 661 // parameter is optional 662 is.ie = function(range) { 663 var match = userAgent.match(/(?:msie |trident.+?; rv:)(\d+)/); 664 return match !== null && compareVersion(match[1], range); 665 }; 666 // ie method does not support 'all' and 'any' interfaces 667 is.ie.api = ['not']; 668 669 // is current device ios? 670 is.ios = function() { 671 return is.iphone() || is.ipad() || is.ipod(); 672 }; 673 // ios method does not support 'all' and 'any' interfaces 674 is.ios.api = ['not']; 675 676 // is current device ipad? 677 // parameter is optional 678 is.ipad = function(range) { 679 var match = userAgent.match(/ipad.+?os (\d+)/); 680 return match !== null && compareVersion(match[1], range); 681 }; 682 // ipad method does not support 'all' and 'any' interfaces 683 is.ipad.api = ['not']; 684 685 // is current device iphone? 686 // parameter is optional 687 is.iphone = function(range) { 688 // original iPhone doesn't have the os portion of the UA 689 var match = userAgent.match(/iphone(?:.+?os (\d+))?/); 690 return match !== null && compareVersion(match[1] || 1, range); 691 }; 692 // iphone method does not support 'all' and 'any' interfaces 693 is.iphone.api = ['not']; 694 695 // is current device ipod? 696 // parameter is optional 697 is.ipod = function(range) { 698 var match = userAgent.match(/ipod.+?os (\d+)/); 699 return match !== null && compareVersion(match[1], range); 700 }; 701 // ipod method does not support 'all' and 'any' interfaces 702 is.ipod.api = ['not']; 703 704 // is current operating system linux? 705 is.linux = function() { 706 return /linux/.test(appVersion); 707 }; 708 // linux method does not support 'all' and 'any' interfaces 709 is.linux.api = ['not']; 710 711 // is current operating system mac? 712 is.mac = function() { 713 return /mac/.test(appVersion); 714 }; 715 // mac method does not support 'all' and 'any' interfaces 716 is.mac.api = ['not']; 717 718 // is current device mobile? 719 is.mobile = function() { 720 return is.iphone() || is.ipod() || is.androidPhone() || is.blackberry() || is.windowsPhone(); 721 }; 722 // mobile method does not support 'all' and 'any' interfaces 723 is.mobile.api = ['not']; 724 725 // is current state offline? 726 is.offline = not(is.online); 727 // offline method does not support 'all' and 'any' interfaces 728 is.offline.api = ['not']; 729 730 // is current state online? 731 is.online = function() { 732 return !navigator || navigator.onLine === true; 733 }; 734 // online method does not support 'all' and 'any' interfaces 735 is.online.api = ['not']; 736 737 // is current browser opera? 738 // parameter is optional 739 is.opera = function(range) { 740 var match = userAgent.match(/(?:^opera.+?version|opr)\/(\d+)/); 741 return match !== null && compareVersion(match[1], range); 742 }; 743 // opera method does not support 'all' and 'any' interfaces 744 is.opera.api = ['not']; 745 746 // is current browser phantomjs? 747 // parameter is optional 748 is.phantom = function(range) { 749 var match = userAgent.match(/phantomjs\/(\d+)/); 750 return match !== null && compareVersion(match[1], range); 751 }; 752 // phantom method does not support 'all' and 'any' interfaces 753 is.phantom.api = ['not']; 754 755 // is current browser safari? 756 // parameter is optional 757 is.safari = function(range) { 758 var match = userAgent.match(/version\/(\d+).+?safari/); 759 return match !== null && compareVersion(match[1], range); 760 }; 761 // safari method does not support 'all' and 'any' interfaces 762 is.safari.api = ['not']; 763 764 // is current device tablet? 765 is.tablet = function() { 766 return is.ipad() || is.androidTablet() || is.windowsTablet(); 767 }; 768 // tablet method does not support 'all' and 'any' interfaces 769 is.tablet.api = ['not']; 770 771 // is current device supports touch? 772 is.touchDevice = function() { 773 return !!document && ('ontouchstart' in freeSelf || 774 ('DocumentTouch' in freeSelf && document instanceof DocumentTouch)); 775 }; 776 // touchDevice method does not support 'all' and 'any' interfaces 777 is.touchDevice.api = ['not']; 778 779 // is current operating system windows? 780 is.windows = function() { 781 return /win/.test(appVersion); 782 }; 783 // windows method does not support 'all' and 'any' interfaces 784 is.windows.api = ['not']; 785 786 // is current device windows phone? 787 is.windowsPhone = function() { 788 return is.windows() && /phone/.test(userAgent); 789 }; 790 // windowsPhone method does not support 'all' and 'any' interfaces 791 is.windowsPhone.api = ['not']; 792 793 // is current device windows tablet? 794 is.windowsTablet = function() { 795 return is.windows() && is.not.windowsPhone() && /touch/.test(userAgent); 796 }; 797 // windowsTablet method does not support 'all' and 'any' interfaces 798 is.windowsTablet.api = ['not']; 799 800 // Object checks 801 /* -------------------------------------------------------------------------- */ 802 803 // has a given object got parameterized count property? 804 is.propertyCount = function(object, count) { 805 if (is.not.object(object) || is.not.number(count)) { 806 return false;
807 } 808 var n = 0; 809 for (var property in object) { 810 if (hasOwnProperty.call(object, property) && ++n > count) { 811 return false; 812 } 813 } 814 return n === count; 815 }; 816 // propertyCount method does not support 'all' and 'any' interfaces 817 is.propertyCount.api = ['not']; 818 819 // is given object has parameterized property? 820 is.propertyDefined = function(object, property) { 821 return is.object(object) && is.string(property) && property in object; 822 }; 823 // propertyDefined method does not support 'all' and 'any' interfaces 824 is.propertyDefined.api = ['not']; 825 826 // Array checks 827 /* -------------------------------------------------------------------------- */ 828 829 // is a given item in an array? 830 is.inArray = function(value, array) { 831 if (is.not.array(array)) { 832 return false; 833 } 834 for (var i = 0; i < array.length; i++) { 835 if (array[i] === value) { 836 return true; 837 } 838 } 839 return false; 840 }; 841 // inArray method does not support 'all' and 'any' interfaces 842 is.inArray.api = ['not']; 843 844 // is a given array sorted? 845 is.sorted = function(array, sign) { 846 if (is.not.array(array)) { 847 return false; 848 } 849 var predicate = comparator[sign] || comparator['>=']; 850 for (var i = 1; i < array.length; i++) { 851 if (!predicate(array[i], array[i - 1])) { 852 return false; 853 } 854 } 855 return true; 856 }; 857 858 // API 859 // Set 'not', 'all' and 'any' interfaces to methods based on their api property 860 /* -------------------------------------------------------------------------- */ 861 862 function setInterfaces() { 863 var options = is; 864 for (var option in options) { 865 if (hasOwnProperty.call(options, option) && is['function'](options[option])) { 866 var interfaces = options[option].api || ['not', 'all', 'any']; 867 for (var i = 0; i < interfaces.length; i++) { 868 if (interfaces[i] === 'not') { 869 is.not[option] = not(is[option]); 870 } 871 if (interfaces[i] === 'all') { 872 is.all[option] = all(is[option]); 873 } 874 if (interfaces[i] === 'any') { 875 is.any[option] = any(is[option]); 876 } 877 } 878 } 879 } 880 } 881 setInterfaces(); 882 883 // Configuration methods 884 // Intentionally added after setInterfaces function 885 /* -------------------------------------------------------------------------- */ 886 887 // change namespace of library to prevent name collisions 888 // var preferredName = is.setNamespace(); 889 // preferredName.odd(3); 890 // => true 891 is.setNamespace = function() { 892 root.is = previousIs; 893 return this; 894 }; 895 896 // set optional regexes to methods 897 is.setRegexp = function(regexp, name) { 898 for (var r in regexes) { 899 if (hasOwnProperty.call(regexes, r) && (name === r)) { 900 regexes[r] = regexp; 901 } 902 } 903 }; 904 905 return is; 906}));
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.