├── .gitignore ├── CHANGELOG.md ├── bower.json ├── package.json ├── index.html ├── LICENSE ├── README.md └── src └── angular-bowser.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components 2 | dev 3 | .idea 4 | node_modules -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.0.4 4 | 5 | * Add npm support 6 | * Update bowser code to use version 1.3.0 7 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-bowser", 3 | "version": "0.0.4", 4 | "homepage": "https://github.com/jacqueslareau/angular-bowser", 5 | "authors": [ 6 | "Jacques Lareau " 7 | ], 8 | "description": "An AngularJS service to detect client browser and version", 9 | "main": "./src/angular-bowser.js", 10 | "keywords": [ 11 | "angular", 12 | "bowser" 13 | ], 14 | "license": "MIT", 15 | "ignore": [ 16 | "**/.*", 17 | "node_modules", 18 | "bower_components", 19 | "test", 20 | "tests" 21 | ], 22 | "dependencies": { 23 | "angular": "^1.3.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-bowser", 3 | "version": "0.0.4", 4 | "description": "AngularJS browser detection kit", 5 | "main": "src/angular-bowser.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/jacqueslareau/angular-bowser.git" 12 | }, 13 | "keywords": [ 14 | "angular", 15 | "bowser", 16 | "browser" 17 | ], 18 | "author": "Jacques Lareau ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/jacqueslareau/angular-bowser/issues" 22 | }, 23 | "homepage": "https://github.com/jacqueslareau/angular-bowser#readme", 24 | "dependencies": { 25 | "angular": "^1.3.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 |
19 | 20 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jacques Lareau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | angular-bowser 2 | ==================== 3 | 4 | This is a simple [AngularJS](http://angularjs.org/) service to provide browser information. 5 | It's heavily based on [bowser](https://github.com/ded/bowser) code. 6 | 7 | ### Dependencies 8 | 9 | None except for AngularJS. 10 | 11 | ### Install 12 | 13 | `bower install --save angular-bowser` 14 | 15 | OR 16 | 17 | `npm install --save angular-bowser` 18 | 19 | ### Usage 20 | 21 | Include src/angular-bowser.js in your html. 22 | 23 | ```html 24 | 25 | ``` 26 | 27 | Add the angular-bowser module as a dependency to your application module: 28 | 29 | ```javascript 30 | angular.module('MyApp', ['jlareau.bowser']); 31 | ``` 32 | 33 | Inject the service where you need it. A good place is in the run section of your application. 34 | 35 | ```javascript 36 | angular.module('MyApp') 37 | .run(['bowser', function(bowser) { 38 | 39 | if ( bowser.msie && bowser.version <= 6 ) { 40 | 41 | alert(`${bowser.name}, Seriously?!`); 42 | 43 | } 44 | 45 | }]); 46 | ``` 47 | 48 | ### Properties 49 | 50 | Example of properties are: firefox, chrome, msie, opera, android, ios, safari 51 | 52 | The browser version is always in the version property. 53 | 54 | For more information, please check [bowser](https://github.com/ded/bowser). 55 | 56 | ### See also 57 | 58 | [ng-device-detector](https://github.com/srfrnk/ng-device-detector) 59 | -------------------------------------------------------------------------------- /src/angular-bowser.js: -------------------------------------------------------------------------------- 1 | !function (name, definition) { 2 | if (typeof module != 'undefined' && module.exports) module.exports = definition() 3 | else if (typeof define == 'function' && define.amd) define(definition) 4 | else this[name] = definition() 5 | }('angular-bowser', function () { 6 | 7 | angular.module('jlareau.bowser', []).factory('bowser', function(){ 8 | 9 | /*! 10 | * Bowser - a browser detector 11 | * https://github.com/ded/bowser 12 | * MIT License | (c) Dustin Diaz 2015 13 | */ 14 | 15 | var t = true 16 | 17 | function detect(ua) { 18 | 19 | function getFirstMatch(regex) { 20 | var match = ua.match(regex); 21 | return (match && match.length > 1 && match[1]) || ''; 22 | } 23 | 24 | function getSecondMatch(regex) { 25 | var match = ua.match(regex); 26 | return (match && match.length > 1 && match[2]) || ''; 27 | } 28 | 29 | var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase() 30 | , likeAndroid = /like android/i.test(ua) 31 | , android = !likeAndroid && /android/i.test(ua) 32 | , nexusMobile = /nexus\s*[0-6]\s*/i.test(ua) 33 | , nexusTablet = !nexusMobile && /nexus\s*[0-9]+/i.test(ua) 34 | , chromeos = /CrOS/.test(ua) 35 | , silk = /silk/i.test(ua) 36 | , sailfish = /sailfish/i.test(ua) 37 | , tizen = /tizen/i.test(ua) 38 | , webos = /(web|hpw)os/i.test(ua) 39 | , windowsphone = /windows phone/i.test(ua) 40 | , windows = !windowsphone && /windows/i.test(ua) 41 | , mac = !iosdevice && !silk && /macintosh/i.test(ua) 42 | , linux = !android && !sailfish && !tizen && !webos && /linux/i.test(ua) 43 | , edgeVersion = getFirstMatch(/edge\/(\d+(\.\d+)?)/i) 44 | , versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i) 45 | , tablet = /tablet/i.test(ua) 46 | , mobile = !tablet && /[^-]mobi/i.test(ua) 47 | , xbox = /xbox/i.test(ua) 48 | , result 49 | 50 | if (/opera|opr|opios/i.test(ua)) { 51 | result = { 52 | name: 'Opera' 53 | , opera: t 54 | , version: versionIdentifier || getFirstMatch(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i) 55 | } 56 | } 57 | else if (/coast/i.test(ua)) { 58 | result = { 59 | name: 'Opera Coast' 60 | , coast: t 61 | , version: versionIdentifier || getFirstMatch(/(?:coast)[\s\/](\d+(\.\d+)?)/i) 62 | } 63 | } 64 | else if (/yabrowser/i.test(ua)) { 65 | result = { 66 | name: 'Yandex Browser' 67 | , yandexbrowser: t 68 | , version: versionIdentifier || getFirstMatch(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i) 69 | } 70 | } 71 | else if (/ucbrowser/i.test(ua)) { 72 | result = { 73 | name: 'UC Browser' 74 | , ucbrowser: t 75 | , version: getFirstMatch(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i) 76 | } 77 | } 78 | else if (/mxios/i.test(ua)) { 79 | result = { 80 | name: 'Maxthon' 81 | , maxthon: t 82 | , version: getFirstMatch(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i) 83 | } 84 | } 85 | else if (/epiphany/i.test(ua)) { 86 | result = { 87 | name: 'Epiphany' 88 | , epiphany: t 89 | , version: getFirstMatch(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i) 90 | } 91 | } 92 | else if (/puffin/i.test(ua)) { 93 | result = { 94 | name: 'Puffin' 95 | , puffin: t 96 | , version: getFirstMatch(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i) 97 | } 98 | } 99 | else if (/sleipnir/i.test(ua)) { 100 | result = { 101 | name: 'Sleipnir' 102 | , sleipnir: t 103 | , version: getFirstMatch(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i) 104 | } 105 | } 106 | else if (/k-meleon/i.test(ua)) { 107 | result = { 108 | name: 'K-Meleon' 109 | , kMeleon: t 110 | , version: getFirstMatch(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i) 111 | } 112 | } 113 | else if (windowsphone) { 114 | result = { 115 | name: 'Windows Phone' 116 | , windowsphone: t 117 | } 118 | if (edgeVersion) { 119 | result.msedge = t 120 | result.version = edgeVersion 121 | } 122 | else { 123 | result.msie = t 124 | result.version = getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i) 125 | } 126 | } 127 | else if (/msie|trident/i.test(ua)) { 128 | result = { 129 | name: 'Internet Explorer' 130 | , msie: t 131 | , version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i) 132 | } 133 | } else if (chromeos) { 134 | result = { 135 | name: 'Chrome' 136 | , chromeos: t 137 | , chromeBook: t 138 | , chrome: t 139 | , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 140 | } 141 | } else if (/chrome.+? edge/i.test(ua)) { 142 | result = { 143 | name: 'Microsoft Edge' 144 | , msedge: t 145 | , version: edgeVersion 146 | } 147 | } 148 | else if (/vivaldi/i.test(ua)) { 149 | result = { 150 | name: 'Vivaldi' 151 | , vivaldi: t 152 | , version: getFirstMatch(/vivaldi\/(\d+(\.\d+)?)/i) || versionIdentifier 153 | } 154 | } 155 | else if (sailfish) { 156 | result = { 157 | name: 'Sailfish' 158 | , sailfish: t 159 | , version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i) 160 | } 161 | } 162 | else if (/seamonkey\//i.test(ua)) { 163 | result = { 164 | name: 'SeaMonkey' 165 | , seamonkey: t 166 | , version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i) 167 | } 168 | } 169 | else if (/firefox|iceweasel|fxios/i.test(ua)) { 170 | result = { 171 | name: 'Firefox' 172 | , firefox: t 173 | , version: getFirstMatch(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i) 174 | } 175 | if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) { 176 | result.firefoxos = t 177 | } 178 | } 179 | else if (silk) { 180 | result = { 181 | name: 'Amazon Silk' 182 | , silk: t 183 | , version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i) 184 | } 185 | } 186 | else if (/phantom/i.test(ua)) { 187 | result = { 188 | name: 'PhantomJS' 189 | , phantom: t 190 | , version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i) 191 | } 192 | } 193 | else if (/slimerjs/i.test(ua)) { 194 | result = { 195 | name: 'SlimerJS' 196 | , slimer: t 197 | , version: getFirstMatch(/slimerjs\/(\d+(\.\d+)?)/i) 198 | } 199 | } 200 | else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) { 201 | result = { 202 | name: 'BlackBerry' 203 | , blackberry: t 204 | , version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i) 205 | } 206 | } 207 | else if (webos) { 208 | result = { 209 | name: 'WebOS' 210 | , webos: t 211 | , version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i) 212 | }; 213 | /touchpad\//i.test(ua) && (result.touchpad = t) 214 | } 215 | else if (/bada/i.test(ua)) { 216 | result = { 217 | name: 'Bada' 218 | , bada: t 219 | , version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i) 220 | }; 221 | } 222 | else if (tizen) { 223 | result = { 224 | name: 'Tizen' 225 | , tizen: t 226 | , version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier 227 | }; 228 | } 229 | else if (/qupzilla/i.test(ua)) { 230 | result = { 231 | name: 'QupZilla' 232 | , qupzilla: t 233 | , version: getFirstMatch(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i) || versionIdentifier 234 | } 235 | } 236 | else if (/chromium/i.test(ua)) { 237 | result = { 238 | name: 'Chromium' 239 | , chromium: t 240 | , version: getFirstMatch(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i) || versionIdentifier 241 | } 242 | } 243 | else if (/chrome|crios|crmo/i.test(ua)) { 244 | result = { 245 | name: 'Chrome' 246 | , chrome: t 247 | , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i) 248 | } 249 | } 250 | else if (android) { 251 | result = { 252 | name: 'Android' 253 | , version: versionIdentifier 254 | } 255 | } 256 | else if (/safari|applewebkit/i.test(ua)) { 257 | result = { 258 | name: 'Safari' 259 | , safari: t 260 | } 261 | if (versionIdentifier) { 262 | result.version = versionIdentifier 263 | } 264 | } 265 | else if (iosdevice) { 266 | result = { 267 | name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod' 268 | } 269 | // WTF: version is not part of user agent in web apps 270 | if (versionIdentifier) { 271 | result.version = versionIdentifier 272 | } 273 | } 274 | else if(/googlebot/i.test(ua)) { 275 | result = { 276 | name: 'Googlebot' 277 | , googlebot: t 278 | , version: getFirstMatch(/googlebot\/(\d+(\.\d+))/i) || versionIdentifier 279 | } 280 | } 281 | else { 282 | result = { 283 | name: getFirstMatch(/^(.*)\/(.*) /), 284 | version: getSecondMatch(/^(.*)\/(.*) /) 285 | }; 286 | } 287 | 288 | // set webkit or gecko flag for browsers based on these engines 289 | if (!result.msedge && /(apple)?webkit/i.test(ua)) { 290 | if (/(apple)?webkit\/537\.36/i.test(ua)) { 291 | result.name = result.name || "Blink" 292 | result.blink = t 293 | } else { 294 | result.name = result.name || "Webkit" 295 | result.webkit = t 296 | } 297 | if (!result.version && versionIdentifier) { 298 | result.version = versionIdentifier 299 | } 300 | } else if (!result.opera && /gecko\//i.test(ua)) { 301 | result.name = result.name || "Gecko" 302 | result.gecko = t 303 | result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i) 304 | } 305 | 306 | // set OS flags for platforms that have multiple browsers 307 | if (!result.msedge && (android || result.silk)) { 308 | result.android = t 309 | } else if (iosdevice) { 310 | result[iosdevice] = t 311 | result.ios = t 312 | } else if (mac) { 313 | result.mac = t 314 | } else if (xbox) { 315 | result.xbox = t 316 | } else if (windows) { 317 | result.windows = t 318 | } else if (linux) { 319 | result.linux = t 320 | } 321 | 322 | // OS version extraction 323 | var osVersion = ''; 324 | if (result.windowsphone) { 325 | osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i); 326 | } else if (iosdevice) { 327 | osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i); 328 | osVersion = osVersion.replace(/[_\s]/g, '.'); 329 | } else if (android) { 330 | osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i); 331 | } else if (result.webos) { 332 | osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i); 333 | } else if (result.blackberry) { 334 | osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i); 335 | } else if (result.bada) { 336 | osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i); 337 | } else if (result.tizen) { 338 | osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i); 339 | } 340 | if (osVersion) { 341 | result.osversion = osVersion; 342 | } 343 | 344 | // device type extraction 345 | var osMajorVersion = osVersion.split('.')[0]; 346 | if ( 347 | tablet 348 | || nexusTablet 349 | || iosdevice == 'ipad' 350 | || (android && (osMajorVersion == 3 || (osMajorVersion >= 4 && !mobile))) 351 | || result.silk 352 | ) { 353 | result.tablet = t 354 | } else if ( 355 | mobile 356 | || iosdevice == 'iphone' 357 | || iosdevice == 'ipod' 358 | || android 359 | || nexusMobile 360 | || result.blackberry 361 | || result.webos 362 | || result.bada 363 | ) { 364 | result.mobile = t 365 | } 366 | 367 | // Graded Browser Support 368 | // http://developer.yahoo.com/yui/articles/gbs 369 | if (result.msedge || 370 | (result.msie && result.version >= 10) || 371 | (result.yandexbrowser && result.version >= 15) || 372 | (result.vivaldi && result.version >= 1.0) || 373 | (result.chrome && result.version >= 20) || 374 | (result.firefox && result.version >= 20.0) || 375 | (result.safari && result.version >= 6) || 376 | (result.opera && result.version >= 10.0) || 377 | (result.ios && result.osversion && result.osversion.split(".")[0] >= 6) || 378 | (result.blackberry && result.version >= 10.1) 379 | ) { 380 | result.a = t; 381 | } 382 | else if ((result.msie && result.version < 10) || 383 | (result.chrome && result.version < 20) || 384 | (result.firefox && result.version < 20.0) || 385 | (result.safari && result.version < 6) || 386 | (result.opera && result.version < 10.0) || 387 | (result.ios && result.osversion && result.osversion.split(".")[0] < 6) 388 | ) { 389 | result.c = t 390 | } else result.x = t 391 | 392 | return result 393 | } 394 | 395 | var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '') 396 | 397 | bowser.test = function (browserList) { 398 | for (var i = 0; i < browserList.length; ++i) { 399 | var browserItem = browserList[i]; 400 | if (typeof browserItem=== 'string') { 401 | if (browserItem in bowser) { 402 | return true; 403 | } 404 | } 405 | } 406 | return false; 407 | } 408 | 409 | /* 410 | * Set our detect method to the main bowser object so we can 411 | * reuse it to test other user agents. 412 | * This is needed to implement future tests. 413 | */ 414 | bowser._detect = detect; 415 | 416 | return bowser 417 | }); 418 | 419 | }); 420 | --------------------------------------------------------------------------------