var DeviceTable = function() { this.initialize.apply(this, arguments) };
DeviceTable.prototype = {
initialize: function(options) {
this.parent = options.parent;
document.body.addEventListener("click", this.onClose.bind(this), true);
var rows = this.parent.querySelectorAll('tbody tr');
for (var r = 0; r < rows.length; r++) {
rows[r].addEventListener("click", this.onShow.bind(this, rows[r]), true);
}
this.popup = null;
},
onClose: function(e) {
var child = false;
var el = e.target;
while (el.parentNode) {
if (el == this.parent) {
child = true;
break;
}
el = el.parentNode;
}
if (!child) this.close();
},
onShow: function(row) {
this.close();
var httpRequest;
if (window.XMLHttpRequest) {
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.open('POST','/api/loadLabDevice', true);
httpRequest.onreadystatechange = process.bind(this);
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send('id=' + encodeURIComponent(row.getAttribute('data-id')));
function process() {
if (httpRequest.readyState == 4 && httpRequest.responseText != '') {
var data = JSON.parse(httpRequest.responseText);
var bb = [
[ 'ie5', 'ie6', 'IE 5'],
[ 'ie6', 'ie6', 'IE 6'],
[ 'ie7', 'ie7', 'IE 7'],
[ 'ie8', 'ie7', 'IE 8'],
[ 'ie9', 'ie9', 'IE 9'],
[ 'ie10', 'ie10', 'IE 10'],
[ 'ie11', 'ie10', 'IE 11'],
[ 'ie10_metro', 'ie-metro', 'IE 10'],
[ 'ie11_metro', 'ie-metro', 'IE 11'],
[ 'wp7', 'ie-metro', 'IE 9'],
[ 'wp8', 'ie-metro', 'IE 10'],
[ 'safari_ios_6', 'safari-ios-6', 'Safari'],
[ 'safari_ios_7', 'safari-ios-7', 'Safari'],
[ 'xpress', 'nokia', 'Xpress'],
[ 'nokia', 'nokia', 'Nokia'],
[ 'maemo', 'nokia', 'Nokia'],
[ 'meego', 'nokia', 'Nokia'],
[ 'webos', 'webos', 'webOS'],
[ 'android', 'android', 'Android'],
[ 'bb', 'bb', 'Browser'],
[ 'bb10', 'bb10', 'Browser'],
[ 'tabletos', 'tabletos', 'Browser'],
[ 'chrome', 'chrome', 'Chrome'],
[ 'coast', 'coast', 'Coast'],
[ 'diigo', 'diigo', 'Diigo'],
[ 'dolphin', 'dolphin', 'Dolphin'],
[ 'firefox', 'firefox', 'Firefox'],
[ 'ilunascape', 'ilunascape', 'iLunascape'],
[ 'maxthon', 'maxthon', 'Maxthon'],
[ 'mercury', 'mercury', 'Mercury'],
[ 'puffin', 'puffin', 'Puffin'],
[ 'silk', 'silk', 'Silk'],
[ 'sleipnir', 'sleipnir', 'Sleipnir'],
[ 'one', 'one', 'One'],
[ 'opera', 'opera', 'Opera'],
[ 'qq', 'qq', 'QQ'],
[ 'uc-iphone', 'uc-iphone', 'UC Web'],
[ 'uc-old', 'uc-old', 'UC Web'],
]
var browsers = "
";
if (data.defaultBrowser || data.defaultFingerprint) {
browsers += "- ";
var stock = true;
if (data.defaultBrowser) {
for (var b = 0; b < bb.length; b++) {
if (data.defaultBrowser == bb[b][0]) {
stock = false;
browsers += "
" + bb[b][2] + "";
}
}
}
if (stock) {
browsers += "Default browser";
}
if (data.defaultFingerprint) {
browsers += "";
}
browsers += " ";
}
for (var b = 0; b < bb.length; b++) {
if (data.otherBrowsers[bb[b][0]]) browsers += "
" + bb[b][2] + " ";
}
if (data.hasInspect) browsers += "
Inspect ";
browsers += "
";
this.popup = document.createElement('div');
this.popup.className = 'popupPanel pointsLeft deviceInfo';
this.popup.innerHTML =
"" + data.deviceManufacturer + " " + data.deviceModel + ( data.url ? "" : "") + "
" +
"" +
"";
row.cells[0].appendChild(this.popup);
}
}
},
close: function() {
if (this.popup) {
this.popup.parentNode.removeChild(this.popup);
this.popup = null;
}
}
}
var SearchField = function() { this.initialize.apply(this, arguments) };
SearchField.prototype = {
initialize: function(options) {
this.parent = options.parent;
this.options = {
value: options.value || null,
onQuery: options.onQuery || null,
onSubmit: options.onSubmit || null
}
this.interval = null;
this.container = document.createElement('div');
this.container.className = 'search';
this.parent.appendChild(this.container);
this.container.innerHTML =
"" +
"";
this.container.addEventListener("click", this.onClick.bind(this), false);
this.container.firstChild.addEventListener("keyup", this.onUpdate.bind(this), true);
this.container.firstChild.addEventListener("change", this.onUpdate.bind(this), true);
this.container.firstChild.nextSibling.addEventListener("click", this.onClear.bind(this), true);
},
onUpdate: function(e) {
if (this.interval) {
window.clearTimeout(this.interval);
}
this.interval = window.setTimeout(this.onQuery.bind(this), 250);
if (e.keyCode == 13) {
if (this.options.onSubmit) {
this.options.onSubmit(this.container.firstChild.value);
}
}
},
onClick: function(e) {
e.stopPropagation();
},
onClear: function(e) {
e.stopPropagation();
this.clear();
if (this.options.onQuery) {
this.options.onQuery('');
}
if (this.options.onSubmit) {
this.options.onSubmit('');
}
},
onQuery: function() {
var value = this.container.firstChild.value;
if (value.length < 3) return;
if (this.options.onQuery) {
this.options.onQuery(value);
}
},
clear: function() {
this.container.firstChild.value = '';
}
}
var ToggleSwitch = function() { this.initialize.apply(this, arguments) };
ToggleSwitch.prototype = {
initialize: function(options) {
this.parent = options.parent;
this.options = {
inactive: options.inactive || '',
active: options.active || '',
onChange: options.onChange || null
}
this.active = false;
this.container = document.createElement('div');
this.container.className = 'toggle';
this.parent.appendChild(this.container);
this.container.innerHTML =
"" +
"" + this.options.inactive + "
" +
"" + this.options.active + "
";
this.container.addEventListener("click", this.onToggle.bind(this), true);
},
onToggle: function() {
this.active = ! this.active;
if (this.active) {
this.container.className += ' selected';
} else {
this.container.className = this.container.className.replace(' selected', '');
}
if (this.options.onChange) {
this.options.onChange(this.active);
}
},
activate: function() {
if (!this.active) {
this.active = true;
this.container.className += ' selected';
}
},
deactivate: function() {
if (this.active) {
this.active = false;
this.container.className = this.container.className.replace(' selected', '');
}
}
}
var FeatureTable = function() { this.initialize.apply(this, arguments) };
FeatureTable.prototype = {
initialize: function(options) {
this.parent = options.parent;
this.tests = options.tests;
this.options = {
title: options.title || '',
browsers: options.browsers || [],
columns: options.columns || 2,
distribute: options.distribute || false,
header: options.header || false,
links: options.links || false,
grading: options.grading || false,
features: options.features || false,
explainations: options.explainations || false,
filter: null,
onChange: options.onChange || false
}
this.panel = null;
this.diff = [];
this.data = [];
for (var i = 0; i < this.options.columns; i++) {
this.data[i] = null;
}
this.createCategories(this.parent, this.tests)
this.results = document.createElement('div');
this.parent.appendChild(this.results);
this.filter(options.filter || '');
},
filter: function(filter, force) {
var that = this;
if (!force && this.options.filter == filter) {
return;
}
this.options.filter = filter;
if (filter == '') {
this.results.innerHTML = '';
for (var i = 0; i < this.tests.length; i++) {
this.createSections(this.results, this.tests[i].items);
}
this.update();
return;
}
var result = [];
var status = [];
var name = [];
function retrieveItems(items, level) {
for (var i = 0; i < items.length; i++) {
if (typeof items[i] == 'object') {
name[level] = items[i].name;
status[level] = items[i].status || null;
if (!filterItem(items[i], level)) {
if (items[i].items) {
retrieveItems(items[i].items, level + 1);
}
}
}
}
}
function addItems(items, level) {
for (var i = 0; i < items.length; i++) {
if (typeof items[i] == 'object') {
name[level] = items[i].name;
status[level] = items[i].status || null;
if (level > 1) {
var s = "";
for (var l = level; l >= 0; l--) {
if (status[l]) {
s = status[l];
break;
}
}
var r = {
key: items[i].key,
name: items[i].name,
status: s
}
if (items[i].value) r.value = items[i].value;
if (items[i].url) r.url = items[i].url;
if (items[i].urls) r.urls = items[i].urls;
if (items[i].items) r.items = items[i].items;
result.push(r);
}
else if (items[i].items) {
addItems(items[i].items, level + 1);
}
}
}
return true;
}
function filterItem(item, level) {
name[level] = item.name;
status[level] = item.status || null;
var selected = true;
if (filter == ':diff')
selected = level > 1 ? that.diff[item.key] : false;
else
selected = item.name.toLowerCase().indexOf(filter) != -1;
if (selected) {
if (level > 1) {
var s = "";
for (var l = level; l >= 0; l--) {
if (status[l]) {
s = status[l];
break;
}
}
var r = {
key: item.key,
name: name.slice(2, level + 1).join(' ▸ '),
status: s
}
if (item.value) r.value = item.value;
if (item.url) r.url = item.url;
if (item.urls) r.urls = item.urls;
if (item.items) r.items = item.items;
return result.push(r);
}
else if (item.items) {
return addItems(item.items, level + 1);
}
}
}
retrieveItems(this.tests, 0);
this.results.innerHTML = '';
this.createSections(this.results, [{ name: filter == ':diff' ? 'Difference' : filter, items: result }]);
this.update();
},
loadColumn: function(column, browser) {
var id = browser;
if (typeof browser == 'object') {
id = browser.platform + (browser.version ? '-' + browser.version : '');
}
var that = this;
var httpRequest;
if (window.XMLHttpRequest) {
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.open('POST','/api/loadBrowser', true);
httpRequest.onreadystatechange = process;
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send('id=' + encodeURIComponent(id));
function process() {
if (httpRequest.readyState == 4 && httpRequest.responseText != '') {
var data = JSON.parse(httpRequest.responseText);
var f = that.options.filter;
that.filter('');
that.updateColumn(column, data);
that.filter(f);
}
}
},
calculateColumn: function(column) {
var that = this;
new Test(process);
function process(r) {
var c = new Calculate(r, tests);
that.updateColumn(column, {
id: 'mybrowser',
nickname: 'My browser',
score: c.score,
points: c.points,
results: r.results
})
}
},
clearColumn: function(column) {
this.data[column] = null;
this.diff = [];
if (this.options.onChange) {
var ids = [];
for (var i = 0; i < this.options.columns; i++) {
if (this.data[i]) {
if (this.data[i].id)
ids.push(this.data[i].id);
else if (this.data[i].version)
ids.push(this.data[i].platform + '-' + this.data[i].version);
else
ids.push(this.data[i].platform);
}
}
this.options.onChange(ids);
}
var row = document.getElementById('row-header');
var cell = row.childNodes[column + 1];
cell.className = 'empty';
cell.firstChild.firstChild.innerHTML = '';
cell.firstChild.childNodes[1].selectedIndex = 0;
for (var c = 0; c < this.tests.length; c++)
for (var i = 0; i < this.tests[c].items.length; i++) {
var test = this.tests[c].items[i];
if (typeof test != 'string') {
if (typeof test.items != 'undefined') {
var row = document.getElementById('head-' + test.id);
if (row) {
var cell = row.childNodes[column + 1];
cell.innerHTML = '';
}
this.clearItems(column, test.id, test.items);
}
}
}
this.filter(this.options.filter, true);
},
clearItems: function(column, id, tests) {
for (var i = 0; i < tests.length; i++) {
if (typeof tests[i] != 'string') {
var key = tests[i].key;
var row = document.getElementById('row-' + key);
if (row) {
var cell = row.childNodes[column + 1];
cell.innerHTML = '';
cell.className = '';
}
if (typeof tests[i].items != 'undefined') {
this.clearItems(column, key, tests[i].items);
}
var base = null;
var diff = false;
for (var c = 0; c < this.options.columns; c++) {
if (this.data[c]) {
if (match = (new RegExp(key + '=(-?[0-9]+)')).exec(this.data[c].results)) {
var result = parseInt(match[1], 10);
if (base === null) {
base = result;
}
else {
if (result != base) {
diff = true;
break;
}
}
}
}
}
this.diff[key] = diff;
}
}
},
update: function() {
for (var i = 0; i < this.options.columns; i++) {
if (this.data[i]) {
this.updateColumn(i, this.data[i]);
}
}
},
updateColumn: function(column, data) {
this.data[column] = data;
this.diff = [];
if (this.options.onChange) {
var ids = [];
for (var i = 0; i < this.options.columns; i++) {
if (this.data[i]) {
if (this.data[i].id)
ids.push(this.data[i].id);
else if (this.data[i].version)
ids.push(this.data[i].platform + '-' + this.data[i].version);
else
ids.push(this.data[i].platform);
}
}
this.options.onChange(ids);
}
var row = document.getElementById('row-header');
var cell = row.childNodes[column + 1];
cell.className = '';
cell.firstChild.firstChild.innerHTML = '' + data.nickname + '' + data.score + '';
for (var c = 0; c < this.tests.length; c++)
for (var i = 0; i < this.tests[c].items.length; i++) {
var test = this.tests[c].items[i];
if (typeof test != 'string') {
if (typeof test != 'undefined') {
var points = 0;
var maximum = 0;
if (match = (new RegExp(test.id + "=([0-9]+)(?:\\/([0-9]+))?(?:\\+([0-9]+))?")).exec(data.points)) {
points = match[1];
if (match[2]) maximum = match[2];
}
var row = document.getElementById('head-' + test.id);
if (row) {
var cell = row.childNodes[column + 1];
var content = "";
if (this.options.grading) {
var grade = '';
var percent = parseInt(points / maximum * 100, 10);
switch (true) {
case percent == 0: grade = 'none'; break;
case percent <= 30: grade = 'badly'; break;
case percent <= 60: grade = 'reasonable'; break;
case percent <= 95: grade = 'good'; break;
default: grade = 'great'; break;
}
if (points == maximum)
content += "" + points + "";
else
content += "" + points + "/" + maximum + "";
} else {
content += "" + points + "";
}
content += "
";
cell.innerHTML = content;
}
this.updateItems(column, data, test.items);
}
}
}
},
updateItems: function(column, data, tests) {
var count = [ 0, 0 ];
for (var i = 0; i < tests.length; i++) {
if (typeof tests[i] != 'string') {
var key = tests[i].key;
var row = document.getElementById('row-' + key);
if (row) {
var cell = row.childNodes[column + 1];
var classes = [ 'used' ];
if (typeof tests[i].items != 'undefined') {
var results = this.updateItems(column, data, tests[i].items);
if (results[0] == results[1]) {
cell.innerHTML = '' + 'Yes' + ' ✔
';
classes.push('yes');
} else if (results[1] == 0) {
cell.innerHTML = '' + 'No' + ' ✘
';
classes.push('no');
} else {
cell.innerHTML = '' + 'Partial' + ' ○
';
}
}
else {
if (match = (new RegExp(key + '=(-?[0-9]+)')).exec(data.results)) {
var result = parseInt(match[1], 10);
if (result & YES) {
switch(true) {
case !! (result & BUGGY): cell.innerHTML = 'Buggy
'; break;
case !! (result & OLD): cell.innerHTML = 'Partial ○
'; count[1]++; break;
case !! (result & PREFIX): cell.innerHTML = 'Prefixed ✔
'; classes.push('yes'); count[1]++; break;
case !! (result & EXPERIMENTAL): cell.innerHTML = 'Prefixed ✔
'; classes.push('yes'); count[1]++; break;
default: cell.innerHTML = 'Yes ✔
'; classes.push('yes'); count[1]++; break;
}
}
else {
switch(true) {
case !! (result & UNKNOWN): cell.innerHTML = 'Unknown ?
'; break;
case !! (result & BLOCKED): cell.innerHTML = 'Broken !
'; classes.push('no'); break;
case !! (result & DISABLED): cell.innerHTML = 'Disabled ✘
'; classes.push('no'); break;
default: cell.innerHTML = 'No ✘
'; classes.push('no'); break;
}
}
} else {
cell.innerHTML = 'Unknown ?
';
}
}
cell.className = classes.join(' ');
var base = null;
var diff = false;
for (var c = 0; c < this.options.columns; c++) {
if (this.data[c]) {
if (match = (new RegExp(key + '=(-?[0-9]+)')).exec(this.data[c].results)) {
var result = parseInt(match[1], 10);
if (base === null) {
base = result;
}
else {
if (result != base) {
diff = true;
break;
}
}
}
}
}
this.diff[key] = diff;
} else {
if (typeof tests[i].items != 'undefined') {
var results = this.updateItems(column, data, tests[i].items);
}
}
count[0]++;
}
}
return count;
},
askForUniqueId: function(c) {
var id = prompt('Enter the unique id of the results you want to see')
if (id) {
this.loadColumn(c, 'custom:' + id);
}
},
createCategories: function(parent, tests) {
var table = document.createElement('table');
table.id = 'table-header';
parent.appendChild(table);
var tbody = document.createElement('tbody');
table.appendChild(tbody);
var tr = document.createElement('tr');
tr.id = 'row-header';
tbody.appendChild(tr);
var th = document.createElement('th');
th.innerHTML = this.options.title;
tr.appendChild(th);
for (var c = 0; c < this.options.columns; c++) {
var that = this;
var td = document.createElement('td');
td.className = 'empty';
tr.appendChild(td);
var wrapper = document.createElement('div');
td.appendChild(wrapper);
var div = document.createElement('div');
div.className = 'name';
wrapper.appendChild(div);
var menu = document.createElement('div');
menu.className = 'popup popupPanel pointsRight hasSearch';
wrapper.appendChild(menu);
var header = document.createElement('div');
header.className = 'toolbar';
menu.appendChild(header);
var scroll = document.createElement('div');
scroll.className = 'scroll';
menu.appendChild(scroll);
var list = document.createElement('ul');
scroll.appendChild(list);
(function(c, menu, list, header) {
var search = new SearchField({
parent: header,
onQuery: function(query) {
build(list, that.options.browsers, query != "", query);
}
});
document.body.addEventListener('click', function(e) {
menu.className = menu.className.replace(' visible', '');
}, false);
div.addEventListener('click', function(e) {
if (that.data[c] == null) {
if (e.altKey) {
that.askForUniqueId(c);
}
else
menu.className += ' visible';
}
else
that.clearColumn(c);
e.stopPropagation();
}, true);
list.addEventListener('click', function(e) {
var close = true;
if (e.target) {
var target = e.target;
while (target.tagName != 'LI' && target.parentNode) {
target = target.parentNode;
}
if (target.hasAttribute('data-action')) {
var action = target.getAttribute('data-action');
if (action == 'more') {
build(list, that.options.browsers, true);
close = false;
}
if (action == 'less') {
build(list, that.options.browsers, false);
close = false;
}
if (action == 'calculate') {
that.calculateColumn(c);
}
if (action == 'custom') {
window.setTimeout(function() {
that.askForUniqueId(c);
}, 0);
}
if (action == 'load') {
var id = target.getAttribute('data-id');
that.loadColumn(c, that.options.browsers[id]);
}
}
}
if (close) {
menu.className = menu.className.replace(' visible', '');
}
e.stopPropagation();
}, true);
})(c, menu, list, header);
build(list, this.options.browsers, false);
function build(list, browsers, all, filter) {
list.innerHTML = '';
if (!filter) {
var item = document.createElement('li');
item.setAttribute('data-action', 'calculate');
item.innerHTML = 'My browser';
list.appendChild(item);
var item = document.createElement('li');
item.setAttribute('data-action', 'custom');
item.innerHTML = 'Enter unique id...';
list.appendChild(item);
}
var type = null;
for (var i = 0; i < browsers.length; i++) {
if (!filter || browsers[i].nickname.toLowerCase().indexOf(filter.toLowerCase()) != -1) {
if (all || browsers[i].visible) {
if (type != browsers[i].type) {
var item = document.createElement('li');
item.className = 'indent-0 title';
list.appendChild(item);
switch(browsers[i].type) {
case 'desktop': item.innerHTML = 'Desktop browsers'; break;
case 'gaming': item.innerHTML = 'Gaming'; break;
case 'mobile': item.innerHTML = 'Mobiles'; break;
case 'tablet': item.innerHTML = 'Tablets'; break;
case 'television': item.innerHTML = 'Television'; break;
}
}
var item = document.createElement('li');
item.setAttribute('data-action', 'load');
item.setAttribute('data-id', i);
item.innerHTML = browsers[i].nickname + (browsers[i].details ? ' (' + browsers[i].details + ')' : '');
list.appendChild(item);
type = browsers[i].type;
}
}
}
if (!filter) {
if (!all) {
var item = document.createElement('li');
item.className = 'more';
item.setAttribute('data-action', 'more');
item.innerHTML = 'Show more';
list.appendChild(item);
} else {
var item = document.createElement('li');
item.className = 'less';
item.setAttribute('data-action', 'less');
item.innerHTML = 'Show less';
list.appendChild(item);
}
}
}
}
},
createSections: function(parent, tests) {
for (var i = 0; i < tests.length; i++) {
if (typeof tests[i] == 'string') {
var h2 = document.createElement('h2');
h2.innerHTML = tests[i];
parent.appendChild(h2);
} else {
var table = document.createElement('table');
if (tests[i].id) table.id = 'table-' + tests[i].id;
parent.appendChild(table);
var thead = document.createElement('thead');
table.appendChild(thead);
var tr = document.createElement('tr');
if (tests[i].id) tr.id = 'head-' + tests[i].id;
thead.appendChild(tr);
var th = document.createElement('th');
if (tests[i].name) th.innerHTML = tests[i].name;
tr.appendChild(th);
for (var c = 0; c < this.options.columns; c++) {
var td = document.createElement('td');
tr.appendChild(td);
}
if (typeof tests[i].items != 'undefined') {
var tbody = document.createElement('tbody');
table.appendChild(tbody);
var status = typeof tests[i].status != 'undefined' ? tests[i].status : '';
this.createItems(tbody, 0, tests[i].items, {
id: tests[i].id,
status: status,
urls: []
});
}
}
}
},
createItems: function(parent, level, tests, data) {
var ids = [];
for (var i = 0; i < tests.length; i++) {
var tr = document.createElement('tr');
parent.appendChild(tr);
if (typeof tests[i] == 'string') {
if (this.options.explainations || tests[i].substr(0, 4) != '') {
var th = document.createElement('th');
th.colSpan = this.options.columns + 1;
th.className = 'details';
tr.appendChild(th);
th.innerHTML = tests[i];
}
} else {
var key = tests[i].key;
var th = document.createElement('th');
th.innerHTML = "" + tests[i].name + "
";
tr.appendChild(th);
for (var c = 0; c < this.options.columns; c++) {
var td = document.createElement('td');
tr.appendChild(td);
}
tr.id = 'row-' + key;
if (level > 0) {
tr.className = 'isChild';
}
if (typeof tests[i].items != 'undefined') {
var urls = null;
if (this.options.links) {
if (typeof tests[i].urls != 'undefined') {
urls = tests[i].urls;
}
else if (typeof tests[i].url != 'undefined') {
urls = { 'w3c': tests[i].url };
}
}
tr.className += 'hasChild';
var children = this.createItems(parent, level + 1, tests[i].items, {
id: key,
status: typeof tests[i].status != 'undefined' ? tests[i].status : data.status,
urls: urls
});
this.hideChildren(tr, children);
(function(that, tr, th, children) {
th.onclick = function() {
that.toggleChildren(tr, children);
};
})(this, tr, th, children);
} else {
var urls;
var value = 0;
if (typeof tests[i].value != 'undefined') {
value = tests[i].value;
}
if (typeof tests[i].urls != 'undefined') {
urls = tests[i].urls;
}
else if (typeof tests[i].url != 'undefined') {
urls = [ [ 'w3c', tests[i].url ] ];
}
th.className = 'hasLink';
(function(th, data){
th.onclick = function() {
new FeaturePopup(th, data);
};
})(th, {
id: key,
name: tests[i].name,
value: value,
status: typeof tests[i].status != 'undefined' ? tests[i].status : data.status,
urls: (urls || []).concat(data.urls || [])
});
}
ids.push(tr.id);
}
}
return ids;
},
toggleChildren: function(element, ids) {
if (element.className.indexOf(' hidden') == -1) {
this.hideChildren(element, ids);
} else {
this.showChildren(element, ids);
}
},
showChildren: function(element, ids) {
element.className = element.className.replace(' hidden', '');
for (var i = 0; i < ids.length; i++) {
var e = document.getElementById(ids[i]);
e.style.display = '';
}
},
hideChildren: function(element, ids) {
element.className = element.className.replace(' hidden', '');
element.className += ' hidden';
for (var i = 0; i < ids.length; i++) {
var e = document.getElementById(ids[i]);
e.style.display = 'none';
}
}
}
var BrowserTable = function() { this.initialize.apply(this, arguments) };
BrowserTable.prototype = {
initialize: function(options) {
this.parent = options.parent;
this.browsers = options.browsers;
this.options = {
title: options.title || '',
tests: options.tests || [],
columns: options.columns || 2,
header: options.header || false,
links: options.links || false,
grading: options.grading || false,
explainations: options.explainations || false,
filter: '',
onChange: options.onChange || false
}
this.data = [];
for (var i = 0; i < this.options.columns; i++) {
this.data[i] = null;
}
this.createSections(this.parent);
this.filter(options.filter || '');
},
filter: function(filter) {
if (this.options.filter != filter) {
this.options.filter = filter;
filter = filter.toLowerCase();
for (var i = 0; i < this.browsers.length; i++) {
var row = document.getElementById('row-' + this.browsers[i].uid);
var visible = true;
if (filter != '') {
if (filter == ':mostused') {
visible = this.browsers[i].visible;
}
else {
visible = this.browsers[i].nickname.toLowerCase().indexOf(filter) != -1
}
}
row.style.display = visible ? '' : 'none';
}
}
},
loadColumn: function(column, key) {
var httpRequest;
if (window.XMLHttpRequest) {
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.open('POST','/api/loadFeature', true);
httpRequest.onreadystatechange = process;
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send('key=' + encodeURIComponent(key));
var that = this;
function process() {
if (httpRequest.readyState == 4 && httpRequest.responseText != '') {
var data = JSON.parse(httpRequest.responseText);
that.updateColumn(column, data);
}
}
},
clearColumn: function(column) {
this.data[column] = null;
if (this.options.onChange) {
var ids = [];
for (var i = 0; i < this.options.columns; i++) {
if (this.data[i])
ids.push(this.data[i].id);
}
this.options.onChange(ids);
}
if (this.options.header) {
var row = document.getElementById('row-header');
var cell = row.childNodes[column + 1];
cell.className = 'empty';
cell.firstChild.firstChild.innerHTML = '';
cell.firstChild.childNodes[1].selectedIndex = 0;
}
for (var i = 0; i < this.browsers.length; i++) {
var row = document.getElementById('row-' + this.browsers[i].uid);
var cell = row.childNodes[column + 1];
cell.className = '';
cell.innerHTML = '';
}
},
updateColumn: function(column, data) {
this.data[column] = data;
if (this.options.onChange) {
var keys = [];
for (var i = 0; i < this.options.columns; i++) {
if (this.data[i])
keys.push(this.data[i].key);
}
this.options.onChange(keys);
}
if (this.options.header) {
var row = document.getElementById('row-header');
var cell = row.childNodes[column + 1];
cell.className = '';
var item, parent;
if (item = this.getItemByKey(this.options.tests, data.key)) {
if (data.key.split('.').length > 2) {
if (parent = this.getItemByKey(this.options.tests, data.key.split('.').slice(0,-1).join('.'))) {
cell.firstChild.firstChild.innerHTML = '' + parent.name + '
' + item.name + '';
} else {
cell.firstChild.firstChild.innerHTML = '' + item.name + '';
}
}
else {
cell.firstChild.firstChild.innerHTML = '' + item.name + '';
}
}
}
for (var i = 0; i < this.browsers.length; i++) {
var row = document.getElementById('row-' + this.browsers[i].uid);
var cell = row.childNodes[column + 1];
var classes = [ 'used' ];
cell.className = 'used';
if (match = (new RegExp(this.browsers[i].platform + '-' + this.browsers[i].version + '=(-?[0-9]+)')).exec(data.supported)) {
var result = parseInt(match[1], 10);
if (result & YES) {
switch(true) {
case !! (result & BUGGY): cell.innerHTML = 'Buggy
'; break;
case !! (result & OLD): cell.innerHTML = 'Partial ○
'; break;
case !! (result & PREFIX): cell.innerHTML = 'Prefixed ✔
'; classes.push('yes'); break;
case !! (result & EXPERIMENTAL): cell.innerHTML = 'Prefixed ✔
'; classes.push('yes'); break;
default: cell.innerHTML = 'Yes ✔
'; classes.push('yes'); break;
}
}
else {
switch(true) {
case !! (result & UNKNOWN): cell.innerHTML = 'Unknown ?
'; break;
case !! (result & BLOCKED): cell.innerHTML = 'Broken !
'; classes.push('no'); break;
case !! (result & DISABLED): cell.innerHTML = 'Disabled ✘
'; classes.push('no'); break;
default: cell.innerHTML = 'No ✘
'; classes.push('no'); break;
}
}
}
else
cell.innerHTML = 'Unknown ?
';
cell.className = classes.join(' ');
}
},
createSections: function(parent) {
var that = this;
var tests = this.getList(this.options.tests);
if (this.options.header) {
var table = document.createElement('table');
table.id = 'table-header';
parent.appendChild(table);
var tbody = document.createElement('tbody');
table.appendChild(tbody);
var tr = document.createElement('tr');
tr.id = 'row-header';
tbody.appendChild(tr);
var th = document.createElement('th');
th.innerHTML = this.options.title;
tr.appendChild(th);
for (var c = 0; c < this.options.columns; c++) {
var td = document.createElement('td');
td.className = 'empty';
tr.appendChild(td);
var wrapper = document.createElement('div');
td.appendChild(wrapper);
var div = document.createElement('div');
div.className = 'name';
wrapper.appendChild(div);
var menu = document.createElement('div');
menu.className = 'popup popupPanel pointsRight hasSearch';
wrapper.appendChild(menu);
var header = document.createElement('div');
header.className = 'toolbar';
menu.appendChild(header);
var scroll = document.createElement('div');
scroll.className = 'scroll';
menu.appendChild(scroll);
var list = document.createElement('ul');
scroll.appendChild(list);
(function(c, menu, list, header) {
var search = new SearchField({
parent: header,
onQuery: function(query) {
build(list, tests, query);
}
});
document.body.addEventListener('click', function(e) {
menu.className = menu.className.replace(' visible', '');
}, false);
div.addEventListener('click', function(e) {
if (that.data[c] == null)
menu.className += ' visible';
else
that.clearColumn(c);
e.stopPropagation();
}, true);
list.addEventListener('click', function(e) {
var close = true;
if (e.target) {
var target = e.target;
while (target.tagName != 'LI' && target.parentNode) {
target = target.parentNode;
}
if (target.hasAttribute('data-action')) {
var action = target.getAttribute('data-action');
if (action == 'load') {
var key = target.getAttribute('data-key');
that.loadColumn(c, key);
}
}
}
if (close) {
menu.className = menu.className.replace(' visible', '');
}
e.stopPropagation();
}, true);
})(c, menu, list, header);
build(list, tests);
function build(list, tests, filter) {
list.innerHTML = '';
var type = null;
for (var i = 0; i < tests.length; i++) {
if (!filter || (typeof tests[i].key != 'undefined' && tests[i].name.toLowerCase().indexOf(filter.toLowerCase()) != -1)) {
var item = document.createElement('li');
if (!filter) item.className = 'indent-' + tests[i].indent;
if (typeof tests[i].key != 'undefined') {
item.setAttribute('data-action', 'load');
item.setAttribute('data-key', tests[i].key);
} else {
item.className += ' title';
}
item.innerHTML = tests[i].name;
list.appendChild(item);
}
}
}
}
}
var table = document.createElement('table');
parent.appendChild(table);
var tbody = document.createElement('tbody');
table.appendChild(tbody);
var type = null;
for (var i = 0; i < this.browsers.length; i++) {
if (type != this.browsers[i].type) {
var tr = document.createElement('tr');
tbody.appendChild(tr);
var th = document.createElement('th');
th.className = 'details';
th.colSpan = this.options.columns + 1;
tr.appendChild(th);
switch(this.browsers[i].type) {
case 'desktop': th.innerHTML = 'Desktop browsers
'; break;
case 'gaming': th.innerHTML = 'Gaming
'; break;
case 'mobile': th.innerHTML = 'Mobiles
'; break;
case 'tablet': th.innerHTML = 'Tablets
'; break;
case 'television': th.innerHTML = 'Television
'; break;
}
}
var tr = document.createElement('tr');
tr.id = 'row-' + this.browsers[i].uid;
tbody.appendChild(tr);
var th = document.createElement('th');
th.className = 'hasLink';
th.innerHTML = this.browsers[i].nickname + (this.browsers[i].details ? ' (' + this.browsers[i].details + ')' : '');
tr.appendChild(th);
(function(th, type, data){
th.onclick = function() {
new BrowserPopup(th, type, data);
};
})(th, type, {
platform: this.browsers[i].platform,
version: this.browsers[i].version,
id: this.browsers[i].id,
name: this.browsers[i].nickname,
score: this.browsers[i].score,
urls: []
});
for (var c = 0; c < this.options.columns; c++) {
var td = document.createElement('td');
tr.appendChild(td);
}
type = this.browsers[i].type;
}
},
getList: function(items, level) {
if (typeof level == 'undefined') level = 0;
var result = [];
for (var i = 0; i < items.length; i++) {
if (typeof items[i] == 'object') {
if (typeof items[i].items == 'undefined') {
if (level > 0) {
result.push({
key: items[i].key,
name: items[i].name,
indent: level
})
}
}
if (typeof items[i].items != 'undefined') {
if (level > 0) {
result.push({
name: items[i].name,
indent: level
})
}
if (children = this.getList(items[i].items, level + 1)) {
for (var c = 0; c < children.length; c++) {
result.push(children[c]);
}
}
}
}
}
return result;
},
getItemByKey: function(items, key, level) {
if (typeof level == 'undefined') level = 0;
for (var i = 0; i < items.length; i++) {
if (typeof items[i] == 'object') {
if (items[i].key == key) return items[i];
if (typeof items[i].items != 'undefined') {
if (result = this.getItemByKey(items[i].items, key, level + 1)) {
return result;
}
}
}
}
}
}
var DiffTable = function() { this.initialize.apply(this, arguments) };
DiffTable.prototype = {
initialize: function(options) {
this.parent = options.parent;
this.metadata = options.metadata;
this.data = options.data;
this.createSections(this.parent);
},
createSections: function(parent) {
var table = document.createElement('table');
parent.appendChild(table);
var tbody = document.createElement('tbody');
table.appendChild(tbody);
for (var i = 0; i < this.data.length; i++) {
if (this.metadata.getItem(this.data[i].id)) {
var tr = document.createElement('tr');
tbody.appendChild(tr);
var th = document.createElement('th');
th.innerHTML = "" + this.metadata.getTrail(this.data[i].id, ' ▸ ') + "";
tr.appendChild(th);
var td = document.createElement('td');
td.innerHTML = "" + this.getStatus(this.data[i].from) + " → " + this.getStatus(this.data[i].to) + "
";
tr.appendChild(td);
}
}
},
getStatus: function(status) {
html = '';
status = parseInt(status, 10);
if (status & YES) {
switch(true) {
case !! (status & BUGGY): html = 'Buggy
'; break;
case !! (status & OLD): html = 'Partial ○
'; break;
case !! (status & PREFIX): html = 'Prefixed ✔
'; break;
case !! (status & EXPERIMENTAL): html = 'Prefixed ✔
'; break;
default: html = 'Yes ✔
'; break;
}
}
else {
switch(true) {
case !! (status & UNKNOWN): html = 'Unknown ?
'; break;
case !! (status & BLOCKED): html = 'Not functional !
'; break;
case !! (status & DISABLED): html = 'Disabled ✘
'; break;
default: html = 'No ✘
'; break;
}
}
return html;
}
}
var BrowserPopup = function() { this.initialize.apply(this, arguments) };
BrowserPopup.current = null;
BrowserPopup.prototype = {
initialize: function(parent, type, data) {
if (BrowserPopup.current) {
BrowserPopup.current.close();
}
var browser = data.platform + (data.version ? "-" + data.version : "");
var content = "";
content += "";
content += "
" + data.score + "
Points";
content += "
";
content += "
";
content += "
";
if (typeof data.urls != 'undefined') {
content += "";
for (var i = 0; i < data.urls.length; i++) {
}
content += "
";
}
this.panel = document.createElement('div');
this.panel.className = 'linksPanel popupPanel pointsLeft';
this.panel.innerHTML = content;
parent.appendChild(this.panel);
BrowserPopup.current = this;
},
close: function() {
this.panel.parentNode.removeChild(this.panel);
BrowserPopup.current = null;
}
}
document.addEventListener('click', function() { if (BrowserPopup.current) BrowserPopup.current.close() }, true)
document.addEventListener('touchstart', function() { if (BrowserPopup.current) BrowserPopup.current.close() }, true)