Browse Source

boilerplate code and stubbed functions

Brandon Wong 1 year ago
commit
199866667a
7 changed files with 320 additions and 0 deletions
  1. 37 0
      background.js
  2. 41 0
      content_scripts/content.js
  3. 3 0
      icons/placeholder.txt
  4. 30 0
      manifest.json
  5. 65 0
      popup/popup.css
  6. 29 0
      popup/popup.html
  7. 115 0
      popup/popup.js

+ 37 - 0
background.js

@@ -0,0 +1,37 @@
+// Background script for the extension
+
+// Function to navigate a tab to a new URL
+function navigateTab(tabId, url) {
+  return browser.tabs.update(tabId, { url: url });
+}
+
+// Listen for messages from popup or content scripts
+browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
+  if (message.command === 'navigate') {
+    if (message.tabId && message.url) {
+      navigateTab(message.tabId, message.url)
+        .then(() => sendResponse({ status: 'success' }))
+        .catch(error => sendResponse({ status: 'error', message: error.message }));
+      return true; // Required for async sendResponse
+    }
+  }
+});
+
+// Listen for tab updates to potentially inject scripts on certain URLs
+browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
+  if (changeInfo.status === 'complete' && tab.url) {
+    // Check if the URL matches your patterns and inject scripts as needed
+    const urlPatterns = [
+      /example\.com/,
+      /another-site\.org/
+      // Add more URL patterns as needed
+    ];
+    
+    const shouldInject = urlPatterns.some(pattern => pattern.test(tab.url));
+    
+    if (shouldInject) {
+      browser.tabs.executeScript(tabId, { file: '/content_scripts/content.js' })
+        .catch(error => console.error('Error injecting script:', error));
+    }
+  }
+});

+ 41 - 0
content_scripts/content.js

@@ -0,0 +1,41 @@
+(function() {
+  console.log('Content script loaded');
+  
+  /**
+   * Check if the current URL matches the pattern
+   * @param {string} urlPattern - URL pattern to match
+   * @returns {boolean} - Whether the current URL matches the pattern
+   */
+  function matchesUrlPattern(urlPattern) {
+    const regex = new RegExp(urlPattern);
+    return regex.test(window.location.href);
+  }
+
+  /**
+   * Function to inject and execute custom code on the page
+   */
+  function injectCustomCode() {
+    console.log('Custom code injected into the page');
+    
+    // Example: Add a banner to the top of the page
+    const banner = document.createElement('div');
+    banner.textContent = 'This page has been modified by My Firefox Extension';
+    banner.style.cssText = 'position: fixed; top: 0; left: 0; width: 100%; background: #ffcc00; padding: 10px; text-align: center; z-index: 9999;';
+    document.body.prepend(banner);
+    
+    // You can add more functionality here
+  }
+
+  // Listen for messages from the popup or background script
+  browser.runtime.onMessage.addListener((message) => {
+    if (message.command === 'injectCode') {
+      injectCustomCode();
+      return Promise.resolve({status: 'Injection completed'});
+    }
+  });
+  
+  // Check if we should automatically inject code based on URL
+  if (matchesUrlPattern('example\\.com')) {
+    injectCustomCode();
+  }
+})();

+ 3 - 0
icons/placeholder.txt

@@ -0,0 +1,3 @@
+Please replace this file with actual icon files:
+- icon-48.png (48x48 pixels)
+- icon-96.png (96x96 pixels)

+ 30 - 0
manifest.json

@@ -0,0 +1,30 @@
+{
+  "manifest_version": 2,
+  "name": "My Firefox Extension",
+  "version": "1.0",
+  "description": "A Firefox extension with code injection, navigation, and storage capabilities",
+  "icons": {
+    "48": "icons/icon-48.png",
+    "96": "icons/icon-96.png"
+  },
+  "permissions": [
+    "activeTab",
+    "tabs",
+    "storage",
+    "<all_urls>"
+  ],
+  "browser_action": {
+    "default_icon": "icons/icon-48.png",
+    "default_title": "My Firefox Extension",
+    "default_popup": "popup/popup.html"
+  },
+  "background": {
+    "scripts": ["background.js"]
+  },
+  "content_scripts": [
+    {
+      "matches": ["*://*.example.com/*"],
+      "js": ["content_scripts/content.js"]
+    }
+  ]
+}

+ 65 - 0
popup/popup.css

@@ -0,0 +1,65 @@
+body {
+  width: 300px;
+  font-family: Arial, sans-serif;
+}
+
+.container {
+  padding: 10px;
+}
+
+h1 {
+  font-size: 18px;
+  margin-bottom: 15px;
+}
+
+h2 {
+  font-size: 16px;
+  margin-top: 15px;
+  margin-bottom: 10px;
+}
+
+button {
+  margin: 5px 0;
+  padding: 8px;
+  width: 100%;
+  background-color: #0060df;
+  color: white;
+  border: none;
+  cursor: pointer;
+  border-radius: 4px;
+}
+
+button:hover {
+  background-color: #003eaa;
+}
+
+input {
+  width: 100%;
+  padding: 8px;
+  margin: 5px 0;
+  box-sizing: border-box;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+
+.button-group {
+  display: flex;
+  gap: 5px;
+}
+
+.button-group button {
+  flex: 1;
+}
+
+.storage-section {
+  margin-top: 15px;
+  padding-top: 10px;
+  border-top: 1px solid #eee;
+}
+
+#status, #storage-result {
+  margin-top: 10px;
+  padding: 5px;
+  color: #333;
+  min-height: 20px;
+}

