Added tab-content-service base class

This commit is contained in:
Ray 2024-12-15 18:40:40 +00:00
parent 12da6f7776
commit 3cc3652275
13 changed files with 1465 additions and 1023 deletions

View File

@ -2,7 +2,8 @@ class MessagingService {
async GetHyperlinkNodes(sender, callback) { async GetHyperlinkNodes(sender, callback) {
const a = this; const a = this;
const nodes = await document.body.getElementsByTagName("a"); const nodes = await document.querySelectorAll("a");
let result = []; let result = [];
for (let i=0; i<nodes.length; i++) { for (let i=0; i<nodes.length; i++) {
@ -18,16 +19,13 @@ class MessagingService {
}); });
} }
// for (let i=0; i<result.length; i++) {
// result[i].occurrence = result.filter(item => JSON.stringify(item) === JSON.stringify(result[i])).length;
// }
await callback(result); await callback(result);
} }
async GetImageNodes(sender, callback) { async GetImageNodes(sender, callback) {
const a = this; const a = this;
const nodes = await document.body.getElementsByTagName("img"); const nodes = await document.querySelectorAll("img");
let result = []; let result = [];
for (let i=0; i<nodes.length; i++) { for (let i=0; i<nodes.length; i++) {
@ -49,6 +47,41 @@ class MessagingService {
callback(document.location.href); callback(document.location.href);
} }
async GetMetaNodes(sender, callback) {
const a = this;
const nodes = await document.querySelectorAll("meta");
let result = [];
for (let i=0; i<nodes.length; i++) {
result.push({
content: (nodes[i].getAttribute("content") ?? ""),
name: (nodes[i].getAttribute("name") ?? ""),
httpEquiv: (nodes[i].getAttribute("http-equiv") ?? ""),
occurrence: 1
});
}
await callback(result);
}
async GetScriptNodes(sender, callback) {
const a = this;
const nodes = await document.querySelectorAll("script");
let result = [];
for (let i=0; i<nodes.length; i++) {
result.push({
src: (nodes[i].getAttribute("src") ?? ""),
type: (nodes[i].getAttribute("type") ?? ""),
occurrence: 1
});
}
await callback(result);
}
#encodeHtml(htmlContent) { #encodeHtml(htmlContent) {
const map = { const map = {
"&": "&amp;", "&": "&amp;",
@ -79,12 +112,3 @@ chrome.runtime.onMessage.addListener(async function(request, sender, callback) {
await messageService[request.event](sender, callback); await messageService[request.event](sender, callback);
}); });
// var optHideWatchedVideos = new Promise(function(resolve) {
// chrome.storage.local.get(['switch1'], function(result) {
// resolve(result.switch1);
// });
// });

File diff suppressed because one or more lines are too long

View File

@ -21,12 +21,32 @@
<button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button> <button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>
<button class="nav-link" id="nav-hyperlinks-tab" data-bs-toggle="tab" data-bs-target="#nav-hyperlinks" type="button" role="tab" aria-controls="nav-hyperlinks" aria-selected="false">Hyperlinks</button> <button class="nav-link" id="nav-hyperlinks-tab" data-bs-toggle="tab" data-bs-target="#nav-hyperlinks" type="button" role="tab" aria-controls="nav-hyperlinks" aria-selected="false">Hyperlinks</button>
<button class="nav-link" id="nav-images-tab" data-bs-toggle="tab" data-bs-target="#nav-images" type="button" role="tab" aria-controls="nav-images" aria-selected="false">Images</button> <button class="nav-link" id="nav-images-tab" data-bs-toggle="tab" data-bs-target="#nav-images" type="button" role="tab" aria-controls="nav-images" aria-selected="false">Images</button>
<button class="nav-link" id="nav-disabled-tab" data-bs-toggle="tab" data-bs-target="#nav-disabled" type="button" role="tab" aria-controls="nav-disabled" aria-selected="false" disabled>Disabled</button> <button class="nav-link" id="nav-scripts-tab" data-bs-toggle="tab" data-bs-target="#nav-scripts" type="button" role="tab" aria-controls="nav-scripts" aria-selected="false">Scripts</button>
<button class="nav-link" id="nav-metas-tab" data-bs-toggle="tab" data-bs-target="#nav-metas" type="button" role="tab" aria-controls="nav-metas" aria-selected="false">Metas</button>
</div> </div>
</nav> </nav>
<div class="tab-content" id="nav-tabContent"> <div class="tab-content" id="nav-tabContent">
<div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab" tabindex="0">...</div> <div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab" tabindex="0">
<div class="tab-pane py-3 fade" id="nav-hyperlinks" role="tabpanel" aria-labelledby="nav-hyperlinks-tab" tabindex="0">
<div class="container-fluid py-4">
<div class="row mb-2">
<div class="col-sm-12">
<img src="./icon128.png" class="mx-auto d-block" alt="Logo" />
</div>
</div>
<div class="row">
<div class="col-sm-12 text-center">
<h3>Peji Inspektor</h3>
<p>
Peji Inspektor is a browser extension for finding nodes on a web page.
These nodes (or tags) can be filtered and searched to find hyperlinks, images and other assets.
</p>
</div>
</div>
</div>
</div>
<div class="tab-pane py-3 fade" id="nav-hyperlinks" role="tabpanel" aria-labelledby="nav-hyperlinks-tab" tabindex="1">
<div class="container-fluid"> <div class="container-fluid">
<div class="pt-2 pb-2 mb-2 border-bottom"> <div class="pt-2 pb-2 mb-2 border-bottom">
@ -34,11 +54,11 @@
<label for="textBox1" class="col-sm-2 col-form-label fw-bold">Search</label> <label for="textBox1" class="col-sm-2 col-form-label fw-bold">Search</label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<input type="text" class="form-control" role="textbox" id="textBox1" /> <input type="text" class="form-control" id="textBox1" />
<select class="form-select pe-0 input-group-text" name="comboBox1"> <select class="form-select pe-0 input-group-text">
<option value="anchor">Anchor</option> <option value="text">Anchor</option>
<option value="link" selected>Link</option> <option value="href" selected>Link</option>
</select> </select>
<button type="button" class="btn btn-secondary input-group-text">&#10005;</button> <button type="button" class="btn btn-secondary input-group-text">&#10005;</button>
@ -50,7 +70,7 @@
<div class="col-5"> <div class="col-5">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<button class="btn btn-primary" type="button">Load Results</button> <button class="btn btn-primary" type="button">Load Results</button>
<select class="form-select" name="comboBox2"> <select class="form-select">
<option value="table" selected>Table</option> <option value="table" selected>Table</option>
<option value="csv">CSV</option> <option value="csv">CSV</option>
<option value="links">Links</option> <option value="links">Links</option>
@ -82,22 +102,13 @@
<div class="row pb-2 mb-2 border-bottom"></div> <div class="row pb-2 mb-2 border-bottom"></div>
<div class="row pt-2 mb-2"> <div class="row pt-2 mb-2">
<div class="col px-0"> <div class="col px-0" role="results"></div>
<table class="table table-bordered table-hover table-sm table-striped">
<thead></thead>
<tbody></tbody>
</table>
<textarea class="form-control font-monospace text-sm px-1 py-1" rows="16"></textarea>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="tab-pane fade" id="nav-images" role="tabpanel" aria-labelledby="nav-images-tab" tabindex="0"> <div class="tab-pane py-3 fade" id="nav-images" role="tabpanel" aria-labelledby="nav-images-tab" tabindex="2">
<div class="container-fluid"> <div class="container-fluid">
<div class="pt-2 pb-2 mb-2 border-bottom"> <div class="pt-2 pb-2 mb-2 border-bottom">
@ -105,9 +116,9 @@
<label for="textBox2" class="col-sm-2 col-form-label fw-bold">Search</label> <label for="textBox2" class="col-sm-2 col-form-label fw-bold">Search</label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<input type="text" class="form-control" role="textbox" id="textBox2" /> <input type="text" class="form-control" id="textBox2" />
<select class="form-select pe-0 input-group-text" name="comboBox1"> <select class="form-select pe-0 input-group-text">
<option value="alt">Alternative Text</option> <option value="alt">Alternative Text</option>
<option value="src" selected>Source</option> <option value="src" selected>Source</option>
</select> </select>
@ -121,7 +132,7 @@
<div class="col-5"> <div class="col-5">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<button class="btn btn-primary" type="button">Load Results</button> <button class="btn btn-primary" type="button">Load Results</button>
<select class="form-select" name="comboBox2"> <select class="form-select">
<option value="table" selected>Table</option> <option value="table" selected>Table</option>
<option value="csv">CSV</option> <option value="csv">CSV</option>
<option value="links">Links</option> <option value="links">Links</option>
@ -153,22 +164,137 @@
<div class="row pb-2 mb-2 border-bottom"></div> <div class="row pb-2 mb-2 border-bottom"></div>
<div class="row pt-2 mb-2"> <div class="row pt-2 mb-2">
<div class="col px-0"> <div class="col px-0"role="results"></div>
<table class="table table-bordered table-hover table-sm table-striped">
<thead></thead>
<tbody></tbody>
</table>
<textarea class="form-control font-monospace text-sm px-1 py-1" rows="16"></textarea>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="tab-pane fade" id="nav-disabled" role="tabpanel" aria-labelledby="nav-disabled-tab" tabindex="0">...</div> <div class="tab-pane py-3 fade" id="nav-scripts" role="tabpanel" aria-labelledby="nav-scripts-tab" tabindex="3">
<div class="container-fluid">
<div class="pt-2 pb-2 mb-2 border-bottom">
<div class="row mb-2">
<label for="textBox3" class="col-sm-2 col-form-label fw-bold">Search</label>
<div class="col-sm-10">
<div class="input-group input-group-sm">
<input type="text" class="form-control" id="textBox3" />
<select class="form-select pe-0 input-group-text">
<option value="type">Type</option>
<option value="src" selected>Source</option>
</select>
<button type="button" class="btn btn-secondary input-group-text">&#10005;</button>
</div>
</div>
</div>
<div class="row mt-2 mb-2">
<div class="col-2"></div>
<div class="col-5">
<div class="input-group input-group-sm">
<button class="btn btn-primary" type="button">Load Results</button>
<select class="form-select">
<option value="table" selected>Table</option>
<option value="csv">CSV</option>
<option value="links">Links</option>
</select>
</div>
</div>
<div class="col-5 px-0">
<div class="pt-2" role="label"></div>
</div>
</div>
</div>
<div class="fw-bold clearfix cursor-pointer" data-bs-toggle="collapse" data-bs-target="#collapsPanel5" aria-expanded="false" aria-controls="collapsPanel5">&#11208;&nbsp;Options</div>
<div class="row pb-2 mb-2 border-bottom collapse" id="collapsPanel5">
<div class="col-sm-2"></div>
<div class="col-sm-10">
<div class="row px-0" role="options"></div>
</div>
</div>
<div class="fw-bold clearfix cursor-pointer" data-bs-toggle="collapse" data-bs-target="#collapsPanel6" aria-expanded="false" aria-controls="collapsPanel6">&#11208;&nbsp;Filters</div>
<div class="row collapse" id="collapsPanel6">
<div class="col-sm-2"></div>
<div class="col-sm-10">
<div class="row px-0" role="filters"></div>
</div>
</div>
<div class="row pb-2 mb-2 border-bottom"></div>
<div class="row pt-2 mb-2">
<div class="col px-0"role="results"></div>
</div>
</div>
</div>
<div class="tab-pane py-3 fade" id="nav-metas" role="tabpanel" aria-labelledby="nav-metas-tab" tabindex="3">
<div class="container-fluid">
<div class="pt-2 pb-2 mb-2 border-bottom">
<div class="row mb-2">
<label for="textBox3" class="col-sm-2 col-form-label fw-bold">Search</label>
<div class="col-sm-10">
<div class="input-group input-group-sm">
<input type="text" class="form-control" id="textBox3" />
<select class="form-select pe-0 input-group-text">
<option value="content">Content</option>
<option value="name" selected>Name</option>
</select>
<button type="button" class="btn btn-secondary input-group-text">&#10005;</button>
</div>
</div>
</div>
<div class="row mt-2 mb-2">
<div class="col-2"></div>
<div class="col-5">
<div class="input-group input-group-sm">
<button type="button" class="btn btn-primary">Load Results</button>
<select class="form-select">
<option value="table" selected>Table</option>
<option value="csv">CSV</option>
<option value="links">Links</option>
</select>
</div>
</div>
<div class="col-5 px-0">
<div class="pt-2" role="label"></div>
</div>
</div>
</div>
<div class="fw-bold clearfix cursor-pointer" data-bs-toggle="collapse" data-bs-target="#collapsPanel7" aria-expanded="false" aria-controls="collapsPanel7">&#11208;&nbsp;Options</div>
<div class="row pb-2 mb-2 border-bottom collapse" id="collapsPanel7">
<div class="col-sm-2"></div>
<div class="col-sm-10">
<div class="row px-0" role="options"></div>
</div>
</div>
<div class="fw-bold clearfix cursor-pointer" data-bs-toggle="collapse" data-bs-target="#collapsPanel8" aria-expanded="false" aria-controls="collapsPanel8">&#11208;&nbsp;Filters</div>
<div class="row collapse" id="collapsPanel8">
<div class="col-sm-2"></div>
<div class="col-sm-10">
<div class="row px-0" role="filters"></div>
</div>
</div>
<div class="row pb-2 mb-2 border-bottom"></div>
<div class="row pt-2 mb-2">
<div class="col px-0"role="results"></div>
</div>
</div>
</div>
</div> </div>

View File

@ -1,17 +1,23 @@
// src/popup.js // src/popup.js
import PopupService from './popup/popup-service.js'; import PopupService from './popup/popup-service.js';
import AContentService from './popup/acontent-service.js'; import AContentService from './popup/a-content-service.js';
import ImgContentService from './popup/imgcontent-service.js'; import ImgContentService from './popup/img-content-service.js';
import ScriptContentService from './popup/script-content-service.js';
import MetaContentService from './popup/meta-content-service.js';
const popupService = new PopupService(); const popupService = new PopupService();
const aContentService = new AContentService(popupService); const aContentService = new AContentService(popupService);
const imgContentService = new ImgContentService(popupService); const imgContentService = new ImgContentService(popupService);
const scriptContentService = new ScriptContentService(popupService);
const metaContentService = new MetaContentService(popupService);
document.addEventListener("DOMContentLoaded", async function(event) { document.addEventListener("DOMContentLoaded", function(event) {
aContentService.InitialiseComponents(); aContentService.InitialiseComponents();
imgContentService.InitialiseComponents(); imgContentService.InitialiseComponents();
scriptContentService.InitialiseComponents();
metaContentService.InitialiseComponents();
}); });

View File

@ -0,0 +1,280 @@
import '../../../literyz-js/extensions.dist.js';
import TabContentService from './tab-content-service.js';
class AContentService extends TabContentService {
constructor(popupService) {
super(popupService);
const a = this;
a._containerId = "nav-hyperlinks";
a._optionsCol1 = [
{ id: 1, text: "Show Anchor as HTML", checked: false },
{ id: 4, text: "Resolve Relative URL", checked: false }
];
a._optionsCol2 = [
{ id: 3, text: "Sort By Anchor Text", checked: true },
{ id: 2, text: "Trim Anchor Text", checked: true }
];
a._filtersCol1 = [
{ id: 12, text: "Hide External Links", checked: true },
{ id: 5, text: "Hide Duplicates", checked: true },
{ id: 14, text: "Hide Blank Anchors", checked: true },
{ id: 15, text: "Hide Blank Links", checked: true },
{ id: 11, text: "Hide Fragments", checked: true },
{ id: 13, text: "Hide Mailto/Tel", checked: true },
{ id: 16, text: "Hide Javascript", checked: true }
];
a._filtersCol2 = [
{ id: 6, text: "Show Title", checked: true },
{ id: 7, text: "Show Target", checked: false },
{ id: 8, text: "Show Rel", checked: false },
{ id: 9, text: "Show Type", checked: false },
{ id: 10, text: "Show Count", checked: false }
];
}
async _retrieveResult() {
return await this._popupService.GetHyperlinks();
}
async _filterResult(items) {
const a = this;
const currentUrl = await a._popupService.GetLocation();
const currentHostname = (new URL(currentUrl)).hostname;
let result = [];
for (let i=0; i<items.length; i++) {
const item = items[i];
// Hide fragments
if (a._getCheckBox(11)) {
if (item.href.startsWith("#")) {
continue;
}
}
// Hide Blank Links
if (a._getCheckBox(15)) {
if (String.isNullOrWhitespace(item.href)) {
continue;
}
}
// Hide mailto/tel
if (a._getCheckBox(13)) {
if (item.href.toLowerCase().startsWith("telno:") || item.href.toLowerCase().startsWith("mailto:")) {
continue;
}
}
// Hide javascript
if (a._getCheckBox(16)) {
if (item.href.toLowerCase().startsWith("javascript:")) {
continue;
}
}
const absoluteUrl = new URL(item.href, currentUrl);
// Hide external links
if (a._getCheckBox(12)) {
if (currentHostname != absoluteUrl.hostname) {
continue;
}
}
// Show anchor as html
let text = (a._getCheckBox(1) ? item.innerHTML : item.innerText);
// Hide Blank Anchors
if (a._getCheckBox(14)) {
if (String.isNullOrWhitespace(text)) {
continue;
}
}
// Resolve relative url
const href = (a._getCheckBox(4) ? absoluteUrl.href : item.href);
// Trim anchor text
if (a._getCheckBox(2)) {
text = text.trim();
}
// Search term
if (!String.isNullOrWhitespace(a._textBox1.value)) {
if (a._getComboBox(1) == "href") {
if (!href.toLowerCase().includes(a._textBox1.value.toLowerCase())) {
continue;
}
} else {
if (!text.toLowerCase().includes(a._textBox1.value.toLowerCase())) {
continue;
}
}
}
result.push({
text: text,
href: href,
title: (a._getCheckBox(6) ? item.title : ""),
target: (a._getCheckBox(7) ? item.target : ""),
rel: (a._getCheckBox(8) ? item.rel : ""),
type: (a._getCheckBox(9) ? item.type : ""),
occurrence: ""
});
}
// Show occurrence
if (a._getCheckBox(10)) {
// Calc occurrences, store in cache
let occurrenceCache = [];
for (let i=0; i<result.length; i++) {
const occurrence = result.filter(item => JSON.stringify(item) === JSON.stringify(result[i])).length;
occurrenceCache.push(occurrence);
}
// Update result with occurrence
for (let i=0; i<result.length; i++) {
result[i].occurrence = occurrenceCache[i];
}
}
// Hide duplicates
if (a._getCheckBox(5)) {
result = result.distinct();
}
// Sort by anchor text
if (a._getCheckBox(3)) {
result = result.orderBy("text");
}
return result;
}
_renderTable(results) {
const a = this;
const table = a._generateTable();
a._setHtml(a._panel3, table);
const thead = a._panel3.querySelectorAll("thead")[0];
const tbody = a._panel3.querySelectorAll("tbody")[0];
// Write thead
thead.innerHTML = "<tr>" + a.#generateTableHeader() + "</tr>";
// Write tbody
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.text, item.href ];
if (a._getCheckBox(6)) {
row.push(item.title);
}
if (a._getCheckBox(7)) {
row.push(item.target);
}
if (a._getCheckBox(8)) {
row.push(item.rel);
}
if (a._getCheckBox(9)) {
row.push(item.type);
}
if (a._getCheckBox(10)) {
row.push(item.occurrence);
}
tbody.innerHTML += a.GenerateRow(row);
}
}
_renderCSV(results) {
const a = this;
const textarea = a._generateTextarea();
a._setHtml(a._panel3, textarea);
const tbody = a._panel3.querySelectorAll("textarea")[0];
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.text, item.href ];
if (a._getCheckBox(6)) {
row.push(item.title);
}
if (a._getCheckBox(7)) {
row.push(item.target);
}
if (a._getCheckBox(8)) {
row.push(item.rel);
}
if (a._getCheckBox(9)) {
row.push(item.type);
}
if (a._getCheckBox(10)) {
row.push(item.occurrence);
}
tbody.value += a.GenerateCSVLine("\t", row);
tbody.value += "\n";
}
}
_renderLinks(results) {
const a = this;
const textarea = a._generateTextarea();
a._setHtml(a._panel3, textarea);
const tbody = a._panel3.querySelectorAll("textarea")[0];
for (let i=0; i<results.length; i++) {
const item = results[i];
tbody.value += a.GenerateCSVLine("\t", [ item.href ]);
tbody.value += "\n";
}
}
#generateTableHeader() {
const a = this;
const columns1 = [
"Anchor Text",
"Address"
];
const columns2 = [
{ id: 6, name: "Title" },
{ id: 7, name: "Target" },
{ id: 8, name: "Rel" },
{ id: 9, name: "Type" },
{ id: 10, name: "Count" }
];
return a._generateTableHeader(columns1, columns2);
}
}
export default AContentService;

