From 47d2193936b7f2a90a5e66ec4601d9ed4d8f6f97 Mon Sep 17 00:00:00 2001 From: "H.Plato" Date: Mon, 8 Aug 2016 17:30:54 -0500 Subject: [PATCH 01/28] IA7 v1.3.100 - basic support for interacting with time_cron data, specifically around the schedule.pm object --- lib/json_server.pl | 2 +- web/ia7/house/main.shtml | 2 +- web/ia7/include/javascript.js | 58 ++- web/ia7/include/jqCron.css | 108 +++++ web/ia7/include/jqCron.en.js | 36 ++ web/ia7/include/jqCron.js | 853 ++++++++++++++++++++++++++++++++++ web/ia7/index.shtml | 9 +- 7 files changed, 1063 insertions(+), 5 deletions(-) create mode 100644 web/ia7/include/jqCron.css create mode 100644 web/ia7/include/jqCron.en.js create mode 100644 web/ia7/include/jqCron.js diff --git a/lib/json_server.pl b/lib/json_server.pl index 3235573fa..941b3014e 100644 --- a/lib/json_server.pl +++ b/lib/json_server.pl @@ -884,7 +884,7 @@ sub json_object_detail { my %json_objects; my %json_complete_object; my @f = qw( category filename measurement rf_id set_by members - state states state_log type label sort_order groups hidden parents + state states state_log type label sort_order groups hidden parents schedule idle_time text html seconds_remaining fp_location fp_icons fp_icon_set img link level); # Build list of fields based on those requested. diff --git a/web/ia7/house/main.shtml b/web/ia7/house/main.shtml index fbb530279..52a32939b 100644 --- a/web/ia7/house/main.shtml +++ b/web/ia7/house/main.shtml @@ -82,7 +82,7 @@

MisterHouse was created by Bruce Winter. Ron Klinkien developed the v2.3 web interface. Kevin Robert Keegan - developed the v4 web interface, updates by H.Plato. IA7 v1.2.350 Font Awesome by Dave Gandy - http://fontawesome.io

+ developed the v4 web interface, updates by H.Plato. IA7 v1.3.100 Font Awesome by Dave Gandy - http://fontawesome.io

diff --git a/web/ia7/include/javascript.js b/web/ia7/include/javascript.js index f94874e7a..b7f647b4f 100644 --- a/web/ia7/include/javascript.js +++ b/web/ia7/include/javascript.js @@ -552,7 +552,7 @@ var loadList = function() { var button_text = ''; var button_html = ''; var entity_arr = []; - URLHash.fields = "category,label,sort_order,members,state,states,state_log,hidden,type,text"; + URLHash.fields = "category,label,sort_order,members,state,states,state_log,hidden,type,text,schedule"; $.ajax({ type: "GET", url: "/json/"+HashtoJSONArgs(URLHash), @@ -761,6 +761,7 @@ var loadList = function() { var getButtonColor = function (state) { var color = "default"; + if (state !== undefined) state = state.toLowerCase(); if (state == "on" || state == "open" || state == "disarmed" || state == "unarmed" || state == "ready" || state == "dry" || state == "up" || state == "100%" || state == "online" || state == "unlocked") { color = "success"; } else if (state == "motion" || state == "closed" || state == "armed" || state == "wet" || state == "fault" || state == "down" || state == "offline" || state == "locked") { @@ -801,7 +802,7 @@ var filterSubstate = function (state) { filter = 1 } } - + if (state !== undefined) state = state.toLowerCase(); if (state == "manual" || state == "double on" || state == "double off" || @@ -2315,6 +2316,59 @@ var create_state_modal = function(entity) { //remove states from anything that doesn't have more than 1 state $('#control').find('.states').find('.btn-group').remove(); } +// Unique Schedule Data here + $('#control').find('.modal-body').find('.sched_control').remove(); + $('#control').find('.modal-footer').find('.sched_submit').remove(); + + if (json_store.objects[entity].schedule !== undefined) { + $('#control').find('.modal-body').append("

Schedule Control

"); + console.log("Schedule object found "+ json_store.objects[entity].schedule); + for (var i = 0; i < json_store.objects[entity].schedule.length; i++){ +//For now, don't add complexity of parsing the entire cron string, +//Format, index,minute,hour,day of month(ignore),month(ignore),day of week (1-5=weekday, 6-7=weekend [This is wrong, should be 0,6]) + var index = json_store.objects[entity].schedule[i].substring(0,json_store.objects[entity].schedule[i].indexOf(',')); + var cron = json_store.objects[entity].schedule[i].substring(json_store.objects[entity].schedule[i].indexOf(',')+1,json_store.objects[entity].schedule[i].length); + //console.log("index="+index+" cron="+cron); + $('#control').find('.sched_control').append("
"+index+"
"); + $('.schedule'+i).jqCron({ + enabled_minute: true, + multiple_dom: true, + multiple_month: false, + multiple_mins: true, + multiple_dow: true, + multiple_time_hours: true, + multiple_time_minutes: true, + default_period: 'week', + default_value : cron, + no_reset_button: true, + bind_to: $('.sched'+i+'value'), + bind_method: { + set: function($element, value) { + $element.html(value); + } + }, + lang: 'en' + }); + } + $('#control').find('.modal-footer').prepend(''); + + } else { +// $('#control').find('.modal-footer').remove(); + } + $('.sched_submit').on('click', function(){ + //url= '/SUBSET;none?select_item='+$(this).parents('.control-dialog').attr("entity")+'&select_state='+$(this).text(); + //for each jqCron item get the values and stringify them. + var string = ""; + $('.mhsched').each(function(index,value) { + console.log(index + "," + $( this ).attr("id") + "," + $( this ).text() + ","); + string += $( this ).attr("id") + ',"' + $( this ).text() + '",'; + }); + var url="/SUB?web_update_schedule"+encodeURI("("+$(this).parents('.control-dialog').attr("entity")+","+string+")"); + alert(url); + $.get(url); + + }); +// if (json_store.ia7_config.prefs.state_log_show !== "no") { //state log show last 4 (separate out set_by as advanced) - keeps being added to each time it opens // could load all log items, and only unhide the last 4 -- maybe later diff --git a/web/ia7/include/jqCron.css b/web/ia7/include/jqCron.css new file mode 100644 index 000000000..455a668e4 --- /dev/null +++ b/web/ia7/include/jqCron.css @@ -0,0 +1,108 @@ + +/* + * This file is part of the Arnapou jqCron package. + * + * (c) Arnaud Buathier + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +.jqCron-selector { + position: relative; +} +.jqCron-cross, +.jqCron-selector-title { + cursor: pointer; + border-radius: 3px; + border: 1px solid #ddd; + margin: 0 0.2em; + padding: 0 0.5em; +} +.jqCron-container.disable .jqCron-cross:hover, +.jqCron-container.disable .jqCron-selector-title:hover, +.jqCron-cross, +.jqCron-selector-title { + background: #eee; + border-color: #ddd; +} +.jqCron-cross:hover, +.jqCron-selector-title:hover { + background-color: #ddd; + border-color: #aaa; +} +.jqCron-cross { + border-radius: 1em; + font-size: 80%; + padding: 0 0.3em; +} +.jqCron-selector-list { + background: #eee; + border: 1px solid #aaa; + -webkit-box-shadow: 2px 2px 3px #ccc; + box-shadow: 2px 2px 3px #ccc; + left: 0.2em; + list-style: none; + margin: 0; + padding: 0; + position: absolute; + top: 1.5em; + z-index: 1; +} +.jqCron-selector-list li { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + cursor: default; + display: inline-block; + margin: 0; + padding: 0.1em 0.4em; + width: 100%; +} +.jqCron-selector-list li.selected { + background: #0088cc; + color: white; +} +.jqCron-selector-list li:hover { + background: #5fb9e7; + color: white; +} +.jqCron-selector-list.cols2 { + width: 4em; +} +.jqCron-selector-list.cols2 li { + width: 50%; +} +.jqCron-selector-list.cols3 { + width: 6em; +} +.jqCron-selector-list.cols3 li { + width: 33%; +} +.jqCron-selector-list.cols4 { + width: 8em; +} +.jqCron-selector-list.cols4 li { + width: 25%; +} +.jqCron-selector-list.cols5 { + width: 10em; +} +.jqCron-selector-list.cols5 li { + width: 20%; +} +.jqCron-error .jqCron-selector-title { + background: #fee; + border: 1px solid #fdd; + color: red; +} +.jqCron-container.disable * { + color: #888; +} +.jqCron-container.disable .jqCron-selector-title { + background: #eee !important; +} + + + diff --git a/web/ia7/include/jqCron.en.js b/web/ia7/include/jqCron.en.js new file mode 100644 index 000000000..760d039e6 --- /dev/null +++ b/web/ia7/include/jqCron.en.js @@ -0,0 +1,36 @@ +/* + * This file is part of the Arnapou jqCron package. + * + * (c) Arnaud Buathier + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +jqCronDefaultSettings.texts.en = { + empty: 'every', + empty_minutes: 'every', + empty_time_hours: 'every hour', + empty_time_minutes: 'every minute', + empty_day_of_week: 'every day of the week', + empty_day_of_month: 'every day of the month', + empty_month: 'every month', + name_minute: 'minute', + name_hour: 'hour', + name_day: 'day', + name_week: 'week', + name_month: 'month', + name_year: 'year', + text_period: 'Every ', + text_mins: ' at minute(s) past the hour', + text_time: ' at :', + text_dow: ' on ', + text_month: ' of ', + text_dom: ' on ', + error1: 'The tag %s is not supported !', + error2: 'Bad number of elements', + error3: 'The jquery_element should be set into jqCron settings', + error4: 'Unrecognized expression', + weekdays: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'], + months: ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'] +}; diff --git a/web/ia7/include/jqCron.js b/web/ia7/include/jqCron.js new file mode 100644 index 000000000..e68e2adae --- /dev/null +++ b/web/ia7/include/jqCron.js @@ -0,0 +1,853 @@ +/* + * This file is part of the Arnapou jqCron package. + * + * (c) Arnaud Buathier + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Default settings + */ +var jqCronDefaultSettings = { + texts: {}, + monthdays: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], + hours: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], + minutes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59], + lang: 'en', + enabled_minute: false, + enabled_hour: true, + enabled_day: true, + enabled_week: true, + enabled_month: true, + enabled_year: true, + multiple_dom: false, + multiple_month: false, + multiple_mins: false, + multiple_dow: false, + multiple_time_hours: false, + multiple_time_minutes: false, + numeric_zero_pad: false, + default_period: 'day', + default_value: '', + no_reset_button: true, + disabled: false, + bind_to: null, + bind_method: { + set: function($element, value) { + $element.is(':input') ? $element.val(value) : $element.data('jqCronValue', value); + }, + get: function($element) { + return $element.is(':input') ? $element.val() : $element.data('jqCronValue'); + } + } +}; + +/** + * Custom extend of json for jqCron settings. + * We don't use jQuery.extend because simple extend does not fit our needs, and deep extend has a bad + * feature for us : it replaces keys of "Arrays" instead of replacing the full array. + */ +(function($){ + var extend = function(dst, src) { + for(var i in src) { + if($.isPlainObject(src[i])) { + dst[i] = extend(dst[i] && $.isPlainObject(dst[i]) ? dst[i] : {}, src[i]); + } + else if($.isArray(src[i])) { + dst[i] = src[i].slice(0); + } + else if(src[i] !== undefined) { + dst[i] = src[i]; + } + } + return dst; + }; + this.jqCronMergeSettings = function(obj) { + return extend(extend({}, jqCronDefaultSettings), obj || {}); + }; +}).call(this, jQuery); + +/** + * Shortcut to get the instance of jqCron instance from one jquery object + */ +(function($){ + $.fn.jqCronGetInstance = function() { + return this.data('jqCron'); + }; +}).call(this, jQuery); + +/** + * Main plugin + */ +(function($){ + $.fn.jqCron = function(settings) { + var saved_settings = settings; + return this.each(function() { + var cron, saved; + var $this = $(this); + var settings = jqCronMergeSettings(saved_settings); // clone settings + var translations = settings.texts[settings.lang]; + + if (typeof(translations) !== 'object' || $.isEmptyObject(translations)) { + console && console.error( + 'Missing translations for language "' + settings.lang + '". ' + + 'Please include jqCron.' + settings.lang + '.js or manually provide ' + + 'the necessary translations when calling $.fn.jqCron().' + ); + return; + } + + if(!settings.jquery_container) { + if($this.is(':container')) { + settings.jquery_element = $this.uniqueId('jqCron'); + } + else if($this.is(':autoclose')) { + // delete already generated dom if exists + if($this.next('.jqCron').length == 1) { + $this.next('.jqCron').remove(); + } + // generate new + settings.jquery_element = $('').uniqueId('jqCron').insertAfter($this); + } + else { + console && console.error(settings.texts[settings.lang].error1.replace('%s', this.tagName)); + return; + } + } + + // autoset bind_to if it is an input + if($this.is(':input')) { + settings.bind_to = settings.bind_to || $this; + } + + // init cron object + if(settings.bind_to){ + if(settings.bind_to.is(':input')) { + // auto bind from input to object if an input, textarea ... + settings.bind_to.blur(function(){ + var value = settings.bind_method.get(settings.bind_to); + $this.jqCronGetInstance().setCron(value); + }); + } + saved = settings.bind_method.get(settings.bind_to); + cron = new jqCron(settings); + cron.setCron(saved); + } + else { + cron = new jqCron(settings); + } + $(this).data('jqCron', cron); + }); + }; +}).call(this, jQuery); + +/** + * jqCron class + */ +(function($){ + var jqCronInstances = []; + + function jqCron(settings) { + var _initialized = false; + var _self = this; + var _$elt = this; + var _$obj = $(''); + var _$blocks = $(''); + var _$blockPERIOD = $(''); + var _$blockDOM = $(''); + var _$blockMONTH = $(''); + var _$blockMINS = $(''); + var _$blockDOW = $(''); + var _$blockTIME = $(''); + var _$cross = $(''); + var _selectors = []; + var _selectorPeriod, _selectorMins, _selectorTimeH, _selectorTimeM, _selectorDow, _selectorDom, _selectorMonth; + + // instanciate a new selector + function newSelector($block, multiple, type){ + var selector = new jqCronSelector(_self, $block, multiple, type); + selector.$.bind('selector:open', function(){ + // we close all opened selectors of all other jqCron + for(var n = jqCronInstances.length; n--; ){ + if(jqCronInstances[n] != _self) { + jqCronInstances[n].closeSelectors(); + } + else { + // we close all other opened selectors of this jqCron + for(var o = _selectors.length; o--; ){ + if(_selectors[o] != selector) { + _selectors[o].close(); + } + } + } + } + }); + selector.$.bind('selector:change', function(){ + var boundChanged = false; + // don't propagate if not initialized + if(!_initialized) return; + // bind data between two minute selectors (only if they have the same multiple settings) + if(settings.multiple_mins == settings.multiple_time_minutes) { + if(selector == _selectorMins) { + boundChanged = _selectorTimeM.setValue(_selectorMins.getValue()); + } + else if(selector == _selectorTimeM) { + boundChanged = _selectorMins.setValue(_selectorTimeM.getValue()); + } + } + // we propagate the change event to the main object + boundChanged || _$obj.trigger('cron:change', _self.getCron()); + }); + _selectors.push(selector); + return selector; + } + + // disable the selector + this.disable = function(){ + _$obj.addClass('disable'); + settings.disable = true; + _self.closeSelectors(); + }; + + // return if the selector is disabled + this.isDisabled = function() { + return settings.disable == true; + }; + + // enable the selector + this.enable = function(){ + _$obj.removeClass('disable'); + settings.disable = false; + }; + + // get cron value + this.getCron = function(){ + var period = _selectorPeriod.getValue(); + var items = ['*', '*', '*', '*', '*']; + if(period == 'hour') { + items[0] = _selectorMins.getCronValue(); + } + if(period == 'day' || period == 'week' || period == 'month' || period == 'year') { + items[0] = _selectorTimeM.getCronValue(); + items[1] = _selectorTimeH.getCronValue(); + } + if(period == 'month' || period == 'year') { + items[2] = _selectorDom.getCronValue(); + } + if(period == 'year') { + items[3] = _selectorMonth.getCronValue(); + } + if(period == 'week') { + items[4] = _selectorDow.getCronValue(); + } + return items.join(' '); + }; + + // set cron (string like * * * * *) + this.setCron = function(str) { + if(!str) return; + try { + str = str.replace(/\s+/g, ' ').replace(/^ +/, '').replace(/ +$/, ''); // sanitize + var mask = str.replace(/[^\* ]/g, '-').replace(/-+/g, '-').replace(/ +/g, ''); + var items = str.split(' '); + if (items.length != 5) _self.error(_self.getText('error2')); + if(mask == '*****') { // 1 possibility + _selectorPeriod.setValue('minute'); + } + else if(mask == '-****') { // 1 possibility + _selectorPeriod.setValue('hour'); + _selectorMins.setCronValue(items[0]); + _selectorTimeM.setCronValue(items[0]); + } + else if(mask.substring(2, mask.length) == '***') { // 4 possibilities + _selectorPeriod.setValue('day'); + _selectorMins.setCronValue(items[0]); + _selectorTimeM.setCronValue(items[0]); + _selectorTimeH.setCronValue(items[1]); + } + else if(mask.substring(2, mask.length) == '-**') { // 4 possibilities + _selectorPeriod.setValue('month'); + _selectorMins.setCronValue(items[0]); + _selectorTimeM.setCronValue(items[0]); + _selectorTimeH.setCronValue(items[1]); + _selectorDom.setCronValue(items[2]); + } + else if(mask.substring(2, mask.length) == '**-') { // 4 possibilities + _selectorPeriod.setValue('week'); + _selectorMins.setCronValue(items[0]); + _selectorTimeM.setCronValue(items[0]); + _selectorTimeH.setCronValue(items[1]); + _selectorDow.setCronValue(items[4]); + } + else if (mask.substring(3, mask.length) == '-*') { // 8 possibilities + _selectorPeriod.setValue('year'); + _selectorMins.setCronValue(items[0]); + _selectorTimeM.setCronValue(items[0]); + _selectorTimeH.setCronValue(items[1]); + _selectorDom.setCronValue(items[2]); + _selectorMonth.setCronValue(items[3]); + } + else { + _self.error(_self.getText('error4')); + } + _self.clearError(); + } catch(e) {} + }; + + // close all child selectors + this.closeSelectors = function(){ + for(var n = _selectors.length; n--; ){ + _selectors[n].close(); + } + }; + + // get the main element id + this.getId = function(){ + return _$elt.attr('id'); + } + + // get the translated text + this.getText = function(key) { + var text = settings.texts[settings.lang][key] || null; + if(typeof(text) == "string" && text.match(')/gi, ''); + text = '' + text + ''; + } + return text; + }; + + // get the human readable text + this.getHumanText = function() { + var texts=[]; + _$obj + .find('> span > span:visible') + .find('.jqCron-text, .jqCron-selector > span') + .each(function() { + var text = $(this).text().replace(/\s+$/g, '').replace(/^\s+/g, ''); + text && texts.push(text); + }); + return texts.join(' ').replace(/\s:\s/g, ':'); + } + + // get settings + this.getSettings = function(){ + return settings; + }; + + // display an error + this.error = function(msg) { + console && console.error('[jqCron Error] ' + msg); + _$obj.addClass('jqCron-error').attr('title', msg); + throw msg; + }; + + // clear error + this.clearError = function(){ + _$obj.attr('title', '').removeClass('jqCron-error'); + }; + + // clear + this.clear = function() { + _selectorDom.setValue([]); + _selectorDow.setValue([]); + _selectorMins.setValue([]); + _selectorMonth.setValue([]); + _selectorTimeH.setValue([]); + _selectorTimeM.setValue([]); + _self.triggerChange(); + }; + + // init (called in constructor) + this.init = function(){ + var n,i,list; + if(_initialized) return; + + settings = jqCronMergeSettings(settings); + settings.jquery_element || _self.error(_self.getText('error3')); + _$elt = settings.jquery_element; + _$elt.append(_$obj); + _$obj.data('id', settings.id); + _$obj.data('jqCron', _self); + _$obj.append(_$blocks); + settings.no_reset_button || _$obj.append(_$cross); + (!settings.disable) || _$obj.addClass('disable'); + _$blocks.append(_$blockPERIOD); + _$blocks.append(_$blockDOM); + _$blocks.append(_$blockMONTH); + _$blocks.append(_$blockMINS); + _$blocks.append(_$blockDOW); + _$blocks.append(_$blockTIME); + + // various binding + _$cross.click(function(){ + _self.isDisabled() || _self.clear(); + }); + + // binding from cron to target + _$obj.bind('cron:change', function(evt, value){ + if(!settings.bind_to) return; + settings.bind_method.set && settings.bind_method.set(settings.bind_to, value); + _self.clearError(); + }); + + // PERIOD + _$blockPERIOD.append(_self.getText('text_period')); + _selectorPeriod = newSelector(_$blockPERIOD, false, 'period'); + settings.enabled_minute && _selectorPeriod.add('minute', _self.getText('name_minute')); + settings.enabled_hour && _selectorPeriod.add('hour', _self.getText('name_hour')); + settings.enabled_day && _selectorPeriod.add('day', _self.getText('name_day')); + settings.enabled_week && _selectorPeriod.add('week', _self.getText('name_week')); + settings.enabled_month && _selectorPeriod.add('month', _self.getText('name_month')); + settings.enabled_year && _selectorPeriod.add('year', _self.getText('name_year')); + _selectorPeriod.$.bind('selector:change', function(e, value){ + _$blockDOM.hide(); + _$blockMONTH.hide(); + _$blockMINS.hide(); + _$blockDOW.hide(); + _$blockTIME.hide(); + if(value == 'hour') { + _$blockMINS.show(); + } + else if(value == 'day') { + _$blockTIME.show(); + } + else if(value == 'week') { + _$blockDOW.show(); + _$blockTIME.show(); + } + else if(value == 'month') { + _$blockDOM.show(); + _$blockTIME.show(); + } + else if(value == 'year') { + _$blockDOM.show(); + _$blockMONTH.show(); + _$blockTIME.show(); + } + }); + _selectorPeriod.setValue(settings.default_period); + + // MINS (minutes) + _$blockMINS.append(_self.getText('text_mins')); + _selectorMins = newSelector(_$blockMINS, settings.multiple_mins, 'minutes'); + for(i=0, list=settings.minutes; i'); + var _$title = $(''); + var _$selector = $(''); + var _values = {}; + var _value = []; + var _hasNumericTexts = true; + var _numeric_zero_pad = _cron.getSettings().numeric_zero_pad; + + // return an array without doublon + function array_unique(l){ + var i=0,n=l.length,k={},a=[]; + while(i' + value + ''); + _$list.append($item); + _values[key] = $item; + $item.click(function(){ + if(_multiple && $(this).hasClass('selected')) { + _self.removeValue(key); + } + else { + _self.addValue(key); + if(!_multiple) _self.close(); + } + }); + }; + + // expose main jquery object + this.$ = _$selector; + + // constructor + _$block.find('b:eq(0)').after(_$selector).remove(); + _$selector + .addClass('jqCron-selector-' + _$block.find('.jqCron-selector').length) + .append(_$title) + .append(_$list) + .bind('selector:open', function(){ + if(_hasNumericTexts) { + var nbcols = 1, n = _$list.find('li').length; + if(n > 5 && n <= 16) nbcols = 2; + else if(n > 16 && n <= 23) nbcols = 3; + else if(n > 23 && n <= 40) nbcols = 4; + else if(n > 40) nbcols = 5; + _$list.addClass('cols'+nbcols); + } + _$list.show(); + }) + .bind('selector:close', function(){ + _$list.hide(); + }) + .bind('selector:change', function(){ + _$title.html(_self.getTitleText()); + }) + .click(function(e){ + e.stopPropagation(); + }) + .trigger('selector:change') + ; + $.fn.disableSelection && _$selector.disableSelection(); // only work with jQuery UI + _$title.click(function(e){ + (_self.isOpened() || _cron.isDisabled()) ? _self.close() : _self.open(); + }); + _self.close(); + _self.clear(); + } + this.jqCronSelector = jqCronSelector; +}).call(this, jQuery); + +/** + * Generate unique id for each element. + * Skip elements which have already an id. + */ +(function($){ + var jqUID = 0; + var jqGetUID = function(prefix){ + var id; + while(1) { + jqUID++; + id = ((prefix || 'JQUID')+'') + jqUID; + if(!document.getElementById(id)) return id; + } + }; + $.fn.uniqueId = function(prefix) { + return this.each(function(){ + if($(this).attr('id')) return; + var id = jqGetUID(prefix); + $(this).attr('id', id); + }); + }; +}).call(this, jQuery); + + +/** + * Extends jQuery selectors with new block selector + */ +(function($){ + $.extend($.expr[':'], { + container: function(a) { + return (a.tagName+'').toLowerCase() in { + a:1, + abbr:1, + acronym:1, + address:1, + b:1, + big:1, + blockquote:1, + button:1, + cite:1, + code:1, + dd: 1, + del:1, + dfn:1, + div:1, + dt:1, + em:1, + fieldset:1, + form:1, + h1:1, + h2:1, + h3:1, + h4:1, + h5:1, + h6: 1, + i:1, + ins:1, + kbd:1, + label:1, + li:1, + p:1, + pre:1, + q:1, + samp:1, + small:1, + span:1, + strong:1, + sub: 1, + sup:1, + td:1, + tt:1 + }; + }, + autoclose: function(a) { + return (a.tagName+'').toLowerCase() in { + area:1, + base:1, + basefont:1, + br:1, + col:1, + frame:1, + hr:1, + img:1, + input:1, + link:1, + meta:1, + param:1 + }; + } + }); +}).call(this, jQuery); diff --git a/web/ia7/index.shtml b/web/ia7/index.shtml index f5fcfc9a8..0869a7608 100644 --- a/web/ia7/index.shtml +++ b/web/ia7/index.shtml @@ -54,9 +54,14 @@ + + + + + - + From d8db80c57221feaac5afbc624af4b16d2804e855 Mon Sep 17 00:00:00 2001 From: "H.Plato" Date: Fri, 26 Aug 2016 13:53:57 -0600 Subject: [PATCH 11/28] IA7 v1.3.300 - initial support for schedule dropdown if states are defined --- lib/SCHEDULE.pm | 115 ++++++++++++++-------------------- lib/ia7_utilities.pl | 2 +- web/ia7/house/main.shtml | 2 +- web/ia7/include/javascript.js | 73 ++++++++++++--------- 4 files changed, 95 insertions(+), 97 deletions(-) diff --git a/lib/SCHEDULE.pm b/lib/SCHEDULE.pm index 9f900778a..e0687e3d9 100644 --- a/lib/SCHEDULE.pm +++ b/lib/SCHEDULE.pm @@ -13,6 +13,7 @@ sub new #for my $index (1..$self->{'schedule_count'}) { for my $index (1..10) { $self->restore_data('schedule_'.$index); + $self->restore_data('schedule_label_'.$index); } return $self; } @@ -44,44 +45,58 @@ sub set { sub set_schedule { my ($self,$index,$entry,$label) = @_; - #my $index = (split /,/, $entry)[0]; - #$[ = 1; - #@{$self->{'schedule'}}[$index] = $entry if (defined($entry)); + ::print_log("[SCHEDULE] - set_schedule - Index " . $index . " Schedule: ". $entry ." Label ". $label); if ($index > $self->{'schedule_count'}) { $self->{'schedule_count'} = $index } $self->{'schedule_'.$index} = $entry if (defined($entry)); - $self->{'schedule_set_flag'} = 1; + $self->{'schedule_label_'.$index} = $label if (defined($label)); + unless ($entry) { + undef $self->{'schedule_label_'.$index}; + undef $self->{'schedule_'.$index}; + } $self->{set_time} = $main::Time; } +sub delete_schedule { + my ($self,$index) = @_; + $self->set_schedule($index); +} + + sub get_schedule{ - my ($self,$label_only) = @_; + my ($self) = @_; my @schedule; my $count; + my @states; my $object = @{$self->{generic_object}}[0] if (@{$self->{generic_object}}[0]); - if ($label_only) { - if (defined($object->{state_count})) { $count = $object->{state_count}; } - else { $count = 7;} - for my $index (1..$count) { - if (defined($object->{$index})) { $schedule[$index] = $object->{$index}; } - else { $schedule[$index] = $index; } - } - return \@schedule; - } - if ((defined($object->{state_count})) && ($object->{state_count} > $self->{'schedule_count'})) { $count = $object->{state_count} } - else { $count = $self->{'schedule_count'} } - - $schedule[0][0] = 0; - $schedule[0][1] = '0 0 5 1 1'; - $schedule[0][2] = 0; - for my $index (1..$count) { - #::print_log("[SCHEDULE] - index - ".$index . " entry - ". $self->{'schedule_'.$index}); - #$[ = 1; - $schedule[$index][0] = $index; - $schedule[$index][1] = $self->{'schedule_'.$index}; - if (defined($object->{$index})) { $schedule[$index][2] = $object->{$index}; } - else { $schedule[$index][2] = $index; } + if (defined($object->{state_count})) { + $count = $object->{state_count}; + if ($count eq 0) { + @states = $object->{child}->get_states; + #unshift @states, 0; + } else { + for my $index (1..$count) { + $states[$index-1] = $object->{$index}; + } } + } + else { $states[0]=undef } + + #if ((defined($object->{state_count})) && ($object->{state_count} > $self->{'schedule_count'})) { $count = $object->{state_count} } + #else { $count = $self->{'schedule_count'} } + $count = $self->{'schedule_count'}; + $schedule[0][0] = 0; #Index + $schedule[0][1] = '0 0 5 1 1'; #schedule + $schedule[0][2] = 0; #Label + $schedule[0][3] = \@states; + for my $index (1..$count) { + $schedule[$index][0] = $index; + $schedule[$index][1] = $self->{'schedule_'.$index}; + if (defined($self->{'schedule_label_'.$index}) ) { $schedule[$index][2] = $self->{'schedule_label_'.$index} } + #elsif (defined($object->{$index})) { $schedule[$index][2] = $object->{$index}; } + else { $schedule[$index][2] = $index; } + #$schedule[$index][3] = \@states; + } return \@schedule; } @@ -186,41 +201,7 @@ sub register { sub check_date { my ($self,$object) = @_; -# if ($Startup||$Reload) { - #$self->restore_data('active_object','active_action','schedule_count'); - #$self->_set_instance_active_object($$self{instance},$$self{active_action}) if (defined($$self{instance}) && $$self{active_object}); - # for my $index (1..$self->{'schedule_count'}) { - # $self->restore_data('schedule_'.$index) unless($self->{'schedule_set_flag'}); - # } -# } - -# unless(defined($self->get_instance_active_object)) { -# $self->_set_instance_active_object($$self{instance},$$self{active_action}) if (defined($$self{instance}) && $$self{active_object}); -# } - -# $self->restore_data('active_object') unless(defined($self->{'active_object'})); -# $self->restore_data('active_action') unless(defined($self->{'active_action'})); -# $self->restore_data('schedule_count') unless(defined($self->{'schedule_count'})); - # unless($self->{'schedule_set_flag'}) { -# for my $index (1..$self->{'schedule_count'}) { -# $self->restore_data('schedule_'.$index) unless(defined($self->{'schedule_'.$index})); -# } - # } - - -# if ($::New_Minute) { -# ::print_log("[SCHEDULE] - active object ". $self->{'active_object'} ) if (defined($self->{'active_object'})); -# ::print_log("[SCHEDULE] - active_action ". $self->{'active_action'} ) if (defined($self->{'active_action'})); -# ::print_log("[SCHEDULE] - schedule_count ". $self->{'schedule_count'} ) if (defined($self->{'schedule_count'})); -# -# for my $index (1..$self->{'schedule_count'}) { -# # $self->set_schedule('schedule_'.$index); -# ::print_log("[SCHEDULE] - restored schedule ".$self->{'schedule_'.$index} ." for ".$self->get_object_name); -# } -# #::print_log("[SCHEDULE] - restored active object ". $self->get_object_name ) if (($self->am_i_active_object($$self{instance})); -# } - - + if ($::Startup or $::Reload) { $self->{'reloaded'} = 1 } my $occupied_state = ($$self{occupied}->state_now) if (defined($$self{occupied})); if ($occupied_state) { $self->ChangeACSetpoint if (($self->am_i_active_object($$self{instance})) && (lc(state $self) eq 'on')) } @@ -257,11 +238,11 @@ sub setACSetpoint { } sub set_action { - my ($self,$object,$action) = @_; + my ($self,$object,$index) = @_; if ($object->isa('SCHEDULE_Generic')) { - ::print_log("[SCHEDULE] Setting ".$object->{child}->get_object_name." state to ".$object->{$action}); - $self->_set_instance_active_object($$self{instance},$action) if (defined($$self{instance})); - $object->{child}->SUPER::set($object->{$action},$self->get_object_name,1); + ::print_log("[SCHEDULE] Setting ".$object->{child}->get_object_name." state to ".$self->{'schedule_label_'.$index}); + $self->_set_instance_active_object($$self{instance},$index) if (defined($$self{instance})); + $object->{child}->SUPER::set($self->{'schedule_label_'.$index},$self->get_object_name,1); } elsif ($object->isa('SCHEDULE_Temp')) { ::print_log("[SCHEDULE] set_action - Temp object: ".$object->get_object_name." Parent object: ".$self->get_object_name); @@ -399,7 +380,7 @@ sub new $$self{state_count} = ((scalar @_) - 3); my @states; for my $i (3..(scalar @_)) { if (defined @_[$i]) { $self->{$i-2}=@_[$i]; push (@states, @_[$i]); } } - @{$$self{states}} = @states; + @{$$self{states}} = @states if (defined @states); $$self{parent}->register($self,$child); return $self; } diff --git a/lib/ia7_utilities.pl b/lib/ia7_utilities.pl index b15f55b52..8ed216a73 100644 --- a/lib/ia7_utilities.pl +++ b/lib/ia7_utilities.pl @@ -25,7 +25,7 @@ sub main::ia7_update_schedule { $j++; } else { #delete schedule &main::print_log("deleting schedule " . $i ); - $obj->set_schedule($i,undef,$i); + $obj->set_schedule($i); } } } diff --git a/web/ia7/house/main.shtml b/web/ia7/house/main.shtml index 52a32939b..1c9606ec6 100644 --- a/web/ia7/house/main.shtml +++ b/web/ia7/house/main.shtml @@ -82,7 +82,7 @@

MisterHouse was created by Bruce Winter. Ron Klinkien developed the v2.3 web interface. Kevin Robert Keegan - developed the v4 web interface, updates by H.Plato. IA7 v1.3.100 Font Awesome by Dave Gandy - http://fontawesome.io

+ developed the v4 web interface, updates by H.Plato. IA7 v1.3.300 Font Awesome by Dave Gandy - http://fontawesome.io

diff --git a/web/ia7/include/javascript.js b/web/ia7/include/javascript.js index e08a8d51b..933aad8ea 100644 --- a/web/ia7/include/javascript.js +++ b/web/ia7/include/javascript.js @@ -2322,15 +2322,21 @@ var create_state_modal = function(entity) { if (json_store.objects[entity].schedule !== undefined) { - var add_schedule = function(index,cron,label) { + var add_schedule = function(index,cron,label,state_sets) { if (cron === null) return; if (label == undefined) label = index; + var sched_label_html = "
" + if (state_sets[0] !== null) { + console.log("State sets detected ["+state_sets+"]"); + sched_label_html = "
" + } + var sched_row_html = "
"+sched_label_html+"
" $('#control').find('.sched_control').append("
"); // $('#control').find('.sched_control').append("
"+index+"
"); // $('#control').find('.sched_control').append("
"+label+"
"); // $('#control').find('.sched_control').append("
"); - $('#control').find('.sched_control').append("
"); - +// $('#control').find('.sched_control').append("
"); + $('#control').find('.sched_control').append(sched_row_html); $('.schedule'+index).jqCron({ enabled_minute: true, @@ -2363,6 +2369,12 @@ var create_state_modal = function(entity) { $('.sched_submit').removeClass('btn-default'); $('.sched_submit').addClass('btn-success'); }); + // So that the label and cron cell row heights line up + $('.cron-data').resize(function() { + console.log('cron text has changed '+$(this).attr("id")+" "+$(this).height()); + $(".sched"+$(this).attr("id")+"label").height($(this).height()-12); + }); + $('#control').find('.schedule'+index).find('.schedule_row').append(""); $('.schedrm').on('click', function(){ var sched_id = $( this ).attr("id") @@ -2377,44 +2389,29 @@ var create_state_modal = function(entity) { //updates all the existing indexes? //label should be editable then? }); - - + } $('#control').find('.modal-body').append("

Schedule Control

"); console.log("Schedule object found "+ json_store.objects[entity].schedule); // $('#control').find('.sched_control').append(""); - + var sched_states = json_store.objects[entity].schedule[0][3]; +// if (json_store.objects[entity].schedule[0][3] !== undefined) console.log("sched3="+json_store.objects[entity].schedule[0][3]); for (var i = 1; i < json_store.objects[entity].schedule.length; i++){ -//For now, don't add complexity of parsing the entire cron string, -//Format, index,minute,hour,day of month(ignore),month(ignore),day of week (1-5=weekday, 6-7=weekend [This is wrong, should be 0,6]) -// var sched_label = json_store.objects[entity].schedule[i].substring(0,json_store.objects[entity].schedule[i].indexOf(',')); -// var sched_cron = json_store.objects[entity].schedule[i].substring(json_store.objects[entity].schedule[i].indexOf(',')+1,json_store.objects[entity].schedule[i].length); var sched_index = json_store.objects[entity].schedule[i][0]; var sched_cron = json_store.objects[entity].schedule[i][1]; var sched_label = json_store.objects[entity].schedule[i][2]; - console.log("add_schedule index="+sched_index+" cron="+sched_cron+" label="+sched_label); - add_schedule(sched_index,sched_cron,sched_label); + console.log("add_schedule index="+sched_index+" cron="+sched_cron+" label="+sched_label+" state_set="+sched_states); + add_schedule(sched_index,sched_cron,sched_label,sched_states); } -// $('.schedadd').appendTo('.sched_control'); - $('#control').find('.modal-footer').prepend(''); - - } - console.log('sched length=' + $('.sched_control').length); - - if ($('.sched_control').length == 0) { //no schedule data so no button needed. - $('#control').find('.modal-footer').hide(); - } else { - $('#control').find('.modal-footer').show(); - } + $('#control').find('.modal-footer').prepend(''); $('.schedadd').on('click', function(){ - //alert('add new schedule'); var newid = Number($('.cron_entry:last').attr("id"))+1; if (isNaN(newid)) newid=1; - console.log("index should be "+newid); - add_schedule(newid,'0 0 * * 1-7',newid); + console.log("add new schedule, index should be "+newid+" states are"+sched_states); + add_schedule(newid,'0 0 * * 1-7',newid,sched_states); $('.sched_submit').removeClass('disabled'); $('.sched_submit').removeClass('btn-default'); $('.sched_submit').addClass('btn-success'); @@ -2435,8 +2432,28 @@ var create_state_modal = function(entity) { $('.sched_submit').removeClass('btn-success'); $('.sched_submit').addClass('btn-default'); - }); -// + }); + //only show the controls in advanced ot developer mode + if (display_mode == "simple") { + $('.sched_submit').hide(); + $('.schedrm').hide(); + $('.schedadd').hide(); + $('#control').find('.modal-footer').hide(); + } + + + } + + + //no schedule data so no button needed. + if ($('.sched_control').length == 0) { + $('#control').find('.modal-footer').hide(); + } else { + $('#control').find('.modal-footer').show(); + } + + + if (json_store.ia7_config.prefs.state_log_show !== "no") { //state log show last 4 (separate out set_by as advanced) - keeps being added to each time it opens // could load all log items, and only unhide the last 4 -- maybe later From 6084d04ca758e5559fdc3ee7dbe93011470b89f2 Mon Sep 17 00:00:00 2001 From: "H.Plato" Date: Sat, 27 Aug 2016 14:31:59 -0600 Subject: [PATCH 12/28] IA7 v1.3.350 - working dropdowns for schedules with defined states --- web/ia7/house/main.shtml | 2 +- web/ia7/include/javascript.js | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/web/ia7/house/main.shtml b/web/ia7/house/main.shtml index 1c9606ec6..a5ecb38c7 100644 --- a/web/ia7/house/main.shtml +++ b/web/ia7/house/main.shtml @@ -82,7 +82,7 @@

MisterHouse was created by Bruce Winter. Ron Klinkien developed the v2.3 web interface. Kevin Robert Keegan - developed the v4 web interface, updates by H.Plato. IA7 v1.3.300 Font Awesome by Dave Gandy - http://fontawesome.io

+ developed the v4 web interface, updates by H.Plato. IA7 v1.3.350 Font Awesome by Dave Gandy - http://fontawesome.io

diff --git a/web/ia7/include/javascript.js b/web/ia7/include/javascript.js index 933aad8ea..0b5f901d3 100644 --- a/web/ia7/include/javascript.js +++ b/web/ia7/include/javascript.js @@ -2328,7 +2328,14 @@ var create_state_modal = function(entity) { var sched_label_html = "
" if (state_sets[0] !== null) { console.log("State sets detected ["+state_sets+"]"); - sched_label_html = "
" + var display_label = label + if (display_label.length > 7) display_label = display_label.substring(0,6)+".."; + sched_label_html = ""; } var sched_row_html = "
"+sched_label_html+"
" $('#control').find('.sched_control').append("
"); @@ -2374,7 +2381,17 @@ var create_state_modal = function(entity) { console.log('cron text has changed '+$(this).attr("id")+" "+$(this).height()); $(".sched"+$(this).attr("id")+"label").height($(this).height()-12); }); - + $('.dropdown-menu li a').on('click',function() { + console.log('dropdown'); + $('.schedule'+$(this).attr("id")+'value').attr("label",$(this).text()); + var display_label = $(this).text(); + if (display_label.length > 7) display_label = display_label.substring(0,6)+".."; + $(".sched"+$(this).attr("id")+"label").text(display_label); + $(".sched"+$(this).attr("id")+"label").val($(this).text()); + $('.sched_submit').removeClass('disabled'); + $('.sched_submit').removeClass('btn-default'); + $('.sched_submit').addClass('btn-success'); + }); $('#control').find('.schedule'+index).find('.schedule_row').append(""); $('.schedrm').on('click', function(){ var sched_id = $( this ).attr("id") @@ -2410,8 +2427,10 @@ var create_state_modal = function(entity) { $('.schedadd').on('click', function(){ var newid = Number($('.cron_entry:last').attr("id"))+1; if (isNaN(newid)) newid=1; + var newlabel = newid; + if (sched_states[0] !== null) newlabel=sched_states[0]; console.log("add new schedule, index should be "+newid+" states are"+sched_states); - add_schedule(newid,'0 0 * * 1-7',newid,sched_states); + add_schedule(newid,'0 0 * * 1-7',newlabel,sched_states); $('.sched_submit').removeClass('disabled'); $('.sched_submit').removeClass('btn-default'); $('.sched_submit').addClass('btn-success'); From 917e45c3e914908e46544f5fa07a06ab440443de Mon Sep 17 00:00:00 2001 From: "H.Plato" Date: Mon, 29 Aug 2016 16:10:49 -0600 Subject: [PATCH 13/28] IA7 v1.3.400 - cleaned up schedule code, added in object logger framework --- lib/Generic_Item.pm | 73 ++++++++++++++++++++- lib/ia7_utilities.pl | 2 +- lib/json_server.pl | 2 +- web/ia7/house/main.shtml | 2 +- web/ia7/include/javascript.js | 119 ++++++++++++++-------------------- web/ia7/include/jqCron.css | 8 ++- web/ia7/index.shtml | 34 +++++----- 7 files changed, 148 insertions(+), 92 deletions(-) diff --git a/lib/Generic_Item.pm b/lib/Generic_Item.pm index 6b4c6c2f0..689c37283 100644 --- a/lib/Generic_Item.pm +++ b/lib/Generic_Item.pm @@ -1,5 +1,6 @@ use strict; - +#hp 1133 +# data/object_logs//YYYY/MM.log package Generic_Item_Hash; require Tie::Hash; @@ -1130,6 +1131,9 @@ sub set_state_log { $state = '' unless defined $state; $set_by_name = '' unless defined $set_by_name; $target = '' unless defined $target; +# + $self->logger($state,$set_by_name,$target) if ($self->{logger_enable}); + unshift( @{ $$self{state_log} }, "$main::Time_Date $state set_by=$set_by_name" @@ -1144,6 +1148,25 @@ sub set_state_log { return ( $set_by, $target ); } +=item C + +TODO + +=cut +sub logger { + my ($self,$state,$set_by_name,$target) = @_; + my $object_name = $self->{object_name}; + $object_name =~ s/^\$//; + my $tickcount = int(&::get_tickcount() * 1000); #log in milliseconds + #create directory structure if it doesn't exist + mkdir ($::config_parms{data_dir} . "/object_logs") unless (-d $::config_parms{data_dir} . "/object_logs"); + mkdir ($::config_parms{data_dir} . "/object_logs/" . $object_name) unless (-d $::config_parms{data_dir} . "/object_logs/" . $object_name); + mkdir ($::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . $::Year) unless (-d $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . $::Year); + mkdir ($::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . $::Year . "/" . $::Month) unless (-d $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . $::Year . "/" . $::Month); + #write the data to the log; time, ticks (milliseconds), object, state, set_by, target + &::logit ($::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . $::Year . "/" . $::Month . "/" . $::Mday . ".log", "$main::Time_Date,$tickcount,$object_name,$state,$set_by_name," . ( ($target) ? "$target" : '') ."\n",0); +} + =item C TODO @@ -1244,6 +1267,54 @@ sub xPL_enable { $self->{xpl_enable} = $enable; } +=item C + +TODO. Can only be run at startup or reload. + +=cut + +sub logger_enable { + return unless $main::Reload; + my ( $self, $enable ) = @_; + $self->{logger_enable} = $enable; +} + +=item C + +Returns 1 if logger is enabled on the object. Otherwise 0. + +=cut + +sub get_logger_status { + my ( $self, $enable ) = @_; + return ($self->{logger_enable} ? 1 : 0); +} + +=item C + +Returns logged data at date, back days number of days +Date format is epoch +=cut + +sub get_logger_data { + my ( $self, $epoch, $days ) = @_; + $days = 0 unless (defined $days); + my $object_name = $self->{object_name}; + $object_name =~ s/^\$//; + my $data = ""; + for (my $i = 0; $i < $days; $i++) { + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($epoch); +# print "Checking " . $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . "\n"; +# print "Reading " . $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . "\n" if ( -e $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . ".log"); + $data .= ::file_read($::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . ".log") if ( -e $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . ".log"); + $epoch = $epoch - (60*60*24); + } + + return $data; +} + + + =item C If the state of the generic_item changes, then code will trigger, with the lexical variables $state and $object getting set. The code is a string that will be eval'd and the variables are available to it, but not to any subroutines called by it unless you pass them. You can also set the state variable explicitly since you usually know the item. The code is a string that will be eval'd. diff --git a/lib/ia7_utilities.pl b/lib/ia7_utilities.pl index 8ed216a73..816ed72ae 100644 --- a/lib/ia7_utilities.pl +++ b/lib/ia7_utilities.pl @@ -25,7 +25,7 @@ sub main::ia7_update_schedule { $j++; } else { #delete schedule &main::print_log("deleting schedule " . $i ); - $obj->set_schedule($i); + $obj->delete_schedule($i); } } } diff --git a/lib/json_server.pl b/lib/json_server.pl index 941b3014e..d11f2d50d 100644 --- a/lib/json_server.pl +++ b/lib/json_server.pl @@ -884,7 +884,7 @@ sub json_object_detail { my %json_objects; my %json_complete_object; my @f = qw( category filename measurement rf_id set_by members - state states state_log type label sort_order groups hidden parents schedule + state states state_log type label sort_order groups hidden parents schedule logger_status idle_time text html seconds_remaining fp_location fp_icons fp_icon_set img link level); # Build list of fields based on those requested. diff --git a/web/ia7/house/main.shtml b/web/ia7/house/main.shtml index a5ecb38c7..cdade12e4 100644 --- a/web/ia7/house/main.shtml +++ b/web/ia7/house/main.shtml @@ -82,7 +82,7 @@

MisterHouse was created by Bruce Winter. Ron Klinkien developed the v2.3 web interface. Kevin Robert Keegan - developed the v4 web interface, updates by H.Plato. IA7 v1.3.350 Font Awesome by Dave Gandy - http://fontawesome.io

+ developed the v4 web interface, updates by H.Plato. IA7 v1.3.400 Font Awesome by Dave Gandy - http://fontawesome.io

diff --git a/web/ia7/include/javascript.js b/web/ia7/include/javascript.js index 0b5f901d3..1684ca03c 100644 --- a/web/ia7/include/javascript.js +++ b/web/ia7/include/javascript.js @@ -552,7 +552,7 @@ var loadList = function() { var button_text = ''; var button_html = ''; var entity_arr = []; - URLHash.fields = "category,label,sort_order,members,state,states,state_log,hidden,type,text,schedule"; + URLHash.fields = "category,label,sort_order,members,state,states,state_log,hidden,type,text,schedule,logger_status"; $.ajax({ type: "GET", url: "/json/"+HashtoJSONArgs(URLHash), @@ -858,7 +858,7 @@ var sortArrayByArray = function (listArray, sortArray){ //Used to dynamically update the state of objects var updateList = function(path) { var URLHash = URLToHash(); - URLHash.fields = "state,state_log,schedule,type"; + URLHash.fields = "state,state_log,schedule,logger_status,type"; URLHash.long_poll = 'true'; URLHash.time = json_store.meta.time; if (updateSocket !== undefined && updateSocket.readyState != 4){ @@ -919,7 +919,7 @@ var updateItem = function(item,link,time) { time = ""; } var path_str = "/objects" // override, for now, would be good to add voice_cmds - var arg_str = "fields=state,states,label,state_log,schedule&long_poll=true&items="+item+"&time="+time; + var arg_str = "fields=state,states,label,state_log,schedule,logger_status&long_poll=true&items="+item+"&time="+time; updateSocket = $.ajax({ type: "GET", url: "/LONG_POLL?json('GET','"+path_str+"','"+arg_str+"')", @@ -967,7 +967,7 @@ var updateStaticPage = function(link,time) { } }) var URLHash = URLToHash(); - URLHash.fields = "state,states,state_log,schedule,label,type"; + URLHash.fields = "state,states,state_log,schedule,logger_status,label,type"; URLHash.long_poll = 'true'; URLHash.time = json_store.meta.time; if (updateSocket !== undefined && updateSocket.readyState != 4){ @@ -976,7 +976,7 @@ var updateStaticPage = function(link,time) { } var path_str = "/objects" // override, for now, would be good to add voice_cmds - var arg_str = "fields=state%2Cstates%2Cstate_log%2Cschedule%2Clabel&long_poll=true&items="+items+"&time="+time; + var arg_str = "fields=state%2Cstates%2Cstate_log%2Cschedule%2Clogger_status%2Clabel&long_poll=true&items="+items+"&time="+time; updateSocket = $.ajax({ type: "GET", @@ -1081,7 +1081,7 @@ var loadCollection = function(collection_keys) { if (item !== undefined) { if (json_store.objects[item] === undefined) { var path_str = "/objects"; - var arg_str = "fields=state,states,label,state_log,schedule&items="+item; + var arg_str = "fields=state,states,label,state_log,schedule,logger_status,&items="+item; $.ajax({ type: "GET", url: "/json"+path_str+"?"+arg_str, @@ -1937,7 +1937,7 @@ var floorplan = function(group,time) { }; var path_str = "/objects"; - var fields = "fields=fp_location,state,states,fp_icons,schedule,fp_icon_set,img,link,label,type"; + var fields = "fields=fp_location,state,states,fp_icons,schedule,logger_status,fp_icon_set,img,link,label,type"; if (json_store.ia7_config.prefs.state_log_show === "yes") fields += ",state_log"; @@ -2316,22 +2316,20 @@ var create_state_modal = function(entity) { //remove states from anything that doesn't have more than 1 state $('#control').find('.states').find('.btn-group').remove(); } -// Unique Schedule Data here + $('#control').find('.modal-body').find('.sched_control').remove(); $('#control').find('.modal-footer').find('.sched_submit').remove(); - + // Unique Schedule Data here if (json_store.objects[entity].schedule !== undefined) { var add_schedule = function(index,cron,label,state_sets) { if (cron === null) return; if (label == undefined) label = index; - var sched_label_html = "
" + var sched_label_html = "
" if (state_sets[0] !== null) { - console.log("State sets detected ["+state_sets+"]"); var display_label = label if (display_label.length > 7) display_label = display_label.substring(0,6)+".."; - sched_label_html = ""; } - var sched_row_html = "
"+sched_label_html+"
" + var sched_row_html = "
"+sched_label_html+"
" $('#control').find('.sched_control').append("
"); $('#control').find('.sched_control').append(sched_row_html); @@ -2371,7 +2371,6 @@ var create_state_modal = function(entity) { }); // So that the label and cron cell row heights line up $('.cron-data').resize(function() { - console.log('cron text has changed '+$(this).attr("id")+" "+$(this).height()); $(".sched"+$(this).attr("id")+"label").height($(this).height()-12); }); $('.dropdown-menu li a').on('click',function() { @@ -2427,6 +2426,7 @@ var create_state_modal = function(entity) { }); string = string.replace(/,\s*$/, ""); //remove the last comma var url="/SUB?ia7_update_schedule"+encodeURI("("+$(this).parents('.control-dialog').attr("entity")+","+string+")"); +// alert(url); $.get(url); $('.sched_submit').addClass('disabled'); $('.sched_submit').removeClass('btn-success'); From ec5d98d2cd82c7402b54a30cdc221d1b91b1f6d2 Mon Sep 17 00:00:00 2001 From: "H.Plato" Date: Wed, 31 Aug 2016 16:26:54 -0600 Subject: [PATCH 15/28] IA7 v1.3.500 - object logger graphing and modal links --- lib/Generic_Item.pm | 5 +- lib/json_server.pl | 24 +++-- web/ia7/house/main.shtml | 2 +- web/ia7/include/javascript.js | 179 +++++++++++++++++++++++++++++++++- web/ia7/index.shtml | 2 +- 5 files changed, 196 insertions(+), 16 deletions(-) diff --git a/lib/Generic_Item.pm b/lib/Generic_Item.pm index 689c37283..09128f4fc 100644 --- a/lib/Generic_Item.pm +++ b/lib/Generic_Item.pm @@ -1157,7 +1157,7 @@ sub logger { my ($self,$state,$set_by_name,$target) = @_; my $object_name = $self->{object_name}; $object_name =~ s/^\$//; - my $tickcount = int(&::get_tickcount() * 1000); #log in milliseconds + my $tickcount = int(&::get_tickcount()); #log in milliseconds #create directory structure if it doesn't exist mkdir ($::config_parms{data_dir} . "/object_logs") unless (-d $::config_parms{data_dir} . "/object_logs"); mkdir ($::config_parms{data_dir} . "/object_logs/" . $object_name) unless (-d $::config_parms{data_dir} . "/object_logs/" . $object_name); @@ -1302,12 +1302,13 @@ sub get_logger_data { my $object_name = $self->{object_name}; $object_name =~ s/^\$//; my $data = ""; + $epoch = $epoch - ($days * 60 * 60 * 24); for (my $i = 0; $i < $days; $i++) { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($epoch); # print "Checking " . $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . "\n"; # print "Reading " . $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . "\n" if ( -e $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . ".log"); $data .= ::file_read($::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . ".log") if ( -e $::config_parms{data_dir} . "/object_logs/" . $object_name . "/" . ($year + 1900) . "/" . ($mon + 1) . "/" . $mday . ".log"); - $epoch = $epoch - (60*60*24); + $epoch = $epoch + (60*60*24); } return $data; diff --git a/lib/json_server.pl b/lib/json_server.pl index 91de83df2..a3561dbdb 100644 --- a/lib/json_server.pl +++ b/lib/json_server.pl @@ -425,13 +425,13 @@ sub json_get { 'enable' => 100, 'enabled' => 100, 'online' => 100, - 'off' => 0, - 'close' => 0, - 'closed' => 0, - 'still' => 0, - 'disable' => 0, - 'disabled' => 0, - 'offline' => 0, + 'off' => -100, + 'close' => -100, + 'closed' => -100, + 'still' => -100, + 'disable' => -100, + 'disabled' => -100, + 'offline' => -100, 'dim' => 50, ); my $unknown_value = 40; @@ -445,6 +445,7 @@ sub json_get { $days = $args{days}[0] if (defined $args{days}[0]); foreach my $name ( @{ $args{items} } ) { my $o = &get_object_by_name($name); + next unless (defined $o); next unless $o->get_logger_status(); my $label = $o->set_label(); $label = $name unless (defined $label); @@ -468,7 +469,7 @@ sub json_get { } } $states{$value} = $state; - push @{$dataset[$index]->{data}}, [ $time2, $value ]; + push @{$dataset[$index]->{data}}, [ int($time2), int($value) ]; } push @{$dataset[$index]->{label}}, $label; $index++; @@ -478,7 +479,12 @@ sub json_get { for my $j (sort keys %states) { push @yaxticks, [ $j, $states{$j} ]; } - $data{'yaxis'}->{'ticks'} = \@yaxticks; #\%states; + $data{'options'}->{'yaxis'}->{'ticks'} = \@yaxticks; #\%states; + $data{'options'}->{'legend'}->{'show'} = "true"; + $data{'options'}->{'xaxis'}->{'mode'} = "time"; + $data{'options'}->{'points'}->{'show'} = "true"; + $data{'options'}->{'xaxis'}->{'timezone'} = "browser"; + $data{'options'}->{'grid'}->{'hoverable'} = "true"; $data{'data'} = \@dataset; $json_data{'history'} = \%data; } diff --git a/web/ia7/house/main.shtml b/web/ia7/house/main.shtml index cdade12e4..eb4b9c8ee 100644 --- a/web/ia7/house/main.shtml +++ b/web/ia7/house/main.shtml @@ -82,7 +82,7 @@

MisterHouse was created by Bruce Winter. Ron Klinkien developed the v2.3 web interface. Kevin Robert Keegan - developed the v4 web interface, updates by H.Plato. IA7 v1.3.400 Font Awesome by Dave Gandy - http://fontawesome.io

+ developed the v4 web interface, updates by H.Plato. IA7 v1.3.500 Font Awesome by Dave Gandy - http://fontawesome.io

diff --git a/web/ia7/include/javascript.js b/web/ia7/include/javascript.js index b924f803a..13b71cdd0 100644 --- a/web/ia7/include/javascript.js +++ b/web/ia7/include/javascript.js @@ -238,7 +238,11 @@ function changePage (){ else if(path.indexOf('rrd') === 0){ var path_arg = path.split('?'); graph_rrd(path_arg[1],path_arg[2]); - } + } + else if(path.indexOf('history') === 0){ + var path_arg = path.split('?'); + graph_history(path_arg[1],"x",path_arg[2]); + } else if(URLHash._request == 'trigger'){ trigger(); } @@ -1618,6 +1622,166 @@ var graph_rrd = function(start,group,time) { }); }; +var graph_history = function(items,start,days,time) { + + var URLHash = URLToHash(); + if (typeof time === 'undefined'){ + $('#list_content').html("
"); + $('#top-graph').append("
"); + $('#top-graph').append("
"); + $('#top-graph').append("

"); + + time = 0; + } + + URLHash.time = time; + URLHash.long_poll = 'true'; + if (updateSocket !== undefined && updateSocket.readyState != 4){ + // Only allow one update thread to run at once + updateSocket.abort(); + } + var path_str = "/history" + //var arg_str = "start="+start+"&group="+group+"&long_poll=true&time="+time; + //var arg_str = "start="+start+"&group="+group+"&time="+time; + arg_str = "&items="+items+"&days="+days+"&time="+time; + updateSocket = $.ajax({ + type: "GET", + //url: "/LONG_POLL?json('GET','"+path_str+"','"+arg_str+"')", + url: "/json"+path_str+"?"+arg_str, + dataType: "json", + success: function( json, statusText, jqXHR ) { + var requestTime = time; + if (jqXHR.status == 200) { + JSONStore(json); + // HP should probably use jquery, but couldn't get sequencing right. + // HP jquery would allow selected values to be replaced in the future. + + if (json.data.data !== undefined) { //If no data, at least show the header and an error +//TODO + } + var dropdown_html = ''; + + $('#hist-periods').append(dropdown_html); + + + //sort the legend + json.data.data.sort(function(a, b){ + if(a.label < b.label) return -1; + if(a.label > b.label) return 1; + return 0; + }) + + // put the selection list on the side. + for (var i = 0; i < json.data.data.length; i++){ + var legli = $('
  • ').appendTo('#hist-legend'); + $('').appendTo(legli); + $('
  • ').appendTo('#hist-legend'); - $('').appendTo(legli); - $('
  • ').appendTo('#hist-legend'); + $('').appendTo(legli); + $('
  • "; + $('#rtable').html(html); + } requestTime = json.meta.time; } if (jqXHR.status == 200 || jqXHR.status == 204) { //Call update again, if page is still here //KRK best way to handle this is likely to check the URL hash - if ($('#top-graph').length !== 0){ //TODO live updates - //If the graph page is still active request more data -// graph_rrd(start,group,requestTime); - } } } }); From 02cc94cc57c1f1b68eb11db5f2c917218af35a6e Mon Sep 17 00:00:00 2001 From: "H.Plato" Date: Tue, 20 Sep 2016 19:25:07 -0600 Subject: [PATCH 27/28] fixed table formatting --- web/ia7/include/javascript.js | 13 +++++-------- web/ia7/index.shtml | 7 ++++++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/web/ia7/include/javascript.js b/web/ia7/include/javascript.js index 1c1bf4df2..36c896fae 100644 --- a/web/ia7/include/javascript.js +++ b/web/ia7/include/javascript.js @@ -1629,9 +1629,9 @@ var object_history = function(items,start,days,time) { $('#top-graph').append("
    "); $('#top-graph').append("

    "); } else { - $('#list_content').html("
    "); - $('#display_table').append("
    "); - $('#display_table').append("
    "); + $('#list_content').html("
    "); + $('#hist-table').append("
    "); + $('#hist-table').append("
    "); } time = 0; } @@ -1704,7 +1704,6 @@ var object_history = function(items,start,days,time) { if(a.label > b.label) return 1; return 0; }) -console.log("g1"); // put the selection list on the side. for (var i = 0; i < json.data.data.length; i++){ var legli = $('
  • ').appendTo('#hist-legend'); @@ -1715,7 +1714,6 @@ console.log("g1"); 'for': json.data.data[i].label }).appendTo(legli); } -console.log("g2"); function plotAccordingToChoices() { var data = []; @@ -1731,11 +1729,10 @@ console.log("g2"); // take away the border so that it looks better and span the graph from start to end. json.data.options.grid.borderWidth = 0; -//TODO fix time from new format - get it from the datepicker? json.data.options.xaxis.min = new Date($('.hist_end').val()).getTime(); json.data.options.xaxis.max = new Date($('.hist_start').val()).getTime() + (24 * 60 * 60 * 1000); -console.log("data="+JSON.stringify(data)); -console.log("xmin="+json.data.options.xaxis.min+" xmax="+json.data.options.xaxis.max); +//console.log("data="+JSON.stringify(data)); +//console.log("xmin="+json.data.options.xaxis.min+" xmax="+json.data.options.xaxis.max); $.plot($("#hist-graph"), data, json.data.options); $('.legend').hide(); } diff --git a/web/ia7/index.shtml b/web/ia7/index.shtml index 8939aba41..9ea21d99f 100644 --- a/web/ia7/index.shtml +++ b/web/ia7/index.shtml @@ -156,6 +156,12 @@ #top-graph { margin-left: 10px; } + #hist-table { + margin-left: 10px; + } + .hist-table-margin { + padding-right: 35px; + } #rrd-graph { width:700px; height:500px; @@ -173,7 +179,6 @@ float:left; margin-left:50px; } - .alerts { position: absolute; top: 3px; From 9f09508c5c770df28b3865532d92af281e0a133e Mon Sep 17 00:00:00 2001 From: hplato Date: Sun, 25 Sep 2016 14:53:57 -0600 Subject: [PATCH 28/28] Cron & Tobi Fixes Fixed jqCron needing 1-7 for DOW. added in conversion subroutine. Included Tobi's fixes for datepicker. --- web/ia7/include/javascript.js | 100 +++++++++++++++++++++++----------- web/ia7/include/jqCron.en.js | 4 +- 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/web/ia7/include/javascript.js b/web/ia7/include/javascript.js index fbd24d403..c06d61b55 100644 --- a/web/ia7/include/javascript.js +++ b/web/ia7/include/javascript.js @@ -1690,8 +1690,10 @@ var object_history = function(items,start,days,time) { $('.update_history').click(function() { console.log ("start="+$('.hist_start').val()+" end="+$('.hist_end').val()); - var new_start = new Date($('.hist_start').val()).getTime(); - var new_end = new Date($('.hist_end').val()).getTime(); +// var new_start = new Date($('.hist_start').val()).getTime(); +// var new_end = new Date($('.hist_end').val()).getTime(); + var new_start = new Date($('.hist_start').val().split('-')).getTime(); + var new_end = new Date($('.hist_end').val().split('-')).getTime(); var end_days = (new_start - new_end) / (24 * 60 * 60 * 1000) new_start = new_start / 1000; object_history(items,new_start,end_days); @@ -1722,15 +1724,18 @@ var object_history = function(items,start,days,time) { for (var i = 0; i < json.data.data.length; i++) { if (json.data.data[i].label == key) { data.push(json.data.data[i]); - return true; + return true; } } }); // take away the border so that it looks better and span the graph from start to end. json.data.options.grid.borderWidth = 0; - json.data.options.xaxis.min = new Date($('.hist_end').val()).getTime(); - json.data.options.xaxis.max = new Date($('.hist_start').val()).getTime() + (24 * 60 * 60 * 1000); +// json.data.options.xaxis.min = new Date($('.hist_end').val()).getTime(); +// json.data.options.xaxis.max = new Date($('.hist_start').val()).getTime() + (24 * 60 * 60 * 1000); + json.data.options.xaxis.min = new Date($('.hist_end').val().split('-')).getTime(); + json.data.options.xaxis.max = new Date($('.hist_start').val().split('-')).getTime() + (24 * 60 * 60 * 1000); + //console.log("data="+JSON.stringify(data)); //console.log("xmin="+json.data.options.xaxis.min+" xmax="+json.data.options.xaxis.max); $.plot($("#hist-graph"), data, json.data.options); @@ -1833,6 +1838,7 @@ var fp_display_height=0; // updated by fp_resize_floorplan_image var fp_scale = 100; // updated by fp_reposition_entities var fp_grabbed_entity = null; // store item for drag & drop var fp_icon_select_item_id = null; // store item id on right click for icon set selection +var fp_icon_image_size = 48; var noDragDrop = function() { return false; @@ -1853,7 +1859,7 @@ var fp_getOrCreateIcon = function (json, entity, i, coords){ ''+ + '>'+ ''; if (coords !== ""){ $('#graphic').append(html); @@ -1884,7 +1890,8 @@ var fp_resize_floorplan_image = function(){ var fp_reposition_entities = function(){ var t0 = performance.now(); - var offset = $("#fp_graphic").offset(); + var fp_graphic_offset = $("#fp_graphic").offset(); + console.log("fp_graphic_offset: "+ JSON.stringify(fp_graphic_offset)); var width = fp_display_width; var hight = fp_display_height; var onePercentWidthInPx = width/100; @@ -1892,8 +1899,8 @@ var fp_reposition_entities = function(){ var fp_get_offset_from_location = function(item) { var y = item[0]; var x = item[1]; - var newy = offset.top + y * onePercentHeightInPx; - var newx = offset.left + x * onePercentWidthInPx; + var newy = fp_graphic_offset.top + y * onePercentHeightInPx; + var newx = fp_graphic_offset.left + x * onePercentWidthInPx; return { "top": newy, "left": newx @@ -1918,21 +1925,22 @@ var fp_reposition_entities = function(){ } else { nwidth = 790; } - - fp_scale = Math.round( width/nwidth * 100); + var fp_scale = width/nwidth; + var fp_scale_percent = Math.round( fp_scale * 100); - console.log("width="+width+" nwidth="+nwidth+" scale="+fp_scale); + console.log("width="+width+" nwidth="+nwidth+" scale="+fp_scale_percent); // update the location of all the objects... $(".floorplan_item").each(function(index) { var classstr = $(this).attr("class"); var coords = classstr.split(/coords=/)[1]; - $(this).width(fp_scale + "%"); + $(this).width(fp_scale_percent + "%"); if (coords.length === 0){ return; } var fp_location = coords.split(/x/); var fp_offset = fp_get_offset_from_location(fp_location); + console.log("coords="+coords); // this seems to make the repositioning slow // ~ 300+ms on my nexus7 firefox-beta vs <100ms with this code commented out @@ -1942,13 +1950,14 @@ var fp_reposition_entities = function(){ // } else { // $(this).attr('src',$(this).attr('src').replace('32.png','48.png')); // } - - var adjust = $(this).width()/2; + var element_id = $(this).attr('id'); + var adjust = fp_icon_image_size*fp_scale/2; + console.log("adjust="+adjust+" fp_offset.top="+fp_offset.top+" fp_offset.left="+fp_offset.left); var fp_off_center = { "top": fp_offset.top - adjust, "left": fp_offset.left - adjust }; - fp_set_pos($(this).attr('id'), fp_off_center); + fp_set_pos(element_id, fp_off_center); }); $('.icon_select img').each(function(){ @@ -1962,7 +1971,23 @@ var fp_set_pos = function(id, offset){ var item = $('#' + id); // do not move the span, this make the popup to narrow somehow // item.closest("span").offset(offset); + var left11 = item.css("left"); + var left12 = item[0].style.left; + var top11 = item.css("top"); + var top12 = item[0].style.top; + var before = item.offset(); + var init = false + if (item.css("left") == "auto") { + console.log("auto found, fixing left property"); + offset.left = 0 - fp_icon_image_size/2; + } item.offset(offset); + var after = item.offset(); + var left21 = item.css("left"); + var left22 = item[0].style.left; + console.log("offset.top="+offset.top+" offset.left="+offset.left+" before.top="+before.top+" before.left="+before.left+" after.top="+after.top+" after.left="+after.left); + console.log("top11="+top11+" top12="+top12); + console.log("left11="+left11+" left12="+left12+" left21="+left21+" left22="+left22); }; var fp_is_point_on_fp = function (p){ @@ -2062,14 +2087,14 @@ var floorplan = function(group,time) { if (fp_grabbed_entity === null) return; - set_set_coordinates_from_offset(fp_grabbed_entity.id); + set_coordinates_from_offset(fp_grabbed_entity.id); fp_reposition_entities(); fp_grabbed_entity = null; }); } - var set_set_coordinates_from_offset = function (id) + var set_coordinates_from_offset = function (id) { var E = $('#'+id); var offsetE = E.offset(); @@ -2403,14 +2428,13 @@ var get_fp_image = function(item,size,orientation) { var image_name; var image_color = getButtonColor(item.state); var baseimg_width = $(window).width(); - var image_size = "48"; - // if (baseimg_width < 500) image_size = "32" // iphone scaling - //kvar image_size = "32" + // if (baseimg_width < 500) fp_icon_image_size = "32" // iphone scaling + //kvar fp_icon_image_size = "32" if (item.fp_icons !== undefined) { if (item.fp_icons[item.state] !== undefined) return item.fp_icons[item.state]; } if (item.fp_icon_set !== undefined) { - return "fp_"+item.fp_icon_set+"_"+image_color+"_"+image_size+".png"; + return "fp_"+item.fp_icon_set+"_"+image_color+"_"+fp_icon_image_size+".png"; } // if item.fp_icons.return item.fp_icons[state]; if(item.type === "Light_Item" || item.type === "Fan_Light" || @@ -2422,25 +2446,25 @@ var get_fp_image = function(item,size,orientation) { item.type === "UIO_Item" || item.type === "X10_Item" || item.type === "xPL_Plugwise" || item.type === "X10_Appliance") { - return "fp_light_"+image_color+"_"+image_size+".png"; + return "fp_light_"+image_color+"_"+fp_icon_image_size+".png"; } if(item.type === "Motion_Item" || item.type === "X10_Sensor" || item.type === "Insteon::MotionSensor" ) { - return "fp_motion_"+image_color+"_"+image_size+".png"; + return "fp_motion_"+image_color+"_"+fp_icon_image_size+".png"; } if(item.type === "Door_Item" || item.type === "Insteon::IOLinc_door") { - return "fp_door_"+image_color+"_"+image_size+".png"; + return "fp_door_"+image_color+"_"+fp_icon_image_size+".png"; } if(item.type === "FPCamera_Item" ) { - return "fp_camera_default_"+image_size+".png"; + return "fp_camera_default_"+fp_icon_image_size+".png"; } - return "fp_unknown_info_"+image_size+".png"; + return "fp_unknown_info_"+fp_icon_image_size+".png"; }; var create_img_popover = function(entity) { @@ -2530,7 +2554,18 @@ var create_state_modal = function(entity) { $('#control').find('.modal-footer').find('.sched_submit').remove(); // Unique Schedule Data here if (json_store.objects[entity].schedule !== undefined) { - + + var modify_jqcon_dow = function(cronstr,offset) { + var cron = cronstr.split(/\s+/); + console.log("dow="+cron[cron.length-1]); + cron[cron.length-1] = cron[cron.length-1].replace(/\d/gi, function adjust(x) { + console.log("x="+x+" offset="+offset); + return parseInt(x) + parseInt(offset); + });; + console.log("dow="+cron[cron.length-1]); + return cron.join(" "); + } + var add_schedule = function(index,cron,label,state_sets) { if (cron === null) return; if (label == undefined) label = index; @@ -2609,7 +2644,7 @@ var create_state_modal = function(entity) { console.log("schedule.length="+json_store.objects[entity].schedule.length); for (var i = 1; i < json_store.objects[entity].schedule.length; i++){ var sched_index = json_store.objects[entity].schedule[i][0]; - var sched_cron = json_store.objects[entity].schedule[i][1]; + var sched_cron = modify_jqcon_dow(json_store.objects[entity].schedule[i][1],1); var sched_label = json_store.objects[entity].schedule[i][2]; console.log("si="+sched_index+",sc="+sched_cron+",sl="+sched_label+",ss="+sched_states); add_schedule(sched_index,sched_cron,sched_label,sched_states); @@ -2633,7 +2668,10 @@ var create_state_modal = function(entity) { if ($(this).hasClass("disabled")) return; var string = ""; $('.mhsched').each(function(index,value) { - string += $( this ).attr("id") + ',"' + $( this ).text() + '",' + $( this ).attr("label") + ','; + console.log("string="+string); +// string += $( this ).attr("id") + ',"' + $( this ).text() + '",' + $( this ).attr("label") + ','; + string += $( this ).attr("id") + ',"' + modify_jqcon_dow($(this).text(),"-1") + '",' + $( this ).attr("label") + ','; + console.log("string="+string); }); string = string.replace(/,\s*$/, ""); //remove the last comma var url="/SUB?ia7_update_schedule"+encodeURI("("+$(this).parents('.control-dialog').attr("entity")+","+string+")"); @@ -3019,4 +3057,4 @@ $(document).ready(function() { // // You should have received a copy of the GNU General Public License along with this program; // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// +// \ No newline at end of file diff --git a/web/ia7/include/jqCron.en.js b/web/ia7/include/jqCron.en.js index 779d36836..9823c5bd4 100644 --- a/web/ia7/include/jqCron.en.js +++ b/web/ia7/include/jqCron.en.js @@ -34,7 +34,7 @@ jqCronDefaultSettings.texts.en = { error2: 'Bad number of elements', error3: 'The jquery_element should be set into jqCron settings', error4: 'Unrecognized expression', - weekdays_short: ['M','Tu','W','Th','F','Sa','Su'], - weekdays: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'], + weekdays_short: ['Su','M','Tu','W','Th','F','Sa'], + weekdays: ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'], months: ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'] };