1var API_BASE = 'https://proxy.corsfix.com/?http://html5test.eu5.net/api' 2 3/* Polyfills */ 4 5if (!Function.prototype.bind) { 6 Function.prototype.bind = function (oThis) { 7 if (typeof this !== "function") { 8 // closest thing possible to the ECMAScript 5 internal IsCallable function 9 throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); 10 } 11 12 var aArgs = Array.prototype.slice.call(arguments, 1), 13 fToBind = this, 14 fNOP = function () {}, 15 fBound = function () { 16 return fToBind.apply(this instanceof fNOP && oThis 17 ? this 18 : oThis, 19 aArgs.concat(Array.prototype.slice.call(arguments))); 20 }; 21 22 fNOP.prototype = this.prototype; 23 fBound.prototype = new fNOP(); 24 25 return fBound; 26 }; 27} 28 29(function (win, doc) { 30 if (win.addEventListener) return; //No need to polyfill 31 32 function docHijack(p) { var old = doc[p]; doc[p] = function (v) { return addListen(old(v)) } } 33 function addEvent(on, fn, self) { 34 return (self = this).attachEvent('on' + on, function (e) { 35 var e = e || win.event; 36 e.preventDefault = e.preventDefault || function () { e.returnValue = false } 37 e.stopPropagation = e.stopPropagation || function () { e.cancelBubble = true } 38 fn.call(self, e); 39 }); 40 } 41 function addListen(obj, i) { 42 if (!obj) return obj; 43 if (i = obj.length) while (i--) obj[i].addEventListener = addEvent; 44 else obj.addEventListener = addEvent; 45 return obj; 46 } 47 48 addListen([doc, win]); 49 if ('Element' in win) win.Element.prototype.addEventListener = addEvent; //IE8 50 else { //IE < 8 51 doc.attachEvent('onreadystatechange', function () { addListen(doc.all) }); //Make sure we also init at domReady 52 docHijack('getElementsByTagName'); 53 docHijack('getElementById'); 54 docHijack('createElement'); 55 addListen(doc.all); 56 } 57})(window, document); 58 59 60/* Utility functions */ 61 62function loadWhichBrowser(cb) { 63 var callback = cb; 64 65 var p = [], w = window, d = document, e = f = 0; p.push('ua=' + encodeURIComponent(navigator.userAgent)); e |= w.ActiveXObject ? 1 : 0; e |= w.opera ? 2 : 0; e |= w.chrome ? 4 : 0; 66 e |= 'getBoxObjectFor' in d || 'mozInnerScreenX' in w ? 8 : 0; e |= ('WebKitCSSMatrix' in w || 'WebKitPoint' in w || 'webkitStorageInfo' in w || 'webkitURL' in w) ? 16 : 0; 67 e |= (e & 16 && ({}.toString).toString().indexOf("\n") === -1) ? 32 : 0; p.push('e=' + e); f |= 'sandbox' in d.createElement('iframe') ? 1 : 0; f |= 'WebSocket' in w ? 2 : 0; 68 f |= w.Worker ? 4 : 0; f |= w.applicationCache ? 8 : 0; f |= w.history && history.pushState ? 16 : 0; f |= d.documentElement.webkitRequestFullScreen ? 32 : 0; f |= 'FileReader' in w ? 64 : 0; 69 p.push('f=' + f); p.push('r=' + Math.random().toString(36).substring(7)); p.push('w=' + screen.width); p.push('h=' + screen.height); 70 71 var timeout = null; 72 73 function load() { 74 if (typeof WhichBrowser != 'undefined') { 75 return; 76 } 77 78 var script = document.createElement('script'); 79 script.src = 'https://api.whichbrowser.net/rel/detect.js?' + p.join('&'); 80 document.getElementsByTagName('head')[0].appendChild(script); 81 82 wait(); 83 } 84 85 function wait() { 86 if (!timeout) { 87 timeout = window.setTimeout(load, 3000); 88 } 89 90 if (typeof WhichBrowser == 'undefined') { 91 window.setTimeout(wait, 100) 92 } 93 else { 94 window.clearTimeout(timeout); 95 callback(); 96 } 97 } 98 99 load(); 100} 101 102function submit(method, payload) { 103 var httpRequest; 104 if (window.XMLHttpRequest) { 105 httpRequest = new XMLHttpRequest(); 106 } else if (window.ActiveXObject) { 107 httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); 108 } 109 110 httpRequest.open('POST', API_BASE + '/' + method, true); 111 httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 112 httpRequest.send('payload=' + encodeURIComponent(payload)); 113} 114 115function decodeParameters() { 116 var params = {}; 117 118 if (location.search) { 119 var parts = location.search.substring(1).split('&'); 120 121 for (var i = 0; i < parts.length; i++) { 122 var nv = parts[i].split('='); 123 if (!nv[0]) continue; 124 params[nv[0]] = decodeURIComponent(nv[1]) || true; 125 } 126 } 127 128 return params; 129} 130 131function submitResults(r, c) { 132 var parameters = decodeParameters(); 133 var identifier = typeof parameters.identifier != 'undefined' ? parameters.identifier : ''; 134 var source = typeof parameters.source != 'undefined' ? parameters.source : ''; 135 var task = typeof parameters.task != 'undefined' ? parameters.task : ''; 136 137 try { 138 var payload = '{' + 139 '"release": "' + r.release + '",' + 140 '"source": "' + source + '",' + 141 '"protocol": "' + location.protocol + '",' + 142 '"identifier": "' + escapeSlashes(identifier) + '",' + 143 '"task": "' + task + '",' + 144 '"uniqueid": "' + r.uniqueid + '",' + 145 '"score": ' + c.score + ',' + 146 '"maximum": ' + c.maximum + ',' + 147 '"camouflage": "' + (Browsers.camouflage ? '1' : '0') + '",' + 148 '"features": "' + (Browsers.features.join(',')) + '",' + 149 '"browserName": "' + (Browsers.browser.name ? Browsers.browser.name : '') + '",' + 150 '"browserChannel": "' + (Browsers.browser.channel ? Browsers.browser.channel : '') + '",' + 151 '"browserVersion": "' + (Browsers.browser.version ? Browsers.browser.version.toString() : '') + '",' + 152 '"browserVersionType": "' + (Browsers.browser.version ? Browsers.browser.version.type : '') + '",' + 153 '"browserVersionMajor": "' + (Browsers.browser.version ? Browsers.browser.version.major : '') + '",' + 154 '"browserVersionMinor": "' + (Browsers.browser.version ? Browsers.browser.version.minor : '') + '",' + 155 '"browserVersionOriginal": "' + (Browsers.browser.version ? Browsers.browser.version.original : '') + '",' + 156 '"browserMode": "' + (Browsers.browser.mode ? Browsers.browser.mode : '') + '",' + 157 '"engineName": "' + (Browsers.engine.name ? Browsers.engine.name : '') + '",' + 158 '"engineVersion": "' + (Browsers.engine.version ? Browsers.engine.version.toString() : '') + '",' + 159 '"osName": "' + (Browsers.os.name ? Browsers.os.name : '') + '",' + 160 '"osFamily": "' + (Browsers.os.family ? Browsers.os.family : '') + '",' + 161 '"osVersion": "' + (Browsers.os.version ? Browsers.os.version.toString() : '') + '",' + 162 '"deviceManufacturer": "' + (Browsers.device.manufacturer ? Browsers.device.manufacturer : '') + '",' + 163 '"deviceModel": "' + (Browsers.device.model ? Browsers.device.model : '') + '",' + 164 '"deviceSeries": "' + (Browsers.device.series ? Browsers.device.series : '') + '",' + 165 '"deviceType": "' + (Browsers.device.type ? Browsers.device.type : '') + '",' + 166 '"deviceIdentified": "' + (Browsers.device.identified ? '1' : '0') + '",' + 167 '"deviceWidth": "' + (screen.width) + '",' + 168 '"deviceHeight": "' + (screen.height) + '",' +
169 '"useragent": "' + navigator.userAgent + '",' + 170 '"humanReadable": "' + Browsers.toString() + '",' + 171 '"points": "' + c.points + '",' + 172 '"results": "' + escapeSlashes(r.results) + '"' + 173 '}'; 174 175 submit('submit', payload); 176 } catch (e) { 177 alert('Could not submit results: ' + e.message); 178 } 179} 180 181function escapeSlashes(string) { 182 return string.replace(/\\/g, '\\\\'). 183 replace(/\u0008/g, '\\b'). 184 replace(/\t/g, '\\t'). 185 replace(/\n/g, '\\n'). 186 replace(/\f/g, '\\f'). 187 replace(/\r/g, '\\r'). 188 replace(/'/g, '\\\''). 189 replace(/"/g, '\\"'); 190} 191 192 193var NO = 0, 194 YES = 1, 195 OLD = 2, 196 BUGGY = 4, 197 PREFIX = 8, 198 BLOCKED = 16, 199 DISABLED = 32, 200 UNCONFIRMED = 64, 201 UNKNOWN = 128, 202 EXPERIMENTAL = 256; 203 204 205 206var Metadata = function () { this.initialize.apply(this, arguments) }; 207Metadata.prototype = { 208 initialize: function (data) { 209 this.data = data; 210 this.list = {}; 211 212 for (var i = 0; i < this.data.length; i++) { 213 this.iterate(this.data[i].items, '', -1, []); 214 } 215 }, 216 217 iterate: function (data, prefix, level, path) { 218 for (var i = 0; i < data.length; i++) { 219 var key; 220 221 if (typeof data[i].id != 'undefined') { 222 key = prefix + (prefix == '' ? '' : '.') + data[i].id; 223 } 224 225 if (typeof data[i].key != 'undefined') { 226 key = data[i].key; 227 } 228 229 if (key) { 230 path[level + 1] = key; 231 232 if (typeof data[i].key == 'undefined') { 233 data[i].key = key; 234 } 235 236 if (typeof data[i].name != 'undefined') { 237 this.list[key] = { 238 name: data[i].name, 239 path: path.slice(0, level + 1) 240 }; 241 } 242 243 if (typeof data[i].items != 'undefined') { 244 this.iterate(data[i].items, key, level + 1, path); 245 } 246 } 247 } 248 }, 249 250 getItem: function (key) { 251 var item = this.list[key]; 252 return item; 253 }, 254 255 getTrail: function (key, separator) { 256 var item = this.list[key]; 257 258 if (item) { 259 var trail = []; 260 261 for (var i = 0; i < item.path.length; i++) { 262 if (typeof this.list[item.path[i]] != 'undefined') { 263 trail.push(this.list[item.path[i]].name); 264 } else { 265 trail.push('?'); 266 } 267 } 268 269 trail.push(item.name); 270 271 return trail.join(separator); 272 } 273 274 return '?'; 275 } 276} 277 278var Calculate = function () { this.initialize.apply(this, arguments) }; 279Calculate.prototype = { 280 initialize: function (test, data) { 281 this.parameters = { 282 test: test, 283 data: data 284 }; 285 286 this.maximum = 0; 287 this.score = 0; 288 this.points = []; 289 290 for (var i = 0; i < this.parameters.data.length; i++) { 291 this.iterate(this.parameters.data[i].items, ''); 292 } 293 294 this.points = this.points.join(','); 295 }, 296 297 iterate: function (data, prefix) { 298 for (var i = 0; i < data.length; i++) { 299 if (data[i].key) { 300 if (prefix == '') { 301 var score = this.score; 302 var maximum = this.maximum; 303 } 304 305 if (typeof data[i].value != 'undefined') { 306 this.calculate(data[i].key, data[i]); 307 } 308 309 if (typeof data[i].items != 'undefined') { 310 this.iterate(data[i].items, data[i].key); 311 } 312 313 if (prefix == '') { 314 this.points.push(data[i].id + '=' + (this.score - score) + '/' + (this.maximum - maximum)); 315 } 316 } 317 } 318 }, 319 320 calculate: function (prefix, data) { 321 var result = true; 322 var value = typeof data.value == 'object' ? data.value : { maximum: data.value }; 323 324 if (typeof data.value.conditional == 'undefined') { 325 this.maximum += value.maximum; 326 } 327 328 if (typeof data.items == 'object') { 329 result = 0; 330 passed = true; 331 332 for (var i = 0; i < data.items.length; i++) { 333 if (data.items[i].key) { 334 var r = this.getResult(data.items[i].key); 335 passed &= r | YES; 336 result |= r; 337 } 338 } 339 340 if (!passed) { 341 result = false;
342 } 343 } 344 else { 345 result = this.getResult(prefix); 346 } 347 348 if (result & YES) { 349 var valid = true; 350 351 if (typeof data.value.conditional == 'string') { 352 if (data.value.conditional.substr(0, 1) == '!') { 353 var conditional = this.getResult(data.value.conditional.substr(1)); 354 355 if (conditional & YES) { 356 valid = false; 357 } 358 } 359 } 360 361 if (valid) { 362 if (result & PREFIX && typeof value.award == 'object' && typeof value.award.PREFIX != 'undefined') { 363 this.score += value.award.PREFIX; 364 } 365 else if (result & BUGGY && typeof value.award == 'object' && typeof value.award.BUGGY != 'undefined') { 366 this.score += value.award.BUGGY; 367 } 368 else if (result & OLD && typeof value.award == 'object' && typeof value.award.OLD != 'undefined') { 369 this.score += value.award.OLD; 370 } 371 else { 372 this.score += value.maximum; 373 } 374 } 375 } 376 }, 377 378 getResult: function (key) { 379 if (match = (new RegExp(key + '=(-?[0-9]+)')).exec(this.parameters.test.results)) { 380 return parseInt(match[1], 10); 381 } 382 383 return null; 384 } 385}; 386 387 388 389/* Base UI functions */ 390 391var Index = function () { this.initialize.apply(this, arguments) }; 392Index.prototype = { 393 initialize: function (options) { 394 var that = this; 395 this.options = options; 396 397 var menu = document.createElement('div'); 398 menu.id = 'indexmenu'; 399 options.index.appendChild(menu); 400 401 var categories = document.createElement('ul'); 402 menu.appendChild(categories); 403 404 for (var i = 0; i < options.tests.length; i++) { 405 var category = document.createElement('li'); 406 category.className = 'category ' + options.tests[i].id; 407 categories.appendChild(category); 408 409 var link = document.createElement('a'); 410 link.href = '#category-' + options.tests[i].id; 411 link.onclick = function () { that.closeIndex(); }; 412 link.innerHTML = options.tests[i].name; 413 category.appendChild(link); 414 415 if (options.tests[i].items.length) { 416 var items = document.createElement('ul'); 417 category.appendChild(items); 418 419 for (var j = 0; j < options.tests[i].items.length; j++) { 420 var item = document.createElement('li'); 421 items.appendChild(item); 422 423 var link = document.createElement('a'); 424 link.href = '#table-' + options.tests[i].items[j].id; 425 link.onclick = function () { that.closeIndex(); }; 426 link.innerHTML = options.tests[i].items[j].name; 427 item.appendChild(link); 428 } 429 } 430 } 431 432 var button = document.createElement('button'); 433 button.innerHTML = 'î'; 434 button.id = 'indexbutton'; 435 button.onclick = this.toggleIndex; 436 options.index.appendChild(button); 437 438 options.wrapper.onclick = this.closeIndex; 439 }, 440 441 toggleIndex: function () { 442 if (document.body.className.indexOf(' indexVisible') == -1) { 443 document.body.className = document.body.className.replace(' indexVisible', '') + ' indexVisible'; 444 } else { 445 document.body.className = document.body.className.replace(' indexVisible', ''); 446 } 447 }, 448 449 closeIndex: function () { 450 document.body.className = document.body.className.replace(' indexVisible', ''); 451 } 452} 453 454 455var Confirm = function () { this.initialize.apply(this, arguments) }; 456Confirm.prototype = { 457 initialize: function (parent, options) { 458 this.options = options; 459 460 this.useragent = document.createElement('p'); 461 this.useragent.className = 'useragent'; 462 parent.appendChild(this.useragent); 463 this.useragent.innerHTML = 'You are using ' + Browsers; 464 465 this.confirm = document.createElement('span'); 466 this.confirm.innerHTML = 'Correct?'; 467 this.useragent.appendChild(this.confirm); 468 469 var correct = document.createElement('a'); 470 correct.addEventListener('click', function () { this.confirmUseragent(); }.bind(this), true); 471 correct.className = 'correct'; 472 correct.innerHTML = 'â'; 473 this.confirm.appendChild(correct); 474 475 var wrong = document.createElement('a'); 476 wrong.addEventListener('click', function (e) { e.stopPropagation(); this.reportUseragent(); }.bind(this), true); 477 wrong.className = 'wrong'; 478 wrong.innerHTML = 'â'; 479 this.confirm.appendChild(wrong); 480 481 this.thanks = document.createElement('span'); 482 this.thanks.style.display = 'none'; 483 this.thanks.innerHTML = 'Thanks!'; 484 this.useragent.appendChild(this.thanks); 485 }, 486 487 confirmUseragent: function () { 488 this.options.onConfirm(); 489 this.showThanks(); 490 }, 491
492 reportUseragent: function () { 493 this.options.onReport(); 494 495 new Feedback(this.confirm, { 496 suggestion: 'I am using' + ' ' + Browsers, 497 498 onFeedback: function (value) { 499 this.options.onFeedback(value); 500 }.bind(this), 501 502 onClose: function () { 503 this.showThanks(); 504 }.bind(this) 505 }); 506 }, 507 508 showThanks: function () { 509 this.confirm.style.display = 'none'; 510 this.thanks.style.display = 'inline'; 511 512 window.setTimeout(function () { 513 this.thanks.style.display = 'none'; 514 }.bind(this), 2500); 515 } 516} 517 518var Save = function () { this.initialize.apply(this, arguments) }; 519Save.prototype = { 520 initialize: function (parent, options) { 521 var that = this; 522 523 this.parent = parent; 524 this.options = options; 525 this.created = false; 526 527 this.popup = document.createElement('div'); 528 this.popup.className = 'popupPanel pointsLeft save'; 529 this.popup.style.display = 'none'; 530 this.parent.appendChild(this.popup); 531 532 document.addEventListener('click', this.close.bind(this), false) 533 document.addEventListener('touchstart', this.close.bind(this), false) 534 535 this.parent.addEventListener('click', this.open.bind(this), true) 536 this.parent.addEventListener('touchstart', this.open.bind(this), true) 537 }, 538 539 create: function () { 540 this.created = true; 541 542 this.popup.innerHTML += 543 "<div id='save'>" + 544 "<p>You can see the results here:</p>" + 545 "<p><a href='https://html5test.co/s/?" + this.options.id + "'>html5test.co/s/?" + this.options.id + "</a></p>" + 546 "<p>Or scan this QR-code:</p>" + 547 "<p>" + 548 "<img src='https://quickchart.io/qr?size=200&text=" + encodeURIComponent("https://html5test.co/s/?" + this.options.id) + "' width='200' height='200'>" + 549 "</p>" + 550 "<p>The unique id for this test is:<br><code>" + this.options.id + "</code></p>" + 551 "</div>"; 552 553 if (this.options.onSave) { 554 this.options.onSave(); 555 } 556 }, 557 558 open: function (e) { 559 e.stopPropagation(); 560 561 var ignore = false; 562 var el = e.target || e.srcElement; 563 564 while (el != this.parent && ignore == false) { 565 if (el.className.indexOf('popupPanel') != -1) ignore = true; 566 el = el.parentNode; 567 } 568 569 if (!ignore) { 570 e.preventDefault(); 571 572 if (!this.created) { 573 this.create(); 574 } 575 576 this.popup.style.display = 'block'; 577 } 578 }, 579 580 close: function (e) { 581 this.popup.style.display = 'none'; 582 } 583} 584 585 586 587var Feedback = function () { this.initialize.apply(this, arguments) }; 588Feedback.prototype = { 589 initialize: function (parent, options) { 590 var that = this; 591 592 this.parent = parent; 593 this.options = options; 594 595 this.popup = document.createElement('div'); 596 this.popup.className = 'popupPanel pointsRight feedback'; 597 this.popup.style.display = 'none'; 598 this.parent.appendChild(this.popup); 599 600 this.popup.addEventListener('click', function (e) { e.stopPropagation() }, false) 601 this.popup.addEventListener('touchstart', function (e) { e.stopPropagation() }, false) 602 603 document.addEventListener('click', this.close.bind(this), false) 604 document.addEventListener('touchstart', this.close.bind(this), false) 605 606 this.create(); 607 }, 608 609 create: function () { 610 this.created = true; 611 612 this.popup.innerHTML += 613 "<div id='feedback'>" + 614 "<h3>What is wrong with this identification?</h3>" + 615 "<textarea id='correction'>" + this.options.suggestion + "</textarea>" + 616 "<button id='sendCorrection'><span>â</span>Send correction</button>" + 617 "</div>"; 618 619 this.popup.style.display = 'block'; 620 621 var button = document.getElementById('sendCorrection') 622 button.addEventListener('click', this.send.bind(this), false); 623 }, 624 625 send: function () { 626 var field = document.getElementById('correction') 627 628 if (field.value != this.options.suggestion) { 629 if (this.options.onFeedback) { 630 this.options.onFeedback(field.value); 631 } 632 } 633 634 this.close(); 635 }, 636 637 close: function (e) { 638 this.popup.style.display = 'none'; 639 this.popup.parentNode.removeChild(this.popup); 640 641 if (this.options.onClose) { 642 this.options.onClose(); 643 } 644 } 645} 646 647 648 649var ResultsTable = function () { this.initialize.apply(this, arguments) }; 650ResultsTable.prototype = { 651 652 initialize: function (options) { 653 this.parent = options.parent; 654 this.tests = options.tests; 655 this.options = { 656 title: options.title || '', 657 browsers: options.browsers || [], 658 columns: options.columns || 2, 659 distribute: options.distribute || false, 660 header: options.header || false, 661 links: options.links || false, 662 grading: options.grading || false, 663 features: options.features || false, 664 explainations: options.explainations || false, 665 666 onChange: options.onChange || false 667 } 668 669 var that = this; 670 671 function close(e) { 672 if (that.panel) { 673 var cell = that.panel.parentNode; 674 var node = e.target; 675 676 while (node.parentNode) { 677 if (node == that.panel) return; 678 node = node.parentNode; 679 } 680 681 that.panel.parentNode.removeChild(that.panel); 682 that.panel = null; 683 684 var node = e.target; 685 while (node.parentNode) { 686 if (node == cell) return e.stopPropagation(); 687 node = node.parentNode; 688 } 689 } 690 } 691 692 document.addEventListener('click', close, true) 693 document.addEventListener('touchstart', close, true) 694 695 this.data = [null]; 696 697 this.createCategories(this.parent, this.tests); 698 }, 699 700 updateColumn: function (column, data) { 701 this.data[column] = data; 702 703 for (var c = 0; c < this.tests.length; c++) 704 for (var i = 0; i < this.tests[c].items.length; i++) { 705 var test = this.tests[c].items[i]; 706 707 if (typeof test != 'string') { 708 if (typeof test != 'undefined') { 709 var points = 0; 710 var maximum = 0; 711
712 if (match = (new RegExp(test.id + "=([0-9]+)(?:\\/([0-9]+))?(?:\\+([0-9]+))?")).exec(data.points)) { 713 points = match[1]; 714 if (match[2]) maximum = match[2]; 715 } 716 717 var row = document.getElementById('head-' + test.id); 718 var cell = row.childNodes[0].firstChild.nextSibling; 719 720 var content = "<div class='grade'>"; 721 722 if (this.options.grading) { 723 var grade = ''; 724 var percent = parseInt(points / maximum * 100, 10); 725 switch (true) { 726 case percent == 0: grade = 'none'; break; 727 case percent <= 30: grade = 'badly'; break; 728 case percent <= 60: grade = 'reasonable'; break; 729 case percent <= 95: grade = 'good'; break; 730 default: grade = 'great'; break; 731 } 732 733 if (points == maximum) 734 content += "<span class='" + grade + "'>" + points + "</span>"; 735 else 736 content += "<span class='" + grade + "'>" + points + "/" + maximum + "</span>"; 737 } else { 738 content += "<span>" + points + "</span>"; 739 } 740 741 content += "</div>"; 742 743 cell.innerHTML = content; 744 this.updateItems(column, data, test.items); 745 } 746 } 747 } 748 }, 749 750 updateItems: function (column, data, tests) { 751 var count = [0, 0]; 752 753 for (var i = 0; i < tests.length; i++) { 754 if (typeof tests[i] != 'string') { 755 var key = tests[i].key; 756 757 var row = document.getElementById('row-' + key); 758 var cell = row.childNodes[column + 1]; 759 760 if (typeof tests[i].items != 'undefined') { 761 var results = this.updateItems(column, data, tests[i].items); 762 763 if (results[0] == results[1]) { 764 cell.innerHTML = '<div>Yes <span class="check">â</span></div>'; 765 } else if (results[1] == 0) { 766 cell.innerHTML = '<div>No <span class="ballot">â</span></div>'; 767 row.className += ' missing'; 768 } else { 769 cell.innerHTML = '<div><span class="partially">Partial</span> <span class="partial">â</span></div>'; 770 row.className += ' missing'; 771 } 772 } else { 773 if (match = (new RegExp(key + '=(-?[0-9]+)')).exec(data.results)) { 774 var result = parseInt(match[1], 10); 775 776 if (result & YES) { 777 switch (true) { 778 case !!(result & BUGGY): cell.innerHTML = '<div>Buggy <span class="buggy">î</span></div>'; row.className += ' missing'; break;
779 case !!(result & OLD): cell.innerHTML = '<div>Partial <span class="partial">â</span></div>'; row.className += ' missing'; count[1]++; break; 780 case !!(result & PREFIX): cell.innerHTML = '<div>Prefixed <span class="check">â</span></div>'; count[1]++; break; 781 default: cell.innerHTML = '<div>Yes <span class="check">â</span></div>'; count[1]++; break; 782 } 783 } 784 else { 785 switch (true) { 786 case !!(result & UNKNOWN): cell.innerHTML = '<div>Unknown <span class="partial">?</span></div>'; break; 787 case !!(result & BLOCKED): cell.innerHTML = '<div>Not functional <span class="buggy">!</span></div>'; break; 788 case !!(result & DISABLED): cell.innerHTML = '<div>Disabled <span class="ballot">â</span></div>'; break; 789 default: cell.innerHTML = '<div>No <span class="ballot">â</span></div>'; break; 790 } 791 row.className += ' missing'; 792 } 793 } else { 794 cell.innerHTML = '<div><span class="partially">Unknown</span> <span class="partial">?</span></div>'; 795 row.className += ' missing'; 796 } 797 } 798 799 count[0]++; 800 } 801 } 802 803 return count; 804 }, 805 806 createCategories: function (parent, tests) { 807 var left, right; 808 809 left = document.createElement('div'); 810 left.className = 'left'; 811 left.innerHTML = '<div></div>'; 812 parent.appendChild(left); 813 814 right = document.createElement('div'); 815 right.className = 'right'; 816 right.innerHTML = '<div></div>'; 817 parent.appendChild(right); 818 819 820 for (var i = 0; i < tests.length; i++) { 821 var container = parent; 822 if (tests[i].column == 'left') container = left.firstChild; 823 if (tests[i].column == 'right') container = right.firstChild; 824 825 var div = document.createElement('div'); 826 div.className = 'category ' + tests[i].id; 827 div.id = 'category-' + tests[i].id; 828 container.appendChild(div); 829 830 var h2 = document.createElement('h2'); 831 h2.innerHTML = tests[i].name; 832 div.appendChild(h2); 833 834 this.createSections(div, tests[i].items); 835 } 836 }, 837 838 createSections: function (parent, tests) { 839 for (var i = 0; i < tests.length; i++) { 840 var table = document.createElement('table'); 841 table.cellSpacing = 0; 842 table.id = 'table-' + tests[i].id; 843 parent.appendChild(table); 844 845 var thead = document.createElement('thead'); 846 table.appendChild(thead); 847 848 var tr = document.createElement('tr'); 849 tr.id = 'head-' + tests[i].id; 850 thead.appendChild(tr); 851 852 var th = document.createElement('th'); 853 th.innerHTML = tests[i].name + "<div></div>"; 854 th.colSpan = this.options.columns + 1; 855 tr.appendChild(th); 856 857 if (typeof tests[i].items != 'undefined') { 858 var tbody = document.createElement('tbody'); 859 table.appendChild(tbody); 860 861 var status = typeof tests[i].status != 'undefined' ? tests[i].status : ''; 862 863 this.createItems(tbody, 0, tests[i].items, { 864 id: tests[i].id, 865 status: status, 866 urls: [] 867 }); 868 } 869 } 870 }, 871 872 createItems: function (parent, level, tests, data) { 873 var ids = []; 874 875 for (var i = 0; i < tests.length; i++) { 876 var tr = document.createElement('tr'); 877 parent.appendChild(tr); 878 879 if (typeof tests[i] == 'string') { 880 if (this.options.explainations || tests[i].substr(0, 4) != '<em>') { 881 var th = document.createElement('th'); 882 th.colSpan = this.options.columns + 1; 883 th.className = 'details'; 884 tr.appendChild(th); 885 886 th.innerHTML = tests[i]; 887 } 888 } else { 889 var key = tests[i].key; 890 891 var th = document.createElement('th'); 892 th.innerHTML = "<div class='status " + (typeof tests[i].status != 'undefined' ? tests[i].status : data.status) + "'><span>" + tests[i].name + "</span></div>"; 893 tr.appendChild(th); 894 895 for (var c = 0; c < this.options.columns; c++) { 896 var td = document.createElement('td'); 897 tr.appendChild(td); 898 } 899 900 tr.id = 'row-' + key; 901 902 if (level > 0) { 903 tr.className = 'isChild'; 904 } 905 906 if (typeof tests[i].items != 'undefined') { 907 var urls = null; 908 909 if (this.options.links) { 910 if (typeof tests[i].urls != 'undefined') { 911 urls = tests[i].urls; 912 } 913 else if (typeof tests[i].url != 'undefined') { 914 urls = { 'w3c': tests[i].url }; 915 } 916 } 917 918 tr.className += 'hasChild'; 919 920 var children = this.createItems(parent, level + 1, tests[i].items, { 921 id: key, 922 status: typeof tests[i].status != 'undefined' ? tests[i].status : data.status, 923 urls: urls 924 }); 925 926 this.hideChildren(tr, children); 927 928 (function (that, tr, th, children) { 929 th.onclick = function () { 930 that.toggleChildren(tr, children); 931 }; 932 })(this, tr, th, children); 933 } else { 934 var urls; 935 var value = 0; 936 var showLinks = false;
937 938 if (typeof tests[i].value != 'undefined') { 939 value = tests[i].value; 940 } 941 942 if (typeof tests[i].urls != 'undefined') { 943 urls = tests[i].urls; 944 showLinks = true; 945 } 946 else if (typeof tests[i].url != 'undefined') { 947 urls = [['w3c', tests[i].url]]; 948 showLinks = true; 949 } 950 951 th.className = 'hasLink'; 952 953 (function (that, th, data) { 954 th.onclick = function () { 955 new FeaturePopup(th, data); 956 }; 957 })(this, th, { 958 id: key, 959 name: tests[i].name, 960 value: value, 961 status: typeof tests[i].status != 'undefined' ? tests[i].status : data.status, 962 urls: (urls || []).concat(data.urls || []) 963 }); 964 } 965 966 ids.push(tr.id); 967 } 968 } 969 970 return ids; 971 }, 972 973 toggleChildren: function (element, ids) { 974 if (element.className.indexOf(' hidden') == -1) { 975 this.hideChildren(element, ids); 976 } else { 977 this.showChildren(element, ids); 978 } 979 }, 980 981 showChildren: function (element, ids) { 982 element.className = element.className.replace(' hidden', ''); 983 984 for (var i = 0; i < ids.length; i++) { 985 var e = document.getElementById(ids[i]); 986 e.style.display = 'table-row'; 987 } 988 }, 989 990 hideChildren: function (element, ids) { 991 element.className = element.className.replace(' hidden', ''); 992 element.className += ' hidden'; 993 994 for (var i = 0; i < ids.length; i++) { 995 var e = document.getElementById(ids[i]); 996 e.style.display = 'none'; 997 } 998 } 999} 1000 1001 1002 1003var FeaturePopup = function () { this.initialize.apply(this, arguments) }; 1004FeaturePopup.current = null; 1005FeaturePopup.prototype = { 1006 initialize: function (parent, data) { 1007 if (FeaturePopup.current) { 1008 FeaturePopup.current.close(); 1009 } 1010 1011 var maximum = data.value; 1012 if (typeof maximum == 'object') { 1013 maximum = maximum.maximum; 1014 } 1015 1016 var content = ""; 1017 content += "<div class='info'>"; 1018 content += "<div class='column left status " + data.status + "'><span>" + data.status + "</span></div>"; 1019 content += "<div class='column middle" + (maximum ? '' : ' none') + "'><em>" + (maximum || 'â') + "</em> <span>" + (maximum != 1 ? 'Points' : 'Point') + "</span></div>"; 1020 content += "<div class='column right'><a href='/compare/feature/" + data.id + ".html' class='compare'><span>Compare</span></a></div>"; 1021 content += "</div>"; 1022 content += "<div class='links'>"; 1023 1024 for (var i = 0; i < data.urls.length; i++) { 1025 if (data.urls[i][0] == 'w3c') content += "<a href='" + data.urls[i][1] + "' class='w3c'>Go to the specification at W3C.org</a>"; 1026 if (data.urls[i][0] == 'whatwg') content += "<a href='" + data.urls[i][1] + "' class='whatwg'>Go to the specification at Whatwg.org</a>"; 1027 if (data.urls[i][0] == 'khronos') content += "<a href='" + data.urls[i][1] + "' class='khronos'>Go to the specification at Khronos.org</a>"; 1028 if (data.urls[i][0] == 'ietf') content += "<a href='" + data.urls[i][1] + "' class='ietf'>Go to the specification at IETF.org</a>"; 1029 if (data.urls[i][0] == 'webm') content += "<a href='" + data.urls[i][1] + "' class='webm'>Go to the specification at WebMproject.org</a>"; 1030 if (data.urls[i][0] == 'xiph') content += "<a href='" + data.urls[i][1] + "' class='xiph'>Go to the specification at Xiph.org</a>"; 1031 if (data.urls[i][0] == 'ecma') content += "<a href='" + data.urls[i][1] + "' class='ecma'>Go to the specification at ECMA</a>"; 1032 if (data.urls[i][0] == 'ricg') content += "<a href='" + data.urls[i][1] + "' class='ricg'>Go to Responsive Images Community Group</a>"; 1033 if (data.urls[i][0] == 'wp') content += "<a href='https://docs.webplatform.org/wiki" + data.urls[i][1] + "' class='wp'>Documentation at WebPlatform.org</a>"; 1034 if (data.urls[i][0] == 'mdn') content += "<a href='https://developer.mozilla.org/en-US/docs" + data.urls[i][1] + "' class='mdn'>Documentation at Mozilla Developer Network</a>"; 1035 } 1036 1037 content += "</div>"; 1038 1039 this.panel = document.createElement('div'); 1040 this.panel.className = 'linksPanel popupPanel pointsLeft'; 1041 this.panel.innerHTML = content; 1042 parent.appendChild(this.panel); 1043 1044 FeaturePopup.current = this; 1045 }, 1046 1047 close: function () { 1048 this.panel.parentNode.removeChild(this.panel); 1049 FeaturePopup.current = null; 1050 } 1051} 1052 1053document.addEventListener('click', function () { if (FeaturePopup.current) FeaturePopup.current.close() }, true) 1054document.addEventListener('touchstart', function () { if (FeaturePopup.current) FeaturePopup.current.close() }, true)
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.