View File

@ -1,502 +0,0 @@
import '../../../literyz-js/extensions.dist.js';
import ContentService from './content-service.js';
class AContentService extends ContentService {
#containerPanel = null;
#popupService = null;
constructor(popupService) {
super();
this.#popupService = popupService;
}
InitialiseComponents() {
const a = this;
a.Clear();
a.#initialiseComponents_Options();
a.#initialiseComponents_Filters();
a.Button1.addEventListener('click', async function (e) {
a.Button2.disabled = true;
a.TextBox1.value = "";
await a.Search();
a.Button2.disabled = false;
});
a.Button2.addEventListener('click', async function (e) {
a.Button2.disabled = true;
await a.Search();
a.Button2.disabled = false;
});
}
#initialiseComponents_Options() {
const a = this;
let col1 = "";
col1 += a.GenerateCheckBox(1, "Show Anchor as HTML", false);
col1 += a.GenerateCheckBox(4, "Resolve Relative URL", false);
let col2 = "";
col2 += a.GenerateCheckBox(3, "Sort By Anchor Text", true);
col2 += a.GenerateCheckBox(2, "Trim Anchor Text", true);
let html = a.GenerateCols(col1, col2);
a.SetHtml(a.Panel1, html);
}
#initialiseComponents_Filters() {
const a = this;
let col1 = "";
col1 += a.GenerateCheckBox(12, "Hide External Links", true);
col1 += a.GenerateCheckBox(5, "Hide Duplicates", true);
col1 += a.GenerateCheckBox(14, "Hide Blank Anchors", true);
col1 += a.GenerateCheckBox(15, "Hide Blank Links", true);
col1 += a.GenerateCheckBox(11, "Hide Fragments", true);
col1 += a.GenerateCheckBox(13, "Hide Mailto/Tel", true);
col1 += a.GenerateCheckBox(16, "Hide Javascript", true);
let col2 = "";
col2 += a.GenerateCheckBox(6, "Show Title", true);
col2 += a.GenerateCheckBox(7, "Show Target", false);
col2 += a.GenerateCheckBox(8, "Show Rel", false);
col2 += a.GenerateCheckBox(9, "Show Type", false);
col2 += a.GenerateCheckBox(10, "Show Count", false);
let html = a.GenerateCols(col1, col2);
a.SetHtml(a.Panel2, html);
}
get Button1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("button")[0];
}
get Button2() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("button")[1];
}
get Container() {
const a = this;
if (a.#containerPanel == null) {
a.#containerPanel = document.getElementById("nav-hyperlinks");
}
return a.#containerPanel;
}
get Label1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("[role='label']")[0];
}
get MemoBox1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("textarea")[0];
}
get Panel1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("div[role='options']")[0];
}
get Panel2() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("div[role='filters']")[0];
}
get Table1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("table")[0];
}
get TextBox1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("input[role='textbox']")[0];
}
Clear() {
const a = this;
a.Table1.style.display = 'none';
a.MemoBox1.style.display = 'none';
a.SetHtml(a.Panel1, "");
a.SetHtml(a.Panel2, "");
}
async Search() {
const a = this;
a.Label1.innerText = "";
a.Table1.style.display = 'none';
a.MemoBox1.style.display = 'none';
const result = await a.#popupService.GetHyperlinks();
const totalCount = result.length;
const newResults = await a.#filterResult(result.copy());
if (newResults.length == totalCount) {
a.Label1.innerText = "Showing " + totalCount + " result" + (totalCount == 1 ? "" : "s");
} else {
a.Label1.innerText = "Showing " + newResults.length + " of " + totalCount + " result" + (totalCount == 1 ? "" : "s");
}
switch (a.#getComboBox(2)) {
case "table":
a.#renderTable(newResults);
break;
case "csv":
a.#renderCSV(newResults);
break;
case "links":
a.#renderLinks(newResults);
break;
default:
break;
}
}
async #filterResult(items) {
const a = this;
const currentUrl = await a.#popupService.GetLocation();
const currentHostname = (new URL(currentUrl)).hostname;
let result = [];
for (let i=0; i<items.length; i++) {
const item = items[i];
// Hide fragments
if (a.#getCheckBox(11)) {
if (item.href.startsWith("#")) {
continue;
}
}
// Hide blank links
if (a.#getCheckBox(15)) {
if (String.isNullOrWhitespace(item.href)) {
continue;
}
}
// Hide mailto/tel
if (a.#getCheckBox(13)) {
if (item.href.toLowerCase().startsWith("telno:") || item.href.toLowerCase().startsWith("mailto:")) {
continue;
}
}
// Hide javascript
if (a.#getCheckBox(16)) {
if (item.href.toLowerCase().startsWith("javascript:")) {
continue;
}
}
const absoluteUrl = new URL(item.href, currentUrl);
// Hide external links
if (a.#getCheckBox(12)) {
if (currentHostname != absoluteUrl.hostname) {
continue;
}
}
// Show anchor as html
let text = (a.#getCheckBox(1) ? item.innerHTML : item.innerText);
// Hide blank anchors
if (a.#getCheckBox(14)) {
if (String.isNullOrWhitespace(text)) {
continue;
}
}
// Resolve relative url
const href = (a.#getCheckBox(4) ? absoluteUrl.href : item.href);
// Trim anchor text
if (a.#getCheckBox(2)) {
text = text.trim();
}
// Search term
if (!String.isNullOrWhitespace(a.TextBox1.value)) {
if (a.#getComboBox(1) == "anchor") {
if (!text.toLowerCase().includes(a.TextBox1.value.toLowerCase())) {
continue;
}
} else {
if (!href.toLowerCase().includes(a.TextBox1.value.toLowerCase())) {
continue;
}
}
}
result.push({
text: text,
href: href,
title: (a.#getCheckBox(6) ? item.title : ""),
target: (a.#getCheckBox(7) ? item.target : ""),
rel: (a.#getCheckBox(8) ? item.rel : ""),
type: (a.#getCheckBox(9) ? item.type : ""),
occurrence: ""
});
}
// Show occurrence
if (a.#getCheckBox(10)) {
// Calc occurrences, store in cache
let occurrenceCache = [];
for (let i=0; i<result.length; i++) {
const occurrence = result.filter(item => JSON.stringify(item) === JSON.stringify(result[i])).length;
occurrenceCache.push(occurrence);
}
// Update result with occurrence
for (let i=0; i<result.length; i++) {
result[i].occurrence = occurrenceCache[i];
}
}
// Hide duplicates
if (a.#getCheckBox(5)) {
result = result.distinct();
}
// Sort by anchor text
if (a.#getCheckBox(3)) {
result = result.orderBy("text");
}
return result;
}
#generateTHeader() {
const a = this;
const columns = [
{ id: 6, name: "Title" },
{ id: 7, name: "Target" },
{ id: 8, name: "Rel" },
{ id: 9, name: "Type" },
{ id: 10, name: "Count" }
];
let html = "";
html += "<th>Anchor Text</th>";
html += "<th>Address</th>";
for (let i=0; i<columns.length; i++) {
if (a.#getCheckBox(columns[i].id)) {
html += "<th>" + columns[i].name + "</th>";
}
}
return html;
}
#getCheckBox(num) {
const a = this;
if (a.Container == null) {
return false;
}
const result = a.Container.querySelectorAll("input[name='checkbox" + num + "']");
if (result.length <= 0) {
return false;
}
return result[0].checked;
}
#getComboBox(num) {
const a = this;
if (a.Container == null) {
return "";
}
const result = a.Container.querySelectorAll("select[name='comboBox" + num + "']");
if (result.length <= 0) {
return "";
}
return result[0].value;
}
#getRadioGroup(num) {
const a = this;
if (a.Container == null) {
return "";
}
const result = a.Container.querySelectorAll("input[name='radioGroup" + num + "']:checked");
if (result.length <= 0) {
return "";
}
return result[0].value;
}
#renderTable(results) {
const a = this;
const thead = a.Table1.querySelectorAll("thead")[0];
const tbody = a.Table1.querySelectorAll("tbody")[0];
thead.innerHTML = "";
tbody.innerHTML = "";
a.Table1.style.display = 'table';
// Write thead
thead.innerHTML = "<tr>" + a.#generateTHeader() + "</tr>";
// Write tbody
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.text, item.href ];
if (a.#getCheckBox(6)) {
row.push(item.title);
}
if (a.#getCheckBox(7)) {
row.push(item.target);
}
if (a.#getCheckBox(8)) {
row.push(item.rel);
}
if (a.#getCheckBox(9)) {
row.push(item.type);
}
if (a.#getCheckBox(10)) {
row.push(item.occurrence);
}
tbody.innerHTML += a.GenerateRow(row);
}
}
#renderCSV(results) {
const a = this;
a.MemoBox1.value = "";
a.MemoBox1.style.display = 'inline-block';
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.text, item.href ];
if (a.#getCheckBox(6)) {
row.push(item.title);
}
if (a.#getCheckBox(7)) {
row.push(item.target);
}
if (a.#getCheckBox(8)) {
row.push(item.rel);
}
if (a.#getCheckBox(9)) {
row.push(item.type);
}
if (a.#getCheckBox(10)) {
row.push(item.occurrence);
}
a.MemoBox1.value += a.GenerateCSVLine("\t", row);
a.MemoBox1.value += "\n";
}
}
#renderLinks(results) {
const a = this;
a.MemoBox1.value = "";
a.MemoBox1.style.display = 'inline-block';
for (let i=0; i<results.length; i++) {
const item = results[i];
a.MemoBox1.value += a.GenerateCSVLine("\t", [ item.href ]);
a.MemoBox1.value += "\n";
}
}
}
export default AContentService;

