├── README.md ├── css └── caniuse.css ├── fonts ├── agents.eot ├── agents.svg ├── agents.ttf └── agents.woff ├── index.html └── js ├── caniuse.js └── caniuse.min.js /README.md: -------------------------------------------------------------------------------- 1 | caniuse-widget 2 | ============== 3 | 4 | Web widget for "When Can I Use" to display browser stats from your blog. 5 | 6 | Find out more at: [http://andismith.github.com/caniuse-widget/](http://andismith.github.com/caniuse-widget/) -------------------------------------------------------------------------------- /css/caniuse.css: -------------------------------------------------------------------------------- 1 | /* fonts for browser icons (used with permission from IcoMoon.io) */ 2 | @font-face { 3 | font-family: 'agents'; 4 | src: url('../fonts/agents.eot'); 5 | src: url('../fonts/agents.eot?#iefix') format('embedded-opentype'), url('../fonts/agents.svg#agents') format('svg'), url('../fonts/agents.woff') format('woff'), url('../fonts/agents.ttf') format('truetype'); 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | .caniuse { 10 | padding: 10px; 11 | } 12 | .caniuse h1, 13 | .caniuse h2, 14 | .caniuse h3, 15 | .caniuse h4, 16 | .caniuse p { 17 | line-height: 1.4; 18 | margin: 5px; 19 | text-align: center; 20 | } 21 | .caniuse h1 { 22 | font-size: 1.8em; 23 | } 24 | .caniuse h2 { 25 | font-size: 1.4em; 26 | } 27 | .caniuse h3 { 28 | font-size: 1.2em; 29 | } 30 | .caniuse p { 31 | font-size: 0.8em; 32 | } 33 | .caniuse .status { 34 | font-style: italic; 35 | } 36 | .caniuse .agents, 37 | .caniuse .legend { 38 | margin: 0 auto; 39 | max-width: 1200px; 40 | overflow: hidden; 41 | width: auto; 42 | list-style-type: none; 43 | margin: 0; 44 | overflow: auto; 45 | padding: 0; 46 | width: auto; 47 | margin: 0 auto; 48 | max-width: 400px; 49 | } 50 | .caniuse .agents > li, 51 | .caniuse .legend > li { 52 | float: left; 53 | } 54 | .caniuse .agents li, 55 | .caniuse .legend li { 56 | box-shadow: inset 0 -5px 2px rgba(175, 175, 195, 0.02); 57 | float: left; 58 | margin-right: 1.2024048096192386%; 59 | padding: 5px 0; 60 | text-align: center; 61 | width: 19.03807615230461%; 62 | } 63 | .caniuse .agents li.y, 64 | .caniuse .legend li.y, 65 | .caniuse .agents li.x, 66 | .caniuse .legend li.x { 67 | background: #cf9; 68 | } 69 | .caniuse .agents li.a, 70 | .caniuse .legend li.a { 71 | background: #cd5; 72 | } 73 | .caniuse .agents li.p, 74 | .caniuse .legend li.p { 75 | background: #aaf; 76 | } 77 | .caniuse .agents li.n, 78 | .caniuse .legend li.n { 79 | background: #f99; 80 | } 81 | .caniuse .agents li.u, 82 | .caniuse .legend li.u { 83 | background: #ccc; 84 | } 85 | .caniuse .agents li:last-child, 86 | .caniuse .legend li:last-child { 87 | margin-right: 0; 88 | } 89 | .caniuse .agents li { 90 | font-size: 1em; 91 | /* android */ 92 | 93 | /* chrome */ 94 | 95 | /* firefox */ 96 | 97 | /* ie */ 98 | 99 | /* ios */ 100 | 101 | /* opera */ 102 | 103 | /* safari */ 104 | 105 | /* hover states */ 106 | 107 | } 108 | .caniuse .agents li:hover, 109 | .caniuse .agents li:hover:before { 110 | color: #fff; 111 | text-shadow: 0 1px 0 #aaa; 112 | } 113 | .caniuse .agents li:before { 114 | color: #555; 115 | font-size: 2em; 116 | } 117 | .caniuse .agents li[class^="icon-"]:before, 118 | .caniuse .agents li [class*=" icon-"]:before { 119 | font-family: 'agents'; 120 | font-style: normal; 121 | speak: none; 122 | font-weight: normal; 123 | -webkit-font-smoothing: antialiased; 124 | } 125 | .caniuse .agents li.icon-android:before { 126 | content: "\e006"; 127 | } 128 | .caniuse .agents li.icon-chrome:before, 129 | .caniuse .agents li.icon-and_chr:before { 130 | content: "\e004"; 131 | } 132 | .caniuse .agents li.icon-firefox:before, 133 | .caniuse .agents li.icon-and_ff:before { 134 | content: "\e000"; 135 | } 136 | .caniuse .agents li.icon-ie:before, 137 | .caniuse .agents li.icon-windows:before { 138 | content: "\e001"; 139 | /* alternate windows icon: content: "\e007" */ 140 | 141 | } 142 | .caniuse .agents li.icon-ios_saf:before { 143 | content: "\e005"; 144 | } 145 | .caniuse .agents li.icon-opera:before, 146 | .caniuse .agents li.icon-op_mini:before, 147 | .caniuse .agents li.icon-op_mob:before { 148 | content: "\e002"; 149 | } 150 | .caniuse .agents li.icon-safari:before { 151 | content: "\e003"; 152 | } 153 | .caniuse .agents li.icon-ios_saf:hover, 154 | .caniuse .agents li.icon-safari:hover { 155 | background: #869abb; 156 | } 157 | .caniuse .agents li.icon-android:hover { 158 | background: #97c03d; 159 | } 160 | .caniuse .agents li.icon-chrome:hover, 161 | .caniuse .agents li.icon-and_chr:hover { 162 | background: #40ace8; 163 | } 164 | .caniuse .agents li.icon-firefox:hover, 165 | .caniuse .agents li.icon-and_ff:hover { 166 | background: #dc6f26; 167 | } 168 | .caniuse .agents li.icon-ie:hover, 169 | .caniuse .agents li.icon-windows:hover { 170 | background: #1a4cbd; 171 | } 172 | .caniuse .agents li.icon-opera:hover, 173 | .caniuse .agents li.icon-op_mini:hover, 174 | .caniuse .agents li.icon-op_mob:hover { 175 | background: #f0232a; 176 | } 177 | .caniuse .legend { 178 | border-top: 1px dotted #aaa; 179 | margin: 20px auto 10px; 180 | padding-top: 10px; 181 | } 182 | .caniuse .legend li { 183 | font-size: 0.8em; 184 | } 185 | .caniuse .legend li.key { 186 | font-weight: bold; 187 | } 188 | .caniuse .version { 189 | display: block; 190 | } 191 | -------------------------------------------------------------------------------- /fonts/agents.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andismith/caniuse-widget/50d104efd06ce9df8b4ba706fcba5e2b71598429/fonts/agents.eot -------------------------------------------------------------------------------- /fonts/agents.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | This is a custom SVG font generated by IcoMoon. 6 | 1 7 | 8 | 9 | 10 | 11 | 12 | 40 | 50 | 54 | 76 | 82 | 89 | 97 | 101 | 102 | -------------------------------------------------------------------------------- /fonts/agents.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andismith/caniuse-widget/50d104efd06ce9df8b4ba706fcba5e2b71598429/fonts/agents.ttf -------------------------------------------------------------------------------- /fonts/agents.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andismith/caniuse-widget/50d104efd06ce9df8b4ba706fcba5e2b71598429/fonts/agents.woff -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | The "When Can I Use" Web Widget Demo 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |

Demo

20 | 21 |
22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /js/caniuse.js: -------------------------------------------------------------------------------- 1 | /*jshint curly: true, eqeqeq: true, immed: true, indent: 4, browser: true, jquery: true, evil: true, regexdash: true, browser: true, trailing: true, sub: true, unused: true, devel: true */ 2 | 3 | // author: andi smith 4 | // website: www.andismith.com 5 | // version: 0.1 6 | 7 | var canIUse = (function () { 8 | 9 | /* CONFIGURATION =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ 10 | 11 | // URL to the data feed 12 | var SOURCE_DATA_URL = 'https://raw.github.com/Fyrd/caniuse/master/data.json'; 13 | 14 | /* Turn auto run on page load on or off with AUTO_RUN. 15 | If you turn it off, just use canIUse.render() to kick it off again. 16 | If you don't want the WhenCanIUse data to load in the background, turn BE_READY to false. 17 | */ 18 | var AUTO_RUN = true, 19 | BE_READY = true; 20 | 21 | /* Configure the browsers you want to show here. 22 | The order defines the order they will appear on the page. 23 | 24 | Browser options are: 25 | * android - Android 26 | * and_ff - Android Firefox 27 | * and_chr - Android Chrome 28 | * bb - Blackberry 29 | * chrome - Google Chrome 30 | * firefox - Mozilla Firefox 31 | * ie - Internet Explorer 32 | * ios_saf - iOS Safari 33 | * opera - Opera 34 | * op_mini - Opera Mini 35 | * op_mob - Opera Mobile 36 | * safari - Apple Safari 37 | */ 38 | var BROWSERS = ['chrome', 'firefox', 'ie', 'opera', 'safari', 'ios_saf', 'android', 'op_mob', 'and_chr', 'and_ff']; 39 | 40 | // Customise HTML here 41 | var TMPL_TITLE = '

{title}

', // feature title {title} 42 | TMPL_STATUS = '

{status}

', // feature status (W3C Recommendation) {status} 43 | TMPL_DESCRIPTION = '

Supported from the following versions:

', // description to user 44 | TMPL_DESKTOP_TITLE = '

Desktop

', // desktop header 45 | TMPL_MOBILE_TITLE = '

Mobile / Tablet

', // mobile header 46 | TMPL_SUPPORT_WRAPPER = '', // support wrapper {items} 47 | TMPL_SUPPORT = '
  • {version}{prefixed}
  • ', 48 | TMPL_PREFIX_NOTE = '

    * denotes prefix required.

    ', 49 | TMPL_LEGEND = '', 50 | TMPL_FOOTER = '

    Stats from caniuse.com

    ', 51 | TMPL_LOADING = '

    Loading

    ', 52 | TMPL_ERROR = '

    Error

    Feature "{feature}" not found!

    '; 53 | 54 | /* END CONFIGURATION =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ 55 | 56 | var canIUseData, // store data for multiple uses. 57 | storeElementId, // temp storage for elementId if we need to JSONP request 58 | populateOnLoad; // temp storage for if we should populate 59 | 60 | 61 | 62 | // get feature data based on feature name 63 | function getFeature(featureName) { 64 | featureName = featureName.toLowerCase(); 65 | if (canIUseData.query) { 66 | return canIUseData.query.results.json.data[featureName]; 67 | } else if (canIUseData.data) { 68 | return canIUseData.data[featureName]; 69 | } else { 70 | return null; 71 | } 72 | } 73 | 74 | // get the full text description for the support status 75 | function getSupportStatus(key) { 76 | var status = { 77 | "y": "Yes", 78 | "x": "With Prefix", 79 | "n": "No", 80 | "a": "Partial Support", 81 | "p": "Polyfill", 82 | "u": "Unknown" 83 | }; 84 | 85 | return status[key]; 86 | } 87 | 88 | // get the specification status 89 | function getSpecStatus(key) { 90 | var status = { 91 | "rec": "W3C Recommendation", 92 | "pr": "W3C Proposed Recommendation", 93 | "cr": "W3C Candidate Recommendation", 94 | "wd": "W3C Working Draft", 95 | "other": "Non-W3C, but Reputable", 96 | "unoff": "Unofficial or W3C 'Note'" 97 | }; 98 | 99 | return status[key] || "Unknown"; 100 | } 101 | 102 | // find the first version that had this status 103 | function find(needle, haystack) { 104 | 105 | var result = { 106 | "version": -1, 107 | "prefixed": false 108 | }, 109 | compare = -1; 110 | 111 | for (var item in haystack) { 112 | if (haystack.hasOwnProperty(item) && haystack[item].indexOf(needle) > -1) { 113 | // some browser versions are formatted n-n, take the first number for comparison 114 | compare = parseFloat(item.split('-')[0]); 115 | // is this version lower than the current version we have stored? 116 | if (result.version === -1 || result.version > compare) { 117 | result.version = compare; 118 | result.prefixed = (haystack[item].indexOf('x') > -1); 119 | } 120 | } 121 | } 122 | return result; 123 | } 124 | 125 | function findSupport(browserData) { 126 | var status = ['y', 'a', 'p'], 127 | result = {}; 128 | // find what support is available for this browser 129 | for (var i = 0; i < status.length; i++) { 130 | result = find(status[i], browserData); 131 | if (result.version !== -1) { 132 | return { 133 | 'result': status[i], // what type of support 134 | 'prefixed': result.prefixed, 135 | 'version': (result.version !== '0') ? result.version : '0' // the version with that support 136 | }; 137 | } 138 | } 139 | return { 140 | 'result': 'n', 141 | 'prefixed': false, 142 | 'version': 'No' 143 | }; 144 | } 145 | 146 | /* put the data in a more platable format */ 147 | function generateResults(feature) { 148 | var agents = {}, 149 | results = {}, 150 | currentBrowser = '', 151 | support = {}; 152 | 153 | agents = canIUseData.agents || canIUseData.query.results.json.agents; 154 | 155 | results.title = feature.title; // feature name 156 | results.code = feature; // feature code? 157 | results.status = getSpecStatus(feature.status); // feature specification status 158 | results.agents = []; 159 | 160 | for (var i = 0, l = BROWSERS.length; i < l; i++) { 161 | 162 | currentBrowser = BROWSERS[i]; 163 | 164 | if (agents[currentBrowser]) { 165 | 166 | support = findSupport(feature.stats[BROWSERS[i]]); 167 | 168 | results.agents.push({ 169 | "browsercode": currentBrowser, 170 | "prefixed": support.prefixed, 171 | "supportcode": support.result, 172 | "support": getSupportStatus(support.result), 173 | "title": agents[currentBrowser].browser, 174 | "type": agents[currentBrowser].type.toLowerCase(), 175 | "version": support.version 176 | }); 177 | } 178 | } 179 | 180 | return results; 181 | } 182 | 183 | 184 | function generateHtml(results) { 185 | 186 | var html = '', 187 | resultHtml = '', 188 | desktopHtml = '', 189 | mobileHtml = '', 190 | prefixes = false, 191 | result = {}, 192 | i = 0, 193 | l = 0; 194 | 195 | resultHtml = TMPL_TITLE.replace('{title}', results.title); 196 | resultHtml += TMPL_STATUS.replace('{status}', results.status); 197 | resultHtml += TMPL_DESCRIPTION; 198 | 199 | for (i = 0, l = results.agents.length; i < l; i++) { 200 | result = results.agents[i]; // simply things 201 | 202 | // we need to show that prefix notice, captain 203 | if (result.prefixed) { 204 | prefixes = true; 205 | } 206 | 207 | html = TMPL_SUPPORT.replace(/\{browsercode\}/g, result.browsercode) 208 | .replace(/\{prefixed\}/g, (result.prefixed === true) ? '*' : '') 209 | .replace(/\{supportcode\}/g, result.supportcode) 210 | .replace(/\{support\}/g, result.support) 211 | .replace(/\{browser\}/g, result.title) 212 | .replace(/\{version\}/g, result.version); 213 | 214 | if (result.type === 'desktop') { 215 | desktopHtml += html; 216 | } else if (result.type === 'mobile') { 217 | mobileHtml += html; 218 | } 219 | } 220 | 221 | // only show if we are including desktop browsers 222 | if (desktopHtml !== '') { 223 | resultHtml += TMPL_DESKTOP_TITLE; 224 | resultHtml += TMPL_SUPPORT_WRAPPER.replace(/\{items\}/g, desktopHtml); 225 | } 226 | 227 | // only show if we are including mobile browsers 228 | if (mobileHtml !== '') { 229 | resultHtml += TMPL_MOBILE_TITLE; 230 | resultHtml += TMPL_SUPPORT_WRAPPER.replace(/\{items\}/g, mobileHtml); 231 | } 232 | 233 | if (prefixes) { 234 | resultHtml += TMPL_PREFIX_NOTE; 235 | } 236 | 237 | resultHtml += TMPL_LEGEND; 238 | resultHtml += TMPL_FOOTER.replace(/\{feature\}/g, results.featureCode); 239 | return resultHtml; 240 | } 241 | 242 | function generate(elementId) { 243 | var $canIUse = [], 244 | $instance, 245 | featureCode = '', 246 | feature = {}, 247 | result = {}, 248 | i = 0, 249 | l = 0; 250 | 251 | if (typeof elementId === "undefined") { 252 | $canIUse = document.querySelectorAll('.caniuse'); 253 | } else { 254 | $canIUse.push(document.getElementById(elementId)); 255 | } 256 | 257 | l = $canIUse.length; 258 | 259 | for (i = 0; i < l; i++) { 260 | $instance = $canIUse[i]; 261 | featureCode = $instance.getAttribute('data-feature') || 'unknown'; 262 | feature = getFeature(featureCode); 263 | if (feature) { 264 | result = generateResults(feature); 265 | result.featureCode = featureCode; 266 | $instance.innerHTML = generateHtml(result); 267 | } else { 268 | $instance.innerHTML = TMPL_ERROR.replace(/\{feature\}/g, featureCode); 269 | } 270 | } 271 | } 272 | 273 | function showLoading(elementId) { 274 | var $canIUse = [], 275 | $instance, 276 | i = 0, 277 | l = 0; 278 | 279 | if (typeof elementId === "undefined") { 280 | $canIUse = document.querySelectorAll('.caniuse'); 281 | } else { 282 | $canIUse.push(document.getElementById(elementId)); 283 | } 284 | 285 | l = $canIUse.length; 286 | 287 | for (i = 0; i < l; i++) { 288 | $instance = $canIUse[i]; 289 | $instance.innerHTML = TMPL_LOADING; 290 | } 291 | } 292 | 293 | /* 294 | * Load the data that will be used to display information. 295 | */ 296 | function loadData(elementId, populate) { 297 | var url = '', 298 | script = document.createElement('SCRIPT'); 299 | 300 | url = 'http://query.yahooapis.com/v1/public/yql?q=' + 301 | 'select * from json where url = \'' + SOURCE_DATA_URL + '\'' + 302 | '&format=json&jsonCompat=new&callback=canIUseDataLoaded'; 303 | 304 | // remember these for when our JSONP returns 305 | storeElementId = elementId; 306 | populateOnLoad = populate; 307 | 308 | script.src = url; 309 | document.body.appendChild(script); 310 | } 311 | 312 | function populate(elementId) { 313 | if (typeof canIUseData === 'undefined') { 314 | showLoading(elementId); 315 | loadData(elementId, true); 316 | } else { 317 | generate(elementId); 318 | } 319 | } 320 | 321 | /* 322 | * Public Methods 323 | */ 324 | return { 325 | render: populate, 326 | dataLoaded: function (data) { 327 | canIUseData = data; 328 | if (populateOnLoad) { 329 | generate(storeElementId); 330 | } 331 | }, 332 | init: (function () { 333 | if (AUTO_RUN) { 334 | populate(); 335 | } else if (BE_READY) { 336 | loadData(undefined, false); 337 | } 338 | })() 339 | }; 340 | }()); 341 | 342 | function canIUseDataLoaded(data) { 343 | canIUse.dataLoaded(data); 344 | } -------------------------------------------------------------------------------- /js/caniuse.min.js: -------------------------------------------------------------------------------- 1 | // author: andi smith 2 | // website: www.andismith.com 3 | // version: 0.1 4 | 5 | function canIUseDataLoaded(e){canIUse.dataLoaded(e)}var canIUse=function(){function b(e){e=e.toLowerCase();if(m.query){return m.query.results.json.data[e]}else if(m.data){return m.data[e]}else{return null}}function w(e){var t={y:"Yes",x:"With Prefix",n:"No",a:"Partial Support",p:"Polyfill",u:"Unknown"};return t[e]}function E(e){var t={rec:"W3C Recommendation",pr:"W3C Proposed Recommendation",cr:"W3C Candidate Recommendation",wd:"W3C Working Draft",other:"Non-W3C, but Reputable",unoff:"Unofficial or W3C 'Note'"};return t[e]||"Unknown"}function S(e,t){var n={version:-1,prefixed:false},r=-1;for(var i in t){if(t.hasOwnProperty(i)&&t[i].indexOf(e)>-1){r=parseFloat(i.split("-")[0]);if(n.version===-1||n.version>r){n.version=r;n.prefixed=t[i].indexOf("x")>-1}}}return n}function x(e){var t=["y","a","p"],n={};for(var r=0;r