diff --git a/README.md b/README.md index dc65d7f1..404a8be5 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ fhem-tablet-ui ======== Just another dashboard for FHEM http://fhem.de/fhem.html +But with a clear intention: Keep it short and simple! + ![](http://knowthelist.github.io/fhem-tablet-ui/fhem-tablet-ui-example.png) @@ -29,28 +31,28 @@ Change the wiget container according your rooms
KUECHE
-
-
+
+
-
-
HerdLicht
-
+
+
HerdLicht
+
``` Change the widgets you have and want to see on the dashboard ```html -
+
``` All widgets have individual parameter settings. Set following attributes according your needs. ####All widgets -- **type** : widget type -- **device** : FHEM device name (call FHEM's 'list' command to get names) -- **class** : css classes for look and formatting of the widget +- **data-type** : widget type +- **data-device** : FHEM device name (call FHEM's 'list' command to get names) +- **class** : css classes for look and formatting of the widget ####Switch widgets - **data-get** : name of the reading to get from FHEM (default 'STATE') @@ -58,7 +60,7 @@ All widgets have individual parameter settings. Set following attributes accordi - **data-get-off** : value for OFF status to get. (default 'off') - **data-set-on** : value for ON status to set. (default: value of data-get-on) - **data-set-off** : value for OFF status to set. (default: value of data-get-off) -- **data-icon** : name of the font-awesome icon. +- **data-icon** : name of the font-awesome icon. (default: fa-lightbulb-o) ####Contact widgets - **data-get** : name of the reading to get from FHEM (default 'STATE') @@ -68,9 +70,12 @@ All widgets have individual parameter settings. Set following attributes accordi ####Label widgets - **data-get** : name of the reading to get from FHEM -- **data-fix** : keeping a specified number of decimals. (default '1') +- **data-fix** : keeping a specified number of decimals. (default '-1' -> non-numeric) - **data-icon** : name of the font-awesome icon. - **data-part** : split position of the space separated value to show. +- **data-colors** : a array of color values to affect the colour of the label according to the limit value +- **data-limits** : a array of numeric values to affect the colour of the label +- **data-unit** : add a unit after a numeric value. use encoded strings e.g. "%B0C%0A" ####Push widgets - **data-set** : command to send to FHEM (set \ \) @@ -92,7 +97,23 @@ All widgets have individual parameter settings. Set following attributes accordi - **data-get** : name of the reading to get from FHEM (default 'STATE') - **data-set** : command to send to FHEM (set \ \ \) (default '') 4 states are valid: 1,2,3 or 4 (1=home,2=night,3=away,4=holiday) - + +####Slider widgets (currently vertical only) +- **data-get** : name of the reading to get from FHEM (default 'STATE') +- **data-set** : command to send to FHEM (set \ \ \) (default '') +- **data-min** : minimal value to set (default 0) +- **data-max** : maximal value to set (default 100) + +####Dimmer widgets +- **data-get** : name of the reading to get from FHEM (default 'STATE') +- **data-get-on** : value for ON status to get. (default 'on') +- **data-get-off** : value for OFF status to get. (default 'off') +- **data-set-off** : value for OFF status to set. (default: value of data-get-off) +- **data-set** : command to send to FHEM (set \ \ \) (default '') +- **data-icon** : name of the font-awesome icon. (default: fa-lightbulb-o) + +data-get-on and data-get-off accept RegEx values. e.g. data-get-on="[0-9]{1,3}|on" means set switch on if STATE is a numeric value or 'on'. + Select one of over 500 icons from http://fortawesome.github.io/Font-Awesome/icons. Just enter the icon name (with suffix "fa-"), all icons are available. e.g. data-icon="fa-volume-up" To disable longpoll, set an other value then 1 @@ -110,11 +131,13 @@ Currently there are 7 types of widgets. - **push** : e.g. up / down - **volume** : dial to set a single value (e.g. 0-60) - **homestatus** : selector for 4 states (1=home,2=night,3=away,4=holiday) +- **dimmer** : toogle button with a setter for on value +- **slider** : vertical slider to select between min/max value By default the ui gets/sets the fhem parameter 'STATE' (not 'state'). ####Thermostat -Configure as device='...' that item which delivers temp and desired-temp as reading. +Configure as data-device='...' that item which delivers temp and desired-temp as reading. Default parameters are: ``` @@ -122,11 +145,11 @@ data-get="desired-temp" data-temp="measured-temp" data-set="desired-temp" ``` Therefor for HomaMatic HM-CC-RT-DN this is sufficient. ```html -
+
``` The long format looks like this: ```html -
+
``` The wigets will show the valve value only in case of a valid data-valve attribute. The default for data-valve ist null. That means, a empty data-valve attribute hides the valve label for the widget. @@ -137,10 +160,10 @@ Example for HM-WDS40-TH-I Funk-Temperatur-/Feuchtesensor innen STATE T: 20.0 H: 61 ``` ```html -
-
Temperatur
-
-
Luftfeuchte
+
+
Temperatur
+
+
Luftfeuchte
``` But the same result can reached by getting single readings: ``` @@ -148,27 +171,41 @@ humidity 58 temperature 20.1 ``` ```html -
-
Temperatur
-
-
Luftfeuchte
+
+
Temperatur
+
+
Luftfeuchte
+``` + +Example for how to influence the color of the label according to value limits +```html +
``` Example for how to create a widget for shutter via push: show state and set up/down ```html -
-
Rollo
+
+
Rollo
``` ####Switch Example for how to create a widget for MILIGHT via toggle button. Usage of RegEx pattern for state request: ```html -
``` +####Dimmer +Example for how to create a widget for a dimmer via toggle button incl. dimmer. Usage of RegEx pattern get all values for state on: +```html +
+``` + License ------- This project is licensed under [MIT](http://www.opensource.org/licenses/mit-license.php). diff --git a/css/fhem-tablet-ui.css b/css/fhem-tablet-ui.css index 51c497b3..f7dda056 100755 --- a/css/fhem-tablet-ui.css +++ b/css/fhem-tablet-ui.css @@ -44,7 +44,7 @@ text-align: center; margin-bottom: -5px !important; } - .small { +.small { font-size: 80%; } @@ -57,6 +57,12 @@ input { visibility:hidden; } +.slider_vertical{ +height: 100px !important; +max-height: 100px !important; +margin:10px 0px 0px 27% !important; +} + .jq-toast-wrap{ z-index:100; } diff --git a/index.html b/index.html index 9b7b8928..c423163a 100755 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ /* * Just another dashboard for FHEM * - * Version: 1.2.1 + * Version: 1.3.0 * Requires: jQuery v1.7+, font-awesome, jquery.gridster, jquery.toast * URL: https://github.com/knowthelist/fhem-tablet-ui * @@ -20,32 +20,40 @@ */ --> - - - + + + + - + + + - - - - - - + + + + + + + + + + +
  • @@ -53,112 +61,118 @@
  • GARTEN
    -
    -
    Licht
    -
    -
    Rollo
    -
    -
    Tür
    -
    -
    Temperatur
    +
    +
    Licht
    +
    +
    Rollo
    +
    +
    Tür
    +
    +
    Außen
    +
    +
    Temperatur
  • BAD
    -
    +
    -
    -
    Badradio
    +
    +
    Badradio
  • SCHLAFZIMMER
    -
    +
    -
    -
    Fenster
    +
    +
    Fenster
  • KINDERZIMMER
    -
    +
    -
    -
    Fenster
    +
    +
    Fenster
  • GALERIE
    -
    -
    Licht
    +
    +
    Licht
  • KUECHE
    -
    -
    +
    +
    -
    -
    HerdLicht
    -
    +
    +
    HerdLicht
    +
  • HOMESTATUS
    -
    +
  • WOHNZIMMER
    -
    -
    +
    +
    -
    -
    SchrankLicht
    +
    +
    SchrankLicht
    -
    -
    Terassentür
    +
    +
    Terassentür
    -
    -
    Temperatur
    -
    -
    Luftfeuchte
    +
    +
    Temperatur
    +
    +
    Luftfeuchte
    -
  • -
  • MULTIMEDIA
    -
    -
    TV
    +
    +
    TV
    -
    -
    Radio
    +
    +
    Radio
    -
    -
    -
    radio
    +
    +
    +
    radio
    -
    -
    Volume
    +
    +
    Volume
  • - +
  • +
    LIGHTS
    +
    +
    Light1
    +
    +
    Light2
    +
diff --git a/js/fhem-tablet-ui.js b/js/fhem-tablet-ui.js index 56f4eba5..ce353461 100755 --- a/js/fhem-tablet-ui.js +++ b/js/fhem-tablet-ui.js @@ -2,7 +2,7 @@ /** * Just another dashboard for FHEM * -* Version: 1.2.3 +* Version: 1.3.0 * Requires: jQuery v1.7+, font-awesome, jquery.gridster, jquery.toast * * Copyright (c) 2015 Mario Stephan @@ -12,19 +12,60 @@ var deviceStates={}; var readings = {"STATE":true}; var devices = {}; +var types = {}; var ready = true; var reading_cntr; +var DEBUG = false; var doLongPoll = false; var timer; +var dir; var shortpollInterval = 30 * 1000; // 30 seconds var devs=Array(); +var plugins = { + modules: [], + addModule: function (module) { + this.modules.push(module); + }, + load: function (name) { + $.ajax({ + url: dir+'/'+name+'.js', + dataType: "script", + cache: true, + async: false, + context:{name: name}, + success: function () { + DEBUG && console.log('Loaded plugin: '+this.name); + var module = eval(this.name); + plugins.addModule(module); + module.init(); + }, + }); + }, + update: function (dev,par) { + $.each(this.modules, function (index, module) { + //Iterate each module and run update function + module.update(dev,par); + }); + } +} + + + $( document ).ready(function() { - wx = 1 * $("meta[name='widget_base_width']").attr("content"); - wy = 1 * $("meta[name='widget_base_height']").attr("content"); + wx = parseInt( $("meta[name='widget_base_width']").attr("content") ); + wy = parseInt( $("meta[name='widget_base_height']").attr("content") ); doLongPoll = ($("meta[name='longpoll']").attr("content") == '1'); + DEBUG = ($("meta[name='debug']").attr("content") == '1'); + //self path + dir = $('script[src$="fhem-tablet-ui.js"]').attr('src'); + var name = dir.split('/').pop(); + dir = dir.replace('/'+name,""); + DEBUG && console.log('Plugin dir: '+dir); + + //init gridster gridster = $(".gridster > ul").gridster({ widget_base_dimensions: [wx, wy], widget_margins: [5, 5], @@ -33,216 +74,32 @@ $( document ).ready(function() { } }).data('gridster'); - $('div[type=label]').each(function(index) { - $(this).data('get', $(this).data('get') || 'STATE'); + //make it HTML conform (remove this after migration) + $('div[type]').each(function() { + $(this).attr({ + 'data-type' : $(this).attr('type'), + }) + .removeAttr('type'); }); - - //init widgets - $('div[type="homestatus"]').each(function( index ) { - var clientX=0; - var clientY=0; - var knob_elem = jQuery('', { - type: 'text', - }).data($(this).data()) - .data('curval', 10) - .appendTo($(this)); - - $(this).bind('mousemove', function(e) { - - knob_elem.data('pageX',e.pageX); - knob_elem.data('pageY',e.pageY); - e.preventDefault(); - }); - - var device = $(this).attr('device'); - $(this).data('get', $(this).data('get') || 'STATE'); - - knob_elem.knob({ - 'min': 0, - 'max': 2 * Math.PI, - 'step': 0.01, - 'height':210, - 'width':210, - 'bgColor': $(this).data('bgcolor') || '#aaaaaa', - 'fgColor': $(this).data('fgcolor') || '#aa6900', - 'tkColor': $(this).data('tkcolor') || '#696969', - 'minColor': '#2A2A2A', - 'maxColor': '#696969', - 'thickness': 0.4, - 'displayInput': false, - 'angleOffset' : 0, - 'reading': $(this).data('set') || '', - 'draw' : drawHomeSelector, - 'change' : function (v) { - startInterval(); - }, - 'release' : function (v) { - if (ready){ - setFhemStatus(device, this.o.reading + ' ' + this.o.status); - this.$.data('curval', v); - } - } - }); - }); - - $('div[type="volume"]').each(function( index ) { - var knob_elem = jQuery('', { - type: 'text', - value: '10', - }).appendTo($(this)); - - var device = $(this).attr('device'); - $(this).data('get', $(this).data('get') || 'STATE'); - - knob_elem.knob({ - 'min': $(this).data('min') || 0, - 'max': $(this).data('max') || 70, - 'height':150, - 'width':150, - //'step':.5, - 'angleOffset': $(this).data('angleoffset') || -120, - 'angleArc': $(this).data('anglearc') || 240, - 'bgColor': $(this).data('bgcolor') || 'transparent', - 'fgColor': $(this).data('fgcolor') || '#cccccc', - 'tkColor': $(this).data('tkcolor') || '#696969', - 'minColor': '#aa6900', - 'maxColor': '#aa6900', - 'thickness': .25, - 'tickdistance': 20, - 'cursor': 6, - 'reading': $(this).data('set') || '', - 'draw' : drawDial, - 'change' : function (v) { - startInterval(); - }, - 'release' : function (v) { - if (ready){ - setFhemStatus(device, this.o.reading + ' ' + v); - this.$.data('curval', v); - } - } - }); - + $('div[device]').each(function() { + $(this).attr({ + 'data-device' : $(this).attr('device'), + }) + .removeAttr('device'); }); + //end **** (remove this after migration) - $('div[type="thermostat"]').each(function( index ) { - var knob_elem = jQuery('', { - type: 'text', - value: '10', - }).appendTo($(this)); - - var device = $(this).attr('device'); - //default reading parameter name - $(this).data('get', $(this).data('get') || 'desired-temp'); - $(this).data('temp', $(this).data('temp') || 'measured-temp'); - - knob_elem.knob({ - 'min':10, - 'max':30, - 'height':100, - 'width':100, - //'step':.5, - 'angleOffset': $(this).data('angleoffset') || -120, - 'angleArc': $(this).data('anglearc') || 240, - 'bgColor': $(this).data('bgcolor') || 'transparent', - 'fgColor': $(this).data('fgcolor') || '#cccccc', - 'tkColor': $(this).data('tkcolor') || '#696969', - 'minColor': '#4477ff', - 'maxColor': '#ff0000', - 'thickness': .25, - 'cursor': 6, - 'reading': $(this).data('cmd') || 'desired-temp', - 'draw' : drawDial, - 'change' : function (v) { - //reset poll timer to avoid jump back - startInterval(); - }, - 'release' : function (v) { - if (ready){ - setFhemStatus(device, this.o.reading + ' ' + v); - $.toast('Set '+ device + ' ' + this.o.reading + ' ' + v ); - this.$.data('curval', v); - } - } - }); - - + //collect required widgets types + $('div[data-type]').each(function(index){ + var t = $(this).data("type"); + if(!types[t]) + types[t] = true; }); - - $('div[type="switch"]').each(function(index) { - - var device = $(this).attr('device'); - $(this).data('get', $(this).data('get') || 'STATE'); - $(this).data('get-on', $(this).attr('data-get-on') || $(this).attr('data-on') || 'on'); - $(this).data('get-off', $(this).attr('data-get-off') || $(this).attr('data-off') || 'off'); - $(this).data('set-on', $(this).attr('data-set-on') || $(this).data('get-on')); - $(this).data('set-off', $(this).attr('data-set-off') || $(this).data('get-off')); - var elem = $(this).famultibutton({ - icon: 'fa-lightbulb-o', - backgroundIcon: 'fa-circle', - offColor: '#2A2A2A', - onColor: '#2A2A2A', - - // Called in toggle on state. - toggleOn: function( ) { - setFhemStatus(device,$(this).data('set-on')); - }, - toggleOff: function( ) { - setFhemStatus(device,$(this).data('set-off')); - }, - }); - elem.data('famultibutton',elem); - - }); - $('div[type="push"]').each(function(index) { - - var device = $(this).attr('device'); - var elem = $(this).famultibutton({ - backgroundIcon: 'fa-circle-thin', - offColor: '#505050', - onColor: '#aa6900', - mode: 'push', - - // Called in toggle on state. - toggleOn: function( ) { - setFhemStatus(device,$(this).data('set')); - }, - }); - elem.data('famultibutton',elem); - }); - - $('div[type="contact"]').each(function(index) { - - var elem = $(this).famultibutton({ - icon: 'fa-windows', - backgroundIcon: null, - onColor: '#aa6900', - onBackgroundColor: '#aa6900', - offColor: '#505050', - offBackgroundColor: '#505050', - mode: 'signal', //toggle, push, , - }); - elem.data('famultibutton',elem); - //default reading parameter name - $(this).data('get', $(this).data('get') || 'STATE'); - $(this).data('get-on', $(this).attr('data-get-on') || $(this).attr('data-on') || 'open'); - $(this).data('get-off', $(this).attr('data-get-off') || $(this).attr('data-off') || 'closed'); - - }); - - $("*").focus(function(){ - $(this).blur(); - }); - - $('input').css({visibility:'visible'}); - - //collect required devices - $('div[device]').each(function(index){ - var device = $(this).attr("device"); - if(!devices[device]) - devices[device] = true; devs.push(device); - }); + //init widgets + for (var widget_type in types) { + plugins.load('widget_'+widget_type); + } //collect required readings $('[data-get]').each(function(index){ @@ -250,15 +107,12 @@ $( document ).ready(function() { if(!readings[reading]) readings[reading] = true; }); - $('[data-temp]').each(function(index){ - var reading = $(this).data("temp"); - if(!readings[reading]) - readings[reading] = true; - }); - $('[data-valve]').each(function(index){ - var reading = $(this).data("valve"); - if(!readings[reading]) - readings[reading] = true; + + //collect required devices + $('div[data-device]').each(function(index){ + var device = $(this).data("device"); + if(!devices[device]) + devices[device] = true; devs.push(device); }); //get current values of readings @@ -273,6 +127,10 @@ $( document ).ready(function() { }, 1000); shortpollInterval = 15 * 60 * 1000; // 15 minutes } + + $("*").focus(function(){ + $(this).blur(); + }); // refresh every x secs startInterval(); @@ -289,105 +147,16 @@ function startInterval() { }, shortpollInterval); } -function update(filter) { - ready = false; - var deviceElements; - var deviceType; - - if ( filter == '*' ) - deviceElements= $('div[device]'); - else - deviceElements= $('div[device="'+filter+'"]'); - - deviceElements.each(function(index) { - - deviceType = $(this).attr('type'); - - if (deviceType == 'label'){ - - var value = getDeviceValue( $(this), 'get' ); - if (value){ - var part = $(this).data('part') || -1; - var unit = ($(this).data('unit')) ? unescape($(this).data('unit')) : ''; - var fix = $(this).data('fix'); - fix = ( $.isNumeric(fix) ) ? fix : 1; - var val = getPart(value,part); - val = ( $.isNumeric(val) ) ? Number(val).toFixed(fix) : val; - $(this).html( val + "" - +unit+"" ); - } - } - else if (deviceType == 'thermostat'){ - - var clima = getClimaValues( $(this) ); - if ( clima.desired && clima.temp ){ - var knob_elem = $(this).find('input'); - - if ( clima.desired > 0 && knob_elem.val() != clima.desired ){ - knob_elem.val( clima.desired ).trigger('change'); - } - if ( clima.temp > 0 && knob_elem.data('curval') != clima.temp ){ - knob_elem.trigger( - 'configure', { "isValue": clima.temp, "valveValue": clima.valve } - ); - knob_elem.data('curval', clima.temp); - } - } - } - else if (deviceType == 'volume'){ - - var val = getDeviceValue( $(this), 'get' ); - if (val){ - var knob_elem = $(this).find('input'); - if ( knob_elem.val() != val ) - knob_elem.val( val ).trigger('change'); - } - } - else if (deviceType == 'homestatus'){ - - var value = getDeviceValue( $(this), 'get' ); - if (value && value > -1){ - var knob_elem = $(this).find('input'); - var val=0; - switch( value ) { - case '3': - val=Math.PI; - break; - case '4': - val=Math.PI*0.25; - break; - case '2': - val=Math.PI*1.75; - break; - default: - val=0; - } - if ( knob_elem.data('curval') != val ) - knob_elem.val( val ).trigger('change'); - } - } - else if (deviceType == 'switch' || deviceType == 'contact'){ - - var state = getDeviceValue( $(this), 'get' ); - if (state) { - if ( state == $(this).data('get-on') ) - $(this).data('famultibutton').setOn(); - else if ( state == $(this).data('get-off') ) - $(this).data('famultibutton').setOff(); - else if ( state.match(RegExp('^' + $(this).data('get-on') + '$')) ) - $(this).data('famultibutton').setOn(); - else if ( state.match(RegExp('^' + $(this).data('get-off') + '$')) ) - $(this).data('famultibutton').setOff(); - } - } - }); +function update(dev,par) { + ready = false; + plugins.update(dev,par); ready = true; - console.log('update done (filter:'+filter+')'); + DEBUG && console.log('update done for device:'+dev+' parameter:'+par); } function setFhemStatus(device,status) { startInterval(); - console.log("set "+device+" "+status); + DEBUG && console.log("set "+device+" "+status); $.ajax({ async: true, url: $("meta[name='fhemweb_url']").attr("content") || "../fhem/", @@ -417,7 +186,7 @@ function longPoll(roomName) { - no separat node for parameter name - multiple nodes with the same data (2xdate) */ - console.log('start longpoll'); + DEBUG && console.log('start longpoll'); if (xhr) xhr.abort(); @@ -483,9 +252,8 @@ function longPoll(roomName) { }; params[paraname]=value; deviceStates[key]=params; - update(key); - - //console.log(date + ' / ' + key+' / '+paraname+' / '+val); + DEBUG && console.log(date + ' / ' + key+' / '+paraname+' / '+val); + update(key,paraname); } //console.log(date + ' / ' + key+' / '+paraname+' / '+val); } @@ -541,7 +309,7 @@ function requestFhem(paraname) { } reading_cntr--; if ( reading_cntr < 1 ) { - update('*'); + update('*','*'); reading_cntr = Object.keys(readings).length; } }); @@ -549,12 +317,12 @@ function requestFhem(paraname) { } this.getPart = function (s,p) { - var c = (typeof s != "undefined") ? s.split(" ") : ''; + var c = (s && typeof s != "undefined") ? s.split(" ") : ''; return (c.length >= p && p>0 ) ? c[p-1] : s; }; this.getDeviceValue = function (device, src) { - var devname = device.attr('device'); + var devname = device.data('device'); var paraname = (src && src != '') ? device.data(src) : Object.keys(readings)[0]; if (devname && devname.length>0){ var params = deviceStates[devname]; @@ -563,236 +331,3 @@ this.getDeviceValue = function (device, src) { return null; } -this.getClimaValues = function (device) { - - var state = getDeviceValue( device, ''); - var desi = getDeviceValue( device, 'get'); - return { - temp: getDeviceValue( device, 'temp'), - desired: ( state && state.indexOf('set_') < 0 ) ? desi : getPart(state,2), - valve: getDeviceValue( device, 'valve') - }; -}; - -this.getGradientColor = function(start_color, end_color, percent) { - // strip the leading # if it's there - start_color = start_color.replace(/^\s*#|\s*$/g, ''); - end_color = end_color.replace(/^\s*#|\s*$/g, ''); - - // convert 3 char codes --> 6, e.g. `E0F` --> `EE00FF` - if(start_color.length == 3){ - start_color = start_color.replace(/(.)/g, '$1$1'); - } - - if(end_color.length == 3){ - end_color = end_color.replace(/(.)/g, '$1$1'); - } - - // get colors - var start_red = parseInt(start_color.substr(0, 2), 16), - start_green = parseInt(start_color.substr(2, 2), 16), - start_blue = parseInt(start_color.substr(4, 2), 16); - - var end_red = parseInt(end_color.substr(0, 2), 16), - end_green = parseInt(end_color.substr(2, 2), 16), - end_blue = parseInt(end_color.substr(4, 2), 16); - - // calculate new color - var diff_red = end_red - start_red; - var diff_green = end_green - start_green; - var diff_blue = end_blue - start_blue; - - diff_red = ( (diff_red * percent) + start_red ).toString(16).split('.')[0]; - diff_green = ( (diff_green * percent) + start_green ).toString(16).split('.')[0]; - diff_blue = ( (diff_blue * percent) + start_blue ).toString(16).split('.')[0]; - - // ensure 2 digits by color - if( diff_red.length == 1 ) - diff_red = '0' + diff_red - - if( diff_green.length == 1 ) - diff_green = '0' + diff_green - - if( diff_blue.length == 1 ) - diff_blue = '0' + diff_blue - - return '#' + diff_red + diff_green + diff_blue; - }; - -var drawDial = function () { - var c = this.g, // context - a = this.arc(this.cv), // Arc - pa, // Previous arc - r = 1; - - c.lineWidth = this.lineWidth; - c.lineCap = this.lineCap; - if (this.o.bgColor !== "none") { - c.beginPath(); - c.strokeStyle = this.o.bgColor; - c.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true); - c.stroke(); - } - - var tick_w = (2 * Math.PI) / 360; - var step = (this.o.max - this.o.min) / this.angleArc; - var acAngle = ((this.o.isValue - this.o.min) / step) + this.startAngle; - var dist = this.o.tickdistance || 4; - var mincolor = this.o.minColor || '#ff0000'; - var maxcolor = this.o.maxColor || '#4477ff'; - - // draw ticks - for (tick = this.startAngle; tick < this.endAngle + 0.00001; tick+=tick_w*dist) { - i = step * (tick-this.startAngle)+this.o.min; - - c.beginPath(); - - if ((tick > acAngle && tick < a.s) || (tick-tick_w*4 <= acAngle && tick+tick_w*4 >= a.s)){ - // draw diff range in gradient color - c.strokeStyle = getGradientColor(maxcolor, mincolor, (this.endAngle-tick)/this.angleArc); - } - else { - // draw normal ticks - c.strokeStyle = this.o.tkColor;//'#4477ff'; - } - - // thicker lines every 5 ticks - if ( Math.round(i*10)/10 % 5 == 0 ){ - w = tick_w*2; - w *= (c.strokeStyle != this.o.tkColor) ? 1.5 : 1; - } - else { - w = tick_w; - w *= (c.strokeStyle != this.o.tkColor) ? 2 : 1; - } - // thicker lines every at current value - if (acAngle > tick-tick_w && acAngle < tick+tick_w) - w *= 1.9; - - c.arc( this.xy, this.xy, this.radius, tick, tick+w , false); - c.stroke(); - } - - // draw target temp cursor - c.beginPath(); - this.o.fgColor= getGradientColor(maxcolor, mincolor, (this.endAngle-a.e)/(this.endAngle-this.startAngle)); - c.strokeStyle = r ? this.o.fgColor : this.fgColor; - c.lineWidth = this.lineWidth * 2; - c.arc(this.xy, this.xy, this.radius-this.lineWidth/2, a.s, a.e, a.d); - c.stroke(); - - //draw current value as text - var x = this.radius*0.7*Math.cos(acAngle); - var y = this.radius*0.7*Math.sin(acAngle); - c.fillStyle = this.o.tkColor; - c.font="10px sans-serif"; - c.fillText(this.o.isValue ,this.xy+x-5,this.xy+y+5); - - //draw valve value as text - if ( this.o.valveValue ) { - var x = -5; - var y = this.radius*0.55; - c.fillStyle = this.o.tkColor; - c.font="10px sans-serif"; - c.fillText(this.o.valveValue+'%',this.xy+x,this.xy+y+5); - } - return false; -}; - -var drawHomeSelector = function (event) { - var sector=0; - var c = this.g; // context - var x=this.$.data('pageX'); - var y=this.$.data('pageY'); - var mx=this.x+this.w2; - var my=this.y+this.w2; - var r=this.radius*0.4; - - //Assign sector 1 for center pressed or set value 0 - if ( Math.pow((mx-x),2) + Math.pow((my-y),2) < Math.pow(r,2) - || this.cv == 0 ) - sector=1; - - if (sector==1){ - // inner circle - c.lineWidth = this.radius*0.4; - c.strokeStyle = this.o.fgColor ; - c.beginPath(); - c.arc( this.xy, this.xy, this.radius*0.2, 0, 2 * Math.PI); - c.stroke(); - } - else{ - // outer section - var start=0; - var end = 0; - - if (this.cv > Math.PI*0.5 && this.cv <= Math.PI*1.5){ - start=0; end=Math.PI; sector=3; - } - else if (this.cv > Math.PI*1.5 && this.cv <= Math.PI*2){ - start=Math.PI; end=Math.PI*1.5; sector=2; - } - else if (this.cv > 0 && this.cv <= Math.PI*0.5){ - start=Math.PI*1.5; end=Math.PI*2; sector=4; - } - - c.lineWidth = this.radius*0.6; - c.beginPath(); - c.strokeStyle = this.o.fgColor; - c.arc(this.xy, this.xy, this.radius*0.7, start, end); - c.stroke(); - } - - // sections - c.strokeStyle = this.o.tkColor; - c.lineWidth = this.radius*0.6; - c.beginPath(); - c.arc(this.xy, this.xy, this.radius*0.7, 0, 0.02); - c.stroke(); - c.beginPath(); - c.arc(this.xy, this.xy, this.radius*0.7, Math.PI -0.02, Math.PI); - c.stroke(); - c.beginPath(); - c.arc(this.xy, this.xy, this.radius*0.7, 1.5 * Math.PI-0.02, 1.5 * Math.PI); - c.stroke(); - - // inner circle line - c.lineWidth = 2; - c.strokeStyle = this.o.tkColor; - c.beginPath(); - c.arc( this.xy, this.xy, this.radius*0.4, 0, 2 * Math.PI); - c.stroke(); - - // outer circle line - c.lineWidth = 2; - c.beginPath(); - c.arc( this.xy, this.xy, this.radius, 0, 2 * Math.PI, false); - c.stroke(); - - c.fillStyle = (sector==1)?this.o.minColor:this.o.maxColor; - c.font = "100 11px sans-serif"; - c.fillText("Home", this.xy-14, this.xy+15); - c.font = "22px FontAwesome"; - c.fillText("\uf015", this.xy-12, this.xy+2); - - c.fillStyle = (sector==2)?this.o.minColor:this.o.maxColor; - c.font = "22px FontAwesome"; - c.fillText("\uf236", this.xy-this.radius*0.7, this.xy-this.radius*0.4); - c.font = "100 11px sans-serif"; - c.fillText("Night", this.xy-this.radius*0.9, this.xy-10); - - c.fillStyle = (sector==3)?this.o.minColor:this.o.maxColor; - c.font = "22px FontAwesome"; - c.fillText("\uf1b9", this.xy-12, this.xy+this.radius*0.67); - c.font = "100 11px sans-serif"; - c.fillText("Away", this.xy-12, this.xy+this.radius*0.65+15); - - c.fillStyle = (sector==4)?this.o.minColor:this.o.maxColor; - c.font = "22px FontAwesome"; - c.fillText("\uf0f2", this.xy+this.radius*0.4, this.xy-this.radius*0.4); - c.font = "100 11px sans-serif"; - c.fillText("Holiday", this.xy+this.radius*0.42, this.xy-10); - - this.o.status = sector; - return false; -}; diff --git a/js/widget_contact.js b/js/widget_contact.js new file mode 100755 index 00000000..fc622e41 --- /dev/null +++ b/js/widget_contact.js @@ -0,0 +1,51 @@ +var widget_contact = { + _contact: null, + elements: null, + init: function () { + _contact=this; + _contact.elements = $('div[data-type="contact"]'); + _contact.elements.each(function(index) { + + var elem = $(this).famultibutton({ + icon: 'fa-windows', + backgroundIcon: null, + onColor: '#aa6900', + onBackgroundColor: '#aa6900', + offColor: '#505050', + offBackgroundColor: '#505050', + mode: 'signal', //toggle, push, , + }); + elem.data('famultibutton',elem); + //default reading parameter name + $(this).data('get', $(this).data('get') || 'STATE'); + $(this).data('get-on', $(this).attr('data-get-on') || $(this).attr('data-on') || 'open'); + $(this).data('get-off', $(this).attr('data-get-off') || $(this).attr('data-off') || 'closed'); + + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _contact.elements; + else + deviceElements= _contact.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index,elem) { + if ( $(this).data('get')==par || par =='*'){ + var state = getDeviceValue( $(this), 'get' ); + if (state) { + if ( state == $(this).data('get-on') ) + $(this).data('famultibutton').setOn(); + else if ( state == $(this).data('get-off') ) + $(this).data('famultibutton').setOff(); + else if ( state.match(RegExp('^' + $(this).data('get-on') + '$')) ) + $(this).data('famultibutton').setOn(); + else if ( state.match(RegExp('^' + $(this).data('get-off') + '$')) ) + $(this).data('famultibutton').setOff(); + } + } + }); + } + +}; \ No newline at end of file diff --git a/js/widget_dimmer.js b/js/widget_dimmer.js new file mode 100755 index 00000000..d347af02 --- /dev/null +++ b/js/widget_dimmer.js @@ -0,0 +1,69 @@ +var widget_dimmer = { + _dimmer: null, + elements: null, + init: function () { + _dimmer=this; + _dimmer.elements = $('div[data-type="dimmer"]'); + _dimmer.elements.each(function(index) { + + var device = $(this).data('device'); + $(this).data('get', $(this).data('get') || 'STATE'); + $(this).data('set', $(this).data('set') || ''); + $(this).data('get-on', $(this).attr('data-get-on') || $(this).attr('data-on') || 'on'); + $(this).data('get-off', $(this).attr('data-get-off') || $(this).attr('data-off') || 'off'); + $(this).data('set-off', $(this).attr('data-set-off') || $(this).data('get-off')); + var elem = $(this).famultibutton({ + icon: 'fa-lightbulb-o', + backgroundIcon: 'fa-circle', + offColor: '#2A2A2A', + onColor: '#2A2A2A', + mode: 'dimmer', + + // Called in toggle on state. + toggleOn: function( ) { + var v = $(this).data('famultibutton').getValue(); + setFhemStatus(device,$(this).data('set')+' '+v); + }, + toggleOff: function( ) { + setFhemStatus(device,$(this).data('set-off')); + }, + valueChanged: function(v) { + localStorage.setItem("dimmer_"+device, v); + if ($(this).data('famultibutton').getState()) + setFhemStatus(device,$(this).data('set')+' '+v); + }, + }); + var val = localStorage.getItem("dimmer_"+device); + if ( val ) + elem.setValue( parseInt(val)); + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _dimmer.elements; + else + deviceElements= _dimmer.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index) { + + if ( $(this).data('get')==par || par =='*'){ + + var state = getDeviceValue( $(this), 'get' ); + if (state) { + if ($.isNumeric(state)) $(this).data('famultibutton').setValue( parseInt(state)); + if ( state == $(this).data('get-on') ) + $(this).data('famultibutton').setOn(); + else if ( state == $(this).data('get-off') ) + $(this).data('famultibutton').setOff(); + else if ( state.match(RegExp('^' + $(this).data('get-on') + '$')) ) + $(this).data('famultibutton').setOn(); + else if ( state.match(RegExp('^' + $(this).data('get-off') + '$')) ) + $(this).data('famultibutton').setOff(); + } + } + }); + } + +}; \ No newline at end of file diff --git a/js/widget_homestatus.js b/js/widget_homestatus.js new file mode 100755 index 00000000..0187ea23 --- /dev/null +++ b/js/widget_homestatus.js @@ -0,0 +1,185 @@ +var widget_homestatus = { + _homestatus: null, + elements: null, + drawSelector: function () { + var sector=0; + var c = this.g; // context + var x=this.$.data('pageX'); + var y=this.$.data('pageY'); + var mx=this.x+this.w2; + var my=this.y+this.w2; + var r=this.radius*0.4; + + //Assign sector 1 for center pressed or set value 0 + if ( Math.pow((mx-x),2) + Math.pow((my-y),2) < Math.pow(r,2) + || this.cv == 0 ) + sector=1; + + if (sector==1){ + // inner circle + c.lineWidth = this.radius*0.4; + c.strokeStyle = this.o.fgColor ; + c.beginPath(); + c.arc( this.xy, this.xy, this.radius*0.2, 0, 2 * Math.PI); + c.stroke(); + } + else{ + // outer section + var start=0; + var end = 0; + + if (this.cv > Math.PI*0.5 && this.cv <= Math.PI*1.5){ + start=0; end=Math.PI; sector=3; + } + else if (this.cv > Math.PI*1.5 && this.cv <= Math.PI*2){ + start=Math.PI; end=Math.PI*1.5; sector=2; + } + else if (this.cv > 0 && this.cv <= Math.PI*0.5){ + start=Math.PI*1.5; end=Math.PI*2; sector=4; + } + + c.lineWidth = this.radius*0.6; + c.beginPath(); + c.strokeStyle = this.o.fgColor; + c.arc(this.xy, this.xy, this.radius*0.7, start, end); + c.stroke(); + } + + // sections + c.strokeStyle = this.o.tkColor; + c.lineWidth = this.radius*0.6; + c.beginPath(); + c.arc(this.xy, this.xy, this.radius*0.7, 0, 0.02); + c.stroke(); + c.beginPath(); + c.arc(this.xy, this.xy, this.radius*0.7, Math.PI -0.02, Math.PI); + c.stroke(); + c.beginPath(); + c.arc(this.xy, this.xy, this.radius*0.7, 1.5 * Math.PI-0.02, 1.5 * Math.PI); + c.stroke(); + + // inner circle line + c.lineWidth = 2; + c.strokeStyle = this.o.tkColor; + c.beginPath(); + c.arc( this.xy, this.xy, this.radius*0.4, 0, 2 * Math.PI); + c.stroke(); + + // outer circle line + c.lineWidth = 2; + c.beginPath(); + c.arc( this.xy, this.xy, this.radius, 0, 2 * Math.PI, false); + c.stroke(); + + c.fillStyle = (sector==1)?this.o.minColor:this.o.maxColor; + c.font = "100 11px sans-serif"; + c.fillText("Home", this.xy-14, this.xy+15); + c.font = "22px FontAwesome"; + c.fillText("\uf015", this.xy-12, this.xy+2); + + c.fillStyle = (sector==2)?this.o.minColor:this.o.maxColor; + c.font = "22px FontAwesome"; + c.fillText("\uf236", this.xy-this.radius*0.7, this.xy-this.radius*0.4); + c.font = "100 11px sans-serif"; + c.fillText("Night", this.xy-this.radius*0.9, this.xy-10); + + c.fillStyle = (sector==3)?this.o.minColor:this.o.maxColor; + c.font = "22px FontAwesome"; + c.fillText("\uf1b9", this.xy-12, this.xy+this.radius*0.67); + c.font = "100 11px sans-serif"; + c.fillText("Away", this.xy-12, this.xy+this.radius*0.65+15); + + c.fillStyle = (sector==4)?this.o.minColor:this.o.maxColor; + c.font = "22px FontAwesome"; + c.fillText("\uf0f2", this.xy+this.radius*0.4, this.xy-this.radius*0.4); + c.font = "100 11px sans-serif"; + c.fillText("Holiday", this.xy+this.radius*0.42, this.xy-10); + + this.o.status = sector; + return false; +}, + init: function () { + _homestatus=this; + _homestatus.elements = $('div[data-type="homestatus"]'); + _homestatus.elements.each(function(index) { + + var clientX=0; + var clientY=0; + var knob_elem = jQuery('', { + type: 'text', + }).data($(this).data()) + .data('curval', 10) + .appendTo($(this)); + + $(this).bind('mousemove', function(e) { + + knob_elem.data('pageX',e.pageX); + knob_elem.data('pageY',e.pageY); + e.preventDefault(); + }); + + var device = $(this).data('device'); + $(this).data('get', $(this).data('get') || 'STATE'); + + knob_elem.knob({ + 'min': 0, + 'max': 2 * Math.PI, + 'step': 0.01, + 'height':210, + 'width':210, + 'bgColor': $(this).data('bgcolor') || '#aaaaaa', + 'fgColor': $(this).data('fgcolor') || '#aa6900', + 'tkColor': $(this).data('tkcolor') || '#696969', + 'minColor': '#2A2A2A', + 'maxColor': '#696969', + 'thickness': 0.4, + 'displayInput': false, + 'angleOffset' : 0, + 'reading': $(this).data('set') || '', + 'draw' : _homestatus.drawSelector, + 'change' : function (v) { + startInterval(); + }, + 'release' : function (v) { + if (ready){ + setFhemStatus(device, this.o.reading + ' ' + this.o.status); + this.$.data('curval', v); + } + } + }); + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _homestatus.elements; + else + deviceElements= _homestatus.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index,elem) { + + var value = getDeviceValue( $(this), 'get' ); + if (value && value > -1){ + var knob_elem = $(this).find('input'); + var val=0; + switch( value ) { + case '3': + val=Math.PI; + break; + case '4': + val=Math.PI*0.25; + break; + case '2': + val=Math.PI*1.75; + break; + default: + val=0; + } + if ( knob_elem.data('curval') != val ) + knob_elem.val( val ).trigger('change'); + } + }); + }, + +}; \ No newline at end of file diff --git a/js/widget_label.js b/js/widget_label.js new file mode 100755 index 00000000..520c2798 --- /dev/null +++ b/js/widget_label.js @@ -0,0 +1,47 @@ +var widget_label = { + _label: null, + elements: null, + init: function () { + _label=this; + _label.elements = $('div[data-type="label"]'); + _label.elements.each(function(index) { + $(this).data('get', $(this).data('get') || 'STATE'); + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _label.elements; + else + deviceElements= _label.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index,elem) { + if ( $(this).data('get')==par || par =='*'){ + var value = getDeviceValue( $(this), 'get' ); + if (value){ + var part = $(this).data('part') || -1; + var unit = ($(this).data('unit')) ? unescape($(this).data('unit')) : ''; + var fix = $(this).data('fix'); + fix = ( $.isNumeric(fix) ) ? fix : -1; + var val = getPart(value,part); + val = ( $.isNumeric(val) && fix>=0 ) ? Number(val).toFixed(fix) : val; + $(this).html( val + ""+unit+"" ); + //set colors according limits for numeric values + if ($.isNumeric(val)){ + var limits=$(this).data('limits'); + var colors=$(this).data('colors'); + if (limits && colors && limits.length == colors.length){ + for (var i=0;ilimits[i]) + $(this).css("color", colors[i]); + } + } + } + } + } + + }); + } + +}; \ No newline at end of file diff --git a/js/widget_push.js b/js/widget_push.js new file mode 100755 index 00000000..7883fafe --- /dev/null +++ b/js/widget_push.js @@ -0,0 +1,49 @@ +var widget_push = { + _push: null, + elements: null, + init: function () { + _push=this; + _push.elements = $('div[data-type="push"]'); + _push.elements.each(function(index) { + + var device = $(this).data('device'); + var elem = $(this).famultibutton({ + backgroundIcon: 'fa-circle-thin', + offColor: '#505050', + onColor: '#aa6900', + mode: 'push', + + // Called in toggle on state. + toggleOn: function( ) { + setFhemStatus(device,$(this).data('set')); + }, + + }); + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _push.elements; + else + deviceElements= _push.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index,elem) { + if ( $(this).data('get')==par || par =='*'){ + var value = getDeviceValue( $(this), 'get' ); + if (value){ + var part = $(this).data('part') || -1; + var unit = ($(this).data('unit')) ? unescape($(this).data('unit')) : ''; + var fix = $(this).data('fix'); + fix = ( $.isNumeric(fix) ) ? fix : 1; + var val = getPart(value,part); + val = ( $.isNumeric(val) ) ? Number(val).toFixed(fix) : val; + $(this).html( val + "" + +unit+"" ); + } + } + }); + } + +}; \ No newline at end of file diff --git a/js/widget_slider.js b/js/widget_slider.js new file mode 100755 index 00000000..abe30dd8 --- /dev/null +++ b/js/widget_slider.js @@ -0,0 +1,70 @@ +var widget_slider = { + _slider: null, + elements: null, + init: function () { + _slider=this; + _slider.elements = $('div[data-type="slider"]'); + _slider.elements.each(function(index) { + + var device = $(this).data('device'); + $(this).data('get', $(this).data('get') || 'STATE'); + $(this).data('set', $(this).data('set') || ''); + //ToDo: more data parameter: color etc. + + var storeval = localStorage.getItem("slider_"+device); + var elem = jQuery('', { + type: 'text', + }).appendTo($(this)); + + var pwrng = new Powerange(elem[0], { + vertical: true, + hideRange: true, + 'min': $(this).data('min') || 0, + 'max': $(this).data('max') || 100, + klass: 'slider_vertical', + start: (storeval)?storeval:'5', + }); + $(this).data('Powerange',pwrng); + + var releaseEventType=((document.ontouchend!==null)?'mouseup':'touchend'); + + $(this).bind(releaseEventType, function(e) { + var val = $(this).find('input').val(); + localStorage.setItem("slider_"+device, val); + setFhemStatus(device,$(this).data('set')+' '+val); + $.toast('Set '+ device + ' ' + $(this).data('set')+' '+val); + e.preventDefault(); + }); + + //ToDo: make fit for horizontal + $(this).addClass('slider_vertical'); + + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _slider.elements; + else + deviceElements= _slider.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index) { + + if ( $(this).data('get')==par || par =='*'){ + + var state = getDeviceValue( $(this), 'get' ); + if (state) { + var elem = $(this).find('input'); + if ($.isNumeric(state) && elem) { + var pwrng = $(this).data('Powerange'); + pwrng.setStart(parseInt(state)); + DEBUG && console.log( 'slider dev:'+dev+' par:'+par+' changed to:'+state ); + } + } + } + elem.css({visibility:'visible'}); + }); + } + +}; \ No newline at end of file diff --git a/js/widget_switch.js b/js/widget_switch.js new file mode 100755 index 00000000..712d2594 --- /dev/null +++ b/js/widget_switch.js @@ -0,0 +1,56 @@ +var widget_switch = { + _switch: null, + elements: null, + init: function () { + _switch=this; + _switch.elements = $('div[data-type="switch"]'); + _switch.elements.each(function(index) { + + var device = $(this).data('device'); + $(this).data('get', $(this).data('get') || 'STATE'); + $(this).data('get-on', $(this).attr('data-get-on') || $(this).attr('data-on') || 'on'); + $(this).data('get-off', $(this).attr('data-get-off') || $(this).attr('data-off') || 'off'); + $(this).data('set-on', $(this).attr('data-set-on') || $(this).data('get-on')); + $(this).data('set-off', $(this).attr('data-set-off') || $(this).data('get-off')); + var elem = $(this).famultibutton({ + icon: 'fa-lightbulb-o', + backgroundIcon: 'fa-circle', + offColor: '#2A2A2A', + onColor: '#2A2A2A', + + // Called in toggle on state. + toggleOn: function( ) { + setFhemStatus(device,$(this).data('set-on')); + }, + toggleOff: function( ) { + setFhemStatus(device,$(this).data('set-off')); + }, + }); + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _switch.elements; + else + deviceElements= _switch.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index,elem) { + if ( $(this).data('get')==par || par =='*'){ + var state = getDeviceValue( $(this), 'get' ); + if (state) { + if ( state == $(this).data('get-on') ) + $(this).data('famultibutton').setOn(); + else if ( state == $(this).data('get-off') ) + $(this).data('famultibutton').setOff(); + else if ( state.match(RegExp('^' + $(this).data('get-on') + '$')) ) + $(this).data('famultibutton').setOn(); + else if ( state.match(RegExp('^' + $(this).data('get-off') + '$')) ) + $(this).data('famultibutton').setOff(); + } + } + }); + } + +}; \ No newline at end of file diff --git a/js/widget_template.js b/js/widget_template.js new file mode 100755 index 00000000..80e27529 --- /dev/null +++ b/js/widget_template.js @@ -0,0 +1,31 @@ +var widget_template = { + _template: null, + elements: null, + init: function () { + _template=this; + _template.elements = $('div[data-type="template"]'); + _template.elements.each(function(index) { + var device = $(this).data('device'); + // Init the widget here + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _template.elements; + else + deviceElements= _template.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index,elem) { + if ( $(this).data('get')==par || par =='*'){ + + var value = getDeviceValue( $(this), 'get' ); + if (value){ + // Update the widget here + } + } + }); + } + +}; \ No newline at end of file diff --git a/js/widget_thermostat.js b/js/widget_thermostat.js new file mode 100755 index 00000000..2361fab2 --- /dev/null +++ b/js/widget_thermostat.js @@ -0,0 +1,229 @@ +var widget_thermostat = { + elements: null, + _thermostat:null, + getnix: function() { return 'nix';}, + getClimaValues: function (device) { + + var state = getDeviceValue( device, ''); + var desi = getDeviceValue( device, 'get'); + return { + temp: getDeviceValue( device, 'temp'), + desired: ( state && state.indexOf('set_') < 0 ) ? desi : getPart(state,2), + valve: getDeviceValue( device, 'valve') + }; +}, + getGradientColor: function(start_color, end_color, percent) { + // strip the leading # if it's there + start_color = start_color.replace(/^\s*#|\s*$/g, ''); + end_color = end_color.replace(/^\s*#|\s*$/g, ''); + + // convert 3 char codes --> 6, e.g. `E0F` --> `EE00FF` + if(start_color.length == 3){ + start_color = start_color.replace(/(.)/g, '$1$1'); + } + + if(end_color.length == 3){ + end_color = end_color.replace(/(.)/g, '$1$1'); + } + + // get colors + var start_red = parseInt(start_color.substr(0, 2), 16), + start_green = parseInt(start_color.substr(2, 2), 16), + start_blue = parseInt(start_color.substr(4, 2), 16); + + var end_red = parseInt(end_color.substr(0, 2), 16), + end_green = parseInt(end_color.substr(2, 2), 16), + end_blue = parseInt(end_color.substr(4, 2), 16); + + // calculate new color + var diff_red = end_red - start_red; + var diff_green = end_green - start_green; + var diff_blue = end_blue - start_blue; + + diff_red = ( (diff_red * percent) + start_red ).toString(16).split('.')[0]; + diff_green = ( (diff_green * percent) + start_green ).toString(16).split('.')[0]; + diff_blue = ( (diff_blue * percent) + start_blue ).toString(16).split('.')[0]; + + // ensure 2 digits by color + if( diff_red.length == 1 ) + diff_red = '0' + diff_red + + if( diff_green.length == 1 ) + diff_green = '0' + diff_green + + if( diff_blue.length == 1 ) + diff_blue = '0' + diff_blue + + return '#' + diff_red + diff_green + diff_blue; + }, + drawDial: function () { + var c = this.g, // context + a = this.arc(this.cv), // Arc + pa, // Previous arc + r = 1; + + c.lineWidth = this.lineWidth; + c.lineCap = this.lineCap; + if (this.o.bgColor !== "none") { + c.beginPath(); + c.strokeStyle = this.o.bgColor; + c.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true); + c.stroke(); + } + + var tick_w = (2 * Math.PI) / 360; + var step = (this.o.max - this.o.min) / this.angleArc; + var acAngle = ((this.o.isValue - this.o.min) / step) + this.startAngle; + var dist = this.o.tickdistance || 4; + var mincolor = this.o.minColor || '#ff0000'; + var maxcolor = this.o.maxColor || '#4477ff'; + + // draw ticks + for (tick = this.startAngle; tick < this.endAngle + 0.00001; tick+=tick_w*dist) { + i = step * (tick-this.startAngle)+this.o.min; + + c.beginPath(); + + if ((tick > acAngle && tick < a.s) || (tick-tick_w*4 <= acAngle && tick+tick_w*4 >= a.s)){ + // draw diff range in gradient color + c.strokeStyle = getGradientColor(maxcolor, mincolor, (this.endAngle-tick)/this.angleArc); + } + else { + // draw normal ticks + c.strokeStyle = this.o.tkColor;//'#4477ff'; + } + + // thicker lines every 5 ticks + if ( Math.round(i*10)/10 % 5 == 0 ){ + w = tick_w*2; + w *= (c.strokeStyle != this.o.tkColor) ? 1.5 : 1; + } + else { + w = tick_w; + w *= (c.strokeStyle != this.o.tkColor) ? 2 : 1; + } + // thicker lines every at current value + if (acAngle > tick-tick_w && acAngle < tick+tick_w) + w *= 1.9; + + c.arc( this.xy, this.xy, this.radius, tick, tick+w , false); + c.stroke(); + } + + // draw target temp cursor + c.beginPath(); + this.o.fgColor= getGradientColor(maxcolor, mincolor, (this.endAngle-a.e)/(this.endAngle-this.startAngle)); + c.strokeStyle = r ? this.o.fgColor : this.fgColor; + c.lineWidth = this.lineWidth * 2; + c.arc(this.xy, this.xy, this.radius-this.lineWidth/2, a.s, a.e, a.d); + c.stroke(); + + //draw current value as text + var x = this.radius*0.7*Math.cos(acAngle); + var y = this.radius*0.7*Math.sin(acAngle); + c.fillStyle = this.o.tkColor; + c.font="10px sans-serif"; + c.fillText(this.o.isValue ,this.xy+x-5,this.xy+y+5); + + //draw valve value as text + if ( this.o.valveValue ) { + var x = -5; + var y = this.radius*0.55; + c.fillStyle = this.o.tkColor; + c.font="10px sans-serif"; + c.fillText(this.o.valveValue+'%',this.xy+x,this.xy+y+5); + } + return false; +}, + init: function () { + _thermostat=this; + _thermostat.elements=$('div[data-type="thermostat"]'); + _thermostat.elements.each(function( index ) { + var knob_elem = jQuery('', { + type: 'text', + value: '10', + }).appendTo($(this)); + + var device = $(this).data('device'); + //default reading parameter name + $(this).data('get', $(this).data('get') || 'desired-temp'); + $(this).data('temp', $(this).data('temp') || 'measured-temp'); + + knob_elem.knob({ + 'min':10, + 'max':30, + 'height':100, + 'width':100, + 'step': 1*$(this).data('step') || 1, + 'angleOffset': $(this).data('angleoffset') || -120, + 'angleArc': $(this).data('anglearc') || 240, + 'bgColor': $(this).data('bgcolor') || 'transparent', + 'fgColor': $(this).data('fgcolor') || '#cccccc', + 'tkColor': $(this).data('tkcolor') || '#696969', + 'minColor': '#4477ff', + 'maxColor': '#ff0000', + 'thickness': .25, + 'cursor': 6, + 'reading': $(this).data('set') || 'desired-temp', + 'draw' : _thermostat.drawDial, + 'change' : function (v) { + //reset poll timer to avoid jump back + startInterval(); + }, + 'release' : function (v) { + if (ready){ + setFhemStatus(device, this.o.reading + ' ' + v); + $.toast('Set '+ device + ' ' + this.o.reading + ' ' + v ); + } + } + }); + }); + $('[data-temp]').each(function(index){ + var reading = $(this).data("temp"); + if(!readings[reading]) + readings[reading] = true; + }); + $('[data-valve]').each(function(index){ + var reading = $(this).data("valve"); + if(!readings[reading]) + readings[reading] = true; + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _thermostat.elements; + else + deviceElements= _thermostat.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index) { + + var clima = _thermostat.getClimaValues( $(this) ); + var knob_elem = $(this).find('input'); + + if ( ($(this).data('get')==par || par =='*') && + clima.desired && clima.desired > 0 && knob_elem.data('desvalue') != clima.desired ){ + knob_elem.val( clima.desired ).trigger('change'); + knob_elem.data('desvalue', clima.desired); + DEBUG && console.log( 'thermo dev:'+dev+' par:'+par+' change:clima.desired' ); + } + if ( clima.temp && clima.temp > 0 && knob_elem.data('curvalue') != clima.temp ){ + knob_elem.trigger( + 'configure', { "isValue": clima.temp } + ); + knob_elem.data('curvalue', clima.temp); + DEBUG && console.log( 'thermo dev:'+dev+' par:'+par+' change:clima.temp' ); + } + if ( clima.valve && knob_elem.data('curvalve') != clima.valve ){ + knob_elem.trigger( + 'configure', { "valveValue": clima.valve } + ); + knob_elem.data('curvalve', clima.valve); + DEBUG && console.log( 'thermo dev:'+dev+' par:'+par+' change:clima.valve' ); + } + knob_elem.css({visibility:'visible'}); + }); +}, +}; + diff --git a/js/widget_volume.js b/js/widget_volume.js new file mode 100755 index 00000000..927dfa6b --- /dev/null +++ b/js/widget_volume.js @@ -0,0 +1,145 @@ +var widget_volume = { + _volume: null, + elements: null, + drawDial: function () { + var c = this.g, // context + a = this.arc(this.cv), // Arc + pa, // Previous arc + r = 1; + + c.lineWidth = this.lineWidth; + c.lineCap = this.lineCap; + if (this.o.bgColor !== "none") { + c.beginPath(); + c.strokeStyle = this.o.bgColor; + c.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true); + c.stroke(); + } + + var tick_w = (2 * Math.PI) / 360; + var step = (this.o.max - this.o.min) / this.angleArc; + var acAngle = ((this.o.isValue - this.o.min) / step) + this.startAngle; + var dist = this.o.tickdistance || 4; + var mincolor = this.o.minColor || '#ff0000'; + var maxcolor = this.o.maxColor || '#4477ff'; + + // draw ticks + for (tick = this.startAngle; tick < this.endAngle + 0.00001; tick+=tick_w*dist) { + i = step * (tick-this.startAngle)+this.o.min; + + c.beginPath(); + + if ((tick > acAngle && tick < a.s) || (tick-tick_w*4 <= acAngle && tick+tick_w*4 >= a.s)){ + // draw diff range in gradient color + c.strokeStyle = getGradientColor(maxcolor, mincolor, (this.endAngle-tick)/this.angleArc); + } + else { + // draw normal ticks + c.strokeStyle = this.o.tkColor;//'#4477ff'; + } + + // thicker lines every 5 ticks + if ( Math.round(i*10)/10 % 5 == 0 ){ + w = tick_w*2; + w *= (c.strokeStyle != this.o.tkColor) ? 1.5 : 1; + } + else { + w = tick_w; + w *= (c.strokeStyle != this.o.tkColor) ? 2 : 1; + } + // thicker lines every at current value + if (acAngle > tick-tick_w && acAngle < tick+tick_w) + w *= 1.9; + + c.arc( this.xy, this.xy, this.radius, tick, tick+w , false); + c.stroke(); + } + + // draw target temp cursor + c.beginPath(); + this.o.fgColor= getGradientColor(maxcolor, mincolor, (this.endAngle-a.e)/(this.endAngle-this.startAngle)); + c.strokeStyle = r ? this.o.fgColor : this.fgColor; + c.lineWidth = this.lineWidth * 2; + c.arc(this.xy, this.xy, this.radius-this.lineWidth/2, a.s, a.e, a.d); + c.stroke(); + + //draw current value as text + var x = this.radius*0.7*Math.cos(acAngle); + var y = this.radius*0.7*Math.sin(acAngle); + c.fillStyle = this.o.tkColor; + c.font="10px sans-serif"; + c.fillText(this.o.isValue ,this.xy+x-5,this.xy+y+5); + + //draw valve value as text + if ( this.o.valveValue ) { + var x = -5; + var y = this.radius*0.55; + c.fillStyle = this.o.tkColor; + c.font="10px sans-serif"; + c.fillText(this.o.valveValue+'%',this.xy+x,this.xy+y+5); + } + return false; +}, + init: function () { + _volume=this; + _volume.elements = $('div[data-type="volume"]'); + _volume.elements.each(function(index) { + var knob_elem = jQuery('', { + type: 'text', + value: '10', + }).appendTo($(this)); + + var device = $(this).data('device'); + $(this).data('get', $(this).data('get') || 'STATE'); + + knob_elem.knob({ + 'min': $(this).data('min') || 0, + 'max': $(this).data('max') || 70, + 'height':150, + 'width':150, + 'angleOffset': $(this).data('angleoffset') || -120, + 'angleArc': $(this).data('anglearc') || 240, + 'bgColor': $(this).data('bgcolor') || 'transparent', + 'fgColor': $(this).data('fgcolor') || '#cccccc', + 'tkColor': $(this).data('tkcolor') || '#696969', + 'minColor': '#aa6900', + 'maxColor': '#aa6900', + 'thickness': .25, + 'tickdistance': 20, + 'cursor': 6, + 'reading': $(this).data('set') || '', + 'draw' : _volume.drawDial, + 'change' : function (v) { + startInterval(); + }, + 'release' : function (v) { + if (ready){ + setFhemStatus(device, this.o.reading + ' ' + v); + this.$.data('curval', v); + } + } + }); + }); + }, + update: function (dev,par) { + + var deviceElements; + if ( dev == '*' ) + deviceElements= _volume.elements; + else + deviceElements= _volume.elements.filter('div[data-device="'+dev+'"]'); + + deviceElements.each(function(index,elem) { + + var val = getDeviceValue( $(this), 'get' ); + if (val){ + var knob_elem = $(this).find('input'); + if ( knob_elem.val() != val ) + knob_elem.val( val ).trigger('change'); + knob_elem.css({visibility:'visible'}); + } + + }); + } + +}; \ No newline at end of file diff --git a/lib/fa-multi-button.min.js b/lib/fa-multi-button.min.js index 73b6f8be..7c9b56fa 100755 --- a/lib/fa-multi-button.min.js +++ b/lib/fa-multi-button.min.js @@ -1 +1 @@ -!function(t){t.fn.famultibutton=function(o){function n(){r=!0,l.children().first().css("color",c.onBackgroundColor),l.children().last().css("color",c.onColor)}function e(){r=!1,l.children().first().css("color",c.offBackgroundColor),l.children().last().css("color",c.offColor)}function s(){r&&(r=!1,t("
").animate({width:100},{duration:700,easing:"swing",step:function(t,o){var n=(t-o.start)/(o.end-o.start);l.children().first().css("color",getGradientColor(c.onBackgroundColor,c.offBackgroundColor,n)),l.children().last().css("color",getGradientColor(c.onColor,c.offColor,n))}}))}if(this.length>1)return this.each(function(){t(this).famultibutton(o)}),this;var l=this,r=!1,a={backgroundIcon:"fa-circle",classes:["fa-2x"],icon:"fa-power-off",offColor:"#2A2A2A",offBackgroundColor:"#505050",onColor:"#2A2A2A",onBackgroundColor:"#aa6900",mode:"toggle",toggleOn:null,toggleOff:null},c=t.extend({},a,o),i=function(){if(c=t.extend({},c,l.data()),l.addClass("fa-stack"),jQuery("",{id:"bg","class":"fa fa-stack-2x"}).addClass(c.backgroundIcon).appendTo(l),jQuery("",{id:"fg","class":"fa fa-stack-1x"}).addClass(c.icon).appendTo(l),c.classes&&c.classes.length>0)for(var o=0;o").animate({width:100},{duration:700,easing:"swing",step:function(t,o){var n=(t-o.start)/(o.end-o.start);c.children().first().css("color",getGradientColor(O.onBackgroundColor,O.offBackgroundColor,n)),c.children().last().css("color",getGradientColor(O.onColor,O.offColor,n))}}))}function i(){clearTimeout(u),p=m>0?p-=1:p+=1,p>100&&(p=100),0>p&&(p=0),s();var t=d[Math.abs(m)];u=setTimeout(function(){i()},500-t)}function s(){var t=r[0];if(t.height=c.innerHeight(),t.width=c.innerWidth(),t.getContext){var o=t.getContext("2d");o.strokeStyle=O.offBackgroundColor;for(var n=t.height-Math.round(t.height*p/100),e=0;e1)return this.each(function(){t(this).famultibutton(o)}),this;var r,u,c=this,f=!1,h=!1,d=[0,10,40,80,120,140,150,160,180,200,240,260,280,300,320,420,430,440,450,460,470],g=0,p=0,m=0,v=0,C=0,b=!1,k=!1,x={backgroundIcon:"fa-circle",classes:["fa-2x"],icon:"fa-power-off",offColor:"#2A2A2A",offBackgroundColor:"#505050",onColor:"#2A2A2A",onBackgroundColor:"#aa6900",mode:"toggle",toggleOn:null,toggleOff:null,valueChanged:null},O=t.extend({},x,o),y=function(){if(O=t.extend({},O,c.data()),c.addClass("fa-stack"),jQuery("",{id:"bg","class":"fa fa-stack-2x"}).addClass(O.backgroundIcon).appendTo(c),jQuery("",{id:"fg","class":"fa fa-stack-1x"}).addClass(O.icon).appendTo(c),O.classes&&O.classes.length>0)for(var o=0;o").attr({id:"scale"}).appendTo(c),r=c.find("canvas#scale"),r.css({height:c.innerHeight()+4}),v=parseInt(r.offset().top)-parseInt(c.offset().top),s(),a()),c.data("famultibutton",c),c};if(getGradientColor=function(t,o,n){t=t.replace(/^\s*#|\s*$/g,""),o=o.replace(/^\s*#|\s*$/g,""),3==t.length&&(t=t.replace(/(.)/g,"$1$1")),3==o.length&&(o=o.replace(/(.)/g,"$1$1"));var e=parseInt(t.substr(0,2),16),l=parseInt(t.substr(2,2),16),i=parseInt(t.substr(4,2),16),s=parseInt(o.substr(0,2),16),a=parseInt(o.substr(2,2),16),r=parseInt(o.substr(4,2),16),u=s-e,c=a-l,f=r-i;return u=(u*n+e).toString(16).split(".")[0],c=(c*n+l).toString(16).split(".")[0],f=(f*n+i).toString(16).split(".")[0],1==u.length&&(u="0"+u),1==c.length&&(c="0"+c),1==f.length&&(f="0"+f),"#"+u+c+f},"push"==O.mode){var I=null!==document.ontouchstart?"mousedown":"touchstart",T=null!==document.ontouchend?"mouseup":"touchend",B=null!==document.ontouchleave?"mouseout":"touchleave";this.bind(I,function(t){n(),"function"==typeof O.toggleOn&&O.toggleOn.call(this),t.preventDefault()}),this.bind(T,function(t){l(),t.preventDefault()}),this.bind(B,function(t){l(),t.preventDefault()})}else if("toggle"==O.mode){var I=null!==document.ontouchstart?"click":"touchstart";this.bind(I,function(t){f?(e(),"function"==typeof O.toggleOff&&O.toggleOff.call(this)):(n(),"function"==typeof O.toggleOn&&O.toggleOn.call(this)),t.preventDefault()})}else if("dimmer"==O.mode){var I=null!==document.ontouchstart?"mousedown":"touchstart",D=null!==document.ontouchmove?"mousemove":"touchmove",T=null!==document.ontouchend?"mouseup":"touchend",B=null!==document.ontouchleave?"mouseout":"touchleave";this.bind(I,function(t){var o=t.originalEvent;g=o.touches?o.touches[0].clientY:t.pageY,m=0,k=!0,t.preventDefault()}),this.bind(B,function(t){b&&(b=!1,c.animate({top:0}),clearInterval(u),h=!1,a()),k=!1,t.preventDefault()}),this.bind(T,function(t){b?(b=!1,c.animate({top:0}),clearTimeout(u),h=!1,"function"==typeof O.valueChanged&&O.valueChanged.call(this,p)):f?(e(),"function"==typeof O.toggleOff&&O.toggleOff.call(this)):(n(),"function"==typeof O.toggleOn&&O.toggleOn.call(this)),b=!1,k=!1,a(),s(),t.preventDefault()}),this.bind(D,function(t){k&&(b=!0);var o=t.originalEvent;C=o.touches?o.touches[0].clientY:t.pageY,m=C-g,m>20&&(m=20),-20>m&&(m=-20),b&&(this.style.top=m+"px",h||(a(),i(),h=!0),r.css({top:-m+"px"})),t.preventDefault()})}return this.setOn=function(){n()},this.setOff=function(){e()},this.getState=function(){return f},this.getValue=function(){return p},this.setValue=function(t){p=t,s()},y()}}(jQuery); \ No newline at end of file diff --git a/lib/powerange.min.css b/lib/powerange.min.css new file mode 100755 index 00000000..7ea50b29 --- /dev/null +++ b/lib/powerange.min.css @@ -0,0 +1 @@ +.range-bar{background-color:#404040;border-radius:15px;display:block;height:4px;position:relative;width:100%}.range-quantity{background-color:#aa6900;border-radius:15px;display:block;height:100%;width:0}.range-handle{background-color:#bcbcbc;border-radius:100%;height:20px;left:20px;top:-13px;position:absolute;width:20px;-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);}.range-min,.range-max{color:#181819;font-size:12px;height:20px;padding-top:4px;position:absolute;text-align:center;top:-9px;width:24px}.range-min{left:-30px}.range-max{right:-30px}.vertical{height:100%;width:3px}.vertical .range-quantity{bottom:0;height:0;position:absolute;width:100%}.vertical .range-handle{bottom:0;left:-9px;top:auto}.vertical .range-min,.vertical .range-max{left:-10px;right:auto;top:auto}.vertical .range-min{bottom:-30px}.vertical .range-max{top:-30px}.unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.range-disabled{cursor:default} \ No newline at end of file diff --git a/lib/powerange.min.js b/lib/powerange.min.js new file mode 100755 index 00000000..31cb9fde --- /dev/null +++ b/lib/powerange.min.js @@ -0,0 +1 @@ +(function(){function e(t,s,n){var i=e.resolve(t);if(null==i){n=n||t,s=s||"root";var o=Error('Failed to require "'+n+'" from "'+s+'"');throw o.path=n,o.parent=s,o.require=!0,o}var r=e.modules[i];if(!r._resolving&&!r.exports){var a={};a.exports={},a.client=a.component=!0,r._resolving=!0,r.call(this,a.exports,e.relative(i),a),delete r._resolving,r.exports=a.exports}return r.exports}e.modules={},e.aliases={},e.resolve=function(t){"/"===t.charAt(0)&&(t=t.slice(1));for(var s=[t,t+".js",t+".json",t+"/index.js",t+"/index.json"],n=0;s.length>n;n++){var t=s[n];if(e.modules.hasOwnProperty(t))return t;if(e.aliases.hasOwnProperty(t))return e.aliases[t]}},e.normalize=function(e,t){var s=[];if("."!=t.charAt(0))return t;e=e.split("/"),t=t.split("/");for(var n=0;t.length>n;++n)".."==t[n]?e.pop():"."!=t[n]&&""!=t[n]&&s.push(t[n]);return e.concat(s).join("/")},e.register=function(t,s){e.modules[t]=s},e.alias=function(t,s){if(!e.modules.hasOwnProperty(t))throw Error('Failed to alias "'+t+'", it does not exist');e.aliases[s]=t},e.relative=function(t){function s(e,t){for(var s=e.length;s--;)if(e[s]===t)return s;return-1}function n(s){var i=n.resolve(s);return e(i,t,s)}var i=e.normalize(t,"..");return n.resolve=function(n){var o=n.charAt(0);if("/"==o)return n.slice(1);if("."==o)return e.normalize(i,n);var r=t.split("/"),a=s(r,"deps")+1;return a||(a=0),n=r.slice(0,a+1).join("/")+"/deps/"+n},n.exists=function(t){return e.modules.hasOwnProperty(n.resolve(t))},n},e.register("component-event/index.js",function(e){var t=window.addEventListener?"addEventListener":"attachEvent",s=window.removeEventListener?"removeEventListener":"detachEvent",n="addEventListener"!==t?"on":"";e.bind=function(e,s,i,o){return e[t](n+s,i,o||!1),i},e.unbind=function(e,t,i,o){return e[s](n+t,i,o||!1),i}}),e.register("component-query/index.js",function(e,t,s){function n(e,t){return t.querySelector(e)}e=s.exports=function(e,t){return t=t||document,n(e,t)},e.all=function(e,t){return t=t||document,t.querySelectorAll(e)},e.engine=function(t){if(!t.one)throw Error(".one callback required");if(!t.all)throw Error(".all callback required");return n=t.one,e.all=t.all,e}}),e.register("component-matches-selector/index.js",function(e,t,s){function n(e,t){if(r)return r.call(e,t);for(var s=i.all(t,e.parentNode),n=0;s.length>n;++n)if(s[n]==e)return!0;return!1}var i=t("query"),o=Element.prototype,r=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.msMatchesSelector||o.oMatchesSelector;s.exports=n}),e.register("discore-closest/index.js",function(e,t,s){var n=t("matches-selector");s.exports=function(e,t,s,i){for(e=s?{parentNode:e}:e,i=i||document;(e=e.parentNode)&&e!==document;){if(n(e,t))return e;if(e===i)return}}}),e.register("component-delegate/index.js",function(e,t){var s=t("closest"),n=t("event");e.bind=function(e,t,i,o,r){return n.bind(e,i,function(n){var i=n.target||n.srcElement;n.delegateTarget=s(i,t,!0,e),n.delegateTarget&&o.call(e,n)},r)},e.unbind=function(e,t,s,i){n.unbind(e,t,s,i)}}),e.register("component-events/index.js",function(e,t,s){function n(e,t){if(!(this instanceof n))return new n(e,t);if(!e)throw Error("element required");if(!t)throw Error("object required");this.el=e,this.obj=t,this._events={}}function i(e){var t=e.split(/ +/);return{name:t.shift(),selector:t.join(" ")}}var o=t("event"),r=t("delegate");s.exports=n,n.prototype.sub=function(e,t,s){this._events[e]=this._events[e]||{},this._events[e][t]=s},n.prototype.bind=function(e,t){function s(){var e=[].slice.call(arguments).concat(h);l[t].apply(l,e)}var n=i(e),a=this.el,l=this.obj,c=n.name,t=t||"on"+c,h=[].slice.call(arguments,2);return n.selector?s=r.bind(a,n.selector,c,s):o.bind(a,c,s),this.sub(c,t,s),s},n.prototype.unbind=function(e,t){if(0==arguments.length)return this.unbindAll();if(1==arguments.length)return this.unbindAllOf(e);var s=this._events[e];if(s){var n=s[t];n&&o.unbind(this.el,e,n)}},n.prototype.unbindAll=function(){for(var e in this._events)this.unbindAllOf(e)},n.prototype.unbindAllOf=function(e){var t=this._events[e];if(t)for(var s in t)this.unbind(e,s)}}),e.register("component-indexof/index.js",function(e,t,s){s.exports=function(e,t){if(e.indexOf)return e.indexOf(t);for(var s=0;e.length>s;++s)if(e[s]===t)return s;return-1}}),e.register("component-classes/index.js",function(e,t,s){function n(e){if(!e)throw Error("A DOM element reference is required");this.el=e,this.list=e.classList}var i=t("indexof"),o=/\s+/,r=Object.prototype.toString;s.exports=function(e){return new n(e)},n.prototype.add=function(e){if(this.list)return this.list.add(e),this;var t=this.array(),s=i(t,e);return~s||t.push(e),this.el.className=t.join(" "),this},n.prototype.remove=function(e){if("[object RegExp]"==r.call(e))return this.removeMatching(e);if(this.list)return this.list.remove(e),this;var t=this.array(),s=i(t,e);return~s&&t.splice(s,1),this.el.className=t.join(" "),this},n.prototype.removeMatching=function(e){for(var t=this.array(),s=0;t.length>s;s++)e.test(t[s])&&this.remove(t[s]);return this},n.prototype.toggle=function(e,t){return this.list?(t!==void 0?t!==this.list.toggle(e,t)&&this.list.toggle(e):this.list.toggle(e),this):(t!==void 0?t?this.add(e):this.remove(e):this.has(e)?this.remove(e):this.add(e),this)},n.prototype.array=function(){var e=this.el.className.replace(/^\s+|\s+$/g,""),t=e.split(o);return""===t[0]&&t.shift(),t},n.prototype.has=n.prototype.contains=function(e){return this.list?this.list.contains(e):!!~i(this.array(),e)}}),e.register("component-emitter/index.js",function(e,t,s){function n(e){return e?i(e):void 0}function i(e){for(var t in n.prototype)e[t]=n.prototype[t];return e}s.exports=n,n.prototype.on=n.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks[e]=this._callbacks[e]||[]).push(t),this},n.prototype.once=function(e,t){function s(){n.off(e,s),t.apply(this,arguments)}var n=this;return this._callbacks=this._callbacks||{},s.fn=t,this.on(e,s),this},n.prototype.off=n.prototype.removeListener=n.prototype.removeAllListeners=n.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var s=this._callbacks[e];if(!s)return this;if(1==arguments.length)return delete this._callbacks[e],this;for(var n,i=0;s.length>i;i++)if(n=s[i],n===t||n.fn===t){s.splice(i,1);break}return this},n.prototype.emit=function(e){this._callbacks=this._callbacks||{};var t=[].slice.call(arguments,1),s=this._callbacks[e];if(s){s=s.slice(0);for(var n=0,i=s.length;i>n;++n)s[n].apply(this,t)}return this},n.prototype.listeners=function(e){return this._callbacks=this._callbacks||{},this._callbacks[e]||[]},n.prototype.hasListeners=function(e){return!!this.listeners(e).length}}),e.register("ui-component-mouse/index.js",function(e,t,s){function n(e,t){this.obj=t||{},this.el=e}var i=t("emitter"),o=t("event");s.exports=function(e,t){return new n(e,t)},i(n.prototype),n.prototype.bind=function(){function e(i){s.onmouseup&&s.onmouseup(i),o.unbind(document,"mousemove",t),o.unbind(document,"mouseup",e),n.emit("up",i)}function t(e){s.onmousemove&&s.onmousemove(e),n.emit("move",e)}var s=this.obj,n=this;return n.down=function(i){s.onmousedown&&s.onmousedown(i),o.bind(document,"mouseup",e),o.bind(document,"mousemove",t),n.emit("down",i)},o.bind(this.el,"mousedown",n.down),this},n.prototype.unbind=function(){o.unbind(this.el,"mousedown",this.down),this.down=null}}),e.register("abpetkov-percentage-calc/percentage-calc.js",function(e){e.isNumber=function(e){return"number"==typeof e?!0:!1},e.of=function(t,s){return e.isNumber(t)&&e.isNumber(s)?t/100*s:void 0},e.from=function(t,s){return e.isNumber(t)&&e.isNumber(s)?100*(t/s):void 0}}),e.register("abpetkov-closest-num/closest-num.js",function(e){e.find=function(e,t){var s=null,n=null,o=t[0];for(i=0;t.length>i;i++)s=Math.abs(e-o),n=Math.abs(e-t[i]),s>n&&(o=t[i]);return o}}),e.register("vesln-super/lib/super.js",function(e,t,s){function n(){var t=i.call(arguments);if(t.length)return"function"!=typeof t[0]?e.merge(t):(e.inherits.apply(null,t),void 0)}var i=Array.prototype.slice,e=s.exports=n;e.extend=function(t,s){var n=this,i=function(){return n.apply(this,arguments)};return e.merge([i,this]),e.inherits(i,this),t&&e.merge([i.prototype,t]),s&&e.merge([i,s]),i.extend=this.extend,i},e.inherits=function(e,t){e.super_=t,Object.create?e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}):(e.prototype=new t,e.prototype.constructor=e)},e.merge=function(e){for(var t=2===e.length?e.shift():{},s=null,n=0,i=e.length;i>n;n++){s=e[n];for(var o in s)s.hasOwnProperty(o)&&(t[o]=s[o])}return t}}),e.register("powerange/lib/powerange.js",function(e,t,s){var n=(t("./main"),t("./horizontal")),i=t("./vertical"),o={callback:function(){},decimal:!1,disable:!1,disableOpacity:.5,hideRange:!1,klass:"",min:0,max:100,start:null,step:null,vertical:!1};s.exports=function(e,t){t=t||{};for(var s in o)null==t[s]&&(t[s]=o[s]);return t.vertical?new i(e,t):new n(e,t)}}),e.register("powerange/lib/main.js",function(e,t,s){function n(e,t){return this instanceof n?(this.element=e,this.options=t||{},this.slider=this.create("span","range-bar"),null!==this.element&&"text"===this.element.type&&this.init(),void 0):new n(e,t)}var o=t("mouse"),r=t("events"),a=t("classes"),l=t("percentage-calc");s.exports=n,n.prototype.bindEvents=function(){this.handle=this.slider.querySelector(".range-handle"),this.touch=r(this.handle,this),this.touch.bind("touchstart","onmousedown"),this.touch.bind("touchmove","onmousemove"),this.touch.bind("touchend","onmouseup"),this.mouse=o(this.handle,this),this.mouse.bind()},n.prototype.hide=function(){this.element.style.display="none"},n.prototype.append=function(){var e=this.generate();this.insertAfter(this.element,e)},n.prototype.generate=function(){var e={handle:{type:"span",selector:"range-handle"},min:{type:"span",selector:"range-min"},max:{type:"span",selector:"range-max"},quantity:{type:"span",selector:"range-quantity"}};for(var t in e)if(e.hasOwnProperty(t)){var s=this.create(e[t].type,e[t].selector);this.slider.appendChild(s)}return this.slider},n.prototype.create=function(e,t){var s=document.createElement(e);return s.className=t,s},n.prototype.insertAfter=function(e,t){e.parentNode.insertBefore(t,e.nextSibling)},n.prototype.extraClass=function(e){this.options.klass&&a(this.slider).add(e)},n.prototype.setRange=function(e,t){"number"!=typeof e||"number"!=typeof t||this.options.hideRange||(this.slider.querySelector(".range-min").innerHTML=e,this.slider.querySelector(".range-max").innerHTML=t)},n.prototype.setValue=function(e,t){var s=l.from(parseFloat(e),t),n=l.of(s,this.options.max-this.options.min)+this.options.min,i=!1;n=this.options.decimal?Math.round(100*n)/100:Math.round(n),i=this.element.value!=n?!0:!1,this.element.value=n,this.options.callback(),i&&this.changeEvent()},n.prototype.step=function(e,t){var s=e-t,n=l.from(this.checkStep(this.options.step),this.options.max-this.options.min),o=l.of(n,s),r=[];for(i=0;s>=i;i+=o)r.push(i);return this.steps=r,this.steps},n.prototype.checkValues=function(e){this.options.min>e&&(this.options.start=this.options.min),e>this.options.max&&(this.options.start=this.options.max),this.options.min>=this.options.max&&(this.options.min=this.options.max)},n.prototype.checkStep=function(e){return 0>e&&(e=Math.abs(e)),this.options.step=e,this.options.step},n.prototype.disable=function(){(this.options.min==this.options.max||this.options.min>this.options.max||this.options.disable)&&(this.mouse.unbind(),this.touch.unbind(),this.slider.style.opacity=this.options.disableOpacity,a(this.handle).add("range-disabled"))},n.prototype.unselectable=function(e,t){a(this.slider).has("unselectable")||t!==!0?a(this.slider).remove("unselectable"):a(this.slider).add("unselectable")},n.prototype.changeEvent=function(){if("function"!=typeof Event&&document.fireEvent)this.element.fireEvent("onchange");else{var e=document.createEvent("HTMLEvents");e.initEvent("change",!1,!0),this.element.dispatchEvent(e)}},n.prototype.init=function(){this.hide(),this.append(),this.bindEvents(),this.extraClass(this.options.klass),this.checkValues(this.options.start),this.setRange(this.options.min,this.options.max),this.disable()}}),e.register("powerange/lib/horizontal.js",function(e,t,s){function n(){a.apply(this,arguments),this.options.step&&this.step(this.slider.offsetWidth,this.handle.offsetWidth),this.setStart(this.options.start)}var i=t("super"),o=t("closest-num"),r=t("percentage-calc"),a=t("./main");s.exports=n,i(n,a),n.prototype.setStart=function(e){var t=null===e?this.options.min:e,s=r.from(t-this.options.min,this.options.max-this.options.min)||0,n=r.of(s,this.slider.offsetWidth-this.handle.offsetWidth),i=this.options.step?o.find(n,this.steps):n;this.setPosition(i),this.setValue(this.handle.style.left,this.slider.offsetWidth-this.handle.offsetWidth)},n.prototype.setPosition=function(e){this.handle.style.left=e+"px",this.slider.querySelector(".range-quantity").style.width=e+"px"},n.prototype.onmousedown=function(e){e.touches&&(e=e.touches[0]),this.startX=e.clientX,this.handleOffsetX=this.handle.offsetLeft,this.restrictHandleX=this.slider.offsetWidth-this.handle.offsetWidth,this.unselectable(this.slider,!0)},n.prototype.onmousemove=function(e){e.preventDefault(),e.touches&&(e=e.touches[0]);var t=this.handleOffsetX+e.clientX-this.startX,s=this.steps?o.find(t,this.steps):t;0>=t?this.setPosition(0):t>=this.restrictHandleX?this.setPosition(this.restrictHandleX):this.setPosition(s),this.setValue(this.handle.style.left,this.slider.offsetWidth-this.handle.offsetWidth)},n.prototype.onmouseup=function(){this.unselectable(this.slider,!1)}}),e.register("powerange/lib/vertical.js",function(e,t,s){function n(){l.apply(this,arguments),o(this.slider).add("vertical"),this.options.step&&this.step(this.slider.offsetHeight,this.handle.offsetHeight),this.setStart(this.options.start)}var i=t("super"),o=t("classes"),r=t("closest-num"),a=t("percentage-calc"),l=t("./main");s.exports=n,i(n,l),n.prototype.setStart=function(e){var t=null===e?this.options.min:e,s=a.from(t-this.options.min,this.options.max-this.options.min)||0,n=a.of(s,this.slider.offsetHeight-this.handle.offsetHeight),i=this.options.step?r.find(n,this.steps):n;this.setPosition(i),this.setValue(this.handle.style.bottom,this.slider.offsetHeight-this.handle.offsetHeight)},n.prototype.setPosition=function(e){this.handle.style.bottom=e+"px",this.slider.querySelector(".range-quantity").style.height=e+"px"},n.prototype.onmousedown=function(e){e.touches&&(e=e.touches[0]),this.startY=e.clientY,this.handleOffsetY=this.slider.offsetHeight-this.handle.offsetHeight-this.handle.offsetTop,this.restrictHandleY=this.slider.offsetHeight-this.handle.offsetHeight,this.unselectable(this.slider,!0)},n.prototype.onmousemove=function(e){e.preventDefault(),e.touches&&(e=e.touches[0]);var t=this.handleOffsetY+this.startY-e.clientY,s=this.steps?r.find(t,this.steps):t;0>=t?this.setPosition(0):t>=this.restrictHandleY?this.setPosition(this.restrictHandleY):this.setPosition(s),this.setValue(this.handle.style.bottom,this.slider.offsetHeight-this.handle.offsetHeight)},n.prototype.onmouseup=function(){this.unselectable(this.slider,!1)}}),e.alias("component-events/index.js","powerange/deps/events/index.js"),e.alias("component-events/index.js","events/index.js"),e.alias("component-event/index.js","component-events/deps/event/index.js"),e.alias("component-delegate/index.js","component-events/deps/delegate/index.js"),e.alias("discore-closest/index.js","component-delegate/deps/closest/index.js"),e.alias("discore-closest/index.js","component-delegate/deps/closest/index.js"),e.alias("component-matches-selector/index.js","discore-closest/deps/matches-selector/index.js"),e.alias("component-query/index.js","component-matches-selector/deps/query/index.js"),e.alias("discore-closest/index.js","discore-closest/index.js"),e.alias("component-event/index.js","component-delegate/deps/event/index.js"),e.alias("component-classes/index.js","powerange/deps/classes/index.js"),e.alias("component-classes/index.js","classes/index.js"),e.alias("component-indexof/index.js","component-classes/deps/indexof/index.js"),e.alias("ui-component-mouse/index.js","powerange/deps/mouse/index.js"),e.alias("ui-component-mouse/index.js","mouse/index.js"),e.alias("component-emitter/index.js","ui-component-mouse/deps/emitter/index.js"),e.alias("component-event/index.js","ui-component-mouse/deps/event/index.js"),e.alias("abpetkov-percentage-calc/percentage-calc.js","powerange/deps/percentage-calc/percentage-calc.js"),e.alias("abpetkov-percentage-calc/percentage-calc.js","powerange/deps/percentage-calc/index.js"),e.alias("abpetkov-percentage-calc/percentage-calc.js","percentage-calc/index.js"),e.alias("abpetkov-percentage-calc/percentage-calc.js","abpetkov-percentage-calc/index.js"),e.alias("abpetkov-closest-num/closest-num.js","powerange/deps/closest-num/closest-num.js"),e.alias("abpetkov-closest-num/closest-num.js","powerange/deps/closest-num/index.js"),e.alias("abpetkov-closest-num/closest-num.js","closest-num/index.js"),e.alias("abpetkov-closest-num/closest-num.js","abpetkov-closest-num/index.js"),e.alias("vesln-super/lib/super.js","powerange/deps/super/lib/super.js"),e.alias("vesln-super/lib/super.js","powerange/deps/super/index.js"),e.alias("vesln-super/lib/super.js","super/index.js"),e.alias("vesln-super/lib/super.js","vesln-super/index.js"),e.alias("powerange/lib/powerange.js","powerange/index.js"),"object"==typeof exports?module.exports=e("powerange"):"function"==typeof define&&define.amd?define([],function(){return e("powerange")}):this.Powerange=e("powerange")})(); \ No newline at end of file