View File

@ -1,23 +1,68 @@
// import '../references/extensions.dist.js'; // import '../references/extensions.dist.js';
class ContentService { class ContentService {
_popupService = null;
GenerateCheckBox(num, label, checked) { _containerId = null;
let html = "";
html += "<div class=\"form-check form-switch\">";
html += "<input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"checkbox" + num + "\" name=\"checkbox" + num + "\" " + (checked ? "checked" : "") + ">";
html += "<label class=\"form-check-label\" for=\"checkbox" + num + "\">" + label + "</label>";
html += "</div>";
return html;
constructor(popupService) {
const a = this;
a._popupService = popupService;
} }
GenerateCols(...args) {
let html = "";
for (let i=0; i<args.length; i++) { get Container() {
html += "<div class=\"col\">" + args[i] + "</div>"; const a = this;
}
return document.getElementById(a._containerId);
}
// get Panel1() {
// return this.#getElement("div[role='options']", 1);
// }
// get Panel2() {
// return this.#getElement("div[role='filters']", 1);
// }
// get Panel3() {
// return this.#getElement("div[role='results']", 1);
// }
// Clear(clearAll) {
// const a = this;
// const label1 = a._getLabel(1);
// label1.innerText = "";
// if (Boolean.isTrue(clearAll)) {
// a._setHtml(a.Panel1, "");
// a._setHtml(a.Panel2, "");
// }
// a._setHtml(a.Panel3, "");
// }
// async Search() {
// const a = this;
// a.Clear(false);
// }
GenerateCheckBox(num, label, checked) {
const randId = Math.randomN(100001, 999999);
const id = "checkbox" + randId;
const name = "checkbox" + num;
let html = "";
html += "<div class=\"form-check form-switch\">";
html += "<input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"" + id + "\" name=\"" + name + "\" " + (checked ? "checked" : "") + ">";
html += "<label class=\"form-check-label\" for=\"" + id + "\">" + label + "</label>";
html += "</div>";
return html; return html;
} }
@ -43,15 +88,17 @@ class ContentService {
return result; return result;
} }
GenerateRadioBox(groupNo, num, label, value, checked) { // GenerateRadioBox(groupNo, num, label, value, checked) {
let html = ""; // const randId = Math.randomN(100001, 999999);
html += "<div class=\"form-check\">";
html += "<input class=\"form-check-input\" type=\"radio\" name=\"radioGroup" + groupNo + "\" id=\"radioBox" + num + "\" value=\"" + value + "\" " + (checked ? "checked" : "") + ">";
html += "<label class=\"form-check-label\" for=\"radioBox" + num + "\">" + label + "</label>";
html += "</div>";
return html; // let html = "";
} // html += "<div class=\"form-check\">";
// html += "<input class=\"form-check-input\" type=\"radio\" name=\"radioGroup" + groupNo + "\" id=\"radioBox" + randId + "\" value=\"" + value + "\" " + (checked ? "checked" : "") + ">";
// html += "<label class=\"form-check-label\" for=\"radioBox" + randId + "\">" + label + "</label>";
// html += "</div>";
// return html;
// }
GenerateRow(...args) { GenerateRow(...args) {
const a = this; const a = this;
@ -64,17 +111,113 @@ class ContentService {
let result = ""; let result = "";
for (let i=0; i<args.length; i++) { for (let i=0; i<args.length; i++) {
result = result + a.GenerateRowCell(args[i]); result = result + a._generateTableCell(args[i]);
} }
return "<tr>" + result + "</tr>"; return "<tr>" + result + "</tr>";
} }
GenerateRowCell(value) {
_generateCheckBoxPanel(col1, col2) {
const a = this;
let colContent1 = "";
let colContent2 = "";
for (let i=0; i<col1.length; i++) {
colContent1 += a.GenerateCheckBox(col1[i].id, col1[i].text, col1[i].checked);
}
for (let i=0; i<col2.length; i++) {
colContent2 += a.GenerateCheckBox(col2[i].id, col2[i].text, col2[i].checked);
}
return a.#generateCols(colContent1, colContent2);
}
_generateTextarea() {
let html = "";
html += "<textarea class=\"form-control font-monospace text-sm px-1 py-1\" rows=\"16\"></textarea>";
return html;
}
_generateTable() {
let html = "";
html += "<table class=\"table table-bordered table-hover table-sm table-striped\">";
html += "<thead></thead>";
html += "<tbody></tbody>";
html += "</table>";
return html;
}
_generateTableCell(value) {
return "<td class=\"\"><input type=\"text\" class=\"display\" readonly=\"readonly\" value=\"" + value + "\" /></td>"; return "<td class=\"\"><input type=\"text\" class=\"display\" readonly=\"readonly\" value=\"" + value + "\" /></td>";
} }
SetHtml(element, htmlContent) { _generateTableHeader(fixedColumns, conditionalColumns) {
const a = this;
let html = "";
for (let i=0; i<fixedColumns.length; i++) {
html += "<th>" + fixedColumns[i] + "</th>";
}
for (let i=0; i<conditionalColumns.length; i++) {
if (!a._getCheckBox(conditionalColumns[i].id)) {
continue;
}
html += "<th>" + conditionalColumns[i].name + "</th>";
}
return html;
}
_getButton(num) {
return this.#getElement("button", num);
}
_getCheckBox(id) {
const a = this;
const name = "checkbox" + id;
const el = this.#getElement("input[type='checkbox'][name='" + name + "']", 1);
if (el == null) {
return false;
}
return el.checked;
}
_getComboBox(num) {
const a = this;
const el = a.#getElement("select", num);
if (el == null) {
return "";
}
return el.value;
}
_getLabel(num) {
return this.#getElement("[role='label']", num);
}
_getPanel(name, num) {
return this.#getElement("div[role='" + name + "']", num);
}
_getTextBox(num) {
return this.#getElement("input[type='text']", num);
}
_setHtml(element, htmlContent) {
if (element == null) { if (element == null) {
return; return;
} }
@ -82,6 +225,36 @@ class ContentService {
element.innerHTML = htmlContent; element.innerHTML = htmlContent;
} }
#generateCols(...args) {
let html = "";
for (let i=0; i<args.length; i++) {
html += "<div class=\"col\">" + args[i] + "</div>";
}
return html;
}
#getElement(nodeName, num) {
const a = this;
if (a.Container == null) {
return null;
}
const nodes = a.Container.querySelectorAll(nodeName);
if (nodes.length <= 0) {
return null;
}
if (nodes.length > num) {
return null;
}
return nodes[(num - 1)];
}
} }

