// Device.js // (c) 2014 Matthew Hudson // Device.js is freely distributable under the MIT license. // For all details and documentation: // http://matthewhudson.me/projects/device.js/ (function () { var device, previousDevice, addClass, documentElement, find, handleOrientation, hasClass, orientationEvent, removeClass, userAgent; // Save the previous value of the device variable. previousDevice = window.device; device = {}; // Add device as a global object. window.device = device; // The element. documentElement = window.document.documentElement; // The client user agent string. // Lowercase, so we can use the more efficient indexOf(), instead of Regex userAgent = window.navigator.userAgent.toLowerCase(); // Main functions // -------------- device.ios = function () { return device.iphone() || device.ipod() || device.ipad(); }; device.iphone = function () { return !device.windows() && find('iphone'); }; device.ipod = function () { return find('ipod'); }; device.ipad = function () { return find('ipad'); }; device.android = function () { return !device.windows() && find('android'); }; device.androidPhone = function () { return device.android() && find('mobile'); }; device.androidTablet = function () { return device.android() && !find('mobile'); }; device.blackberry = function () { return find('blackberry') || find('bb10') || find('rim'); }; device.blackberryPhone = function () { return device.blackberry() && !find('tablet'); }; device.blackberryTablet = function () { return device.blackberry() && find('tablet'); }; device.windows = function () { return find('windows'); }; device.windowsPhone = function () { return device.windows() && find('phone'); }; device.windowsTablet = function () { return device.windows() && (find('touch') && !device.windowsPhone()); }; device.fxos = function () { return (find('(mobile;') || find('(tablet;')) && find('; rv:'); }; device.fxosPhone = function () { return device.fxos() && find('mobile'); }; device.fxosTablet = function () { return device.fxos() && find('tablet'); }; device.meego = function () { return find('meego'); }; device.cordova = function () { return window.cordova && location.protocol === 'file:'; }; device.nodeWebkit = function () { return typeof window.process === 'object'; }; device.mobile = function () { return device.androidPhone() || device.iphone() || device.ipod() || device.windowsPhone() || device.blackberryPhone() || device.fxosPhone() || device.meego(); }; device.tablet = function () { return device.ipad() || device.androidTablet() || device.blackberryTablet() || device.windowsTablet() || device.fxosTablet(); }; device.desktop = function () { return !device.tablet() && !device.mobile(); }; device.television = function () { var i, television = [ "googletv", "viera", "smarttv", "internet.tv", "netcast", "nettv", "appletv", "boxee", "kylo", "roku", "dlnadoc", "roku", "pov_tv", "hbbtv", "ce-html" ]; i = 0; while (i < television.length) { if (find(television[i])) { return true; } i++; } return false; }; device.portrait = function () { return (window.innerHeight / window.innerWidth) > 1; }; device.landscape = function () { return (window.innerHeight / window.innerWidth) < 1; }; // Public Utility Functions // ------------------------ // Run device.js in noConflict mode, // returning the device variable to its previous owner. device.noConflict = function () { window.device = previousDevice; return this; }; // Private Utility Functions // ------------------------- // Simple UA string search find = function (needle) { return userAgent.indexOf(needle) !== -1; }; // Check if documentElement already has a given class. hasClass = function (className) { var regex; regex = new RegExp(className, 'i'); return documentElement.className.match(regex); }; // Add one or more CSS classes to the element. addClass = function (className) { var currentClassNames = null; if (!hasClass(className)) { currentClassNames = documentElement.className.replace(/^\s+|\s+$/g, ''); documentElement.className = currentClassNames + " " + className; } }; // Remove single CSS class from the element. removeClass = function (className) { if (hasClass(className)) { documentElement.className = documentElement.className.replace(" " + className, ""); } }; // HTML Element Handling // --------------------- // Insert the appropriate CSS class based on the _user_agent. if (device.ios()) { if (device.ipad()) { addClass("ios ipad tablet"); } else if (device.iphone()) { addClass("ios iphone mobile"); } else if (device.ipod()) { addClass("ios ipod mobile"); } } else if (device.android()) { if (device.androidTablet()) { addClass("android tablet"); } else { addClass("android mobile"); } } else if (device.blackberry()) { if (device.blackberryTablet()) { addClass("blackberry tablet"); } else { addClass("blackberry mobile"); } } else if (device.windows()) { if (device.windowsTablet()) { addClass("windows tablet"); } else if (device.windowsPhone()) { addClass("windows mobile"); } else { addClass("desktop"); } } else if (device.fxos()) { if (device.fxosTablet()) { addClass("fxos tablet"); } else { addClass("fxos mobile"); } } else if (device.meego()) { addClass("meego mobile"); } else if (device.nodeWebkit()) { addClass("node-webkit"); } else if (device.television()) { addClass("television"); } else if (device.desktop()) { addClass("desktop"); } if (device.cordova()) { addClass("cordova"); } // Orientation Handling // -------------------- // Handle device orientation changes. handleOrientation = function () { if (device.landscape()) { removeClass("portrait"); addClass("landscape"); } else { removeClass("landscape"); addClass("portrait"); } }; // Detect whether device supports orientationchange event, // otherwise fall back to the resize event. if (Object.prototype.hasOwnProperty.call(window, "onorientationchange")) { orientationEvent = "orientationchange"; } else { orientationEvent = "resize"; } // Listen for changes in orientation. if (window.addEventListener) { window.addEventListener(orientationEvent, handleOrientation, false); } else if (window.attachEvent) { window.attachEvent(orientationEvent, handleOrientation); } else { window[orientationEvent] = handleOrientation; } handleOrientation(); if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { define(function () { return device; }); } else if (typeof module !== 'undefined' && module.exports) { module.exports = device; } else { window.device = device; } }).call(this);