]>
git.wh0rd.org - chrome-ext/wake-on-lan.git/blob - js/main.js
1 // Written by Mike Frysinger <vapier@gmail.com>.
2 // Released into the public domain.
5 $$('[name=status]').innerText
= msg
;
8 function popup_msg(ele
, msg
) {
9 var popup
= $$('[name=popup_msg]');
10 var pos
= ele
.getBoundingClientRect();
11 popup
.innerText
= msg
;
12 // Might want to add some generalized "center in element" logic.
13 popup
.style
.top
= 5 + pos
.top
+ 'px';
14 popup
.style
.left
= pos
.left
+ 'px';
15 popup
.style
.display
= '';
16 setTimeout(() => { popup
.style
.display
= 'none'; }, 3000);
19 // Create a packet following the spec:
20 // https://en.wikipedia.org/wiki/Wake-on-LAN#Magic_packet
21 function magicpacket(mac
, pass
) {
22 var data
= new ArrayBuffer(6 + 16 * 6 + 6 + 6);
23 var bytes
= new Uint8Array(data
);
26 // First 6 bytes should be all 0xFF.
27 for (i
= 0; i
< 6; ++i
)
28 bytes
[base
+ i
] = 0xff;
31 // Then the MAC address is repeated 16 times.
32 for (i
= 0; i
< 6; ++i
)
33 for (j
= 0; j
< 16 * 6; j
+= 6)
34 bytes
[base
+ j
+ i
] = mac
[i
];
37 // Then 6 bytes before the pass should be 0xFF.
38 for (i
= 0; i
< 6; ++i
)
39 bytes
[base
+ i
] = 0xff;
42 // Finally the 6 bytes of the password.
43 for (i
= 0; i
< 6; ++i
)
44 bytes
[base
+ i
] = pass
[i
];
49 function split_data(v
) {
53 window
['sync_' + v
]();
55 for (i
= 0; i
< 6; ++i
) {
56 idata
= $$('input[name=' + v
+ i
+ ']');
57 if (!/^[0-9a-fA-F]?[0-9a-fA-F]$/.test(idata
.value
.replace(' ', ''))) {
58 status(v
+ ' byte ' + i
+ ' is invalid; must be 2 hex characters');
60 idata
.setSelectionRange(0, idata
.value
.length
);
63 data
[i
] = parseInt(idata
.value
, 16);
70 status('initializing');
72 var form
= $$('form[name=settings]');
73 var shost
= '0.0.0.0';
74 var dhost
= form
.host
.value
;
75 var port
= parseInt(form
.port
.value
);
77 // Get the MAC address & password to convert to packet data.
78 var mac
= split_data('mac');
79 var pass
= split_data('pass');
80 var data
= magicpacket(mac
, pass
);
81 console
.log('packet', new Uint8Array(data
));
83 var checkresult = function(s
, step
, result
) {
85 status('error in ' + step
+ ': ' + net_error_list
[result
]);
86 chrome
.sockets
.udp
.close(s
, nullcb
);
92 // Create the socket ...
93 chrome
.sockets
.udp
.create({}, function(createInfo
) {
94 var s
= createInfo
.socketId
;
96 console
.log('[create] socketInfo', createInfo
);
97 status('binding ' + shost
);
99 // Bind it locally ...
100 chrome
.sockets
.udp
.bind(s
, shost
, 0, function(result
) {
101 console
.log('[bind] result', result
);
103 if (!checkresult(s
, 'bind', result
))
106 status('enabling broadcast');
108 // Turn on broadcast support ...
109 chrome
.sockets
.udp
.setBroadcast(s
, true, function(result
) {
110 console
.log('[setBroadcast] result', result
);
112 if (!checkresult(s
, 'broadcast', result
))
115 status('sending to ' + dhost
+ ':' + port
);
117 // Send the backet ...
118 chrome
.sockets
.udp
.send(s
, data
, dhost
, port
, function(sendInfo
) {
119 console
.log('[send] sendInfo', sendInfo
);
121 if (!checkresult(s
, 'send', sendInfo
.resultCode
))
127 chrome
.sockets
.udp
.close(s
, function() {
128 status('sent to ' + dhost
+ ':' + port
);
136 // Keep the form from submitting.
140 function sync_it(v
) {
141 var smany
= $$('span[name=' + v
+ '-many]');
142 var sone
= $$('span[name=' + v
+ '-one]');
144 // Sync the two sets of fields.
147 var idata
= $$('input[name=' + v
+ ']');
148 var data
= idata
.value
.split(':');
150 if (data
.length
!= 6) {
151 data
= idata
.value
.replace(/[ :]/g, '');
152 if (data
.length
!= 6 * 2) {
153 status('invalid ' + v
+ '; please fix');
156 data
= data
.match(/../g);
158 for (i
= 0; i
< 6; ++i
)
159 if (data
[i
].length
> 2) {
160 status('invalid ' + v
+ ' please fix');
165 for (i
= 0; i
< 6; ++i
)
166 $$('input[name=' + v
+ i
+ ']').value
= data
[i
];
170 for (i
= 0; i
< 6; ++i
) {
171 data
+= $$('input[name=' + v
+ i
+ ']').value
;
176 $$('input[name=' + v
+ ']').value
= data
;
179 function sync_mac() { return sync_it('mac'); }
180 function sync_pass() { return sync_it('pass'); }
183 function paste_mac() {
186 var smany
= $$('span[name=mac-many]');
187 var sone
= $$('span[name=mac-one]');
188 smany
.hidden
= !smany
.hidden
;
189 sone
.hidden
= !sone
.hidden
;
194 function paste_pass() {
197 var smany
= $$('span[name=pass-many]');
198 var sone
= $$('span[name=pass-one]');
199 smany
.hidden
= !smany
.hidden
;
200 sone
.hidden
= !sone
.hidden
;
211 var settings_keys
= [
216 var old_settings_keys
= [
223 var default_theme
= 'dark';
224 var default_name
= 'Default';
225 var default_host
= '192.168.0.255';
226 var default_port
= '40000';
227 var default_mac
= '20:00:00:00:00:00';
228 var default_pass
= '00:00:00:00:00:00';
231 * Set form data based on selected computer settings.
232 * Uses defaults if not available.
234 function load_computer(idx
) {
235 var computer
= computers
[idx
] || {};
236 chrome
.storage
.local
.set({'last_selected': idx
});
238 var form
= $$('form[name=settings]');
240 form
.computer
.value
= computer
['name'] || default_name
;
241 form
.host
.value
= computer
['host'] || default_host
;
242 form
.port
.value
= computer
['port'] || default_port
;
243 // We assume we only get called during init.
245 form
.mac
.value
= computer
['mac'] || default_mac
;
248 form
.pass
.value
= computer
['pass'] || default_pass
;
252 function load_settings() {
253 chrome
.storage
.local
.get(settings_keys
, function(settings
) {
254 set_theme(settings
['theme'] || default_theme
);
255 if ('computers' in settings
) {
256 computers
= settings
['computers'] || [];
257 populate_computers();
258 load_computer(settings
['last_selected'] || 0);
260 // Migrate old settings.
261 chrome
.storage
.local
.get(old_settings_keys
, function(settings
) {
262 computers
[0] = settings
;
263 populate_computers();
266 chrome
.storage
.local
.remove(old_settings_keys
);
273 * Update the currently selected computer then write out the whole thing.
275 function store_settings() {
279 var form
= $$('form[name=settings]');
280 var select
= $$('select[name=computer]');
281 var idx
= select
.selectedIndex
;
283 'name': form
.computer
.value
,
284 'host': form
.host
.value
,
285 'mac': form
.mac
.value
,
286 'pass': form
.pass
.value
,
287 'port': form
.port
.value
,
290 chrome
.storage
.local
.set({
291 'computers': computers
,
296 * If they try deleting all entries, make sure we re-add the default.
298 function check_empty_computers(select
) {
299 if (select
.length
== 0) {
300 var option
= document
.createElement('option');
301 option
.text
= 'Default';
302 select
.add(option
, 0);
308 * Fill out the computer drop down with existing config options.
310 function populate_computers() {
311 var select
= $$('select[name=computer]');
314 for (var i
= 0; i
< computers
.length
; i
++) {
315 var option
= document
.createElement('option');
316 var computer
= computers
[i
] || {};
317 option
.text
= computer
['name'] || default_name
;
318 select
.add(option
, i
);
321 check_empty_computers(select
);
325 * When a computer config is selected, load the corresponding settings.
327 function select_computer() {
328 load_computer($$('select[name=computer]').selectedIndex
);
332 * Toggle between the computer drop down & new name input field.
334 function toggle_add_fields(hide_obj
, show_obj
) {
335 hide_obj
.disabled
= true;
336 hide_obj
.style
.display
= 'none';
337 show_obj
.disabled
= false;
338 show_obj
.style
.display
= 'inline';
343 * Del curent slected computer
345 function del_computer() {
346 var select
= $$('select[name=computer]');
348 var idx
= select
.selectedIndex
;
349 // Delete the currently selected index.
350 computers
.splice(idx
, 1);
353 // Make sure the list isn't entirely empty now.
354 check_empty_computers(select
);
356 // Load/select the next entry in the list.
357 if (idx
== select
.length
&& idx
> 0)
366 * Shows an input box to enter new computer name.
368 function add_computer_start() {
369 var select
= $$('select[name=computer]');
370 var text
= $$('input[name=computer_name]');
372 // If the box isn't visible, show it. Otherwise, they want to
373 // actually add the current settings so create a new entry.
374 if (select
.style
.display
== 'none')
377 toggle_add_fields(select
, text
);
381 * Wait for the enter key in the add text field.
383 function add_computer_check(e
) {
384 if (e
.key
== 'Enter') {
391 * Try to actually create a new computer entry.
393 function add_computer() {
394 var select
= $$('select[name=computer]');
395 var form
= $$('form[name=settings]');
396 var text
= $$('input[name=computer_name]');
398 var name
= text
.value
.trim();
399 // Make sure they've added a valid name first.
400 // Options fields don't allow leading/trailing whitespace.
403 toggle_add_fields(text
, select
);
407 // Make sure they don't try to add a duplicate name.
408 for (var i
= 0; i
< select
.length
; ++i
) {
409 if (select
.options
[i
].value
== name
) {
410 popup_msg(text
, 'ERROR: computer name already exists!');
416 var option
= document
.createElement('option');
418 select
.add(option
, -1);
420 // Let the load_computer logic fill out the default values for us.
421 var idx
= select
.length
- 1;
425 load_computer(select
.length
- 1);
427 toggle_add_fields(text
, select
);
435 window
.onload = function() {
436 $$('input[name=send]').onclick
= send
;
437 $$('select[name=computer]').onchange
= select_computer
;
438 $$('a[name=mac-paste]').onclick
= paste_mac
;
439 $$('a[name=pass-paste]').onclick
= paste_pass
;
440 $$('input[name=del_computer]').onclick
= del_computer
;
441 $$('input[name=add_computer]').onclick
= add_computer_start
;
442 $$('input[name=computer_name]').onkeypress
= add_computer_check
;
443 $$('input[name=theme]').onclick
= toggle_theme
;