]> git.wh0rd.org Git - chrome-ext/web-power-switch.git/blob - popup.js
initial support for power cycling automatically
[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 onoff(o) {
46         const data = o.toUpperCase();
47         switch (data) {
48         case 'OFF':
49                 return 'ON';
50         case 'ON':
51                 return 'OFF';
52         default:
53                 // For example, cycle uses CCL.
54                 return data;
55         }
56 }
57
58 function toggleit(button) {
59         const outlet_num = button.id.split(':')[0];
60         var old_status = button.data;
61         var new_status = onoff(button.data);
62         var url = 'outlet?' + outlet_num + '=' + new_status;
63
64         if (!button.id.endsWith('cycle')) {
65                 const cycler = document.getElementById(`${button.id}:cycle`);
66                 cycler.style.display = new_status === 'ON' ? 'block' : 'none';
67         }
68
69         fetchpage(url, function(xhr, state) {
70                 console.log('switch ' + outlet_num + ': ' + old_status + ' -> ' + new_status);
71                 if (!button.id.endsWith('cycle')) {
72                         button.value = 'Switch ' + old_status;
73                         button.data = new_status;
74                 }
75         });
76 }
77 function toggle() {
78         toggleit(this);
79 }
80
81 function toggle_confirmed() {
82         clearTimeout(this.timeout);
83         this.onclick = toggle_confirm;
84         toggleit(this);
85 }
86
87 function toggle_confirm() {
88         var button = this;
89         this.onclick = toggle_confirmed;
90         this.oldvalue = this.value;
91         this.value = 'Confirm!?';
92         this.timeout = setTimeout(function() {
93                 button.value = button.oldvalue;
94                 button.onclick = toggle_confirm;
95         }, 5000);
96 }
97
98 function trim(str) {
99         return str.replace(/^\s+|\s+$/, '');
100 }
101
102 function initpopup(xhr, state) {
103         var tbl = document.getElementById('buttons');
104         var row, cell, button;
105
106         console.log(xhr, state);
107
108         // There is no clean API for extracting the current state.
109         // Example result:
110         /*
111                 <tr>
112                 <th bgcolor="#DDDDFF" align=left>
113                 Controller: !!!Web Power Switch 6
114                 </th>
115                 </tr>
116         */
117
118         var th, ths = state.currentTarget.responseXML.querySelectorAll('th');
119         for (var i = 0; th = ths[i]; ++i) {
120                 if (th.bgColor != '#DDDDFF')
121                         continue;
122
123                 var controller_name = trim(th.innerText);
124                 if (controller_name.slice(0, 12) != 'Controller: ')
125                         continue;
126
127                 row = tbl.insertRow(-1);
128                 cell = row.insertCell(-1);
129                 cell.colSpan = 10;
130                 cell.align = 'center';
131                 cell.innerText = controller_name.slice(12);
132                 cell.innerHTML = '<a href="' + url_base + '" target="_blank">' + cell.innerHTML + '</a>'
133         }
134
135         var tr, trs = state.currentTarget.responseXML.querySelectorAll('tr');
136         for (var i = 0; tr = trs[i]; ++i) {
137                 if (tr.bgColor != '#F4F4F4')
138                         continue;
139
140                 var outlet_num     = trim(tr.children[0].innerText);
141                 var outlet_name    = trim(tr.children[1].innerText);
142                 var current_status = trim(tr.children[2].innerText);
143                 var new_status     = trim(tr.children[3].innerText);
144                 var confirmable    = tr.children[3].children[0].hasAttribute('onclick');
145
146                 row = tbl.insertRow(-1);
147                 cell = row.insertCell(-1);
148                 if (outlet_name === '')
149                         cell.innerHTML = '<i>unnamed</i>';
150                 else
151                         cell.innerText = outlet_name + ':';
152                 cell = row.insertCell(-1);
153                 button = document.createElement('input');
154                 button.type = 'button';
155                 button.id = outlet_num;
156                 button.value = new_status;
157                 button.data = current_status;
158                 button.onclick = confirmable ? toggle_confirm : toggle;
159                 cell.appendChild(button);
160
161                 // The switch only allows cycling when it's on.
162                 cell = row.insertCell(-1);
163                 button = document.createElement('input');
164                 button.type = 'button';
165                 button.id = `${outlet_num}:cycle`;
166                 button.value = '🗘';
167                 button.data = 'CCL';
168                 button.title = 'Power cycle';
169                 button.onclick = confirmable ? toggle_confirm : toggle;
170                 if (current_status.toUpperCase() === 'OFF') {
171                         button.style.display = 'none';
172                 }
173                 button.style.fontSize = 'smaller';
174                 cell.appendChild(button);
175         }
176
177         setstatus();
178 }
179
180 function setstatus(msg) {
181         var status = document.getElementById('status');
182         status.innerHTML = msg;
183         status.style.visibility = msg ? '' : 'hidden';
184         status.style.float      = msg ? '' : 'left';
185         status.style.position   = msg ? '' : 'absolute';
186 }
187
188 function open_settings_page() {
189         chrome.runtime.openOptionsPage();
190 }
191
192 document.addEventListener('DOMContentLoaded', function() {
193         storage.get(settings_keys, function(settings) {
194                 url_base = settings['url'] || settings_defaults['url'];
195                 user = settings['user'] || settings_defaults['user'];
196                 pass = settings['pass'] || settings_defaults['pass'];
197                 chrome.permissions.contains({
198                         origins: [url_base + '/*']
199                 }, function(granted) {
200                         if (granted) {
201                                 fetchpage('index.htm', initpopup);
202                         } else {
203                                 setstatus(
204                                         'Missing permissions;<br>please visit the ' +
205                                         '<a id="open-settings" href="">settings page</a>' +
206                                         '<br>to grant access.<br>' +
207                                         '<center><input id=retry type=submit value=Retry></center>'
208                                 );
209                                 document.getElementById('open-settings').onclick = open_settings_page;
210                                 // Work around http://crbug.com/125706.
211                                 document.getElementById('retry').onclick = function() {
212                                         chrome.permissions.request({origins: [url_base + '/*']});
213                                         fetchpage('index.htm', initpopup);
214                                 };
215                         }
216                 });
217         });
218 });