Added schedule editor

This commit is contained in:
Martin Schröder 2015-05-08 16:57:55 +02:00 committed by Martin Schröder
parent cfa78a7cb3
commit 89c19c55c6
10 changed files with 258 additions and 10 deletions

View file

@ -37,6 +37,7 @@
<script src="lib/js/bootstrap.min.js"></script>
<script src="lib/js/angular-ui-switch.min.js"></script>
<script src="lib/js/angular-modal-service.min.js"></script>
<script src="lib/js/angular-checklist-model.js"></script>
<!-- ###---### -->
<script src="js/app.js"></script>

View file

@ -61,7 +61,8 @@ angular.module("luci", [
'angularModalService',
"uiSwitch",
"ngAnimate",
"gettext"
"gettext",
"checklist-model"
]);
angular.module("luci")

View file

@ -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();

View file

@ -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;
}
};
}]);

View file

@ -43,17 +43,20 @@ $juci.module("core")
var plugin_root = $juci.module("core").plugin_root;
return {
template: '<div class="row" style="margin-top: 20px; ">'+
'<div class="col-md-7">'+
'<div class="col-md-6">'+
'<label style="font-size: 1.2em">{{title}}</label>'+
'</div>'+
'<div class="col-md-5">'+
'<div class="pull-right" ng-transclude></div>'+
'<div class="col-md-6">'+
'<div class="{{pullClass}}" ng-transclude></div>'+
'</div></div>',
replace: true,
scope: {
title: "@"
},
transclude: true
transclude: true,
link: function (scope, element, attrs) {
if(!("noPull" in attrs)) scope.pullClass = "pull-right";
}
};
})
.directive("luciConfigApply", function(){

View file

@ -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);

View file

@ -31,7 +31,7 @@
<td style="width: 1%"><button class="btn btn-default" ng-click="onDeleteSchedule(item)"><i class="fa fa-trash-o"></i></button></td>
</tr>
<tr>
<td colspan="5"></td>
<td colspan="4"></td>
<td style="width: 1%"><button class="btn btn-default" ng-click="onAddSchedule()"><i class="fa fa-plus"></i></button></td>
</tr>
</tbody>

View file

@ -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();
});
}
});

View file

@ -0,0 +1,30 @@
<form name="ruleForm" class="form-horizontal" novalidate>
<div class="modal-body">
<luci-config>
<luci-config-section>
<luci-config-lines>
<luci-config-line title="{{'Time Frame'|translate}}">
<luci-select ng-model="selectedTimeFrame" on-change="onChangeDays()" ng-items="allTimeFrames"></luci-select>
</luci-config-line>
<luci-config-line title="{{'Days'|translate}}" no-pull >
<div class="row" >
<div class="col-xs-6" ng-repeat="day in allDayNames">
<label >
<input type="checkbox" checklist-model="schedule.days.value" checklist-value="day.value"> {{day.label}}
</label>
</div>
</div>
</luci-config-line>
<luci-config-line title="{{'Time'|translate}}" no-pull>
<div class="row">
<div class="col-xs-2"><label translate>from</label></div>
<div class="col-xs-4"><input class="form-control" type="text" ng-model="data.timeFrom" placeholder="09:00"/></div>
<div class="col-xs-2"><label translate>to</label></div>
<div class="col-xs-4"><input class="form-control" type="text" ng-model="data.timeTo" placeholder="09:00"/></div>
</div>
</luci-config-line>
</luci-config-lines>
</luci-config-section>
</luci-config>
</div>
</form>

View file

@ -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);
}
});