Replace innerHTML with jsonToDOM

main
Elbert Alias 8 years ago
parent 6439bad292
commit d882aca41d

@ -18,7 +18,7 @@
"categoryName6": { "message": "Ecommerce" },
"categoryName7": { "message": "Photo Galleries" },
"categoryName8": { "message": "Wikis" },
"categoryName9": { "message": "Hostin Panels" },
"categoryName9": { "message": "Hosting Panels" },
"categoryName10": { "message": "Analytics" },
"categoryName11": { "message": "Blog" },
"categoryName12": { "message": "JavaScript Framework" },

@ -4,6 +4,6 @@ document.addEventListener('DOMContentLoaded', function() {
var nodes = document.querySelectorAll('[data-i18n]');
nodes.forEach(function(node) {
node.innerHTML = browser.i18n.getMessage(node.dataset.i18n);
node.childNodes[0].nodeValue = browser.i18n.getMessage(node.dataset.i18n);
});
});

@ -0,0 +1,63 @@
jsonToDOM.namespaces = {
html: "http://www.w3.org/1999/xhtml",
xul: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
};
jsonToDOM.defaultNamespace = jsonToDOM.namespaces.html;
function jsonToDOM(jsonTemplate, doc, nodes) {
function namespace(name) {
var reElemNameParts = /^(?:(.*):)?(.*)$/.exec(name);
return { namespace: jsonToDOM.namespaces[reElemNameParts[1]], shortName: reElemNameParts[2] };
}
// Note that 'elemNameOrArray' is: either the full element name (eg. [html:]div) or an array of elements in JSON notation
function tag(elemNameOrArray, elemAttr) {
// Array of elements? Parse each one...
if (Array.isArray(elemNameOrArray)) {
var frag = doc.createDocumentFragment();
Array.forEach(arguments, function(thisElem) {
frag.appendChild(tag.apply(null, thisElem));
});
return frag;
}
// Single element? Parse element namespace prefix (if none exists, default to defaultNamespace), and create element
var elemNs = namespace(elemNameOrArray);
var elem = doc.createElementNS(elemNs.namespace || jsonToDOM.defaultNamespace, elemNs.shortName);
// Set element's attributes and/or callback functions (eg. onclick)
for (var key in elemAttr) {
var val = elemAttr[key];
if (nodes && key == "key") {
nodes[val] = elem;
continue;
}
var attrNs = namespace(key);
if (typeof val == "function") {
// Special case for function attributes; don't just add them as 'on...' attributes, but as events, using addEventListener
elem.addEventListener(key.replace(/^on/, ""), val, false);
}
else {
// Note that the default namespace for XML attributes is, and should be, blank (ie. they're not in any namespace)
elem.setAttributeNS(attrNs.namespace || "", attrNs.shortName, val);
}
}
// Create and append this element's children
var childElems = Array.slice(arguments, 2);
childElems.forEach(function(childElem) {
if (childElem != null) {
elem.appendChild(
childElem instanceof doc.defaultView.Node ? childElem :
Array.isArray(childElem) ? tag.apply(null, childElem) :
doc.createTextNode(childElem));
}
});
return elem;
}
return tag.apply(null, jsonTemplate);
}

@ -9,7 +9,9 @@
if ( /complete|interacrive|loaded/.test(document.readyState) ) {
popup.displayApps(response)
} else {
document.addEventListener('DOMContentLoaded', function() { popup.displayApps(response) });
document.addEventListener('DOMContentLoaded', function() {
popup.displayApps(response)
});
}
});
};
@ -26,45 +28,80 @@
displayApps: function(response) {
var
appName, confidence, version,
detectedApps = document.querySelector('#detected-apps');
html = '';
detectedApps = document.querySelector('#detected-apps'),
categories = [],
json = [];
if ( response.tabCache && response.tabCache.count > 0 ) {
for ( appName in response.tabCache.appsDetected ) {
confidence = response.tabCache.appsDetected[appName].confidenceTotal;
version = response.tabCache.appsDetected[appName].version;
html +=
'<div class="detected-app">' +
'<a target="_blank" href="https://wappalyzer.com/applications/' + popup.slugify(appName) + '">' +
'<img src="images/icons/' + ( response.apps[appName].icon || 'default.svg' ) + '"/>' +
'<span class="label">' +
'<span class="name">' + appName + '</span>' +
( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ) +
'</span>' +
'</a>';
categories = [];
response.apps[appName].cats.forEach(function(cat) {
html +=
'<a target="_blank" href="https://wappalyzer.com/categories/' + popup.slugify(response.categories[cat].name) + '">' +
'<span class="category"><span class="name">' + browser.i18n.getMessage('categoryName' + cat) + '</span></span>' +
'</a>';
categories.push(
[
'a', {
target: '_blank',
href: 'https://wappalyzer.com/categories/' + popup.slugify(response.categories[cat].name)
}, [
'span', {
class: 'category'
}, [
'span', {
class: 'name'
},
browser.i18n.getMessage('categoryName' + cat)
]
]
]
);
});
html +=
'</a>' +
'</div>';
json.push(
[
'div', {
class: 'detected-app'
}, [
'a', {
target: '_blank',
href: 'https://wappalyzer.com/applications/' + popup.slugify(appName)
}, [
'img', {
src: 'images/icons/' + ( response.apps[appName].icon || 'default.svg' )
}
], [
'span', {
class: 'label'
}, [
'span', {
class: 'name'
},
appName
],
( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' )
]
],
categories
]
);
}
} else {
html = '<div class="empty">' + browser.i18n.getMessage('noAppsDetected') + '</div>';
json = [
'div', {
class: 'empty'
},
browser.i18n.getMessage('noAppsDetected')
];
}
detectedApps.innerHTML = html;
detectedApps.appendChild(jsonToDOM(json, document, {}));
// Force redraw after popup animation on Mac OS
setTimeout(function() {
document.body.innerHTML += '<span style="line-height: 1px;"> </span>';
}, 600);
document.body.appendChild(jsonToDOM([ 'span', { style: 'line-height: 1px;' }], document, {}));
}, 800);
},
slugify: function(string) {

@ -7,6 +7,7 @@
<link rel="stylesheet" href="css/popup.css">
<script src="js/browser-polyfill.js"></script>
<script src="js/jsontodom.js"></script>
<script src="js/popup.js"></script>
<script src="js/i18n.js"></script>
</head>