JavaScript · 7406 bytes Raw Blame History
1 // Popup script for LooseCannon
2
3 class LooseCannonPopup {
4 constructor() {
5 this.isActive = false;
6 this.messageCount = 0;
7 this.sessionStartTime = null;
8 this.init();
9 }
10
11 init() {
12 this.setupElements();
13 this.checkServerStatus();
14 this.loadCurrentStatus();
15 this.loadStats();
16 this.setupEventListeners();
17 this.startSessionTimer();
18 }
19
20 setupElements() {
21 this.elements = {
22 serverStatus: document.getElementById('serverStatus'),
23 serverStatusText: document.getElementById('serverStatusText'),
24 personalitySelect: document.getElementById('personalitySelect'),
25 mainToggle: document.getElementById('mainToggle'),
26 toggleStatus: document.getElementById('toggleStatus'),
27 messageCount: document.getElementById('messageCount'),
28 sessionTime: document.getElementById('sessionTime'),
29 emergencyStop: document.getElementById('emergencyStop'),
30 settingsLink: document.getElementById('settingsLink'),
31 logsLink: document.getElementById('logsLink'),
32 helpLink: document.getElementById('helpLink')
33 };
34 }
35
36 setupEventListeners() {
37 // Main toggle
38 this.elements.mainToggle.addEventListener('click', () => {
39 this.toggleActive();
40 });
41
42 // Personality selector
43 this.elements.personalitySelect.addEventListener('change', (e) => {
44 browser.runtime.sendMessage({
45 type: 'SET_PERSONALITY',
46 data: { personality: e.target.value }
47 });
48 });
49
50 // Emergency stop
51 this.elements.emergencyStop.addEventListener('click', () => {
52 this.emergencyStop();
53 });
54
55 // Footer links
56 this.elements.settingsLink.addEventListener('click', (e) => {
57 e.preventDefault();
58 // Open settings page (to be implemented)
59 console.log('Settings clicked');
60 });
61
62 this.elements.logsLink.addEventListener('click', (e) => {
63 e.preventDefault();
64 this.showLogs();
65 });
66
67 this.elements.helpLink.addEventListener('click', (e) => {
68 e.preventDefault();
69 browser.tabs.create({
70 url: 'https://github.com/zeroed-some/LooseCannon/wiki'
71 });
72 });
73 }
74
75 async checkServerStatus() {
76 try {
77 const response = await browser.runtime.sendMessage({
78 type: 'GET_SERVER_STATUS'
79 });
80
81 if (response.connected) {
82 this.elements.serverStatus.classList.remove('disconnected');
83 this.elements.serverStatus.classList.add('connected');
84 this.elements.serverStatusText.textContent = 'Connected';
85
86 // Load personalities if connected
87 this.loadPersonalities();
88 } else {
89 this.elements.serverStatus.classList.remove('connected');
90 this.elements.serverStatus.classList.add('disconnected');
91 this.elements.serverStatusText.textContent = 'Disconnected';
92 }
93 } catch (error) {
94 console.error('Error checking server status:', error);
95 }
96 }
97
98 async loadCurrentStatus() {
99 try {
100 // Get status from active tab
101 const tabs = await browser.tabs.query({ active: true, currentWindow: true });
102 if (tabs[0]) {
103 const response = await browser.tabs.sendMessage(tabs[0].id, {
104 type: 'GET_STATUS'
105 });
106
107 if (response && response.isActive) {
108 this.setActive(true);
109 }
110 }
111 } catch (error) {
112 console.log('No WhatsApp tab active or content script not loaded');
113 }
114 }
115
116 async loadPersonalities() {
117 try {
118 const response = await browser.runtime.sendMessage({
119 type: 'GET_PERSONALITIES'
120 });
121
122 if (response.personalities && response.personalities.length > 0) {
123 // Update personality dropdown with server personalities
124 this.elements.personalitySelect.innerHTML = '';
125 response.personalities.forEach(personality => {
126 const option = document.createElement('option');
127 option.value = personality.id;
128 option.textContent = personality.name;
129 this.elements.personalitySelect.appendChild(option);
130 });
131 }
132 } catch (error) {
133 console.error('Error loading personalities:', error);
134 }
135 }
136
137 async loadStats() {
138 try {
139 const result = await browser.storage.local.get(['conversationLogs']);
140 if (result.conversationLogs) {
141 this.messageCount = result.conversationLogs.length;
142 this.elements.messageCount.textContent = this.messageCount;
143 }
144 } catch (error) {
145 console.error('Error loading stats:', error);
146 }
147 }
148
149 toggleActive() {
150 this.isActive = !this.isActive;
151 this.setActive(this.isActive);
152
153 // Send to active tab
154 browser.tabs.query({ active: true, currentWindow: true }).then(tabs => {
155 if (tabs[0]) {
156 browser.tabs.sendMessage(tabs[0].id, {
157 type: 'SET_ACTIVE',
158 data: { isActive: this.isActive }
159 });
160 }
161 });
162 }
163
164 setActive(active) {
165 this.isActive = active;
166
167 if (active) {
168 this.elements.mainToggle.classList.add('active');
169 this.elements.toggleStatus.textContent = 'Currently Active';
170 if (!this.sessionStartTime) {
171 this.sessionStartTime = Date.now();
172 }
173 } else {
174 this.elements.mainToggle.classList.remove('active');
175 this.elements.toggleStatus.textContent = 'Currently Inactive';
176 this.sessionStartTime = null;
177 }
178 }
179
180 emergencyStop() {
181 // Deactivate everything immediately
182 this.setActive(false);
183
184 // Send stop to all tabs
185 browser.tabs.query({}).then(tabs => {
186 tabs.forEach(tab => {
187 browser.tabs.sendMessage(tab.id, {
188 type: 'SET_ACTIVE',
189 data: { isActive: false }
190 }).catch(() => {
191 // Ignore errors for tabs without content script
192 });
193 });
194 });
195
196 // Clear all stored data
197 if (confirm('Emergency stop activated. Clear all conversation logs?')) {
198 browser.storage.local.remove('conversationLogs');
199 this.messageCount = 0;
200 this.elements.messageCount.textContent = '0';
201 }
202
203 // Show confirmation
204 this.elements.emergencyStop.textContent = 'STOPPED';
205 setTimeout(() => {
206 this.elements.emergencyStop.textContent = 'EMERGENCY STOP ALL';
207 }, 2000);
208 }
209
210 startSessionTimer() {
211 setInterval(() => {
212 if (this.sessionStartTime) {
213 const elapsed = Date.now() - this.sessionStartTime;
214 const minutes = Math.floor(elapsed / 60000);
215 this.elements.sessionTime.textContent = `${minutes}m`;
216 }
217 }, 1000);
218 }
219
220 async showLogs() {
221 try {
222 const result = await browser.storage.local.get(['conversationLogs']);
223 if (result.conversationLogs && result.conversationLogs.length > 0) {
224 // Create a simple log viewer (could be expanded to a new page)
225 const logs = result.conversationLogs.slice(-10); // Last 10 logs
226 const logText = logs.map(log =>
227 `[${new Date(log.timestamp).toLocaleTimeString()}] ${log.chatId}:\nUser: ${log.userMessage}\nBot: ${log.botReply}\n`
228 ).join('\n---\n');
229
230 console.log('=== Conversation Logs ===');
231 console.log(logText);
232 alert('Last 10 conversation logs printed to console (F12)');
233 } else {
234 alert('No conversation logs available');
235 }
236 } catch (error) {
237 console.error('Error showing logs:', error);
238 }
239 }
240 }
241
242 // Initialize popup when DOM is ready
243 document.addEventListener('DOMContentLoaded', () => {
244 new LooseCannonPopup();
245 });