diff --git a/options.html b/options.html index 946ff79..b55b59c 100644 --- a/options.html +++ b/options.html @@ -7,13 +7,58 @@ + -

Extension Options

- -
- -
+
+

Extension Options

+
+

Customize the chart appearance and data:

+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+ +
+ +
+ + + \ No newline at end of file diff --git a/popup.html b/popup.html index 4975736..56d826a 100644 --- a/popup.html +++ b/popup.html @@ -13,8 +13,8 @@

RSI-Histogram

- - + + diff --git a/scripts/background.js b/scripts/background.js index 89fc1cc..68526f5 100644 --- a/scripts/background.js +++ b/scripts/background.js @@ -106,4 +106,21 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { } // Handle other actions... +}); + +// Set the default options when the extension is installed +chrome.runtime.onInstalled.addListener(function(details) { + if (details.reason == "install") { + var defaultOptions = { + chartType: 'line', // default chart type + showTitle: true, // default to show title + showAxisLabels: true, // default to show axis labels + showValues: true, // default to show values + showTickmarks: true, // default to show tickmarks + timeMeasure: 'month' // default time measure + }; + chrome.storage.sync.set({options: defaultOptions}, function() { + console.log('Default options set.'); + }); + } }); \ No newline at end of file diff --git a/scripts/content.js b/scripts/content.js index 7927fe4..18d8230 100644 --- a/scripts/content.js +++ b/scripts/content.js @@ -75,8 +75,9 @@ async function extractDataFromPage(pageNumber, runningTotal = 0) { //let nextPageNumber = nextPageLink.href.match(/page=(\d+)/)[1]; let nextPageData = await extractDataFromPage(nextPageNumber); - //nextPageData.forEach(order => ordersData.push(order)); - console.log('nextPageNumber:', nextPageNumber); + // Update the status element with the next page number + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Processing page ' + nextPageNumber}); + //return ordersData; return ordersData.concat(nextPageData); } else { @@ -122,162 +123,228 @@ extractDataFromPage(1) // createModal is a message handler that creates a modal with a chart. chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { -if (request.action === 'createModal') { - chrome.runtime.sendMessage({action: 'updateStatus', status: 'Creating modal.'}); - - // Create the modal area - var modal = document.createElement('div'); - modal.style.position = 'fixed'; - modal.style.zIndex = '1000'; - modal.style.left = '0'; - modal.style.top = '0'; - modal.style.width = '100vw'; - modal.style.height = '100vh'; - modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; - modal.style.display = 'flex'; - modal.style.flexDirection = 'column'; - modal.style.justifyContent = 'center'; - modal.style.alignItems = 'center'; - chrome.runtime.sendMessage({action: 'updateStatus', status: 'Modal created.'}); - - // Create the modalContent area - var modalContent = document.createElement('div'); - modalContent.style.width = '80vw'; - modalContent.style.Maxheight = '80vh'; - modalContent.style.display = 'flex'; - modalContent.style.flexDirection = 'column'; - modalContent.style.alignItems = 'center'; - modalContent.style.justifyContent = 'center'; - modalContent.style.overflow = 'auto'; - modalContent.style.backgroundColor = '#ffffff'; - modalContent.style.padding = '20px'; - modalContent.style.borderRadius = '10px'; - modalContent.style.position = 'relative'; - chrome.runtime.sendMessage({action: 'updateStatus', status: 'Modal content created.'}); - - // Create a close button in the top right of the content - var closeButton = document.createElement('span'); - closeButton.innerHTML = '×'; - closeButton.style.position = 'absolute'; - closeButton.style.right = '10px'; - closeButton.style.top = '10px'; - closeButton.style.cursor = 'pointer'; - closeButton.style.fontSize = '18px'; - closeButton.style.fontWeight = 'bold'; - closeButton.addEventListener('click', function() { - if (document.body.contains(modal)) { - document.body.removeChild(modal); - } - }); - modalContent.appendChild(closeButton); - chrome.runtime.sendMessage({action: 'updateStatus', status: 'Close button created.'}); - - // Create a canvas for the chart - var canvas = document.createElement('canvas'); - canvas.id = 'myChart'; - canvas.width = '100%'; - canvas.height = '100%'; - modalContent.appendChild(canvas); - chrome.runtime.sendMessage({action: 'updateStatus', status: 'Canvas created.'}); - modal.appendChild(modalContent); - - // Append the modal to the body - document.body.appendChild(modal); + if (request.action === 'createModal') { + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Creating modal.'}); - // Prepare the data for the chart - let labels = request.ordersDataSet.map(order => order.orderPlaced); - let dataAmount = request.ordersDataSet.map(order => order.amount); - let dataRunningTotal = request.ordersDataSet.map(order => order.runningTotal); + // Create the modal area + var modal = document.createElement('div'); + modal.style.position = 'fixed'; + modal.style.zIndex = '1000'; + modal.style.left = '0'; + modal.style.top = '0'; + modal.style.width = '100vw'; + modal.style.height = '100vh'; + modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; + modal.style.display = 'flex'; + modal.style.flexDirection = 'column'; + modal.style.justifyContent = 'center'; + modal.style.alignItems = 'center'; + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Modal created.'}); - // Create the chart + // Create the modalContent area + var modalContent = document.createElement('div'); + modalContent.style.width = '80vw'; + modalContent.style.Maxheight = '80vh'; + modalContent.style.display = 'flex'; + modalContent.style.flexDirection = 'column'; + modalContent.style.alignItems = 'center'; + modalContent.style.justifyContent = 'center'; + modalContent.style.overflow = 'auto'; + modalContent.style.backgroundColor = '#ffffff'; + modalContent.style.padding = '20px'; + modalContent.style.borderRadius = '10px'; + modalContent.style.position = 'relative'; + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Modal content created.'}); + + // Create a close button in the top right of the content + var closeButton = document.createElement('span'); + closeButton.innerHTML = '×'; + closeButton.style.position = 'absolute'; + closeButton.style.right = '10px'; + closeButton.style.top = '10px'; + closeButton.style.cursor = 'pointer'; + closeButton.style.fontSize = '18px'; + closeButton.style.fontWeight = 'bold'; + closeButton.addEventListener('click', function() { + if (document.body.contains(modal)) { + document.body.removeChild(modal); + } + }); + modalContent.appendChild(closeButton); + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Close button created.'}); + + // Create a canvas for the chart + var canvas = document.createElement('canvas'); + canvas.id = 'myChart'; + canvas.width = '100%'; + canvas.height = '100%'; + modalContent.appendChild(canvas); + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Canvas created.'}); + modal.appendChild(modalContent); + + // Append the modal to the body + document.body.appendChild(modal); + } +}); + +// Function to inject Chart.js +function injectChartjs(callback) { chrome.runtime.sendMessage({action: 'injectChartjs'}, (response) => { if (response && response.success) { // Wait for Chartjs to load setTimeout(() => { chrome.runtime.sendMessage({action: 'updateStatus', status: 'Chartjs loaded.'}); - // Check if there's data - if (!labels || !dataAmount || !dataRunningTotal) { - chrome.runtime.sendMessage({action: 'updateStatus', status: 'Failed to create chart: data not found.'}); - return; - } - // Log the dataset to the console - console.log(request.ordersDataSet); - // Create the chart - var ctx = document.getElementById('myChart').getContext('2d'); - var chart = new Chart(ctx, { - type: 'line', - data: { - labels: labels, - datasets: [{ - label: 'Amount', - data: dataAmount, - borderColor: 'rgb(75, 192, 192)', - fill: false - }, { - label: 'Running Total', - data: dataRunningTotal, - borderColor: 'rgb(255, 99, 132)', - fill: false - }] + callback(null); + }, 1000); + } else { + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Failed to load Chartjs.'}); + callback(new Error('Failed to load Chartjs.')); + } + }); +} + +// Function to create the chart +function createChart(options, callback) { + // Check if there's data + if (!options.labels || !options.dataAmount || !options.dataRunningTotal) { + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Failed to create chart: data not found.'}); + callback(new Error('Failed to create chart: data not found.')); + return; + } + + // Log the dataset to the console + console.log(options.ordersDataSet); + + // Prepare the data for the chart + let labels = options.ordersDataSet.map(order => order.orderPlaced); + let dataAmount = options.ordersDataSet.map(order => order.amount); + let dataRunningTotal = options.ordersDataSet.map(order => order.runningTotal); + + // Create the chart + var ctx = document.getElementById('myChart').getContext('2d'); + var chart = new Chart(ctx, { + type: options.chartType, + data: { + labels: labels, + datasets: [{ + label: 'Amount', + data: dataAmount, + borderColor: 'rgb(75, 192, 192)', + fill: false + }, { + label: 'Running Total', + data: dataRunningTotal, + borderColor: 'rgb(255, 99, 132)', + fill: false + }] + }, + options: { + responsive: true, + title: { + display: options.showTitle, + text: 'Order Data' + }, + tooltips: { + mode: 'index', + intersect: false, + }, + hover: { + mode: 'nearest', + intersect: true + }, + scales: { + x: { + type: 'time', + display: options.showAxisLabels, + title: { + display: options.showAxisLabels, + text: 'Order Placed' }, - options: { - responsive: true, - title: { - display: true, - text: 'Order Data' - }, - tooltips: { - mode: 'index', - intersect: false, - }, - hover: { - mode: 'nearest', - intersect: true - }, - scales: { - x: { - type: 'time', - display: true, - title: { - display: true, - text: 'Order Placed' - }, - time: { - unit: 'month' - } - }, - y: { - type: 'linear', - display: true, - title: { - display: true, - text: 'Value' - }, - beginAtZero: true - }, - }, - animation: { - onComplete: function() { - chrome.runtime.sendMessage({action: 'updateStatus', status: 'Chart animation completed.'}); - } - } + time: { + unit: options.timeMeasure + }, + ticks: { + display: options.showTickmarks + } + }, + y: { + type: 'linear', + display: options.showAxisLabels, + title: { + display: options.showAxisLabels, + text: 'Value' + }, + beginAtZero: true, + ticks: { + display: options.showTickmarks + } + }, + }, + animation: { + onComplete: function() { + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Chart animation completed.'}); + } + } + } + }); + + // Store the chart in the window object + window.myChart = chart; + // Store the chart and its data in the window object + window.chartData = { + labels: options.labels, + dataAmount: options.dataAmount, + dataRunningTotal: options.dataRunningTotal + }; + + // Send a status update after the chart has been created + chrome.runtime.sendMessage({action: 'updateStatus', status: 'Chart created.'}) + + callback(null); + } + +chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { + if (request.action === 'downloadChart') { + // Convert the chart to a PNG image + let pngImage = window.myChart.toBase64Image(); + // Create a link to download the data + var link = document.createElement('a'); + link.href = pngImage; + link.download = 'chart.png'; + link.click(); + } +}); + +chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { + if (request.action === 'updateOptions') { + var options = request.options; + + // Retrieve the data from local storage + chrome.storage.local.get({ordersDataSet: []}, function(result) { + let ordersDataSet = result.ordersDataSet; + + // If the chart doesn't exist, create it + if (!window.myChart) { + options.ordersDataSet = ordersDataSet; + createChart(options, (err) => { + if (err) { + console.error(err); } }); + } - // Store the chart and its data in the window object - window.myChart = chart; - window.chartData = { - labels: labels, - dataAmount: dataAmount, - dataRunningTotal: dataRunningTotal - }; + // If the chart exists, update its options + if (window.myChart) { + window.myChart.options.title.display = options.showTitle; + window.myChart.options.scales.xAxes[0].display = options.showAxisLabels; + window.myChart.options.scales.yAxes[0].display = options.showAxisLabels; + window.myChart.options.scales.xAxes[0].ticks.display = options.showTickmarks; + window.myChart.options.scales.yAxes[0].ticks.display = options.showTickmarks; + window.myChart.options.scales.xAxes[0].time.unit = options.timeMeasure; - // Send a status update after the chart has been created - chrome.runtime.sendMessage({action: 'updateStatus', status: 'Chart created.'}) - }, 1000); - } else { - chrome.runtime.sendMessage({action: 'updateStatus', status: 'Failed to load Chartjs.'}); + // Update the chart + window.myChart.update(); } -}); -} -}) \ No newline at end of file + }); + } +}); \ No newline at end of file diff --git a/scripts/options.js b/scripts/options.js new file mode 100644 index 0000000..448ec10 --- /dev/null +++ b/scripts/options.js @@ -0,0 +1,89 @@ +// Load options from chrome.storage +function load_options() { + chrome.storage.sync.get({ + options: { + showTitle: true, + chartTitle: '', + showAxisLabels: true, + showValues: true, + showTickmarks: true, + chartType: 'line', + chartColor: '#000000', + timeMeasure: 'month' + } + }, function(data) { + document.getElementById('showTitle').checked = data.options.showTitle; + document.getElementById('chartTitle').value = data.options.chartTitle; + document.getElementById('showAxisLabels').checked = data.options.showAxisLabels; + document.getElementById('showValues').checked = data.options.showValues; + document.getElementById('showTickmarks').checked = data.options.showTickmarks; + document.getElementById('chartType').value = data.options.chartType; + document.getElementById('chartColor').value = data.options.chartColor; + document.getElementById('timeMeasure').value = data.options.timeMeasure; + }); +} + +// Event listener for DOMContentLoaded to load the options +document.addEventListener('DOMContentLoaded', load_options); + +// Save options to chrome.storage +function save_options(callback) { + var options = { + chartType: document.getElementById('chartType').value, + showTitle: document.getElementById('showTitle').checked, + showAxisLabels: document.getElementById('showAxisLabels').checked, + showTickmarks: document.getElementById('showTickmarks').checked, + timeMeasure: document.getElementById('timeMeasure').value + }; + chrome.storage.sync.set({ + options: options + }, function() { + // Update status to let user know options were saved. + var status = document.getElementById('status'); + status.textContent = 'Options saved.'; + setTimeout(function() { + status.textContent = ''; + }, 750); + if (callback) callback(); // Call the callback function if it's provided + }); +} + +// Event listener for the save button +document.getElementById('saveOptionsButton').addEventListener('click', function(e) { + e.preventDefault(); // Prevent the form from submitting + save_options(load_options); +}); + +document.getElementById('showTitle').addEventListener('change', sendOptions); +document.getElementById('showAxisLabels').addEventListener('change', sendOptions); +document.getElementById('showValues').addEventListener('change', sendOptions); +document.getElementById('showTickmarks').addEventListener('change', sendOptions); +document.getElementById('timeMeasure').addEventListener('change', sendOptions); + +function sendOptions() { + chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { + chrome.tabs.sendMessage(tabs[0].id, { + action: 'updateOptions', + options: { + showTitle: document.getElementById('showTitle').checked, + showAxisLabels: document.getElementById('showAxisLabels').checked, + showValues: document.getElementById('showValues').checked, + showTickmarks: document.getElementById('showTickmarks').checked, + timeMeasure: document.getElementById('timeMeasure').value + } + }); + }); +} + +// Listen for resetButton click +document.getElementById('resetButton').addEventListener('click', function() { + chrome.runtime.sendMessage({action: 'resetData'}); + document.getElementById('status').textContent = 'Data reset started'; +}); + +//listen for statusUpdate messages and add to the temporary status div element +chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { + if (request.action === 'statusUpdate') { + document.getElementById('statusLog').textContent = request.status; + } +}); \ No newline at end of file diff --git a/scripts/popup.js b/scripts/popup.js index dd4722f..66faedd 100644 --- a/scripts/popup.js +++ b/scripts/popup.js @@ -37,8 +37,8 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { }); } }); -// Listen for resetButton click -document.getElementById('resetButton').addEventListener('click', function() { - chrome.runtime.sendMessage({action: 'resetData'}); - document.getElementById('status').textContent = 'Data reset started'; +// Liten for the downloadButton click +document.getElementById('downloadButton').addEventListener('click', function() { + chrome.runtime.sendMessage({action: 'downloadData'}); + document.getElementById('status').textContent = 'Data download started'; }); \ No newline at end of file diff --git a/styles/options.css b/styles/options.css new file mode 100644 index 0000000..238dd72 --- /dev/null +++ b/styles/options.css @@ -0,0 +1,84 @@ +body { + background-color: #1a1a1a; + color: #000; + font-family: 'Courier New', Courier, monospace; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + padding: 0; + box-sizing: border-box; + text-align: center; +} + +button { + background-color: #333333; + color: #ffffff; + border: none; + padding: 10px 20px; + border-radius: 5px; + cursor: pointer; +} + +button:hover { + background-color: #555555; +} + +.appArea { + display: flex; + flex-direction: column; + align-items: center; + background-color: darkgray; + max-width: 80vw; + max-height: 80vh; + width: 100%; +} + +.appArea h1 { + text-align: center; + width: 100%; +} + +.appArea .content { + display: flex; + justify-content: space-between; + width: 100%; +} +.optionsForm { + display: flex; + flex-direction: column; + align-items: center; + background-color: blue; +} +.statusLog { + display: flex; + flex-direction: column; + align-items: center; + background-color: #f2f2f2; + color: #000; + border: none; + padding: 10px; + width: 50%; + height: 200px; + resize: none; + overflow-y: auto; +} + +.container input, .container button { + display: flex; + justify-content: flex-end; + width: 50%; +} + +.container label { + display: flex; + justify-content: flex-start; + width: 50%; +} + +.container input[type=checkbox] { + float: left; + width: auto; +} +