From a98f3ef6a42ca6883b68136d1e87246627f30a9e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 17 Feb 2013 00:00:35 -0500 Subject: [PATCH 1/1] initial extension --- .gitignore | 1 + common.js | 15 ++++ images/outlet-128x128.png | Bin 0 -> 1606 bytes images/outlet-19x19.png | Bin 0 -> 629 bytes images/outlet-38x38.png | Bin 0 -> 828 bytes images/outlet.svg | 118 +++++++++++++++++++++++++++++++ makedist.sh | 42 +++++++++++ manifest.files | 9 +++ manifest.json | 23 ++++++ options.html | 24 +++++++ options.js | 17 +++++ popup.html | 32 +++++++++ popup.js | 142 ++++++++++++++++++++++++++++++++++++++ 13 files changed, 423 insertions(+) create mode 100644 .gitignore create mode 100644 common.js create mode 100644 images/outlet-128x128.png create mode 100644 images/outlet-19x19.png create mode 100644 images/outlet-38x38.png create mode 100644 images/outlet.svg create mode 100755 makedist.sh create mode 100644 manifest.files create mode 100644 manifest.json create mode 100644 options.html create mode 100644 options.js create mode 100644 popup.html create mode 100644 popup.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c4c4ffc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.zip diff --git a/common.js b/common.js new file mode 100644 index 0000000..1b35a75 --- /dev/null +++ b/common.js @@ -0,0 +1,15 @@ +// Written by Mike Frysinger . Released into the public domain. Suck it. + +var storage = chrome.storage.sync; + +var settings_keys = [ + 'url', + 'user', + 'pass', +]; + +var settings_defaults = { + 'url': 'http://192.168.0.100', + 'user': 'admin', + 'pass': '1234', +}; diff --git a/images/outlet-128x128.png b/images/outlet-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..e5719d25cd5edf89bfc282a1d127f6f15b9f4536 GIT binary patch literal 1606 zcmZWpdo2oDvQIK%m=O zyGtyxqF6Kl&<#^Jro@5x?smIC<>U3^5(gdNXlD(?D^l26o+*jQgxP!Z0SGc(QRtp> zK&>Q*iJ&{%U|z!{vgVpZs|ynVNVn0gEj>^4PvtY6a(Az9E4VNtcm7;hbrY+@CnqsN zc80_C%eRW}Rnt$m#d!DNm0xfZXAirm9tk!)671w0JPUJ%I78Vc@fq3MP3kwRMywnB z09)-P+$I@#IGk)HITwYFk1Z~J%g`7e`Mh(?Y|KxRn0oQ%z7~+mT8|g;ECHWnw-l%{7EDjTMBP?qgPmZ1(mejj&2Ip!5G7Gy8R;MbgzOS0}cEEp7t zCN&H1DOuj4zPf3sL>#d4_b)QQ*@tv#<&B(01tUpi{>CVU1e)O(>ax#K{GYmK^e}f) zue){>!|LfH_Zh8LkS5a6!SxtDxMRb~rRQ@yMUI%K2le{2NgsF0_&oZ_ZAvll_4zKF z&yDOlsUT7bP(WZ;fD>dDnl~Jea`%PT4h|q5v=j%mbgZPNepi37v-5j%{vM0mB2O7~ z?1`(Rv>{s=xQxS5?33MWEX@fD%A7C*iI=lybUrsFL+!r450#}H|C-)b4`NjH2#4fs zt|R>wInoXCl43Lq%WkKo)YSsCF!jx2ta~6zkO?$OrLdHixu?2M(&cGVNas~8PcJV@ zWp6YM9Ou1F9Y6jsv3Z~Fjgu^sJYZgB;sZDkjs|H0>B4`yM{e{kKlku>KW?hRXEH+5 zyX=wDQuUvsmYSxeg$mss>{6EQoJbVbJ#rcKJqi4X0Aep;>`#BJ<-awb!*+)aW6Kdv znIJkxDKa3=8-eu*Wi}u0;}?bp8g+W5ECr#(Y)vgKgF5iIy^DnVC7?3-a^ghi68Bj1 zteaiAez}0WJ1ZkUjZ=6_#Uyk&*bG8rs{9WeP`^^Mwc&LeSx89RRQl;HtM$;dww_*h zC=Y_kZSLb*1Lnw{$ zZ)qJ0O?Bf~^Ru%Hx)(_xGah9azu04ZH-wtD;g4P3q?{wx~qU^KP3MGYZxNVXxI9ZjxkJrlM)&$F-2nAn-`q9m|i zNQmDUMfN^3%Bepz6^Il57wdoUvNCUps^s};h5<~n1@vRS+S~hktiL=uggkrZ9#LTG z_~jxj>7oJen(^YrZdu}@{^UG6GLjmFj@_GP?N`0muhz%S*EgZ9&DN|Yh)D2L;BYwI z%P(`+QYgv38VkY|;%111!JdRo5ZLpZqDsNEZ3t7@1EDsCk5INx8XFm#U4JKRXCFBt zr_;`gyUV+K>f=o-)cYhaR-{a5eSOeW%3 zS&Lh)wX`^)xLM`}L_Yu1>6{a6_B-)5m{4eGYiBoH#SV-^cWd2x)4Ju9G9HgNLiY59 zR6k(Zu~<|>;qEiZ$p@;`EG!DX^Bs{g$da9yYK@x_HT`}R8$**o-(fbpK1h0`AX&zb z1kxAR3)>hblJlxK@3K~W+HAaLHuc6G;iiNXTL%j&6D>4Cf(}YC$&ema=-C2`LCm(9 V<-{GQ_eh>Rpxd}uSMKtQ`5WPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01p2E01p2F$0Qa_00007bV*G`2i*b? z6D=h@<1#M*00H$$L_t(I%bk?ZOB+EP#ovZS?7^5HhZdt0^glXB#@V7 zUd+ofl8JRa{;Zoml{YH{tNDRmRh7wo`Dq zTtB+HysDY$=7x%*&)27J@9eajnP%hhdz&VxuK4xffIr*J2%i={Ha2O+O>65Lx`Oto zxas}G1kZMw&DJLYK%ww>hjw?9I+LhfNRp&$!>8_cyNj=Sdw-dQzP`F@5&$3)i59E| z+DNnU`2ESrH_0%nN~MBQsRUJ3pA9v@_ERZ@M~3nJ;-c<`yey-q+pD|F&pO2aPS!{- z+uATUKaW5lV5o_IznF=|FcXXM_0NX~q|<5i4-6m_3c=&?U~y@=ZX?kuMX^}K+tDZ( zd;C|7jlaX@)|RQ?6856G86T#nQ7)HZx3?k^jaZJr66SC^v9kK*pXd1-6<)q|?R2yt P00000NkvXXu0mjfT4fuu literal 0 HcmV?d00001 diff --git a/images/outlet-38x38.png b/images/outlet-38x38.png new file mode 100644 index 0000000000000000000000000000000000000000..fbeb0528f034b086ab2bec721f7e3841da909afa GIT binary patch literal 828 zcmV-C1H=4@P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L03P8003P81Q9*Ub00007bV*G`2i*b? z6D=3@G-Iy-00O*8L_t(o!{t~@OcPNQJ#W(Vw`jT{k%UEm1dUQ@b>jv%8l#j%BvEN& zs4I0Nt_4@X5<|fc{-Ab@k7Tr`rVb!Eb6D)4}V_Fw>rtS32lx9k&hLcRD z?c90i%)RH{nJEDPhGB9LV#Mt(Zf)=I8v`+HZSNHIdOaUWxF0Knh>)aED5!}r%4RW> zDxyad<7JXkG`9y+p`c7eV;7=|hv%U2R?^t*_L{)SscCU)o5ftC&t@?b0synVIZ2HV z#_khBEsX$V);Cvl4GxM1tOkSSi{LcTz)0k)eh_t~0hdc?mf9fS+&oW{OeX7V8Xme@ z^<72rWX(ycjg6m@q9c(A_|ixvv>sN2LEO80hcIX&7@9|=s>x-P=I_H*CI>27hgEhN z0Ho7t=yW>Ca#I(RGWMz7UIdmuHRm$f{r$!+^B@iuod8;`b}g67ospAxwOainlgXST zr4cKuilw}g_VpP506M*1 zayGS8*wZKTSoHe=0H^!<@czTchDjdJ%wTi#7XYBY|2*6tk9=XxKsX%2_w{uEKu1SM z>*qz=-Y}1Zu$Fl2+4BYD^Z9?BUGYvLOBn5?r%@P<#@3fI8jWJ)#&z^`+tAZ(!!3^o zu~ghC;(EDM%pv9|UNmo8qw^wgws!j=O8(PQtHmXs5Atg}<}SXWn< za$ULb;w5s~Ed6Ogt5r^z)oML@1D5;aAPk_W^j6XV0Qd`7SQI)(Ogn1;0000 + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/makedist.sh b/makedist.sh new file mode 100755 index 0000000..76be818 --- /dev/null +++ b/makedist.sh @@ -0,0 +1,42 @@ +#!/bin/bash -e +# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +case $1 in +-h|--help) + echo "Usage: $0 [rev]" + exit 0 + ;; +esac + +json_value() { + local key=$1 + sed -n -r \ + -e '/^[[:space:]]*"'"${key}"'"/s|.*:[[:space:]]*"([^"]*)",?$|\1|p' \ + manifest.json +} + +PN=$(json_value name | sed 's:[[:space:]]:_:g' | tr '[:upper:]' '[:lower:]') +PV=$(json_value version) +rev=${1:-0} +PVR="${PV}.${rev}" +P="${PN}-${PVR}" + +rm -rf "${P}" +mkdir "${P}" + +while read line ; do + [[ ${line} == */* ]] && mkdir -p "${P}/${line%/*}" + ln "${line}" "${P}/${line}" +done < <(sed 's:#.*::' manifest.files) +cp manifest.json "${P}/" + +sed -i \ + -e '/"version"/s:"[^"]*",:"'${PVR}'",:' \ + "${P}/manifest.json" + +zip="${P}.zip" +zip -r "${zip}" "${P}" +rm -rf "${P}" +du -b "${zip}" diff --git a/manifest.files b/manifest.files new file mode 100644 index 0000000..aae31cb --- /dev/null +++ b/manifest.files @@ -0,0 +1,9 @@ +images/outlet-128x128.png +images/outlet-19x19.png +images/outlet-38x38.png +images/outlet.svg +common.js +options.html +options.js +popup.html +popup.js diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..23da87f --- /dev/null +++ b/manifest.json @@ -0,0 +1,23 @@ +{ + "manifest_version": 2, + "minimum_chrome_version": "22", + "name": "Web Power Switch Manager", + "version": "1.0", + "description": "Quickly control Web Power Switches", + "icons": { + "128": "images/outlet-128x128.png" + }, + "browser_action": { + "default_icon": { + "19": "images/outlet-19x19.png", + "38": "images/outlet-38x38.png" + }, + "default_title": "Control Your Switch", + "default_popup": "popup.html" + }, + "options_page": "options.html", + "permissions": [ + "storage", + "http://*/" + ] +} diff --git a/options.html b/options.html new file mode 100644 index 0000000..849f183 --- /dev/null +++ b/options.html @@ -0,0 +1,24 @@ + + + + + +Web Power Switch Manager Options + + + + + + + + + + + + + + + +
URL:
User:
Pass:
+ + diff --git a/options.js b/options.js new file mode 100644 index 0000000..3464826 --- /dev/null +++ b/options.js @@ -0,0 +1,17 @@ +// Written by Mike Frysinger . Released into the public domain. Suck it. + +function update_settings() { + var setting = {}; + setting[this.id] = this.value; + storage.set(setting); +} + +window.onload = function() { + storage.get(settings_keys, function(settings) { + settings_keys.forEach(function(key) { + var field = document.getElementById(key); + field.value = settings[key] || settings_defaults[key]; + field.oninput = update_settings; + }); + }); +}; diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..fa89f3e --- /dev/null +++ b/popup.html @@ -0,0 +1,32 @@ + + + + + +Web Power Switch Manager + + + + + + +
Loading...
+
+ + diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..a88ed94 --- /dev/null +++ b/popup.js @@ -0,0 +1,142 @@ +// Written by Mike Frysinger . Released into the public domain. Suck it. + +var url_base, user, pass; + +function fetchpage(url, callback) { + url = url_base + '/' + url; + + var xhr = new XMLHttpRequest(); + xhr.setstatus = false; + try { + xhr.onreadystatechange = function(state) { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + callback(xhr, state); + } else { + xhr.setstatus = true; + setstatus('Could not connect; check settings'); + console.log('connect error', state); + } + } + } + xhr.onerror = function(error) { + if (!xhr.setstatus) + setstatus('onerror; see console'); + console.log('xhr error:', error); + } + + console.log('fetching', url) + xhr.withCredentials = true; + xhr.open('GET', url, true, user, pass); + xhr.responseType = 'document'; + // The user/pass options above don't seem to work, so do it ourselves. + xhr.setRequestHeader('Authorization', 'Basic ' + btoa(user + ':' + pass)); + xhr.send(); + } catch(e) { + setstatus('Exception; see console'); + console.log('exception:', e); + } +} + +function onoff(o) { + return o.toUpperCase() === 'ON' ? 'OFF' : 'ON'; +} + +function toggleit(button) { + var outlet_num = button.id; + var old_status = button.data; + var new_status = onoff(button.data); + var url = 'outlet?' + outlet_num + '=' + new_status; + + fetchpage(url, function(xhr, state) { + console.log('switch ' + outlet_num + ': ' + old_status + ' -> ' + new_status); + button.value = 'Switch ' + old_status; + button.data = new_status; + }); +} +function toggle() { + toggleit(this); +} + +function toggle_confirmed() { + clearTimeout(this.timeout); + this.onclick = toggle_confirm; + toggleit(this); +} + +function toggle_confirm() { + var button = this; + this.onclick = toggle_confirmed; + this.oldvalue = this.value; + this.value = 'Confirm!?'; + this.timeout = setTimeout(function() { + button.value = button.oldvalue; + button.onclick = toggle_confirm; + }, 5000); +} + +function trim(str) { + return str.replace(/^\s+|\s+$/, ''); +} + +function initpopup(xhr, state) { + var tbl = document.getElementById('buttons'); + var row, cell, button; + + console.log(xhr, state); + + // There is no clean API for extracting the current state. + // Example result: + /* + 1 + Outlet 1 + OFF + Switch ON + + + + */ + + var tr, trs = state.currentTarget.responseXML.querySelectorAll('tr'); + for (var i = 0; tr = trs[i]; ++i) { + if (tr.bgColor != '#F4F4F4') + continue; + + var outlet_num = trim(tr.children[0].innerText); + var outlet_name = trim(tr.children[1].innerText); + var current_status = trim(tr.children[2].innerText); + var new_status = trim(tr.children[3].innerText); + var confirmable = tr.children[3].children[0].hasAttribute('onclick'); + + row = tbl.insertRow(-1); + cell = row.insertCell(-1); + cell.innerText = outlet_name + ':'; + cell = row.insertCell(-1); + button = document.createElement('input'); + button.type = 'button'; + button.id = outlet_num; + button.value = new_status; + button.data = current_status; + button.onclick = confirmable ? toggle_confirm : toggle; + cell.appendChild(button); + } + + setstatus(); +} + +function setstatus(msg) { + var status = document.getElementById('status'); + status.innerText = msg; + status.style.visibility = msg ? '' : 'hidden'; + status.style.float = msg ? '' : 'left'; + status.style.position = msg ? '' : 'absolute'; +} + +document.addEventListener('DOMContentLoaded', function() { + storage.get(settings_keys, function(settings) { + url_base = settings['url'] || settings_defaults['url']; + user = settings['user'] || settings_defaults['user']; + pass = settings['pass'] || settings_defaults['pass']; + fetchpage('index.htm', initpopup); + }); +}); -- 2.39.5