changeset 945:752e620f1293

add input-rgb polymer element Ignore-this: 2ba2ef39af2ef4f6c14036c5ac188e97 darcs-hash:20140712183250-312f9-dbe5a232f2d861b3088e314e2cd53ff70ce839d3
author drewp <drewp@bigasterisk.com>
date Sat, 12 Jul 2014 11:32:50 -0700
parents 5a3121704234
children 8a8a588a491e
files service/pilight/static/input-number/.bowerrc service/pilight/static/input-number/.gitignore service/pilight/static/input-number/Gruntfile.js service/pilight/static/input-number/LICENSE service/pilight/static/input-number/README.md service/pilight/static/input-number/bower.json service/pilight/static/input-number/index.html service/pilight/static/input-number/input-number.css service/pilight/static/input-number/input-number.html service/pilight/static/input-number/input-number.js service/pilight/static/input-number/package.json service/pilight/static/input-number/preview.png service/pilight/static/input-rgb/.bowerrc service/pilight/static/input-rgb/.gitignore service/pilight/static/input-rgb/Gruntfile.js service/pilight/static/input-rgb/LICENSE service/pilight/static/input-rgb/README.md service/pilight/static/input-rgb/bower.json service/pilight/static/input-rgb/index.html service/pilight/static/input-rgb/input-rgb.css service/pilight/static/input-rgb/input-rgb.html service/pilight/static/input-rgb/input-rgb.js service/pilight/static/input-rgb/package.json service/pilight/static/input-rgb/preview.png service/pilight/static/input-slider/.bowerrc service/pilight/static/input-slider/.gitignore service/pilight/static/input-slider/Gruntfile.js service/pilight/static/input-slider/LICENSE service/pilight/static/input-slider/README.md service/pilight/static/input-slider/bower.json service/pilight/static/input-slider/index.html service/pilight/static/input-slider/input-slider.css service/pilight/static/input-slider/input-slider.html service/pilight/static/input-slider/input-slider.js service/pilight/static/input-slider/package.json service/pilight/static/input-slider/preview.png
diffstat 36 files changed, 989 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/.bowerrc	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,3 @@
+{
+  "directory": "../"
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/.gitignore	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,3 @@
+node_modules/
+gh-pages/
+.grunt
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/Gruntfile.js	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,45 @@
+(function() {
+
+  'use strict';
+
+  module.exports = function(grunt) {
+
+    grunt.initConfig({
+
+      copy: {
+        'gh-pages': {
+          files: [
+            {src: '*-*.html', dest: 'gh-pages/'},
+            {src: '*-*.css', dest: 'gh-pages/'},
+            {src: '*-*.js', dest: 'gh-pages/'},
+            {src: 'LICENSE', dest: 'gh-pages/LICENSE'},
+            {src: 'README.md', dest: 'gh-pages/README.md'},
+            {src: 'preview.png', dest: 'gh-pages/preview.png'},
+            {src: 'index.html', dest: 'gh-pages/index.html'},
+          ]
+        }
+      },
+      'gh-pages': {
+        'gh-pages': {
+          options: {
+            base: 'gh-pages',
+            branch: 'gh-pages',
+            message: 'auto-updating gh-pages from dev with grunt'
+          },
+          src: '**/*'
+        }
+      },
+
+    });
+
+    grunt.loadNpmTasks('grunt-contrib-copy');
+    grunt.loadNpmTasks('grunt-gh-pages');
+
+    grunt.registerTask('default', [
+      'copy:gh-pages',
+      'gh-pages:gh-pages'
+    ]);
+
+  };
+
+}());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/LICENSE	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,13 @@
+Copyright (c) 2014 Aleksandar Rodic @arodic
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/README.md	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,5 @@
+Input element for number data type
+
+![input-number](https://arodic.github.com/input-number/preview.png "input-number")
+
+##### [Live Demo](http://arodic.github.com/input-number/)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/bower.json	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,22 @@
+{
+  "name": "input-number",
+  "version": "0.2.7",
+  "homepage": "https://github.com/arodic/input-number",
+  "authors": [
+    "Aleksandar Rodic <aleksandar.xyz@gmail.com>"
+  ],
+  "description": "Custom input element for number data type.",
+  "main": "input-number.html",
+  "keywords": [
+    "input",
+    "field",
+    "polymer",
+    "web-components",
+    "UI",
+    "number"
+  ],
+  "license": "Apache 2.0",
+  "dependencies": {
+    "polymer": "Polymer/polymer#~0.3.3"
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/index.html	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
+  <title>&#60;input-number&#62;</title>
+
+  <script src="../platform/platform.js"></script>
+
+  <link rel="import" href="../show-and-tell/show-and-tell.html">
+
+  <style type="text/css">
+    html {
+      -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+    }
+    body{
+      width: 100%;
+      height: 100%;
+      background: #f3eee8;
+      margin: 0;
+      font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+      font-size: 13px;
+    }
+  </style>
+</head>
+<body unresolved>
+
+<show-and-tell url="../input-number/input-number.html"></show-and-tell>
+
+<script>
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+  ga('create', 'UA-258449-15', 'aleksandarrodic.com');
+  ga('send', 'pageview');
+</script>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/input-number.css	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,15 @@
+:host {
+  display: block;
+  vertical-align: top;
+  overflow-x: hidden;
+  white-space: nowrap;
+  cursor: ew-resize;
+}
+:host(:focus) {
+  outline: 0;
+}
+
+:host::shadow > #blocker {
+  position: absolute;
+  /*background: rgba(0,255,0,0.3);*/
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/input-number.html	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,9 @@
+<link rel="import" href="../polymer/polymer.html">
+
+<polymer-element name="input-number" attributes="value min max step toDeg editable width">
+  <template>
+    <link href="input-number.css" rel="stylesheet" type="text/css">
+    <div id="blocker"></div><content></content>
+  </template>
+  <script type="text/javascript" src="input-number.js"></script>
+</polymer-element>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/input-number.js	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,229 @@
+(function() {
+
+  var style = document.createElement('style');
+  style.type = 'text/css';
+  var css = 'body.ew-resize, body.ew-resize * {cursor: ew-resize; user-select: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none;}\n';
+  style.appendChild(document.createTextNode(css));
+  document.getElementsByTagName('head')[0].appendChild(style);
+
+  var validKeys = [46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 189, 190, 37, 38, 39, 40, 8, 9];
+
+  var oldValue, selection, range, rect;
+
+  var delta = 0;
+  var deltaStep = 5;
+  var x = 0;
+  var y = 0;
+  var xOld = 0;
+
+  Polymer({
+
+    __doc__: {
+      element: 'input-number',
+      description: 'Input element for numeric data type.',
+      status: 'alpha',
+      url: 'https://github.com/arodic/input-number/',
+      demo: 'http://arodic.github.com/input-number/',
+      attributes: [
+        { name: 'value', type: 'number', description: 'Input value.' },
+        { name: 'min', type: 'number', description: 'Minimum value.' },
+        { name: 'max', type: 'number', description: 'Maximum value.' },
+        { name: 'step', type: 'number', description: 'Value increment when dragging in powers of 10.' },
+        { name: 'toDeg', type: 'boolean', description: 'Converts displayed value to degrees.' },
+        { name: 'editable', type: 'boolean', description: 'Determines if the input can be edited.' }
+      ],
+      properties: [],
+      methods: [],
+      events: [
+        {
+          name: 'input-changed',
+          description: 'Fires when value attribute is changed.'
+        }
+      ]
+    },
+
+    value: 0,
+    min: -Infinity,
+    max: Infinity,
+    step: -3,
+    toDeg: false,
+    editable: true,
+    displayValue: 0,
+    ready: function() {
+      this.setAttribute('tabindex', 0);
+      this.setAttribute('contenteditable', true);
+      this.setAttribute('spellcheck', false);
+      this.addEventListener('keydown', this.onKeydown.bind(this));
+      this.addEventListener('focus', this.onFocus.bind(this));
+      this.addEventListener('blur', this.onBlur.bind(this));
+
+      // TODO: make better on mobile
+      this.$.blocker.addEventListener('dblclick', this.onFocus.bind(this));
+      this.$.blocker.addEventListener('contextmenu', this.onFocus.bind(this));
+      this.$.blocker.addEventListener('mousedown', this.onStartDrag.bind(this));
+      this.$.blocker.addEventListener('touchstart', this.onStartDrag.bind(this));
+
+      this.addEventListener('keydown', this.onKeydown.bind(this));
+      this.addEventListener('mouseover', this.updateBlocker.bind(this));
+
+    },
+    domReady: function() {
+      this.stepChanged();
+      this.displayValueChanged();
+      this.updateBlocker();
+    },
+    onStartDrag: function(event) {
+      // event.stopPropagation();
+      event.preventDefault();
+      event = event.changedTouches ? event.changedTouches[0] : event;
+
+      document.body.classList.add('ew-resize');
+      xOld = event.clientX;
+      delta = 0;
+      document.activeElement.blur();
+      this._onDrag = this.onDrag.bind(this);
+      this._onEndDrag = this.onEndDrag.bind(this);
+      document.addEventListener('mousemove', this._onDrag, false);
+      document.addEventListener('mouseup', this._onEndDrag, false);
+      this.addEventListener('touchmove', this._onDrag, false);
+      this.addEventListener('touchend', this._onEndDrag, false);
+      this.addEventListener('touchcancel', this._onEndDrag, false);
+      this.addEventListener('touchleave', this._onEndDrag, false);
+    },
+    onEndDrag: function(event) {
+      // event.stopPropagation();
+      event = event.changedTouches ? event.changedTouches[0] : event;
+
+      document.body.classList.remove('ew-resize');
+      document.removeEventListener('mousemove', this._onDrag, false);
+      document.removeEventListener('mouseup', this._onEndDrag, false);
+      this.removeEventListener('touchmove', this._onDrag, false);
+      this.removeEventListener('touchend', this._onEndDrag, false);
+      this.removeEventListener('touchcancel', this._onEndDrag, false);
+      this.removeEventListener('touchleave', this._onEndDrag, false);
+    },
+    onDrag: function(event) {
+      // event.stopPropagation();
+      // TODO: add acceleration
+      if (!this.editable) return;
+      if (event.type == 'mousemove' && event.which === 0) {
+        this._onEndDrag(event);
+        return;
+      }
+
+      oldValue = this.value;
+
+      event = event.changedTouches ? event.changedTouches[0] : event;
+
+      x = event.clientX;
+      y = event.clientY;
+      delta += x - xOld;
+      xOld = event.clientX;
+
+      while (Math.abs(delta) > deltaStep) {
+        if (delta > deltaStep) {
+          if (this.toDeg) this.value += Math.pow(10, this.step) / 180 * Math.PI;
+          else this.value += Math.pow(10, this.step);
+          delta -= deltaStep;
+        }
+        if (delta < -deltaStep) {
+          if (this.toDeg) this.value -= Math.pow(10, this.step) / 180 * Math.PI;
+          else this.value -= Math.pow(10, this.step);
+          delta += deltaStep;
+        }
+      }
+      this.value = Math.max(this.value, this.min);
+      this.value = Math.min(this.value, this.max);
+      if (this.value != oldValue) this.fire('input-changed', { input: this, oldValue: oldValue, newValue: this.value, delta: this.value - oldValue });
+    },
+
+    onKeydown: function(event) {
+      // TODO: number keyboard on mobile
+      event.stopPropagation();
+      if(event.which == 13) {
+        selection = window.getSelection();
+        selection.removeAllRanges();
+        this.blur();
+        return;
+      }
+
+      oldValue = this.value;
+
+      if (!this.editable || validKeys.indexOf(event.which) == -1) {
+        event.preventDefault();
+        return;
+      }
+      setTimeout(function(){
+        this.updateValue();
+        this.fire('input-changed', { input: this, oldValue: oldValue, newValue: this.value, delta: this.value - oldValue });
+      }.bind(this), 1);
+
+    },
+    onFocus: function(event) {
+      event.preventDefault();
+      selection = window.getSelection();
+      selection.removeAllRanges();
+      range = document.createRange();
+      this.textContent = this.displayValue;
+      range.selectNodeContents(this);
+      selection.addRange(range);
+      this.focused = true;
+    },
+    onBlur: function() {
+      this.updateValue();
+      selection = window.getSelection();
+      selection.removeAllRanges();
+      this.focused = false;
+      this.updateValue();
+      this.valueChanged();
+      this._match = this.displayValue.toString().match(this.regEx);
+      this.textContent = this._match ? parseFloat(this._match[1]) : this.displayValue;
+    },
+    updateValue: function() {
+      if (!isNaN(this.textContent) && (this.textContent.slice(-1) != '.')) {
+        if (this.toDeg)
+          this.value = parseFloat(this.textContent) / 180 * Math.PI;
+        else
+          this.value = parseFloat(this.textContent);
+      }
+    },
+    updateBlocker: function() {
+      rect = this.getBoundingClientRect();
+      this.$.blocker.style.width = rect.width + 'px';
+      this.$.blocker.style.height = rect.height + 'px';
+    },
+    valueChanged: function() {
+      if (this.value < this.min) this.min = this.value;
+      if (this.value > this.max) this.max = this.value;
+
+      if (!this.focused) {
+        if (this.toDeg)
+          this.displayValue = this.value / Math.PI * 180;
+        else
+          this.displayValue = this.value;
+      }
+    },
+    displayValueChanged: function() {
+      this._match = this.displayValue.toString().match(this.regEx);
+      this.textContent = this._match ? parseFloat(this._match[1]) : this.displayValue;
+      this.updateBlocker();
+    },
+    toDegChanged: function() {
+      this.valueChanged();
+    },
+    minChanged: function() {
+      this.value = Math.max(this.value, this.min);
+    },
+    maxChanged: function() {
+      this.value = Math.min(this.value, this.max);
+    },
+    stepChanged: function() {
+      if (this.step < 0) {
+        this.regEx = new RegExp("(^-?\\d+\\.\\d{" + Math.abs(this.step) + "})(\\d)");
+      } else {
+        this.regEx = new RegExp("(^-?\\d+\\.\\d{" + 1 + "})(\\d)");
+      }
+    }
+  });
+
+})();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-number/package.json	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,12 @@
+{
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/arodic/input-number.git"
+  },
+  "author": "Aleksandar Rodic <aleksandar.xyz@gmail.com>",
+  "license": "Apache 2.0",
+  "devDependencies": {
+    "grunt-contrib-copy": "^0.5.0",
+    "grunt-gh-pages": "^0.9.1"
+  }
+}
\ No newline at end of file
Binary file service/pilight/static/input-number/preview.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/.bowerrc	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,3 @@
+{
+  "directory": "../"
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/.gitignore	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,3 @@
+node_modules/
+gh-pages/
+.grunt
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/Gruntfile.js	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,45 @@
+(function() {
+
+  'use strict';
+
+  module.exports = function(grunt) {
+
+    grunt.initConfig({
+
+      copy: {
+        'gh-pages': {
+          files: [
+            {src: '*-*.html', dest: 'gh-pages/'},
+            {src: '*-*.css', dest: 'gh-pages/'},
+            {src: '*-*.js', dest: 'gh-pages/'},
+            {src: 'LICENSE', dest: 'gh-pages/LICENSE'},
+            {src: 'README.md', dest: 'gh-pages/README.md'},
+            {src: 'preview.png', dest: 'gh-pages/preview.png'},
+            {src: 'index.html', dest: 'gh-pages/index.html'},
+          ]
+        }
+      },
+      'gh-pages': {
+        'gh-pages': {
+          options: {
+            base: 'gh-pages',
+            branch: 'gh-pages',
+            message: 'auto-updating gh-pages from dev with grunt'
+          },
+          src: '**/*'
+        }
+      },
+
+    });
+
+    grunt.loadNpmTasks('grunt-contrib-copy');
+    grunt.loadNpmTasks('grunt-gh-pages');
+
+    grunt.registerTask('default', [
+      'copy:gh-pages',
+      'gh-pages:gh-pages'
+    ]);
+
+  };
+
+}());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/LICENSE	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,13 @@
+Copyright (c) 2014 Aleksandar Rodic @arodic
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/README.md	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,5 @@
+Input element for rgb data type
+
+![input-rgb](https://arodic.github.com/input-rgb/preview.png "input-rgb")
+
+##### [Live Demo](http://arodic.github.com/input-rgb/)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/bower.json	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,25 @@
+{
+  "name": "input-rgb",
+  "version": "0.2.7",
+  "homepage": "https://github.com/arodic/input-rgb",
+  "authors": [
+    "Aleksandar Rodic <aleksandar.xyz@gmail.com>"
+  ],
+  "description": "Custom input element for rgb data type.",
+  "main": "input-rgb.html",
+  "keywords": [
+    "input",
+    "field",
+    "polymer",
+    "web-components",
+    "UI",
+    "rgb",
+    "color"
+  ],
+  "license": "Apache 2.0",
+  "dependencies": {
+    "polymer": "Polymer/polymer#~0.3.3",
+    "input-slider": "~0.2.7",
+    "input-number": "~0.2.7"
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/index.html	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
+  <title>&#60;input-rgb&#62;</title>
+
+  <script src="../platform/platform.js"></script>
+
+  <link rel="import" href="../show-and-tell/show-and-tell.html">
+
+  <style type="text/css">
+    html {
+      -webkit-tap-highlight-color: rgb(0, 0, 0, 0);
+    }
+    body{
+      width: 100%;
+      height: 100%;
+      background: #f3eee8;
+      margin: 0;
+      font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+      font-size: 13px;
+    }
+  </style>
+</head>
+<body unresolved>
+
+<show-and-tell url="../input-rgb/input-rgb.html"></show-and-tell>
+
+<script>
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+  ga('create', 'UA-258449-15', 'aleksandarrodic.com');
+  ga('send', 'pageview');
+</script>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/input-rgb.css	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,53 @@
+:host {
+  display: block;
+}
+
+:host > #swatch {
+  display: inline-block;
+}
+
+:host > #swatch > #picker {
+  display: block;
+  float: left;
+  position: absolute;
+  appearance: button;
+  -moz-appearance: button;
+  -webkit-appearance: button;
+  -ms-appearance: button;
+  margin: 0;
+  padding: 0;
+  border: none;
+  opacity: 0;
+}
+
+:host > #r::shadow > #value {
+  background: -webkit-linear-gradient(transparent 91%, red 9%);
+  background: -o-linear-gradient(transparent 91%, red 9%);
+  background: -moz-linear-gradient(transparent 91%, red 9%);
+  background: -ms-linear-gradient(transparent 91%, red 9%);
+  background: linear-gradient(transparent 91%, red 9%);
+}
+
+:host > #g::shadow > #value {
+  background: -webkit-linear-gradient(transparent 91%, green 9%);
+  background: -o-linear-gradient(transparent 91%, green 9%);
+  background: -moz-linear-gradient(transparent 91%, green 9%);
+  background: -ms-linear-gradient(transparent 91%, green 9%);
+  background: linear-gradient(transparent 91%, green 9%);
+}
+
+:host > #b::shadow > #value {
+  background: -webkit-linear-gradient(transparent 91%, blue 9%);
+  background: -o-linear-gradient(transparent 91%, blue 9%);
+  background: -moz-linear-gradient(transparent 91%, blue 9%);
+  background: -ms-linear-gradient(transparent 91%, blue 9%);
+  background: linear-gradient(transparent 91%, blue 9%);
+}
+
+:host > #a::shadow > #value {
+  background: -webkit-linear-gradient(transparent 91%, gray 9%);
+  background: -o-linear-gradient(transparent 91%, gray 9%);
+  background: -moz-linear-gradient(transparent 91%, gray 9%);
+  background: -ms-linear-gradient(transparent 91%, gray 9%);
+  background: linear-gradient(transparent 91%, gray 9%);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/input-rgb.html	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,20 @@
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../input-slider/input-slider.html">
+<link rel="import" href="../input-number/input-number.html">
+
+<polymer-element name="input-rgb" attributes="hex r g b editable">
+  <template>
+    <link href="input-rgb.css" rel="stylesheet" type="text/css">
+    <span id="swatch"><input type="color" id="picker" value="{{hex}}">&nbsp;</span>
+    <input-slider flex id="r" value="{{r}}" editable="{{editable}}" min="0" max="1">
+      <input-number id="r_" value="{{r}}" editable="{{editable}}" min="0" max="1" step="-2"></input-number>
+    </input-slider>
+    <input-slider flex id="g" value="{{g}}" editable="{{editable}}" min="0" max="1">
+      <input-number id="g_" value="{{g}}" editable="{{editable}}" min="0" max="1" step="-2"></input-number>
+    </input-slider>
+    <input-slider flex id="b" value="{{b}}" editable="{{editable}}" min="0" max="1">
+      <input-number id="b_" value="{{b}}" editable="{{editable}}" min="0" max="1" step="-2"></input-number>
+    </input-slider>
+  </template>
+  <script type="text/javascript" src="input-rgb.js"></script>
+</polymer-element>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/input-rgb.js	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,76 @@
+Polymer({
+
+  __doc__: {
+    element: 'input-rgb',
+    description: 'Input element for color data type.',
+    status: 'alpha',
+    url: 'https://github.com/arodic/input-rgb/',
+    demo: 'http://arodic.github.com/input-rgb/',
+    attributes: [
+      { name: 'r', type: 'number', description: 'Red value.' },
+      { name: 'g', type: 'number', description: 'Green value.' },
+      { name: 'b', type: 'number', description: 'Blue value.' },
+      { name: 'hex', type: 'string', description: 'Hexadecimal value of rgb components.' },
+      { name: 'editable', type: 'boolean', description: 'Determines if the input can be edited.' }
+    ],
+    properties: [],
+    methods: [],
+    events: [
+      {
+        name: 'input-changed',
+        description: 'Fires when value attribute is changed.'
+      }
+    ]
+  },
+
+  r: 1,
+  g: 1,
+  b: 1,
+  hex: '#ffffff',
+  observe: {
+    'r g b': 'updateHex'
+  },
+  ready: function() {
+    this.setAttribute('horizontal', true);
+    this.setAttribute('layout', true);
+    this.shadowRoot.addEventListener('input-changed', this.onInputChanged.bind(this));
+  },
+  attached: function() {
+    this.setSwatchSize();
+    this.updateHex();
+  },
+  updateHex: function() {
+    var hex = (this.r * 255) << 16 ^ (this.g * 255) << 8 ^ (this.b * 255) << 0;
+    this.hex = '#' + ('000000' + hex.toString(16)).slice(- 6);
+    this.$.swatch.style.background = this.hex;
+  },
+  onInputChanged: function(event) {
+    event.stopPropagation();
+    this.hold = true;
+    setTimeout(function() { this.hold = false; }, 100);
+    this.fire('input-changed', { input: this, component: event.detail.input.id.replace('_', '') });
+  },
+  hexChanged: function() {
+
+    var hex = parseInt(this.hex.replace(/^#/, ''), 16);
+    hex = hex.toString();
+
+    hex = Math.floor(hex);
+    if (!this.hold) this.fire('input-changed', { input: this });
+
+    this.r = (hex >> 16 & 255) / 255;
+    this.g = (hex >> 8 & 255) / 255;
+    this.b = (hex & 255) / 255;
+
+  },
+  setSwatchSize: function() {
+    var rect = this.$.swatch.getBoundingClientRect();
+    this.$.swatch.style.width = rect.height + 'px';
+    this.$.picker.style.width = rect.height + 'px';
+    this.$.picker.style.height = rect.height + 'px';
+  },
+  editableChanged: function() {
+    if (this.editable) this.$.picker.style.display = 'block';
+    else this.$.picker.style.display = 'none';
+  }
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-rgb/package.json	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,12 @@
+{
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/arodic/input-rgb.git"
+  },
+  "author": "Aleksandar Rodic <aleksandar.xyz@gmail.com>",
+  "license": "Apache 2.0",
+  "devDependencies": {
+    "grunt-contrib-copy": "^0.5.0",
+    "grunt-gh-pages": "^0.9.1"
+  }
+}
\ No newline at end of file
Binary file service/pilight/static/input-rgb/preview.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/.bowerrc	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,3 @@
+{
+  "directory": "../"
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/.gitignore	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,3 @@
+node_modules/
+gh-pages/
+.grunt
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/Gruntfile.js	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,45 @@
+(function() {
+
+  'use strict';
+
+  module.exports = function(grunt) {
+
+    grunt.initConfig({
+
+      copy: {
+        'gh-pages': {
+          files: [
+            {src: '*-*.html', dest: 'gh-pages/'},
+            {src: '*-*.css', dest: 'gh-pages/'},
+            {src: '*-*.js', dest: 'gh-pages/'},
+            {src: 'LICENSE', dest: 'gh-pages/LICENSE'},
+            {src: 'README.md', dest: 'gh-pages/README.md'},
+            {src: 'preview.png', dest: 'gh-pages/preview.png'},
+            {src: 'index.html', dest: 'gh-pages/index.html'},
+          ]
+        }
+      },
+      'gh-pages': {
+        'gh-pages': {
+          options: {
+            base: 'gh-pages',
+            branch: 'gh-pages',
+            message: 'auto-updating gh-pages from dev with grunt'
+          },
+          src: '**/*'
+        }
+      },
+
+    });
+
+    grunt.loadNpmTasks('grunt-contrib-copy');
+    grunt.loadNpmTasks('grunt-gh-pages');
+
+    grunt.registerTask('default', [
+      'copy:gh-pages',
+      'gh-pages:gh-pages'
+    ]);
+
+  };
+
+}());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/LICENSE	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,13 @@
+Copyright (c) 2014 Aleksandar Rodic @arodic
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/README.md	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,5 @@
+Input element for number data type
+
+![input-slider](https://arodic.github.com/input-slider/preview.png "input-slider")
+
+##### [Live Demo](http://arodic.github.com/input-slider/)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/bower.json	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,22 @@
+{
+  "name": "input-slider",
+  "version": "0.2.7",
+  "homepage": "https://github.com/arodic/input-slider",
+  "authors": [
+    "Aleksandar Rodic <aleksandar.xyz@gmail.com>"
+  ],
+  "description": "Custom input element for slider data type.",
+  "main": "input-slider.html",
+  "keywords": [
+    "input",
+    "field",
+    "polymer",
+    "web-components",
+    "UI",
+    "slider"
+  ],
+  "license": "Apache 2.0",
+  "dependencies": {
+    "polymer": "Polymer/polymer#~0.3.3"
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/index.html	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
+  <title>&#60;input-slider&#62;</title>
+
+  <script src="../platform/platform.js"></script>
+
+  <link rel="import" href="../show-and-tell/show-and-tell.html">
+
+  <style type="text/css">
+    html {
+      -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+    }
+    body{
+      width: 100%;
+      height: 100%;
+      background: #f3eee8;
+      margin: 0;
+      font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+      font-size: 13px;
+    }
+  </style>
+</head>
+<body unresolved>
+
+<show-and-tell url="../input-slider/input-slider.html"></show-and-tell>
+
+<script>
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+  ga('create', 'UA-258449-15', 'aleksandarrodic.com');
+  ga('send', 'pageview');
+</script>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/input-slider.css	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,18 @@
+:host {
+  display: block;
+  vertical-align: top;
+  overflow-x: hidden;
+  white-space: nowrap;
+  cursor: ew-resize;
+  position: relative;
+}
+
+:host::shadow > #value {
+  position: relative;
+  background: white;
+}
+
+:host::shadow > #content {
+  position: absolute;
+  top: 0;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/input-slider.html	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,9 @@
+<link rel="import" href="../polymer/polymer.html">
+
+<polymer-element name="input-slider" attributes="value min max step log width height editable">
+  <template>
+    <link href="input-slider.css" rel="stylesheet" type="text/css">
+    <div id="value">&nbsp;</div><div id="content"><content></content></div>
+  </template>
+  <script type="text/javascript" src="input-slider.js"></script>
+</polymer-element>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/input-slider.js	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,131 @@
+(function() {
+
+  var style = document.createElement('style');
+  style.type = 'text/css';
+  var css = 'body.ew-resize, body.ew-resize * {cursor: ew-resize; user-select: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none;}\n';
+  style.appendChild(document.createTextNode(css));
+  document.getElementsByTagName('head')[0].appendChild(style);
+
+  function linToLog(value) {
+    var minv = Math.log(1);
+    var maxv = Math.log(101);
+    var scale = (maxv - minv);
+    return (Math.exp(minv + scale * (value)) - 1) / 100;
+  }
+
+  function logToLin(value) {
+    var minv = Math.log(1);
+    var maxv = Math.log(101);
+    var scale = (maxv - minv);
+    return (Math.log(value * 100 + 1) - minv) / scale;
+  }
+
+  var rect, oldValue, val, displayValue;
+
+  Polymer({
+
+    __doc__: {
+      element: 'input-slider',
+      description: 'Input element for numeric data type.',
+      status: 'alpha',
+      url: 'https://github.com/arodic/input-slider/',
+      demo: 'http://arodic.github.com/input-slider/',
+      attributes: [
+        { name: 'value', type: 'number', description: 'Input value.' },
+        { name: 'min', type: 'number', description: 'Minimum value.' },
+        { name: 'max', type: 'number', description: 'Maximum value.' },
+        { name: 'log', type: 'boolean', description: 'Enables logarithmic scale.' },
+        { name: 'editable', type: 'boolean', description: 'Determines if the input can be edited.' }
+      ],
+      properties: [],
+      methods: [],
+      events: [
+        {
+          name: 'input-changed',
+          description: 'Fires when value attribute is changed.'
+        }
+      ]
+    },
+
+    value: 0,
+    min: 0,
+    max: 1,
+    log: false,
+    editable: true,
+    observe: {'min max log': 'valueChanged'},
+    ready: function() {
+      this.addEventListener('mousedown', this.onStartDrag.bind(this));
+      this.addEventListener('touchstart', this.onStartDrag.bind(this));
+    },
+    domReady: function() {
+      this.valueChanged();
+    },
+    onStartDrag: function(event) {
+      event.preventDefault();
+      event.stopPropagation();
+
+      rect = this.getBoundingClientRect();
+      this.onDrag(event);
+
+      event = event.changedTouches ? event.changedTouches[0] : event;
+
+      if (!this.editable) return;
+
+      document.body.classList.add('ew-resize');
+      document.activeElement.blur();
+
+      this._onDrag = this.onDrag.bind(this);
+      this._onEndDrag = this.onEndDrag.bind(this);
+      document.addEventListener('mousemove', this._onDrag, false);
+      document.addEventListener('mouseup', this._onEndDrag, false);
+      this.addEventListener('touchmove', this._onDrag, false);
+      this.addEventListener('touchend', this._onEndDrag, false);
+      this.addEventListener('touchcancel', this._onEndDrag, false);
+      this.addEventListener('touchleave', this._onEndDrag, false);
+    },
+    onEndDrag: function(event) {
+      event.preventDefault();
+      event.stopPropagation();
+      event = event.changedTouches ? event.changedTouches[0] : event;
+
+      document.body.classList.remove('ew-resize');
+      document.removeEventListener('mousemove', this._onDrag, false);
+      document.removeEventListener('mouseup', this._onEndDrag, false);
+      this.removeEventListener('touchmove', this._onDrag, false);
+      this.removeEventListener('touchend', this._onEndDrag, false);
+      this.removeEventListener('touchcancel', this._onEndDrag, false);
+      this.removeEventListener('touchleave', this._onEndDrag, false);
+    },
+    onDrag: function(event) {
+      event.preventDefault();
+      event.stopPropagation();
+
+      if (!this.editable) return;
+      if (event.type == 'mousemove' && event.which === 0) {
+        this._onEndDrag(event);
+        return;
+      }
+
+      oldValue = this.value;
+
+      event = event.changedTouches ? event.changedTouches[0] : event;
+
+      val = Math.max(0, Math.min(1, (event.clientX - rect.left) / rect.width));
+      if (this.log) val = linToLog(val);
+            
+      this.value = this.min + (this.max - this.min) * val;
+      if (this.value != oldValue) this.fire('input-changed', { input: this });
+
+    },
+
+    valueChanged: function() {
+      if (this.value < this.min) this.min = this.value;
+      if (this.value > this.max) this.max = this.value;
+
+      displayValue = (this.value - this.min) / (this.max - this.min);
+      if (this.log) this.$.value.style.width = logToLin(displayValue) * 100 + '%';
+      else this.$.value.style.width = displayValue * 100 + '%';
+    }
+  });
+
+})();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/pilight/static/input-slider/package.json	Sat Jul 12 11:32:50 2014 -0700
@@ -0,0 +1,12 @@
+{
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/arodic/input-slider.git"
+  },
+  "author": "Aleksandar Rodic <aleksandar.xyz@gmail.com>",
+  "license": "Apache 2.0",
+  "devDependencies": {
+    "grunt-contrib-copy": "^0.5.0",
+    "grunt-gh-pages": "^0.9.1"
+  }
+}
\ No newline at end of file
Binary file service/pilight/static/input-slider/preview.png has changed