View File

@ -0,0 +1,233 @@
import TabContentService from './tab-content-service.js';
class ImgContentService extends TabContentService {
constructor(popupService) {
super(popupService);
const a = this;
a._containerId = "nav-images";
a._optionsCol1 = [
{ id: 203, text: "Sort By Source URL", checked: true },
{ id: 204, text: "Resolve Relative URL", checked: false }
];
a._optionsCol2 = [
{ id: 202, text: "Trim Alternate Text", checked: true }
];
a._filtersCol1 = [
{ id: 212, text: "Hide External Links", checked: false },
{ id: 205, text: "Hide Duplicates", checked: true },
{ id: 214, text: "Hide Blank Alternate Text", checked: false },
{ id: 215, text: "Hide Blank Source URL", checked: true }
];
a._filtersCol2 = [
{ id: 206, text: "Show Alternative Text", checked: true },
{ id: 207, text: "Show Source Set", checked: false },
{ id: 208, text: "Show Image Map", checked: false },
{ id: 210, text: "Show Count", checked: false }
];
}
async _retrieveResult() {
return await this._popupService.GetImages();
}
async _filterResult(items) {
const a = this;
const currentUrl = await a._popupService.GetLocation();
const currentHostname = (new URL(currentUrl)).hostname;
let result = [];
for (let i=0; i<items.length; i++) {
const item = items[i];
// Hide source
if (a._getCheckBox(215)) {
if (String.isNullOrWhitespace(item.src)) {
continue;
}
}
const absoluteUrl = new URL(item.src, currentUrl);
// Hide external links
if (a._getCheckBox(212)) {
if (currentHostname != absoluteUrl.hostname) {
continue;
}
}
// Hide blank alternative text
if (a._getCheckBox(214)) {
if (String.isNullOrWhitespace(item.alt)) {
continue;
}
}
// Resolve source
const src = (a._getCheckBox(204) ? absoluteUrl.href : item.src);
const alt = (a._getCheckBox(202) ? item.alt.trim() : item.alt);
// Search term
if (!String.isNullOrWhitespace(a._textBox1.value)) {
if (a._getComboBox(1) == "src") {
if (!src.toLowerCase().includes(a._textBox1.value.toLowerCase())) {
continue;
}
} else {
if (!alt.toLowerCase().includes(a._textBox1.value.toLowerCase())) {
continue;
}
}
}
result.push({
src: src,
alt: (a._getCheckBox(206) ? alt : ""),
srcset: (a._getCheckBox(207) ? item.srcset : ""),
usemap: (a._getCheckBox(208) ? item.usemap : ""),
occurrence: ""
});
}
// Show occurrence
if (a._getCheckBox(210)) {
// Calc occurrences, store in cache
let occurrenceCache = [];
for (let i=0; i<result.length; i++) {
const occurrence = result.filter(item => JSON.stringify(item) === JSON.stringify(result[i])).length;
occurrenceCache.push(occurrence);
}
// Update result with occurrence
for (let i=0; i<result.length; i++) {
result[i].occurrence = occurrenceCache[i];
}
}
// Hide duplicates
if (a._getCheckBox(205)) {
result = result.distinct();
}
// Sort by source
if (a._getCheckBox(203)) {
result = result.orderBy("src");
}
return result;
}
_renderTable(results) {
const a = this;
const table = a._generateTable();
a._setHtml(a._panel3, table);
const thead = a._panel3.querySelectorAll("thead")[0];
const tbody = a._panel3.querySelectorAll("tbody")[0];
// Write thead
thead.innerHTML = "<tr>" + a.#generateTableHeader() + "</tr>";
// Write tbody
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.src ];
if (a._getCheckBox(206)) {
row.push(item.alt);
}
if (a._getCheckBox(207)) {
row.push(item.srcset);
}
if (a._getCheckBox(208)) {
row.push(item.usemap);
}
if (a._getCheckBox(210)) {
row.push(item.occurrence);
}
tbody.innerHTML += a.GenerateRow(row);
}
}
_renderCSV(results) {
const a = this;
const textarea = a._generateTextarea();
a._setHtml(a._panel3, textarea);
const tbody = a._panel3.querySelectorAll("textarea")[0];
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.src ];
if (a._getCheckBox(206)) {
row.push(item.alt);
}
if (a._getCheckBox(207)) {
row.push(item.srcset);
}
if (a._getCheckBox(208)) {
row.push(item.usemap);
}
if (a._getCheckBox(210)) {
row.push(item.occurrence);
}
tbody.value += a.GenerateCSVLine("\t", row);
tbody.value += "\n";
}
}
_renderLinks(results) {
const a = this;
const textarea = a._generateTextarea();
a._setHtml(a._panel3, textarea);
const tbody = a._panel3.querySelectorAll("textarea")[0];
for (let i=0; i<results.length; i++) {
const item = results[i];
tbody.value += a.GenerateCSVLine("\t", [ item.src ]);
tbody.value += "\n";
}
}
#generateTableHeader() {
const a = this;
const columns1 = [
"Source"
];
const columns2 = [
{ id: 206, name: "Alternative Text" },
{ id: 207, name: "Source Set" },
{ id: 208, name: "Image Map" },
{ id: 210, name: "Count" }
];
return a._generateTableHeader(columns1, columns2);
}
}
export default ImgContentService;

