Export button

main
Elbert Alias 3 years ago
parent 2d0ada890a
commit 3e8869ac47

@ -72,7 +72,7 @@ p {
text-align: right;
}
.button__link:hover:before {
.button__link:before {
background: var(--color-primary);
border-radius: 4px;
content: '';
@ -81,6 +81,10 @@ p {
left: 0;
right: 0;
bottom: 0;
opacity: 0;
}
.button__link:hover:before {
opacity: .1;
}
@ -223,16 +227,22 @@ small {
overflow: hidden;
}
.tab-item:nth-child(2) {
min-width: 500px;
}
.tab-item--hidden {
display: none;
}
.credits {
background: var(--color-secondary);
color: var(--color-text-lighten);
display: block;
font-size: .8rem;
text-align: right;
flex: 1;
padding: 0 1.5rem;
padding: 1rem 1.5rem 0 1.5rem;
margin-bottom: -3px;
line-height: 1rem;
}
@ -393,13 +403,22 @@ small {
}
.plus-download {
background: var(--color-secondary);
padding: 1rem 1.5rem 0 1.5rem;
flex: 1 0;
text-align: right;
padding: 0 1.5rem;
white-space: nowrap;
}
.plus-download .button__link:before {
opacity: .1;
}
.plus-download .button__link:hover:before {
opacity: .2;
}
.plus-download--hidden {
display: none;
visibility: hidden;
}
.plus-error {
@ -849,7 +868,7 @@ body.dynamic-icon .category__heading:hover .category__pin {
color: var(--color-text-dark);
}
.dark .button__link:hover:before {
.dark .button__link:before {
background: white;
}
@ -953,6 +972,11 @@ body.dynamic-icon .category__heading:hover .category__pin {
border-color: var(--color-primary);
}
.dark .credits {
background: var(--color-primary-darken);
}
.dark .footer {
background: var(--color-primary-darken);
border-top: 1px solid var(--color-primary);

@ -49,187 +49,189 @@
<div class="tab tab--technologies tab--active" data-i18n="tabTechnologies">&nbsp;</div>
<div class="tab tab--plus"><span data-i18n="tabPlus">&nbsp;</span></div>
<div class="credits credits--hidden">
<span data-i18n="creditBalance">&nbsp;</span>
<div class="plus-download plus-download--hidden">
<div class="plus-download__button button">
<span class="button__link">
<svg class="button__icon button__icon--left" viewBox="0 0 24 24">
<path fill="currentColor" d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" />
</svg>
<span class="credits__remaining">&nbsp;</span>
<span class="button__text">
Export
</span>
</span>
</div>
</div>
</div>
<div class="tab-item">
<div class="empty empty--hidden">
<div class="empty__text" data-i18n="noAppsDetected">&nbsp;</div>
<div class="tab-items">
<div class="tab-item">
<div class="empty empty--hidden">
<div class="empty__text" data-i18n="noAppsDetected">&nbsp;</div>
<div class="ttt-game">
<div class="ttt-player">
<svg class="ttt-player-icon ttt-player-icon-x ttt-player-icon--ahead" viewBox="0 0 24 24">
<path fill="currentColor" d="M19,10C19,11.38 16.88,12.5 15.5,12.5C14.12,12.5 12.75,11.38 12.75,10H11.25C11.25,11.38 9.88,12.5 8.5,12.5C7.12,12.5 5,11.38 5,10H4.25C4.09,10.64 4,11.31 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12C20,11.31 19.91,10.64 19.75,10H19M12,4C9.04,4 6.45,5.61 5.07,8H18.93C17.55,5.61 14.96,4 12,4M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M12,17.23C10.25,17.23 8.71,16.5 7.81,15.42L9.23,14C9.68,14.72 10.75,15.23 12,15.23C13.25,15.23 14.32,14.72 14.77,14L16.19,15.42C15.29,16.5 13.75,17.23 12,17.23Z" />
</svg>
<svg class="ttt-player-icon ttt-player-icon--behind ttt-player-icon ttt-player-icon--hidden" viewBox="0 0 24 24">
<path fill="currentColor" d="M20 12A8 8 0 1 0 12 20A8 8 0 0 0 20 12M22 12A10 10 0 1 1 12 2A10 10 0 0 1 22 12M15.5 8A1.5 1.5 0 1 1 14 9.5A1.54 1.54 0 0 1 15.5 8M10 9.5A1.5 1.5 0 1 1 8.5 8A1.54 1.54 0 0 1 10 9.5M17 15H13A4 4 0 0 0 9.53 17L7.8 16A6 6 0 0 1 13 13H17Z" />
</svg>
<div class="ttt-game">
<div class="ttt-player">
<svg class="ttt-player-icon ttt-player-icon-x ttt-player-icon--ahead" viewBox="0 0 24 24">
<path fill="currentColor" d="M19,10C19,11.38 16.88,12.5 15.5,12.5C14.12,12.5 12.75,11.38 12.75,10H11.25C11.25,11.38 9.88,12.5 8.5,12.5C7.12,12.5 5,11.38 5,10H4.25C4.09,10.64 4,11.31 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12C20,11.31 19.91,10.64 19.75,10H19M12,4C9.04,4 6.45,5.61 5.07,8H18.93C17.55,5.61 14.96,4 12,4M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M12,17.23C10.25,17.23 8.71,16.5 7.81,15.42L9.23,14C9.68,14.72 10.75,15.23 12,15.23C13.25,15.23 14.32,14.72 14.77,14L16.19,15.42C15.29,16.5 13.75,17.23 12,17.23Z" />
</svg>
<div class="ttt-score ttt-score-x">0</div>
</div>
<svg class="ttt-player-icon ttt-player-icon--behind ttt-player-icon ttt-player-icon--hidden" viewBox="0 0 24 24">
<path fill="currentColor" d="M20 12A8 8 0 1 0 12 20A8 8 0 0 0 20 12M22 12A10 10 0 1 1 12 2A10 10 0 0 1 22 12M15.5 8A1.5 1.5 0 1 1 14 9.5A1.54 1.54 0 0 1 15.5 8M10 9.5A1.5 1.5 0 1 1 8.5 8A1.54 1.54 0 0 1 10 9.5M17 15H13A4 4 0 0 0 9.53 17L7.8 16A6 6 0 0 1 13 13H17Z" />
</svg>
<div class="ttt-grid">
<div class="ttt-row">
<div class="ttt-cell"></div><div class="ttt-cell"></div><div class="ttt-cell"></div>
<div class="ttt-score ttt-score-x">0</div>
</div>
<div class="ttt-row">
<div class="ttt-cell"></div><div class="ttt-cell"></div><div class="ttt-cell"></div>
<div class="ttt-grid">
<div class="ttt-row">
<div class="ttt-cell"></div><div class="ttt-cell"></div><div class="ttt-cell"></div>
</div>
<div class="ttt-row">
<div class="ttt-cell"></div><div class="ttt-cell"></div><div class="ttt-cell"></div>
</div>
<div class="ttt-row">
<div class="ttt-cell"></div><div class="ttt-cell"></div><div class="ttt-cell"></div>
</div>
</div>
<div class="ttt-row">
<div class="ttt-cell"></div><div class="ttt-cell"></div><div class="ttt-cell"></div>
<div class="ttt-player">
<svg class="ttt-player-icon ttt-player-icon-o" viewBox="0 0 24 24">
<path fill="currentColor" d="M9,11.75A1.25,1.25 0 0,0 7.75,13A1.25,1.25 0 0,0 9,14.25A1.25,1.25 0 0,0 10.25,13A1.25,1.25 0 0,0 9,11.75M15,11.75A1.25,1.25 0 0,0 13.75,13A1.25,1.25 0 0,0 15,14.25A1.25,1.25 0 0,0 16.25,13A1.25,1.25 0 0,0 15,11.75M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,11.71 4,11.42 4.05,11.14C6.41,10.09 8.28,8.16 9.26,5.77C11.07,8.33 14.05,10 17.42,10C18.2,10 18.95,9.91 19.67,9.74C19.88,10.45 20,11.21 20,12C20,16.41 16.41,20 12,20Z" />
</svg>
<div class="ttt-score ttt-score-o">0</div>
</div>
</div>
<div class="ttt-player">
<svg class="ttt-player-icon ttt-player-icon-o" viewBox="0 0 24 24">
<path fill="currentColor" d="M9,11.75A1.25,1.25 0 0,0 7.75,13A1.25,1.25 0 0,0 9,14.25A1.25,1.25 0 0,0 10.25,13A1.25,1.25 0 0,0 9,11.75M15,11.75A1.25,1.25 0 0,0 13.75,13A1.25,1.25 0 0,0 15,14.25A1.25,1.25 0 0,0 16.25,13A1.25,1.25 0 0,0 15,11.75M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,11.71 4,11.42 4.05,11.14C6.41,10.09 8.28,8.16 9.26,5.77C11.07,8.33 14.05,10 17.42,10C18.2,10 18.95,9.91 19.67,9.74C19.88,10.45 20,11.21 20,12C20,16.41 16.41,20 12,20Z" />
<svg class="ttt-icon ttt-icon-x" viewBox="0 0 24 24">
<path fill="currentColor" d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
</svg>
<div class="ttt-score ttt-score-o">0</div>
<svg class="ttt-icon ttt-icon-o" viewBox="0 0 24 24">
<path fill="currentColor" d="M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" />
</svg>
</div>
<svg class="ttt-icon ttt-icon-x" viewBox="0 0 24 24">
<path fill="currentColor" d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
</svg>
<svg class="ttt-icon ttt-icon-o" viewBox="0 0 24 24">
<path fill="currentColor" d="M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" />
</svg>
</div>
</div>
<div class="detections"></div>
<div class="detections"></div>
<div class="terms terms--hidden">
<div class="terms__content" data-i18n="termsContent"></div>
<div class="terms terms--hidden">
<div class="terms__content" data-i18n="termsContent"></div>
<div class="terms__buttons">
<button class="terms__button terms__button--accept" data-i18n="termsAccept">&nbsp;</button>
<button class="terms__button terms__button--decline" data-i18n="termsDecline">&nbsp;</button>
</div>
<div class="terms__buttons">
<button class="terms__button terms__button--accept" data-i18n="termsAccept">&nbsp;</button>
<button class="terms__button terms__button--decline" data-i18n="termsDecline">&nbsp;</button>
<a class="terms__privacy" href="https://www.wappalyzer.com/privacy/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" data-i18n="privacyPolicy"></a>
</div>
<a class="terms__privacy" href="https://www.wappalyzer.com/privacy/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" data-i18n="privacyPolicy"></a>
</div>
<div data-template="category" class="category">
<div class="category__heading">
<a class="category__link" href="#"></a>
<div data-template="category" class="category">
<div class="category__heading">
<a class="category__link" href="#"></a>
<svg class="category__pin category__pin--outline" viewBox="0 0 24 24">
<title data-i18n="categoryPin"></title>
<path fill="currentColor" d="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12M8.8,14L10,12.8V4H14V12.8L15.2,14H8.8Z" />
</svg>
<svg class="category__pin category__pin--outline" viewBox="0 0 24 24">
<title data-i18n="categoryPin"></title>
<path fill="currentColor" d="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12M8.8,14L10,12.8V4H14V12.8L15.2,14H8.8Z" />
</svg>
<svg class="category__pin" viewBox="0 0 24 24">
<title data-i18n="categoryPin"></title>
<path fill="currentColor" d="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12Z" />
</svg>
</div>
<svg class="category__pin" viewBox="0 0 24 24">
<title data-i18n="categoryPin"></title>
<path fill="currentColor" d="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12Z" />
</svg>
<div class="technologies"></div>
</div>
<div class="technologies"></div>
</div>
<div data-template="technology" class="technology">
<div class="technology__heading">
<a class="technology__link" href="#">
<div class="technology__icon">
<img alt="" src="../images/icons/default.svg" />
</div>
<div data-template="technology" class="technology">
<div class="technology__heading">
<a class="technology__link" href="#">
<div class="technology__icon">
<img alt="" src="../images/icons/default.svg" />
</div>
<span class="technology__name">&nbsp;</span>
<span class="technology__name">&nbsp;</span>
<span>
<span class="technology__version">&nbsp;</span>
</span>
<span>
<span class="technology__version">&nbsp;</span>
</span>
<span class="technology__confidence">&nbsp;</span>
</a>
<span class="technology__confidence">&nbsp;</span>
</a>
</div>
</div>
</div>
</div>
<div class="tab-item tab-item--hidden">
<div class="plus-download plus-download--hidden">
<div class="plus-download__button button">
<span class="button__link">
<svg class="button__icon button__icon--left" viewBox="0 0 24 24">
<path fill="currentColor" d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" />
</svg>
<div class="tab-item tab-item--hidden">
<div class="credits credits--hidden">
<span data-i18n="creditBalance">&nbsp;</span>
<span class="button__text">
Download CSV
</span>
</span>
<span class="credits__remaining">&nbsp;</span>
</div>
</div>
<div class="plus-error plus-error--hidden">
<div class="plus-error__message">
<div class="plus-error plus-error--hidden">
<div class="plus-error__message">
</div>
</div>
</div>
<div class="loading">
<svg class="progress" viewBox="20 20 40 40">
<circle class="progress__circle"></circle>
</svg>
</div>
<div class="loading">
<svg class="progress" viewBox="20 20 40 40">
<circle class="progress__circle"></circle>
</svg>
</div>
<div class="panels panels--hidden">
</div>
<div class="panels panels--hidden">
</div>
<div class="plus-configure plus-configure--hidden">
<div class="message">
<div class="message__heading">
<span data-i18n="plusMessageHeading">&nbsp;</span>
</div>
<div class="plus-configure plus-configure--hidden">
<div class="message">
<div class="message__heading">
<span data-i18n="plusMessageHeading">&nbsp;</span>
</div>
<p>
<span data-i18n="plusMessage">&nbsp;</span>
</p>
<p>
<span data-i18n="plusMessage">&nbsp;</span>
</p>
<div class="message__button button">
<a class="button__link" href="https://www.wappalyzer.com/plus/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">
<span class="button__text" data-i18n="plusButton">&nbsp;</span>
<div class="message__button button">
<a class="button__link" href="https://www.wappalyzer.com/plus/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer">
<span class="button__text" data-i18n="plusButton">&nbsp;</span>
<svg class="button__icon button__icon--right" viewBox="0 0 24 24">
<path fill="currentColor" d="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" />
</svg>
</a>
<svg class="button__icon button__icon--right" viewBox="0 0 24 24">
<path fill="currentColor" d="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" />
</svg>
</a>
</div>
</div>
</div>
<form class="plus-configure__form">
<div class="control">
<span class="label">
<span data-i18n="optionApiKey">&nbsp;</span>
<form class="plus-configure__form">
<div class="control">
<span class="label">
<span data-i18n="optionApiKey">&nbsp;</span>
<small class="label__description">
(<a href="https://www.wappalyzer.com/apikey/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" data-i18n="optionApiKeyDescription"></a>)
</small>
</span>
<small class="label__description">
(<a href="https://www.wappalyzer.com/apikey/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer" data-i18n="optionApiKeyDescription"></a>)
</small>
</span>
<input type="password" class="plus-configure__apikey input" />
</div>
<input type="password" class="plus-configure__apikey input" />
</div>
<div class="message__button button">
<span class="plus-configure__save button__link">
<svg class="button__icon button__icon--left" viewBox="0 0 24 24">
<path fill="currentColor" d="M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z" />
</svg>
<div class="message__button button">
<span class="plus-configure__save button__link">
<svg class="button__icon button__icon--left" viewBox="0 0 24 24">
<path fill="currentColor" d="M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z" />
</svg>
<span class="button__text" data-i18n="formSave">&nbsp;</span>
</span>
</div>
</form>
</div>
<span class="button__text" data-i18n="formSave">&nbsp;</span>
</span>
</div>
</form>
</div>
<div class="plus-empty plus-empty--hidden" data-i18n="plusEmpty"></div>
<div class="plus-crawl plus-crawl--hidden" data-i18n="plusCrawl"></div>
<div class="plus-empty plus-empty--hidden" data-i18n="plusEmpty"></div>
<div class="plus-crawl plus-crawl--hidden" data-i18n="plusCrawl"></div>
</div>
</div>
<div class="footer">

@ -8,9 +8,6 @@ const { agent, open, i18n, getOption, setOption, promisify, sendMessage } =
const baseUrl = 'https://www.wappalyzer.com'
const utm = '?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer'
let csv = ''
let csvFilename = ''
const footers = [
{
heading: 'Generate sales leads',
@ -107,6 +104,71 @@ function setDisabledDomain(enabled) {
}
}
function getCsv() {
let hostname = ''
let www = false
let https = false
try {
let protocol = ''
;({ hostname, protocol } = new URL(Popup.cache.url))
www = hostname.startsWith('www')
https = protocol === 'https:'
hostname = hostname.replace(/^www\./, '')
} catch (error) {
// Continue
}
const columns = [
'URL',
...Popup.cache.categories.map(({ id }) =>
chrome.i18n.getMessage(`categoryName${id}`)
),
...attributeKeys.map((key) =>
chrome.i18n.getMessage(
`attribute${
key.charAt(0).toUpperCase() + key.slice(1).replace('.', '_')
}`
)
),
]
const csv = [`"${columns.join('","')}"`]
const filename = `wappalyzer${
hostname ? `_${hostname.replace('.', '-')}` : ''
}.csv`
const row = [`http${https ? 's' : ''}://${www ? 'www.' : ''}${hostname}`]
row.push(
...Popup.cache.categories.reduce((categories, { id }) => {
categories.push(
Popup.cache.detections
.filter(({ categories }) =>
categories.some(({ id: _id }) => _id === id)
)
.map(({ name }) => name)
.join(' ; ')
)
return categories
}, [])
)
row.push(
...attributeKeys.map((key) => csvEscape(Popup.cache.attributeValues[key]))
)
csv.push(`"${row.join('","')}"`)
return { csv, filename }
}
function csvEscape(value = '') {
if (Array.isArray(value)) {
value = value
@ -136,6 +198,13 @@ const Popup = {
* Initialise popup
*/
async init() {
Popup.cache = {
url: '',
categories: [],
detections: [],
attributeValues: {},
}
const el = {
body: document.body,
terms: document.querySelector('.terms'),
@ -150,6 +219,7 @@ const Popup = {
headerSwitchDisabled: document.querySelector('.header__switch--disabled'),
plusConfigureApiKey: document.querySelector('.plus-configure__apikey'),
plusConfigureSave: document.querySelector('.plus-configure__save'),
plusDownload: document.querySelector('.plus-download'),
plusDownloadLink: document.querySelector(
'.plus-download__button .button__link'
),
@ -246,6 +316,8 @@ const Popup = {
;[{ url }] = tabs
if (url.startsWith('http')) {
Popup.cache.url = url
const { hostname } = new URL(url)
setDisabledDomain(disabledDomains.includes(hostname))
@ -322,6 +394,7 @@ const Popup = {
el.tabItems[index].classList.remove('tab-item--hidden')
el.credits.classList.add('credits--hidden')
el.plusDownload.classList.remove('plus-download--hidden')
el.footer.classList.remove('footer--hidden')
if (tab.classList.contains('tab--plus')) {
@ -331,7 +404,7 @@ const Popup = {
})
// Download
el.plusDownloadLink.addEventListener('click', (event) => Popup.downloadCsv)
el.plusDownloadLink.addEventListener('click', Popup.downloadCsv)
// Footer
const item =
@ -381,6 +454,8 @@ const Popup = {
// Apply internationalization
i18n()
Popup.cache.categories = await Popup.driver('getCategories')
},
driver(func, args) {
@ -423,9 +498,12 @@ const Popup = {
* @param {Array} detections
*/
async onGetDetections(detections = []) {
Popup.cache.detections = detections
const el = {
empty: document.querySelector('.empty'),
detections: document.querySelector('.detections'),
plusDownload: document.querySelector('.plus-download'),
}
detections = (detections || [])
@ -435,12 +513,14 @@ const Popup = {
if (!detections || !detections.length) {
el.empty.classList.remove('empty--hidden')
el.detections.classList.add('detections--hidden')
el.plusDownload.classList.add('plus-download--hidden')
return
}
el.empty.classList.add('empty--hidden')
el.detections.classList.remove('detections--hidden')
el.plusDownload.classList.remove('plus-download--hidden')
while (el.detections.firstChild) {
el.detections.removeChild(detections.firstChild)
@ -554,9 +634,6 @@ const Popup = {
crawl: document.querySelector('.plus-crawl'),
error: document.querySelector('.plus-error'),
download: document.querySelector('.plus-download'),
downloadLink: document.querySelector(
'.plus-download__button .button__link'
),
errorMessage: document.querySelector('.plus-error__message'),
configure: document.querySelector('.plus-configure'),
credits: document.querySelector('.credits'),
@ -565,6 +642,7 @@ const Popup = {
}
el.error.classList.add('plus-error--hidden')
el.download.classList.add('plus-download--hidden')
if (apiKey) {
el.loading.classList.remove('loading--hidden')
@ -579,7 +657,6 @@ const Popup = {
}
el.panels.classList.add('panels--hidden')
el.download.classList.add('plus-download--hidden')
el.empty.classList.add('plus-empty--hidden')
el.crawl.classList.add('plus-crawl--hidden')
el.error.classList.add('plus-error--hidden')
@ -588,24 +665,6 @@ const Popup = {
el.panels.removeChild(el.panels.lastElementChild)
}
let hostname = ''
let www = false
let https = false
try {
let protocol = ''
;({ hostname, protocol } = new URL(url))
www = hostname.startsWith('www')
https = protocol === 'https:'
hostname = hostname.replace(/^www\./, '')
} catch (error) {
// Continue
}
try {
const response = await fetch(
`https://api.wappalyzer.com/v2/plus/${encodeURIComponent(url)}`,
@ -635,9 +694,8 @@ const Popup = {
10
).toLocaleString()
el.credits.classList.remove('credits--hidden')
el.loading.classList.add('loading--hidden')
el.credits.classList.remove('credits--hidden')
if (crawl) {
document
@ -649,50 +707,11 @@ const Popup = {
if (!Object.keys(attributes).length) {
el.empty.classList.remove('plus-empty--hidden')
el.download.classList.remove('plus-download--hidden')
return
}
const categories = await Popup.driver('getCategories')
const columns = [
'URL',
...categories.map(({ id }) =>
chrome.i18n.getMessage(`categoryName${id}`)
),
...attributeKeys.map((key) =>
chrome.i18n.getMessage(
`attribute${
key.charAt(0).toUpperCase() + key.slice(1).replace('.', '_')
}`
)
),
]
csv = [`"${columns.join('","')}"`]
csvFilename = `wappalyzer${
hostname ? `_${hostname.replace('.', '-')}` : ''
}.csv`
const row = [`http${https ? 's' : ''}://${www ? 'www.' : ''}${hostname}`]
const detections = await Popup.driver('getDetections')
row.push(
...categories.reduce((categories, { id }) => {
categories.push(
detections
.filter(({ categories }) =>
categories.some(({ id: _id }) => _id === id)
)
.map(({ name }) => name)
.join(' ; ')
)
return categories
}, [])
)
const attributeValues = {}
Object.keys(attributes).forEach((set) => {
@ -800,26 +819,7 @@ const Popup = {
el.panels.appendChild(panel)
})
row.push(...attributeKeys.map((key) => csvEscape(attributeValues[key])))
csv.push(`"${row.join('","')}"`)
el.downloadLink.addEventListener('click', (event) => {
event.preventDefault()
const file = URL.createObjectURL(
new Blob([csv.join('\n')], { type: 'text/csv;charset=utf-8' })
)
chrome.downloads.download({
url: file,
filename: `wappalyzer${
hostname ? `_${hostname.replace('.', '-')}` : ''
}.csv`,
})
return false
})
Popup.cache.attributeValues = attributeValues
el.panels.classList.remove('panels--hidden')
el.download.classList.remove('plus-download--hidden')
@ -869,14 +869,20 @@ const Popup = {
i18n()
},
downloadCsv() {
downloadCsv(event) {
console.log('x')
event.preventDefault()
const { csv, filename } = getCsv()
const file = URL.createObjectURL(
new Blob([csv.join('\n')], { type: 'text/csv;charset=utf-8' })
)
chrome.downloads.download({
url: URL.createObjectURL(
new Blob([csv.join('\n')], { type: 'text/csv;charset=utf-8' })
),
filename: csvFilename,
url: file,
filename,
})
return false