|
| 1 | +angular.module('jlareau.bowser', []) |
| 2 | + |
| 3 | + .factory('bowser', [function(){ |
| 4 | + |
| 5 | + var t = true |
| 6 | + |
| 7 | + function detect(ua) { |
| 8 | + |
| 9 | + function getFirstMatch(regex) { |
| 10 | + var match = ua.match(regex); |
| 11 | + return (match && match.length > 1 && match[1]) || ''; |
| 12 | + } |
| 13 | + |
| 14 | + var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase() |
| 15 | + , likeAndroid = /like android/i.test(ua) |
| 16 | + , android = !likeAndroid && /android/i.test(ua) |
| 17 | + , versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i) |
| 18 | + , tablet = /tablet/i.test(ua) |
| 19 | + , mobile = !tablet && /[^-]mobi/i.test(ua) |
| 20 | + , result |
| 21 | + |
| 22 | + if (/opera|opr/i.test(ua)) { |
| 23 | + result = { |
| 24 | + name: 'Opera' |
| 25 | + , opera: t |
| 26 | + , version: versionIdentifier || getFirstMatch(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i) |
| 27 | + } |
| 28 | + } |
| 29 | + else if (/windows phone/i.test(ua)) { |
| 30 | + result = { |
| 31 | + name: 'Windows Phone' |
| 32 | + , windowsphone: t |
| 33 | + , msie: t |
| 34 | + , version: getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i) |
| 35 | + } |
| 36 | + } |
| 37 | + else if (/msie|trident/i.test(ua)) { |
| 38 | + result = { |
| 39 | + name: 'Internet Explorer' |
| 40 | + , msie: t |
| 41 | + , version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i) |
| 42 | + } |
| 43 | + } |
| 44 | + else if (/chrome|crios|crmo/i.test(ua)) { |
| 45 | + result = { |
| 46 | + name: 'Chrome' |
| 47 | + , chrome: t |
| 48 | + , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) |
| 49 | + } |
| 50 | + } |
| 51 | + else if (iosdevice) { |
| 52 | + result = { |
| 53 | + name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod' |
| 54 | + } |
| 55 | + // WTF: version is not part of user agent in web apps |
| 56 | + if (versionIdentifier) { |
| 57 | + result.version = versionIdentifier |
| 58 | + } |
| 59 | + } |
| 60 | + else if (/sailfish/i.test(ua)) { |
| 61 | + result = { |
| 62 | + name: 'Sailfish' |
| 63 | + , sailfish: t |
| 64 | + , version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i) |
| 65 | + } |
| 66 | + } |
| 67 | + else if (/seamonkey\//i.test(ua)) { |
| 68 | + result = { |
| 69 | + name: 'SeaMonkey' |
| 70 | + , seamonkey: t |
| 71 | + , version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i) |
| 72 | + } |
| 73 | + } |
| 74 | + else if (/firefox|iceweasel/i.test(ua)) { |
| 75 | + result = { |
| 76 | + name: 'Firefox' |
| 77 | + , firefox: t |
| 78 | + , version: getFirstMatch(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i) |
| 79 | + } |
| 80 | + if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) { |
| 81 | + result.firefoxos = t |
| 82 | + } |
| 83 | + } |
| 84 | + else if (/silk/i.test(ua)) { |
| 85 | + result = { |
| 86 | + name: 'Amazon Silk' |
| 87 | + , silk: t |
| 88 | + , version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i) |
| 89 | + } |
| 90 | + } |
| 91 | + else if (android) { |
| 92 | + result = { |
| 93 | + name: 'Android' |
| 94 | + , version: versionIdentifier |
| 95 | + } |
| 96 | + } |
| 97 | + else if (/phantom/i.test(ua)) { |
| 98 | + result = { |
| 99 | + name: 'PhantomJS' |
| 100 | + , phantom: t |
| 101 | + , version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i) |
| 102 | + } |
| 103 | + } |
| 104 | + else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) { |
| 105 | + result = { |
| 106 | + name: 'BlackBerry' |
| 107 | + , blackberry: t |
| 108 | + , version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i) |
| 109 | + } |
| 110 | + } |
| 111 | + else if (/(web|hpw)os/i.test(ua)) { |
| 112 | + result = { |
| 113 | + name: 'WebOS' |
| 114 | + , webos: t |
| 115 | + , version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i) |
| 116 | + }; |
| 117 | + /touchpad\//i.test(ua) && (result.touchpad = t) |
| 118 | + } |
| 119 | + else if (/bada/i.test(ua)) { |
| 120 | + result = { |
| 121 | + name: 'Bada' |
| 122 | + , bada: t |
| 123 | + , version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i) |
| 124 | + }; |
| 125 | + } |
| 126 | + else if (/tizen/i.test(ua)) { |
| 127 | + result = { |
| 128 | + name: 'Tizen' |
| 129 | + , tizen: t |
| 130 | + , version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier |
| 131 | + }; |
| 132 | + } |
| 133 | + else if (/safari/i.test(ua)) { |
| 134 | + result = { |
| 135 | + name: 'Safari' |
| 136 | + , safari: t |
| 137 | + , version: versionIdentifier |
| 138 | + } |
| 139 | + } |
| 140 | + else result = {} |
| 141 | + |
| 142 | + // set webkit or gecko flag for browsers based on these engines |
| 143 | + if (/(apple)?webkit/i.test(ua)) { |
| 144 | + result.name = result.name || "Webkit" |
| 145 | + result.webkit = t |
| 146 | + if (!result.version && versionIdentifier) { |
| 147 | + result.version = versionIdentifier |
| 148 | + } |
| 149 | + } else if (!result.opera && /gecko\//i.test(ua)) { |
| 150 | + result.name = result.name || "Gecko" |
| 151 | + result.gecko = t |
| 152 | + result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i) |
| 153 | + } |
| 154 | + |
| 155 | + // set OS flags for platforms that have multiple browsers |
| 156 | + if (android || result.silk) { |
| 157 | + result.android = t |
| 158 | + } else if (iosdevice) { |
| 159 | + result[iosdevice] = t |
| 160 | + result.ios = t |
| 161 | + } |
| 162 | + |
| 163 | + // OS version extraction |
| 164 | + var osVersion = ''; |
| 165 | + if (iosdevice) { |
| 166 | + osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i); |
| 167 | + osVersion = osVersion.replace(/[_\s]/g, '.'); |
| 168 | + } else if (android) { |
| 169 | + osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i); |
| 170 | + } else if (result.windowsphone) { |
| 171 | + osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i); |
| 172 | + } else if (result.webos) { |
| 173 | + osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i); |
| 174 | + } else if (result.blackberry) { |
| 175 | + osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i); |
| 176 | + } else if (result.bada) { |
| 177 | + osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i); |
| 178 | + } else if (result.tizen) { |
| 179 | + osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i); |
| 180 | + } |
| 181 | + if (osVersion) { |
| 182 | + result.osversion = osVersion; |
| 183 | + } |
| 184 | + |
| 185 | + // device type extraction |
| 186 | + var osMajorVersion = osVersion.split('.')[0]; |
| 187 | + if (tablet || iosdevice == 'ipad' || (android && (osMajorVersion == 3 || (osMajorVersion == 4 && !mobile))) || result.silk) { |
| 188 | + result.tablet = t |
| 189 | + } else if (mobile || iosdevice == 'iphone' || iosdevice == 'ipod' || android || result.blackberry || result.webos || result.bada) { |
| 190 | + result.mobile = t |
| 191 | + } |
| 192 | + |
| 193 | + // Graded Browser Support |
| 194 | + // http://developer.yahoo.com/yui/articles/gbs |
| 195 | + if ((result.msie && result.version >= 10) || |
| 196 | + (result.chrome && result.version >= 20) || |
| 197 | + (result.firefox && result.version >= 20.0) || |
| 198 | + (result.safari && result.version >= 6) || |
| 199 | + (result.opera && result.version >= 10.0) || |
| 200 | + (result.ios && result.osversion && result.osversion.split(".")[0] >= 6) |
| 201 | + ) { |
| 202 | + result.a = t; |
| 203 | + } |
| 204 | + else if ((result.msie && result.version < 10) || |
| 205 | + (result.chrome && result.version < 20) || |
| 206 | + (result.firefox && result.version < 20.0) || |
| 207 | + (result.safari && result.version < 6) || |
| 208 | + (result.opera && result.version < 10.0) || |
| 209 | + (result.ios && result.osversion && result.osversion.split(".")[0] < 6) |
| 210 | + ) { |
| 211 | + result.c = t |
| 212 | + } else result.x = t |
| 213 | + |
| 214 | + return result |
| 215 | + } |
| 216 | + |
| 217 | + var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '') |
| 218 | + |
| 219 | + |
| 220 | + /* |
| 221 | + * Set our detect method to the main bowser object so we can |
| 222 | + * reuse it to test other user agents. |
| 223 | + * This is needed to implement future tests. |
| 224 | + */ |
| 225 | + bowser._detect = detect; |
| 226 | + |
| 227 | + return bowser; |
| 228 | + |
| 229 | + }]); |
0 commit comments