View File

@ -1,444 +0,0 @@
import '../../../literyz-js/extensions.dist.js';
import ContentService from './content-service.js';
class ImgContentService extends ContentService {
#containerPanel = null;
#popupService = null;
constructor(popupService) {
super();
this.#popupService = popupService;
}
InitialiseComponents() {
const a = this;
a.Clear();
a.#initialiseComponents_Options();
a.#initialiseComponents_Filters();
a.Button1.addEventListener('click', async function (e) {
a.Button2.disabled = true;
a.TextBox1.value = "";
await a.Search();
a.Button2.disabled = false;
});
a.Button2.addEventListener('click', async function (e) {
a.Button2.disabled = true;
await a.Search();
a.Button2.disabled = false;
});
}
#initialiseComponents_Options() {
const a = this;
let col1 = "";
col1 += a.GenerateCheckBox(203, "Sort By Source URL", true);
col1 += a.GenerateCheckBox(204, "Resolve Relative URL", false);
let col2 = "";
col2 += a.GenerateCheckBox(202, "Trim Alternate Text", true);
let html = a.GenerateCols(col1, col2);
a.SetHtml(a.Panel1, html);
}
#initialiseComponents_Filters() {
const a = this;
let col1 = "";
col1 += a.GenerateCheckBox(212, "Hide External Links", false);
col1 += a.GenerateCheckBox(205, "Hide Duplicates", true);
col1 += a.GenerateCheckBox(214, "Hide Blank Alternate Text", false);
col1 += a.GenerateCheckBox(215, "Hide Blank Source URL", true);
let col2 = "";
col2 += a.GenerateCheckBox(206, "Show Alternative Text", true);
col2 += a.GenerateCheckBox(207, "Show Source Set", false);
col2 += a.GenerateCheckBox(208, "Show Image Map", false);
// col2 += a.GenerateCheckBox(209, "Show Width", false);
// col2 += a.GenerateCheckBox(210, "Show Height", false);
col2 += a.GenerateCheckBox(210, "Show Count", false);
let html = a.GenerateCols(col1, col2);
a.SetHtml(a.Panel2, html);
}
get Button1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("button")[0];
}
get Button2() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("button")[1];
}
get Container() {
const a = this;
if (a.#containerPanel == null) {
a.#containerPanel = document.getElementById("nav-images");
}
return a.#containerPanel;
}
get Label1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("[role='label']")[0];
}
get MemoBox1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("textarea")[0];
}
get Panel1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("div[role='options']")[0];
}
get Panel2() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("div[role='filters']")[0];
}
get Table1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("table")[0];
}
get TextBox1() {
const a = this;
if (a.Container == null) {
return null;
}
return a.Container.querySelectorAll("input[role='textbox']")[0];
}
Clear() {
const a = this;
a.Table1.style.display = 'none';
a.MemoBox1.style.display = 'none';
a.SetHtml(a.Panel1, "");
a.SetHtml(a.Panel2, "");
}
async Search() {
const a = this;
a.Label1.innerText = "";
a.Table1.style.display = 'none';
a.MemoBox1.style.display = 'none';
const result = await a.#popupService.GetImages();
const totalCount = result.length;
const newResults = await a.#filterResult(result.copy());
if (newResults.length == totalCount) {
a.Label1.innerText = "Showing " + totalCount + " result" + (totalCount == 1 ? "" : "s");
} else {
a.Label1.innerText = "Showing " + newResults.length + " of " + totalCount + " result" + (totalCount == 1 ? "" : "s");
}
switch (a.#getComboBox(2)) {
case "table":
a.#renderTable(newResults);
break;
case "csv":
a.#renderCSV(newResults);
break;
case "links":
a.#renderLinks(newResults);
break;
default:
break;
}
}
async #filterResult(items) {
const a = this;
const currentUrl = await a.#popupService.GetLocation();
const currentHostname = (new URL(currentUrl)).hostname;
let result = [];
for (let i=0; i<items.length; i++) {
const item = items[i];
// Hide source
if (a.#getCheckBox(215)) {
if (String.isNullOrWhitespace(item.src)) {
continue;
}
}
const absoluteUrl = new URL(item.src, currentUrl);
// Hide external links
if (a.#getCheckBox(212)) {
if (currentHostname != absoluteUrl.hostname) {
continue;
}
}
// Hide blank alternative text
if (a.#getCheckBox(214)) {
if (String.isNullOrWhitespace(item.alt)) {
continue;
}
}
// Resolve source
const src = (a.#getCheckBox(204) ? absoluteUrl.href : item.src);
const alt = (a.#getCheckBox(202) ? item.alt.trim() : item.alt);
// Search term
if (!String.isNullOrWhitespace(a.TextBox1.value)) {
if (a.#getComboBox(201) == "alt") {
if (!alt.toLowerCase().includes(a.TextBox1.value.toLowerCase())) {
continue;
}
} else {
if (!src.toLowerCase().includes(a.TextBox1.value.toLowerCase())) {
continue;
}
}
}
result.push({
src: src,
alt: (a.#getCheckBox(206) ? alt : ""),
srcset: (a.#getCheckBox(207) ? item.srcset : ""),
usemap: (a.#getCheckBox(208) ? item.usemap : ""),
occurrence: ""
});
}
// Show occurrence
if (a.#getCheckBox(210)) {
// Calc occurrences, store in cache
let occurrenceCache = [];
for (let i=0; i<result.length; i++) {
const occurrence = result.filter(item => JSON.stringify(item) === JSON.stringify(result[i])).length;
occurrenceCache.push(occurrence);
}
// Update result with occurrence
for (let i=0; i<result.length; i++) {
result[i].occurrence = occurrenceCache[i];
}
}
// Hide duplicates
if (a.#getCheckBox(205)) {
result = result.distinct();
}
// Sort by source
if (a.#getCheckBox(203)) {
result = result.orderBy("src");
}
return result;
}
#generateTHeader() {
const a = this;
const columns = [
{ id: 206, name: "Alternative Text" },
{ id: 207, name: "Source Set" },
{ id: 208, name: "Image Map" },
{ id: 210, name: "Count" }
];
let html = "";
html += "<th>Source</th>";
for (let i=0; i<columns.length; i++) {
if (a.#getCheckBox(columns[i].id)) {
html += "<th>" + columns[i].name + "</th>";
}
}
return html;
}
#getCheckBox(num) {
const a = this;
if (a.Container == null) {
return false;
}
const result = a.Container.querySelectorAll("input[name='checkbox" + num + "']");
if (result.length <= 0) {
return false;
}
return result[0].checked;
}
#getComboBox(num) {
const a = this;
if (a.Container == null) {
return "";
}
const result = a.Container.querySelectorAll("select[name='comboBox" + num + "']");
if (result.length <= 0) {
return "";
}
return result[0].value;
}
#renderTable(results) {
const a = this;
const thead = a.Table1.querySelectorAll("thead")[0];
const tbody = a.Table1.querySelectorAll("tbody")[0];
thead.innerHTML = "";
tbody.innerHTML = "";
a.Table1.style.display = 'table';
// Write thead
thead.innerHTML = "<tr>" + a.#generateTHeader() + "</tr>";
// Write tbody
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.src ];
if (a.#getCheckBox(206)) {
row.push(item.alt);
}
if (a.#getCheckBox(207)) {
row.push(item.srcset);
}
if (a.#getCheckBox(208)) {
row.push(item.usemap);
}
if (a.#getCheckBox(210)) {
row.push(item.occurrence);
}
tbody.innerHTML += a.GenerateRow(row);
}
}
#renderCSV(results) {
const a = this;
a.MemoBox1.value = "";
a.MemoBox1.style.display = 'inline-block';
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.src ];
if (a.#getCheckBox(206)) {
row.push(item.alt);
}
if (a.#getCheckBox(207)) {
row.push(item.srcset);
}
if (a.#getCheckBox(208)) {
row.push(item.usemap);
}
if (a.#getCheckBox(210)) {
row.push(item.occurrence);
}
a.MemoBox1.value += a.GenerateCSVLine("\t", row);
a.MemoBox1.value += "\n";
}
}
#renderLinks(results) {
const a = this;
a.MemoBox1.value = "";
a.MemoBox1.style.display = 'inline-block';
for (let i=0; i<results.length; i++) {
const item = results[i];
a.MemoBox1.value += a.GenerateCSVLine("\t", [ item.src ]);
a.MemoBox1.value += "\n";
}
}
}
export default ImgContentService;