+ 29 - 0
popup/popup.html

@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <link rel="stylesheet" href="popup.css">
+</head>
+<body>
+  <div class="container">
+    <h1>My Firefox Extension</h1>
+    <button id="inject-button">Inject Script</button>
+    <button id="navigate-button">Navigate Tab</button>
+    <input type="text" id="navigation-url" placeholder="https://example.com">
+    
+    <div class="storage-section">
+      <h2>Saved Data</h2>
+      <input type="text" id="storage-key" placeholder="Key">
+      <input type="text" id="storage-value" placeholder="Value">
+      <div class="button-group">
+        <button id="save-data">Save</button>
+        <button id="load-data">Load</button>
+      </div>
+      <div id="storage-result"></div>
+    </div>
+    
+    <div id="status"></div>
+  </div>
+  <script src="popup.js"></script>
+</body>
+</html>

+ 115 - 0
popup/popup.js

@@ -0,0 +1,115 @@
+// Function to display status messages
+function showStatus(message) {
+  document.getElementById('status').textContent = message;
+  setTimeout(() => {
+    document.getElementById('status').textContent = '';
+  }, 3000);
+}
+
+// Function to inject script into the current tab
+function injectScript() {
+  browser.tabs.query({active: true, currentWindow: true})
+    .then(tabs => {
+      browser.tabs.sendMessage(tabs[0].id, { command: 'injectCode' })
+        .then(response => {
+          showStatus('Script injected successfully!');
+        })
+        .catch(error => {
+          showStatus('Error: Content script may not be loaded. Try refreshing the page.');
+          // Fallback: Directly inject the content script
+          browser.tabs.executeScript(tabs[0].id, {
+            file: "/content_scripts/content.js"
+          });
+        });
+    });
+}
+
+// Function to navigate to another page
+function navigateTab() {
+  const url = document.getElementById('navigation-url').value;
+  if (!url) {
+    showStatus('Please enter a URL');
+    return;
+  }
+  
+  // Add http:// prefix if missing
+  const formattedUrl = url.includes('://') ? url : `http://${url}`;
+  
+  browser.tabs.query({active: true, currentWindow: true})
+    .then(tabs => {
+      browser.runtime.sendMessage({
+        command: 'navigate',
+        tabId: tabs[0].id,
+        url: formattedUrl
+      })
+      .then(response => {
+        if (response && response.status === 'success') {
+          showStatus('Tab navigated successfully!');
+        } else {
+          showStatus('Error navigating tab: ' + (response ? response.message : 'Unknown error'));
+        }
+      })
+      .catch(error => {
+        showStatus('Error navigating tab: ' + error.message);
+      });
+    });
+}
+
+// Function to save data to storage
+function saveData() {
+  const key = document.getElementById('storage-key').value;
+  const value = document.getElementById('storage-value').value;
+  
+  if (!key) {
+    showStatus('Please enter a key');
+    return;
+  }
+  
+  browser.storage.local.set({ [key]: value })
+    .then(() => {
+      document.getElementById('storage-result').textContent = `Data saved: ${key} = ${value}`;
+    })
+    .catch(error => {
+      document.getElementById('storage-result').textContent = 'Error saving data: ' + error.message;
+    });
+}
+
+// Function to load data from storage
+function loadData() {
+  const key = document.getElementById('storage-key').value;
+  
+  if (!key) {
+    showStatus('Please enter a key');
+    return;
+  }
+  
+  browser.storage.local.get(key)
+    .then(result => {
+      if (result[key] !== undefined) {
+        document.getElementById('storage-value').value = result[key];
+        document.getElementById('storage-result').textContent = `Data loaded: ${key} = ${result[key]}`;
+      } else {
+        document.getElementById('storage-result').textContent = `No data found for key: ${key}`;
+      }
+    })
+    .catch(error => {
+      document.getElementById('storage-result').textContent = 'Error loading data: ' + error.message;
+    });
+}
+
+// Add event listeners when the document is loaded
+document.addEventListener('DOMContentLoaded', function() {
+  document.getElementById('inject-button').addEventListener('click', injectScript);
+  document.getElementById('navigate-button').addEventListener('click', navigateTab);
+  document.getElementById('save-data').addEventListener('click', saveData);
+  document.getElementById('load-data').addEventListener('click', loadData);
+  
+  // Example of using storage to track last usage
+  browser.storage.local.get('lastUsed')
+    .then(result => {
+      if (result.lastUsed) {
+        showStatus('Last used: ' + new Date(result.lastUsed).toLocaleString());
+      }
+      browser.storage.local.set({ 'lastUsed': Date.now() });
+    });
+});