From 89c19c55c609fc0841b559310bc321c7e0ffd7e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Schr=C3=B6der?= Date: Fri, 8 May 2015 16:57:55 +0200 Subject: [PATCH] Added schedule editor --- luciexpress/htdocs/index.html | 1 + luciexpress/htdocs/js/app.js | 3 +- luciexpress/htdocs/js/uci.js | 13 +- .../htdocs/lib/js/angular-checklist-model.js | 116 ++++++++++++++++++ .../plugins/core/widgets/luci.config.js | 11 +- .../plugins/core/widgets/luci.dropdown.js | 6 +- .../plugins/wifi/pages/wifi.schedule.html | 2 +- .../plugins/wifi/pages/wifi.schedule.js | 10 ++ .../widgets/uci.wireless.schedule.edit.html | 30 +++++ .../widgets/uci.wireless.schedule.edit.js | 76 ++++++++++++ 10 files changed, 258 insertions(+), 10 deletions(-) create mode 100644 luciexpress/htdocs/lib/js/angular-checklist-model.js create mode 100644 luciexpress/htdocs/plugins/wifi/widgets/uci.wireless.schedule.edit.html create mode 100644 luciexpress/htdocs/plugins/wifi/widgets/uci.wireless.schedule.edit.js diff --git a/luciexpress/htdocs/index.html b/luciexpress/htdocs/index.html index a3a57dfde..42fb9573b 100644 --- a/luciexpress/htdocs/index.html +++ b/luciexpress/htdocs/index.html @@ -37,6 +37,7 @@ + diff --git a/luciexpress/htdocs/js/app.js b/luciexpress/htdocs/js/app.js index de69bff72..0ba2b7e30 100644 --- a/luciexpress/htdocs/js/app.js +++ b/luciexpress/htdocs/js/app.js @@ -61,7 +61,8 @@ angular.module("luci", [ 'angularModalService', "uiSwitch", "ngAnimate", - "gettext" + "gettext", + "checklist-model" ]); angular.module("luci") diff --git a/luciexpress/htdocs/js/uci.js b/luciexpress/htdocs/js/uci.js index 24fbeebd1..472bacc1f 100644 --- a/luciexpress/htdocs/js/uci.js +++ b/luciexpress/htdocs/js/uci.js @@ -192,6 +192,9 @@ angular.module("luci") function UCIField(value, schema){ if(!schema) throw new Error("No schema specified for the field!"); this.ovalue = value; + if(value != null && value instanceof Array) { + this.ovalue = []; Object.assign(this.ovalue, value); + } this.dirty = false; this.uvalue = undefined; this.schema = schema; @@ -199,6 +202,9 @@ angular.module("luci") UCIField.prototype = { $reset: function(value){ this.ovalue = this.uvalue = value; + if(value != null && value instanceof Array) { + this.ovalue = []; Object.assign(this.ovalue, value); + } this.dirty = false; }, get value(){ @@ -497,8 +503,11 @@ angular.module("luci") next("could not commit config: "+err); }); }, function(err){ - if(err) deferred.reject(err); - else deferred.resolve(err); + // this is to always make sure that we do this outside of this code flow + setTimeout(function(){ + if(err) deferred.reject(err); + else deferred.resolve(err); + },0); }); }); return deferred.promise(); diff --git a/luciexpress/htdocs/lib/js/angular-checklist-model.js b/luciexpress/htdocs/lib/js/angular-checklist-model.js new file mode 100644 index 000000000..146fd91e8 --- /dev/null +++ b/luciexpress/htdocs/lib/js/angular-checklist-model.js @@ -0,0 +1,116 @@ +/** + * Checklist-model + * AngularJS directive for list of checkboxes + */ + +angular.module('checklist-model', []) +.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) { + // contains + function contains(arr, item, comparator) { + if (angular.isArray(arr)) { + for (var i = arr.length; i--;) { + if (comparator(arr[i], item)) { + return true; + } + } + } + return false; + } + + // add + function add(arr, item, comparator) { + arr = angular.isArray(arr) ? arr : []; + if(!contains(arr, item, comparator)) { + arr.push(item); + } + return arr; + } + + // remove + function remove(arr, item, comparator) { + if (angular.isArray(arr)) { + for (var i = arr.length; i--;) { + if (comparator(arr[i], item)) { + arr.splice(i, 1); + break; + } + } + } + return arr; + } + + // http://stackoverflow.com/a/19228302/1458162 + function postLinkFn(scope, elem, attrs) { + // compile with `ng-model` pointing to `checked` + $compile(elem)(scope); + + // getter / setter for original model + var getter = $parse(attrs.checklistModel); + var setter = getter.assign; + var checklistChange = $parse(attrs.checklistChange); + + // value added to list + var value = $parse(attrs.checklistValue)(scope.$parent); + + + var comparator = angular.equals; + + if (attrs.hasOwnProperty('checklistComparator')){ + comparator = $parse(attrs.checklistComparator)(scope.$parent); + } + + // watch UI checked change + scope.$watch('checked', function(newValue, oldValue) { + if (newValue === oldValue) { + return; + } + var current = getter(scope.$parent); + if (newValue === true) { + setter(scope.$parent, add(current, value, comparator)); + } else { + setter(scope.$parent, remove(current, value, comparator)); + } + + if (checklistChange) { + checklistChange(scope); + } + }); + + // declare one function to be used for both $watch functions + function setChecked(newArr, oldArr) { + scope.checked = contains(newArr, value, comparator); + } + + // watch original model change + // use the faster $watchCollection method if it's available + if (angular.isFunction(scope.$parent.$watchCollection)) { + scope.$parent.$watchCollection(attrs.checklistModel, setChecked); + } else { + scope.$parent.$watch(attrs.checklistModel, setChecked, true); + } + } + + return { + restrict: 'A', + priority: 1000, + terminal: true, + scope: true, + compile: function(tElement, tAttrs) { + if (tElement[0].tagName !== 'INPUT' || tAttrs.type !== 'checkbox') { + throw 'checklist-model should be applied to `input[type="checkbox"]`.'; + } + + if (!tAttrs.checklistValue) { + throw 'You should provide `checklist-value`.'; + } + + // exclude recursion + tElement.removeAttr('checklist-model'); + + // local scope var storing individual checkbox model + tElement.attr('ng-model', 'checked'); + + return postLinkFn; + } + }; +}]); diff --git a/luciexpress/htdocs/plugins/core/widgets/luci.config.js b/luciexpress/htdocs/plugins/core/widgets/luci.config.js index fe92431c1..20583037c 100644 --- a/luciexpress/htdocs/plugins/core/widgets/luci.config.js +++ b/luciexpress/htdocs/plugins/core/widgets/luci.config.js @@ -43,17 +43,20 @@ $juci.module("core") var plugin_root = $juci.module("core").plugin_root; return { template: '
'+ - '
'+ + '
'+ ''+ '
'+ - '
'+ - '
'+ + '
'+ + '
'+ '
', replace: true, scope: { title: "@" }, - transclude: true + transclude: true, + link: function (scope, element, attrs) { + if(!("noPull" in attrs)) scope.pullClass = "pull-right"; + } }; }) .directive("luciConfigApply", function(){ diff --git a/luciexpress/htdocs/plugins/core/widgets/luci.dropdown.js b/luciexpress/htdocs/plugins/core/widgets/luci.dropdown.js index 20a6cce78..5ed97086e 100644 --- a/luciexpress/htdocs/plugins/core/widgets/luci.dropdown.js +++ b/luciexpress/htdocs/plugins/core/widgets/luci.dropdown.js @@ -41,6 +41,7 @@ $juci.module("core") else if(scope.selectedItem == x.value){ scope.selectedText = x.label || scope.placeholder; } + //alert(JSON.stringify(x)+" "+JSON.stringify(scope.selectedItem)); return { label: x.label, value: x.value }; } else { if(scope.selectedItem == x){ @@ -66,8 +67,9 @@ $juci.module("core") $('button.button-label', element).html(item.label); break; } - scope.selectedItem = item.value; - + //alert(item.value); + if(scope.selectedItem instanceof Array) scope.selectedItem.splice(0, scope.selectedItem.length); + Object.assign(scope.selectedItem, item.value); scope.onChange(item); }; //scope.selectVal(scope.selectedItem); diff --git a/luciexpress/htdocs/plugins/wifi/pages/wifi.schedule.html b/luciexpress/htdocs/plugins/wifi/pages/wifi.schedule.html index dd1f3f3fc..d9b783db7 100644 --- a/luciexpress/htdocs/plugins/wifi/pages/wifi.schedule.html +++ b/luciexpress/htdocs/plugins/wifi/pages/wifi.schedule.html @@ -31,7 +31,7 @@ - + diff --git a/luciexpress/htdocs/plugins/wifi/pages/wifi.schedule.js b/luciexpress/htdocs/plugins/wifi/pages/wifi.schedule.js index 0e1a23874..10b99ac37 100644 --- a/luciexpress/htdocs/plugins/wifi/pages/wifi.schedule.js +++ b/luciexpress/htdocs/plugins/wifi/pages/wifi.schedule.js @@ -28,4 +28,14 @@ $juci.module("wifi") $scope.$apply(); }); } + + $scope.onEditSchedule = function(sched){ + $scope.schedule = sched; + $scope.showScheduleDialog = 1; + } + $scope.onDeleteSchedule = function(sched){ + sched.$delete().always(function(){ + $scope.$apply(); + }); + } }); diff --git a/luciexpress/htdocs/plugins/wifi/widgets/uci.wireless.schedule.edit.html b/luciexpress/htdocs/plugins/wifi/widgets/uci.wireless.schedule.edit.html new file mode 100644 index 000000000..5f8b80a68 --- /dev/null +++ b/luciexpress/htdocs/plugins/wifi/widgets/uci.wireless.schedule.edit.html @@ -0,0 +1,30 @@ +
+ +
diff --git a/luciexpress/htdocs/plugins/wifi/widgets/uci.wireless.schedule.edit.js b/luciexpress/htdocs/plugins/wifi/widgets/uci.wireless.schedule.edit.js new file mode 100644 index 000000000..c45f1345a --- /dev/null +++ b/luciexpress/htdocs/plugins/wifi/widgets/uci.wireless.schedule.edit.js @@ -0,0 +1,76 @@ +$juci.module("wifi") +.directive("uciWirelessScheduleEdit", function($compile){ + var plugin_root = $juci.module("wifi").plugin_root; + return { + templateUrl: plugin_root+"/widgets/uci.wireless.schedule.edit.html", + scope: { + schedule: "=ngModel" + }, + controller: "uciWirelessScheduleEdit", + replace: true, + require: "^ngModel", + /*link: function(scope, elm, attrs, ctrl){ + scope.ctrl = ctrl; + ctrl.$validators.validate = function (modelValue, viewValue) { + console.log(JSON.stringify(modelValue) +"-"+viewValue); + if (ctrl.$isEmpty(modelValue)) { // consider empty models to be valid + return true; + } + + return false; + } + }*/ + }; +}).controller("uciWirelessScheduleEdit", function($scope, gettext, $uci){ + $scope.selectedTimeFrame = []; + $scope.data = {}; + $scope.allTimeFrames = [ + { label: gettext("Individual Days"), id: "inddays", value: [] }, + { label: gettext("Every Day"), value: ["mon", "tue", "wed", "thu", "fri", "sat", "sun"] }, + { label: gettext("Every Workday"), value: ["mon", "tue", "wed", "thu", "fri"] }, + { label: gettext("All Weekend"), value: ["sat", "sun"] } + ]; + $scope.allDayNames = [ + { label: gettext("Monday"), value: "mon" }, + { label: gettext("Tuesday"), value: "tue" }, + { label: gettext("Wednesday"), value: "wed" }, + { label: gettext("Thursday"), value: "thu" }, + { label: gettext("Friday"), value: "fri" }, + { label: gettext("Saturday"), value: "sat" }, + { label: gettext("Sunday"), value: "sun" } + ]; + $scope.selectedTimeFrame = $scope.allTimeFrames[0].value; + function update_time(){ + try { + function split(value) { return value.split(":").map(function(x){ return Number(x); }); }; + var from = split($scope.data.timeFrom); + var to = split($scope.data.timeTo); + if(from[0] >= 0 && from[0] < 24 && to[0] >= 0 && to[0] < 24 && from[1] >= 0 && from[1] < 60 && to[1] >= 0 && to[1] < 60){ + if((from[0]*60+from[1]) < (to[0]*60+to[1])) { + $scope.schedule.time.value = ("0"+from[0]).slice(-2)+":"+("0"+from[1]).slice(-2)+"-"+("0"+to[0]).slice(-2)+":"+("0"+to[1]).slice(-2); + } else { + console.log("'from' value must be less than 'to' value"); + } + } else { + console.log("invalid time"); + } + } catch(e) {} + } + $scope.$watch("data.timeFrom", function(){ + update_time(); + }, true); + $scope.$watch("data.timeTo", function(){ + update_time(); + }, true); + $scope.$watch("schedule", function(value){ + var parts = value.time.value.split("-");//.map(function(x){ return x.split(":"); }); + $scope.data.timeFrom = parts[0]; + $scope.data.timeTo = parts[1]; + console.log("New model" + value.time.value); + }); + $scope.onChangeDays = function(){ + //$scope.schedule.days.value.splice(0,$scope.schedule.days.value.length); + $scope.schedule.days.value = $scope.selectedTimeFram; + //Object.assign($scope.schedule.days.value, $scope.selectedTimeFrame); + } +});