View File

@ -0,0 +1,188 @@
import TabContentService from './tab-content-service.js';
class MetaContentService extends TabContentService {
constructor(popupService) {
super(popupService);
const a = this;
a._containerId = "nav-metas";
a._optionsCol1 = [
{ id: 303, text: "Sort By Name", checked: true }
];
a._optionsCol2 = [
{ id: 302, text: "Trim Content", checked: true }
];
a._filtersCol1 = [
{ id: 305, text: "Hide Duplicates", checked: true },
{ id: 314, text: "Hide Blank Name", checked: false },
{ id: 315, text: "Hide Blank Content", checked: true }
];
a._filtersCol2 = [
{ id: 310, text: "Show Count", checked: false }
];
}
async _retrieveResult() {
return await this._popupService.GetMetas();
}
async _filterResult(items) {
const a = this;
const currentUrl = await a._popupService.GetLocation();
let result = [];
for (let i=0; i<items.length; i++) {
const item = items[i];
const content = (a._getCheckBox(302) ? item.content.trim() : item.content);
// Hide source
if (a._getCheckBox(315)) {
if (String.isNullOrWhitespace(content)) {
continue;
}
}
// Hide blank type
if (a._getCheckBox(314)) {
if (String.isNullOrWhitespace(item.name)) {
continue;
}
}
// Search term
if (!String.isNullOrWhitespace(a._textBox1.value)) {
if (a._getComboBox(1) == "name") {
if (!item.name.toLowerCase().includes(a._textBox1.value.toLowerCase())) {
continue;
}
} else {
if (!content.toLowerCase().includes(a._textBox1.value.toLowerCase())) {
continue;
}
}
}
result.push({
name: item.name,
content: content,
occurrence: ""
});
}
// Show occurrence
if (a._getCheckBox(310)) {
// Calc occurrences, store in cache
let occurrenceCache = [];
for (let i=0; i<result.length; i++) {
const occurrence = result.filter(item => JSON.stringify(item) === JSON.stringify(result[i])).length;
occurrenceCache.push(occurrence);
}
// Update result with occurrence
for (let i=0; i<result.length; i++) {
result[i].occurrence = occurrenceCache[i];
}
}
// Hide duplicates
if (a._getCheckBox(305)) {
result = result.distinct();
}
// Sort by name
if (a._getCheckBox(303)) {
result = result.orderBy("name");
}
return result;
}
_renderTable(results) {
const a = this;
const table = a._generateTable();
a._setHtml(a._panel3, table);
const thead = a._panel3.querySelectorAll("thead")[0];
const tbody = a._panel3.querySelectorAll("tbody")[0];
// Write thead
thead.innerHTML = "<tr>" + a.#generateTableHeader() + "</tr>";
// Write tbody
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.name, item.content ];
if (a._getCheckBox(310)) {
row.push(item.occurrence);
}
tbody.innerHTML += a.GenerateRow(row);
}
}
_renderCSV(results) {
const a = this;
const textarea = a._generateTextarea();
a._setHtml(a._panel3, textarea);
const tbody = a._panel3.querySelectorAll("textarea")[0];
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.name, item.content ];
if (a._getCheckBox(310)) {
row.push(item.occurrence);
}
tbody.value += a.GenerateCSVLine("\t", row);
tbody.value += "\n";
}
}
_renderLinks(results) {
const a = this;
const textarea = a._generateTextarea();
a._setHtml(a._panel3, textarea);
const tbody = a._panel3.querySelectorAll("textarea")[0];
for (let i=0; i<results.length; i++) {
const item = results[i];
tbody.value += a.GenerateCSVLine("\t", [ item.content ]);
tbody.value += "\n";
}
}
#generateTableHeader() {
const a = this;
const columns1 = [
"Name",
"Content"
];
const columns2 = [
{ id: 310, name: "Count" }
];
return a._generateTableHeader(columns1, columns2);
}
}
export default MetaContentService;

