]> git.wh0rd.org - chrome-ext/web-power-switch.git/commitdiff
initial extension v1.0
authorMike Frysinger <vapier@gentoo.org>
Sun, 17 Feb 2013 05:00:35 +0000 (00:00 -0500)
committerMike Frysinger <vapier@gentoo.org>
Sun, 17 Feb 2013 05:20:28 +0000 (00:20 -0500)
13 files changed:
.gitignore [new file with mode: 0644]
common.js [new file with mode: 0644]
images/outlet-128x128.png [new file with mode: 0644]
images/outlet-19x19.png [new file with mode: 0644]
images/outlet-38x38.png [new file with mode: 0644]
images/outlet.svg [new file with mode: 0644]
makedist.sh [new file with mode: 0755]
manifest.files [new file with mode: 0644]
manifest.json [new file with mode: 0644]
options.html [new file with mode: 0644]
options.js [new file with mode: 0644]
popup.html [new file with mode: 0644]
popup.js [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..c4c4ffc
--- /dev/null
@@ -0,0 +1 @@
+*.zip
diff --git a/common.js b/common.js
new file mode 100644 (file)
index 0000000..1b35a75
--- /dev/null
+++ b/common.js
@@ -0,0 +1,15 @@
+// Written by Mike Frysinger <vapier@gmail.com>.  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 (file)
index 0000000..e5719d2
Binary files /dev/null and b/images/outlet-128x128.png differ
diff --git a/images/outlet-19x19.png b/images/outlet-19x19.png
new file mode 100644 (file)
index 0000000..114b4b8
Binary files /dev/null and b/images/outlet-19x19.png differ
diff --git a/images/outlet-38x38.png b/images/outlet-38x38.png
new file mode 100644 (file)
index 0000000..fbeb052
Binary files /dev/null and b/images/outlet-38x38.png differ
diff --git a/images/outlet.svg b/images/outlet.svg
new file mode 100644 (file)
index 0000000..1623599
--- /dev/null
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="outlet.svg">
+  <defs
+     id="defs4">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective21759" />
+    <inkscape:perspective
+       id="perspective21787"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       sodipodi:type="inkscape:persp3d" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="16"
+     inkscape:cx="291.5045"
+     inkscape:cy="764.33071"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1-3"
+     showgrid="false"
+     inkscape:window-width="1440"
+     inkscape:window-height="879"
+     inkscape:window-x="-4"
+     inkscape:window-y="-4"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <g
+       transform="translate(-83.156683,-227.22927)"
+       id="layer1-3"
+       inkscape:label="Layer 1">
+      <rect
+         y="-520.10016"
+         x="365.11285"
+         height="16.601831"
+         width="15.092574"
+         id="rect3338"
+         style="fill:#dcdedf;fill-opacity:1;stroke:#000000;stroke-width:0.60370296;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+         transform="scale(1,-1)"
+         inkscape:export-xdpi="671.18805"
+         inkscape:export-ydpi="671.18805" />
+      <path
+         d="m 181.40845,418.20724 a 5.7042236,5.8450623 0 1 1 -11.40845,0 5.7042236,5.8450623 0 1 1 11.40845,0 z"
+         sodipodi:ry="5.8450623"
+         sodipodi:rx="5.7042236"
+         sodipodi:cy="418.20724"
+         sodipodi:cx="175.70422"
+         id="path3332"
+         style="fill:#000000;fill-opacity:1;stroke:none"
+         sodipodi:type="arc"
+         transform="matrix(0.30185148,0,0,-0.30185148,319.83513,641.55378)" />
+      <rect
+         y="-512.55389"
+         x="368.13138"
+         height="5.8224154"
+         width="1.5092574"
+         id="rect3334"
+         style="fill:#000000;fill-opacity:1;stroke:none"
+         transform="scale(1,-1)" />
+      <rect
+         y="-511.8396"
+         x="375.67764"
+         height="4.4384866"
+         width="1.5092574"
+         id="rect3336"
+         style="fill:#000000;fill-opacity:1;stroke:none"
+         transform="scale(1,-1)" />
+      <rect
+         style="fill:none;stroke:#000000;stroke-width:0.85022688px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         id="rect3563"
+         width="2.5937731"
+         height="1.1497731"
+         x="371.5748"
+         y="515.74774" />
+    </g>
+  </g>
+</svg>
diff --git a/makedist.sh b/makedist.sh
new file mode 100755 (executable)
index 0000000..76be818
--- /dev/null
@@ -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 (file)
index 0000000..aae31cb
--- /dev/null
@@ -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 (file)
index 0000000..23da87f
--- /dev/null
@@ -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 (file)
index 0000000..849f183
--- /dev/null
@@ -0,0 +1,24 @@
+<!-- Written by Mike Frysinger <vapier@gmail.com>.  Released into the public domain.  Suck it. -->
+<!doctype html>
+<html>
+
+<head>
+<title>Web Power Switch Manager Options</title>
+<script src='common.js'></script>
+<script src='options.js'></script>
+</head>
+
+<body background='images/outlet.svg'>
+<table>
+<tr>
+ <td>URL:</td><td><input type='text' id='url'></td>
+</tr>
+<tr>
+ <td>User:</td><td><input type='text' id='user'></td>
+</tr>
+<tr>
+ <td>Pass:</td><td><input type='text' id='pass'></td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/options.js b/options.js
new file mode 100644 (file)
index 0000000..3464826
--- /dev/null
@@ -0,0 +1,17 @@
+// Written by Mike Frysinger <vapier@gmail.com>.  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 (file)
index 0000000..fa89f3e
--- /dev/null
@@ -0,0 +1,32 @@
+<!-- Written by Mike Frysinger <vapier@gmail.com>.  Released into the public domain.  Suck it. -->
+<!doctype html>
+<html>
+
+<head>
+<title>Web Power Switch Manager</title>
+<script src='common.js'></script>
+<script src='popup.js'></script>
+<style>
+table#buttons {
+       margin: 0px;
+       padding: 0px;
+       border-collapse: collapse;
+}
+body {
+       margin: 0px;
+       padding: 0px;
+}
+td {
+       white-space: nowrap;
+}
+div#status {
+       white-space: nowrap;
+}
+</style>
+</head>
+
+<body>
+<div id='status'>Loading...</div>
+<table id='buttons'></table>
+</body>
+</html>
diff --git a/popup.js b/popup.js
new file mode 100644 (file)
index 0000000..a88ed94
--- /dev/null
+++ b/popup.js
@@ -0,0 +1,142 @@
+// Written by Mike Frysinger <vapier@gmail.com>.  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:
+       /*
+               <tr bgcolor="#F4F4F4"><td align=center>1</td>
+               <td>Outlet 1</td><td>
+               <b><font color=red>OFF</font></b></td><td>
+               <a  href=outlet?1=ON>Switch ON</a>
+               </td><td>
+               <!-- <a  href=outlet?1=CCL>Cycle</a> -->
+               </td></tr>
+       */
+
+       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);
+       });
+});