]> git.wh0rd.org Git - chrome-ext/web-power-switch.git/blob - popup.js
2f4bea59a758ca2896c0548277bc86404647103a
[chrome-ext/web-power-switch.git] / popup.js
1 // Written by Mike Frysinger <vapier@gmail.com>.  Released into the public domain.
2
3 var url_base, user, pass;
4
5 function fetchpage(url, callback) {
6         url = url_base + '/' + url;
7
8         var xhr = new XMLHttpRequest();
9         xhr.setstatus = false;
10         try {
11                 xhr.onreadystatechange = function(state) {
12                         if (xhr.readyState == 4) {
13                                 if (xhr.status == 200) {
14                                         callback(xhr, state);
15                                 } else {
16                                         xhr.setstatus = true;
17                                         setstatus(
18                                                 'Could not connect;<br>check your ' +
19                                                 '<a id="open-settings" href="">settings</a>'
20                                         );
21                                         document.getElementById('open-settings').onclick = open_settings_page;
22                                         console.log('connect error', state);
23                                 }
24                         }
25                 }
26                 xhr.onerror = function(error) {
27                         if (!xhr.setstatus)
28                                 setstatus('onerror; see console');
29                         console.log('xhr error:', error);
30                 }
31
32                 console.log('fetching', url)
33                 xhr.withCredentials = true;
34                 xhr.open('GET', url, true, user, pass);
35                 xhr.responseType = 'document';
36                 // The user/pass options above don't seem to work, so do it ourselves.
37                 xhr.setRequestHeader('Authorization', 'Basic ' + btoa(user + ':' + pass));
38                 xhr.send();
39         } catch(e) {
40                 setstatus('Exception; see console');
41                 console.log('exception:', e);
42         }
43 }
44
45 function get_css_var(key) { return getComputedStyle(document.documentElement).getPropertyValue(`--${key}`); }
46
47 function onoff(o) {
48         const data = o.toUpperCase();
49         switch (data) {
50         case 'OFF':
51                 return 'ON';
52         case 'ON':
53                 return 'OFF';
54         default:
55                 // For example, cycle uses CCL.
56                 return data;
57         }
58 }
59
60 function toggleit(button) {
61         const outlet_num = button.id.split(':')[0];
62         var old_status = button.data;
63         var new_status = onoff(button.data);
64         var url = 'outlet?' + outlet_num + '=' + new_status;
65
66         if (!button.id.endsWith('cycle')) {
67                 const cycler = document.getElementById(`${button.id}:cycle`);
68                 cycler.style.display = new_status === 'ON' ? 'block' : 'none';
69         }
70
71         fetchpage(url, function(xhr, state) {
72                 console.log('switch ' + outlet_num + ': ' + old_status + ' -> ' + new_status);
73                 if (!button.id.endsWith('cycle')) {
74                         button.value = 'Switch ' + old_status;
75                         button.data = new_status;
76                 }
77         });
78 }
79 function toggle() {
80         toggleit(this);
81 }
82
83 function toggle_confirmed() {
84         clearTimeout(this.timeout);
85         this.onclick = toggle_confirm;
86         toggleit(this);
87 }
88
89 function toggle_confirm() {
90         var button = this;
91         this.onclick = toggle_confirmed;
92         this.oldvalue = this.value;
93         this.value = 'Confirm!?';
94         this.timeout = setTimeout(function() {
95                 button.value = button.oldvalue;
96                 button.onclick = toggle_confirm;
97         }, 5000);
98 }
99
100 /* Toggle the selected theme. */
101 function toggle_theme() {
102         const theme = get_css_var('theme') == 'light' ? 'dark' : 'light';
103         const css = $('link#theme-override');
104         css.href = `css/${theme}.css`;
105         storage.set({theme});
106         return false;
107 }
108
109 function initpopup(xhr, state) {
110         var tbl = document.getElementById('buttons');
111         var row, cell, button;
112
113         console.log(xhr, state);
114
115         // There is no clean API for extracting the current state.
116         // Example result:
117         /*
118                 <tr>
119                 <th bgcolor="#DDDDFF" align=left>
120                 Controller: !!!Web Power Switch 6
121                 </th>
122                 </tr>
123         */
124
125         var th, ths = state.currentTarget.responseXML.querySelectorAll('th');
126         for (var i = 0; th = ths[i]; ++i) {
127                 if (th.bgColor != '#DDDDFF')
128                         continue;
129
130                 var controller_name = th.innerText.trim();
131                 if (controller_name.slice(0, 12) != 'Controller: ')
132                         continue;
133
134                 row = tbl.insertRow(-1);
135                 cell = row.insertCell(-1);
136                 cell.colSpan = 10;
137                 cell.align = 'center';
138
139                 const a = document.createElement('a');
140                 a.href = url_base;
141                 a.target = '_blank';
142                 a.text = controller_name.slice(12).trim();
143                 cell.appendChild(a);
144
145                 const button = document.createElement('button');
146                 button.name = 'theme';
147                 button.onclick = toggle_theme;
148                 cell.appendChild(button);
149         }
150
151         var tr, trs = state.currentTarget.responseXML.querySelectorAll('tr');
152         for (var i = 0; tr = trs[i]; ++i) {
153                 if (tr.bgColor != '#F4F4F4')
154                         continue;
155
156                 var outlet_num     = tr.children[0].innerText.trim();
157                 var outlet_name    = tr.children[1].innerText.trim();
158                 var current_status = tr.children[2].innerText.trim();
159                 var new_status     = tr.children[3].innerText.trim();
160                 var confirmable    = tr.children[3].children[0].hasAttribute('onclick');
161
162                 row = tbl.insertRow(-1);
163                 cell = row.insertCell(-1);
164                 if (outlet_name === '')
165                         cell.innerHTML = '<i>unnamed</i>';
166                 else
167                         cell.innerText = outlet_name + ':';
168                 cell = row.insertCell(-1);
169                 button = document.createElement('input');
170                 button.type = 'button';
171                 button.id = outlet_num;
172                 button.value = new_status;
173                 button.data = current_status;
174                 button.onclick = confirmable ? toggle_confirm : toggle;
175                 cell.appendChild(button);
176
177                 // The switch only allows cycling when it's on.
178                 cell = row.insertCell(-1);
179                 button = document.createElement('input');
180                 button.type = 'button';
181                 button.id = `${outlet_num}:cycle`;
182                 button.value = '🗘';
183                 button.data = 'CCL';
184                 button.title = 'Power cycle';
185                 button.onclick = confirmable ? toggle_confirm : toggle;
186                 if (current_status.toUpperCase() === 'OFF') {
187                         button.style.display = 'none';
188                 }
189                 button.style.fontSize = 'smaller';
190                 cell.appendChild(button);
191         }
192
193         setstatus();
194 }
195
196 function setstatus(msg) {
197         var status = document.getElementById('status');
198         status.innerHTML = msg;
199         status.style.visibility = msg ? '' : 'hidden';
200         status.style.float      = msg ? '' : 'left';
201         status.style.position   = msg ? '' : 'absolute';
202 }
203
204 function open_settings_page() {
205         chrome.runtime.openOptionsPage();
206 }
207
208 document.addEventListener('DOMContentLoaded', function() {
209         storage.get(settings_keys, function(settings_storage) {
210                 const settings = Object.assign({}, settings_defaults, settings_storage);
211                 url_base = settings['url'];
212                 user = settings['user'];
213                 pass = settings['pass'];
214                 chrome.permissions.contains({
215                         origins: [url_base + '/*']
216                 }, function(granted) {
217                         if (granted) {
218                                 fetchpage('index.htm', initpopup);
219                         } else {
220                                 setstatus(
221                                         'Missing permissions;<br>please visit the ' +
222                                         '<a id="open-settings" href="">settings page</a>' +
223                                         '<br>to grant access.<br>' +
224                                         '<center><input id=retry type=submit value=Retry></center>'
225                                 );
226                                 document.getElementById('open-settings').onclick = open_settings_page;
227                                 // Work around http://crbug.com/125706.
228                                 document.getElementById('retry').onclick = function() {
229                                         chrome.permissions.request({origins: [url_base + '/*']});
230                                         fetchpage('index.htm', initpopup);
231                                 };
232                         }
233                 });
234         });
235 });