View File

@ -17,7 +17,6 @@ class PopupService {
resolve(payload.copy()); resolve(payload.copy());
}); });
}); });
} }
async GetImages() { async GetImages() {
@ -28,7 +27,16 @@ class PopupService {
resolve(payload.copy()); resolve(payload.copy());
}); });
}); });
}
async GetScripts() {
const a = this;
return new Promise(function(resolve) {
a.SendMessage("GetScriptNodes", async function(payload) {
resolve(payload.copy());
});
});
} }
async GetLocation() { async GetLocation() {
@ -41,6 +49,16 @@ class PopupService {
}); });
} }
async GetMetas() {
const a = this;
return new Promise(function(resolve) {
a.SendMessage("GetMetaNodes", async function(payload) {
resolve(payload.copy());
});
});
}
} }

View File

@ -0,0 +1,211 @@
import TabContentService from './tab-content-service.js';
class ScriptContentService extends TabContentService {
constructor(popupService) {
super(popupService);
const a = this;
a._containerId = "nav-scripts";
a._optionsCol1 = [
{ id: 303, text: "Sort By Source URL", checked: true },
{ id: 304, text: "Resolve Relative URL", checked: false }
];
a._optionsCol2 = [
{ id: 302, text: "Trim Alternate Type", checked: true }
];
a._filtersCol1 = [
{ id: 312, text: "Hide External Links", checked: false },
{ id: 305, text: "Hide Duplicates", checked: true },
{ id: 314, text: "Hide Blank Type", checked: false },
{ id: 315, text: "Hide Blank Source URL", checked: true }
];
a._filtersCol2 = [
{ id: 306, text: "Show Type", checked: true },
{ id: 310, text: "Show Count", checked: false }
];
}
async _retrieveResult() {
return await this._popupService.GetScripts();
}
async _filterResult(items) {
const a = this;
const currentUrl = await a._popupService.GetLocation();
const currentHostname = (new URL(currentUrl)).hostname;
let result = [];
for (let i=0; i<items.length; i++) {
const item = items[i];
// Hide source
if (a._getCheckBox(315)) {
if (String.isNullOrWhitespace(item.src)) {
continue;
}
}
const absoluteUrl = new URL(item.src, currentUrl);
// Hide external links
if (a._getCheckBox(312)) {
if (currentHostname != absoluteUrl.hostname) {
continue;
}
}
// Hide blank type
if (a._getCheckBox(314)) {
if (String.isNullOrWhitespace(item.type)) {
continue;
}
}
// Resolve source
const src = (a._getCheckBox(304) ? absoluteUrl.href : item.src);
const type = (a._getCheckBox(302) ? item.type.trim() : item.type);
// Search term
if (!String.isNullOrWhitespace(a._textBox1.value)) {
if (a._getComboBox(1) == "src") {
if (!src.toLowerCase().includes(a._textBox1.value.toLowerCase())) {
continue;
}
} else {
if (!type.toLowerCase().includes(a._textBox1.value.toLowerCase())) {
continue;
}
}
}
result.push({
src: src,
type: (a._getCheckBox(306) ? type : ""),
occurrence: ""
});
}
// Show occurrence
if (a._getCheckBox(310)) {
// Calc occurrences, store in cache
let occurrenceCache = [];
for (let i=0; i<result.length; i++) {
const occurrence = result.filter(item => JSON.stringify(item) === JSON.stringify(result[i])).length;
occurrenceCache.push(occurrence);
}
// Update result with occurrence
for (let i=0; i<result.length; i++) {
result[i].occurrence = occurrenceCache[i];
}
}
// Hide duplicates
if (a._getCheckBox(305)) {
result = result.distinct();
}
// Sort by source
if (a._getCheckBox(303)) {
result = result.orderBy("src");
}
return result;
}
_renderTable(results) {
const a = this;
const table = a._generateTable();
a._setHtml(a._panel3, table);
const thead = a._panel3.querySelectorAll("thead")[0];
const tbody = a._panel3.querySelectorAll("tbody")[0];
// Write thead
thead.innerHTML = "<tr>" + a.#generateTableHeader() + "</tr>";
// Write tbody
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.src ];
if (a._getCheckBox(306)) {
row.push(item.type);
}
if (a._getCheckBox(310)) {
row.push(item.occurrence);
}
tbody.innerHTML += a.GenerateRow(row);
}
}
_renderCSV(results) {
const a = this;
const textarea = a._generateTextarea();
a._setHtml(a._panel3, textarea);
const tbody = a._panel3.querySelectorAll("textarea")[0];
for (let i=0; i<results.length; i++) {
const item = results[i];
let row = [ item.src ];
if (a._getCheckBox(306)) {
row.push(item.type);
}
if (a._getCheckBox(310)) {
row.push(item.occurrence);
}
tbody.value += a.GenerateCSVLine("\t", row);
tbody.value += "\n";
}
}
_renderLinks(results) {
const a = this;
const textarea = a._generateTextarea();
a._setHtml(a._panel3, textarea);
const tbody = a._panel3.querySelectorAll("textarea")[0];
for (let i=0; i<results.length; i++) {
const item = results[i];
tbody.value += a.GenerateCSVLine("\t", [ item.src ]);
tbody.value += "\n";
}
}
#generateTableHeader() {
const a = this;
const columns1 = [
"Source"
];
const columns2 = [
{ id: 306, name: "Type" },
{ id: 310, name: "Count" }
];
return a._generateTableHeader(columns1, columns2);
}
}
export default ScriptContentService;

View File

@ -0,0 +1,129 @@
import ContentService from './content-service.js';
class TabContentService extends ContentService {
_button1 = null;
_button2 = null;
_label1 = null;
_panel1 = null;
_panel2 = null;
_panel3 = null;
_textBox1 = null;
_optionsCol1 = [];
_optionsCol2 = [];
_filtersCol1 = [];
_filtersCol2 = [];
constructor(popupService) {
super(popupService);
}
InitialiseComponents() {
const a = this;
const buttons = a.Container.querySelectorAll("button");
a._button1 = buttons[0];
a._button2 = buttons[1];
a._label1 = a._getLabel(1);
a._panel1 = a._getPanel("options", 1);
a._panel2 = a._getPanel("filters", 1);
a._panel3 = a._getPanel("results", 1);
a._textBox1 = a._getTextBox(1);
a.Clear(true);
// Initialise options
const htmlContent1 = a._generateCheckBoxPanel(a._optionsCol1, a._optionsCol2);
a._setHtml(a._panel1, htmlContent1);
// Initialise filters
const htmlContent2 = a._generateCheckBoxPanel(a._filtersCol1, a._filtersCol2);
a._setHtml(a._panel2, htmlContent2);
// Events
a._button1.addEventListener('click', async function (e) {
a._button2.disabled = true;
a._textBox1.value = "";
await a.Search();
a._button2.disabled = false;
});
a._button2.addEventListener('click', async function (e) {
a._button2.disabled = true;
await a.Search();
a._button2.disabled = false;
});
}
Clear(clearAll) {
const a = this;
a._label1.innerText = "";
if (Boolean.isTrue(clearAll)) {
a._setHtml(a._panel1, "");
a._setHtml(a._panel2, "");
}
a._setHtml(a._panel3, "");
}
async Search() {
const a = this;
const result = await a._retrieveResult();
const totalCount = result.length;
const newResults = await a._filterResult(result.copy());
if (newResults.length == totalCount) {
a._label1.innerText = "Showing " + totalCount + " result" + (totalCount == 1 ? "" : "s");
} else {
a._label1.innerText = "Showing " + newResults.length + " of " + totalCount + " result" + (totalCount == 1 ? "" : "s");
}
switch (a._getComboBox(2)) {
case "table":
a._renderTable(newResults);
break;
case "csv":
a._renderCSV(newResults);
break;
case "links":
a._renderLinks(newResults);
break;
default:
break;
}
}
async _retrieveResult() {
return [];
}
async _filterResult(result) {
return result;
}
_renderTable(result) {
}
_renderCSV(result) {
}
_renderLinks(result) {
}
}
export default TabContentService;