Commit 2619b847 authored by Vladimir Baranov's avatar Vladimir Baranov

Merge branch 'feature/course-program-scheduler' into develop

parents 210ae171 7cd9c11e
...@@ -2584,26 +2584,82 @@ table.dataTable thead .sorting:after { ...@@ -2584,26 +2584,82 @@ table.dataTable thead .sorting:after {
/* COURSE PROGRAM SCHEDULER */ /* COURSE PROGRAM SCHEDULER */
.course-prg-scheduler .tab-content {
padding:25px 0;
}
.course-prg-scheduler .nav-tabs { .course-prg-scheduler {
margin:15px !important; margin:15px !important;
margin-left:0 !important; margin-left:0 !important;
} }
.course-prg-scheduler .panel-body {
height: 550px;
}
.course-prg-scheduler .tabs-container {
overflow-y: auto;
height: 550px;
}
.course-prg-scheduler .tabs-left {
margin-right: 10px;
border-right: 1px solid #dddddf;
padding: 20px 0 20px 10px !important;
min-height: 550px;
}
.course-prg-scheduler ul.tabs-left li {
border-radius: 5px 0 0 5px;
border: 1px solid #fff;
border-right-color: #dddddf;
position: relative;
right: -1px;
}
.course-prg-scheduler ul.tabs-left li.active, .course-prg-scheduler ul.tabs-left li:hover {
border: 1px solid #dddddf;
border-right-color: #fff;
}
.course-prg-scheduler .tab-content {
padding: 25px 10px 25px 40px;
}
.course-prg-scheduler ul.tabs-left li.active a {
color: #bc1e2d;
}
.course-prg-scheduler ul.tabs-left li a:hover {
background: none;
cursor: pointer;
}
.course-prg-scheduler .tab-content .info-header {
margin-bottom: 30px;
}
.course-prg-scheduler .tab-content .info-header .info-wrapper { .course-prg-scheduler .tab-content .info-header .info-wrapper {
float:left; float:left;
margin-right:45px; margin-right:45px;
height: 50px;
line-height: 50px;
} }
.course-prg-scheduler .tab-content .info-header .info-wrapper .user-name { .course-prg-scheduler .tab-content .info-header .info-wrapper .user-name {
font-family:'robotobold'; font-family:'robotobold';
font-size: 17px; font-size: 17px;
color: #444; color: #444;
margin-left: 10px;
}
.course-prg-scheduler .tab-content .info-wrapper.info-wrapper_hours {
font-size: 17px;
color: #444;
}
.course-prg-scheduler .tab-content .info-wrapper.info-wrapper_hours .info-title {
font-family:'robotobold';
} }
.course-prg-scheduler .tab-content .info-header .info-wrapper .btn { .course-prg-scheduler .tab-content .info-header .info-wrapper .btn {
margin-top:8px; margin-top:8px;
} }
...@@ -2617,75 +2673,141 @@ table.dataTable thead .sorting:after { ...@@ -2617,75 +2673,141 @@ table.dataTable thead .sorting:after {
.course-prg-scheduler .tab-content .table-warning { .course-prg-scheduler .tab-content .table-warning {
background-color: #dedede; background-color: #dedede;
padding: 15px; padding: 10px 15px;
border-radius: 2px; border-radius: 2px;
font-size: 15px; font-size: 15px;
font-family: 'robotomedium'; font-weight: normal;
color: #8e8e8e; color: #444;
display: inline-block; display: inline-block;
margin: 15px auto; margin: 0 auto 15px auto;
}
.course-prg-scheduler .tab-content .table-warning .icon {
color: #8e8e8e;
font-size: 20px;
float: left;
margin-right: 10px;
}
.course-prg-scheduler .tab-content .table-container {
max-height: 350px;
overflow-y: auto;
} }
.course-prg-scheduler .tab-content table tr.headers td { .course-prg-scheduler .tab-content table tr.headers td {
font-family:'robotobold'; font-family:'robotobold';
background-color:#f9f9f9; font-size: 16px;
} }
.course-prg-scheduler .tab-content table tr td:first-child { .course-prg-scheduler .tab-content table , .course-prg-scheduler .tab-content th, .course-prg-scheduler .tab-content td {
font-size:11px; border: 1px solid black;
font-family:'robotobold';
width: 180px;
background-color:#f9f9f9;
} }
.course-prg-scheduler .tab-content table tbody { .course-prg-scheduler .tab-content table tr td:first-child {
border: 1px solid #d6d6d6; font-size: 14px;
/*font-family:'robotobold';*/
width: 180px;
/*background-color:#f9f9f9;*/
} }
.course-prg-scheduler .tab-content table td { .course-prg-scheduler .tab-content table td {
width: 100px; width: 100px;
height: 50px; height: 70px;
text-align:center; text-align:center;
} }
.course-prg-scheduler .tab-content table td .btn { .course-prg-scheduler .loader {
height: 49px; margin-top: 25px;
margin-top: -7px; }
border-radius:0;
.course-prg-scheduler ul.legend {
margin-top: 15px;
} }
.course-prg-scheduler .tab-content table td .btn:hover { .course-prg-scheduler ul.legend li {
background-color:transparent; border: none;
display: inline-block;
padding: 15px 10px;
} }
.course-prg-scheduler .tab-content table td .btn:focus { .course-prg-scheduler ul.legend li .action-indicator {
outline:none !important; margin-right: 5px;
background-color:#fff;
} }
.course-prg-scheduler .tab-content table td .filter-option { .course-prg-scheduler .action-indicator {
text-align:center !important; border: 10px solid #eee;
border-radius: 10px;
display: inline-block;
height: 10px;
width: 10px;
vertical-align: middle;
} }
.course-prg-scheduler .tab-content table td .bootstrap-select ul.dropdown-menu li a { .course-prg-scheduler .action-indicator.action-indicator_appropriate {
padding:10px; border-color: #8ac73e;
} }
.course-prg-scheduler .tab-content table td .bootstrap-select ul.dropdown-menu li a:focus { .course-prg-scheduler .action-indicator.action-indicator_busy{
outline:none; border-color: #ed1b24;
} }
.course-prg-scheduler .panel-body .nav-tabs li.active a { .course-prg-scheduler .action-indicator.action-indicator_uncertain {
border-bottom-color: #ddd; border-color: #f7941d;
border-top-color: #ddd;
border-left-color: #ddd;
border-right-color: transparent;
background-color:#fff;
} }
.course-prg-scheduler .panel-body .nav-tabs li a:hover { .course-prg-scheduler .action-selector {
border-color: #ddd; display: inline-block;
border-left-width: 1px; position: relative;
padding-right: 15px;
cursor: pointer;
right: -7px;
}
.course-prg-scheduler .action-selector:after {
content: ' ';
display: block;
position: absolute;
top: 50%;
right: 0;
margin-top: -2px;
width: 0;
height: 0;
border-style: solid;
border-width: 5px 5px 0 5px;
border-color: #808080 transparent transparent transparent;
}
.course-prg-scheduler .action-selector.readonly {
right: 0;
padding-right: 0;
}
.course-prg-scheduler .action-selector.readonly:after {
display: none;
}
.course-prg-scheduler .action-selector .popover {
display: block;
top: 25px;
left: -19px;
height: 120px;
}
.course-prg-scheduler .action-selector .popover .popover-content {
padding: 0 0 10px;
}
.course-prg-scheduler .action-selector .popover ul.actions-selector-select li {
padding: 7px 17px;
border-bottom: 1px solid #dddddf;
}
.course-prg-scheduler .action-selector .popover ul.actions-selector-select li:hover {
background-color: #f9f9f9;
}
.course-prg-scheduler .action-selector ul.actions-selector-select li:last-child {
border-bottom: none;
} }
/* END OF COURSE PROGRAM SCHEDULER */ /* END OF COURSE PROGRAM SCHEDULER */
...@@ -3000,4 +3122,4 @@ table.dataTable thead .sorting:after { ...@@ -3000,4 +3122,4 @@ table.dataTable thead .sorting:after {
/* for overflowing buttons not collapsing each other */ /* for overflowing buttons not collapsing each other */
.bottom-margined{ .bottom-margined{
margin-bottom: 0.75em; margin-bottom: 0.75em;
} }
\ No newline at end of file
...@@ -483,4 +483,172 @@ angular.module('ulakbus.crud', ['schemaForm', 'ui.bootstrap', 'ulakbus.formServi ...@@ -483,4 +483,172 @@ angular.module('ulakbus.crud', ['schemaForm', 'ui.bootstrap', 'ulakbus.formServi
} }
} }
}; };
}); })
\ No newline at end of file
.controller("crudTimetableDirectiveCtrl", function($scope, WSOps, $q){
// todo: replace with utils service method
function groupBy (list, propName) {
return list.reduce(function(acc, item) {
(acc[item[propName]] = acc[item[propName]] || []).push(item);
return acc;
}, {});
};
$scope.groupBy = groupBy;
$scope.get_wf = function get_wf(data){
var fieldName = $scope.mainFieldName || 'ogretim_elemani_zt';
data.token = $scope.token;
data.wf = $scope.wf;
return WSOps.request(data).then(function(result){
if (result[fieldName]){
return result;
}
Generator.pathDecider(result.client_cmd || ['list'], $scope, result);
// prevent result processing
return $q.reject();
}).then(function(result){
$scope.message = result.notification;
return result[fieldName]
})
}
$scope.prepareTimetable = function prepareTimetable(timetable){
var grouped = groupBy(timetable, "saat");
for (var day in grouped){
var dayItems = grouped[day];
grouped[day] = dayItems.sort(function(a, b){
return a.gun < b.gun ? -1 : 1;
});
}
var acc = [];
for (var t in grouped){
if (grouped.hasOwnProperty(t)){
acc.push([t, grouped[t]]);
}
}
return acc.sort(function(a, b){
return a[0] > b[0] ? 1 : -1;
});
}
})
.directive("crudTimetableDirective", function(){
return {
templateUrl: 'components/crud/templates/timetable.html',
restrict: 'E',
replace: true,
controller: 'crudTimetableDirectiveCtrl',
link: function(iScope, iElem, iAtrrs){
var mainFieldName = 'ogretim_elemani_zt';
iScope.mainFieldName = mainFieldName;
iScope.tablesList = iScope[mainFieldName].ogretim_elemanlari;
iScope.widgetTitle = "Öğretim Elemanı Zaman Tablosu"
initLecturer(iScope[mainFieldName]);
function initLecturer(data){
iScope.currentTable = {
key: data.oe_key,
name: data.name,
avatar_url: data.avatar_url,
totalHours: data.toplam_ders_saati
};
iScope.timetable = iScope.prepareTimetable(data.uygunluk_durumu);
};
iScope.selectTable = function(lecturer){
iScope.loadingTable = true;
iScope.get_wf({
cmd: 'personel_sec',
secili_og_elemani: {key: lecturer.key}
}).then(function(response){
initLecturer(response);
}).finally(function(){
iScope.loadingTable = false;
})
};
iScope.changeValue = function(time){
iScope.loadingAction = true;
iScope.get_wf({
cmd: 'degistir',
change: {
'key': time.key,
'durum': time.durum
}
}).then(function(table){
var days = table.uygunluk_durumu;
// update durum value from the response
for (var i=0; i<days.length; i++){
if (days[i].key == time.key){
time.durum = days[i].durum;
break;
}
}
}).finally(function(){
iScope.loadingAction = false;
})
}
}
}
})
.directive("crudTimetableDirective2", function(){
return {
templateUrl: 'components/crud/templates/timetable.html',
restrict: 'E',
replace: true,
controller: 'crudTimetableDirectiveCtrl',
link: function(iScope, iElem, iAtrrs){
var mainFieldName = 'derslik_zaman_tablosu';
iScope.mainFieldName = mainFieldName;
iScope.tablesList = iScope[mainFieldName].derslikler;
iScope.widgetTitle = "Derslik Zaman Tablosu";
initTable(iScope[mainFieldName]);
function initTable(data){
iScope.currentTable = {
key: data.oe_key,
name: data.name,
avatar_url: data.avatar_url
};
iScope.timetable = iScope.prepareTimetable(data.zaman_plani);
};
iScope.selectTable = function(lecturer){
iScope.loadingTable = true;
iScope.get_wf({
cmd: 'personel_sec',
secili_og_elemani: {key: lecturer.key}
}).then(function(response){
initLecturer(response);
}).finally(function(){
iScope.loadingTable = false;
})
};
iScope.changeValue = function(time){
iScope.loadingAction = true;
iScope.get_wf({
cmd: 'degistir',
change: {
'key': time.key,
'durum': time.durum
}
}).then(function(table){
var days = table.uygunluk_durumu;
// update durum value from the response
for (var i=0; i<days.length; i++){
if (days[i].key == time.key){
time.durum = days[i].durum;
break;
}
}
}).finally(function(){
iScope.loadingAction = false;
})
}
}
}
});
<div ng-hide="show_crud === false" class="container-fluid"> <div ng-hide="show_crud === false" class="container-fluid">
<crud-timetable-directive ng-if="ogretim_elemani_zt"></crud-timetable-directive>
<crud-timetable-directive2 ng-if="derslik_zaman_tablosu"></crud-timetable-directive2>
<div ng-class="{'col-md-8': meta.allow_filters}"> <div ng-class="{'col-md-8': meta.allow_filters}">
<msgbox ng-show="msgbox"></msgbox> <msgbox ng-show="msgbox"></msgbox>
<h3 ng-class="{'mid-h3': !objects}">{{ schema.title }}</h3> <h3 ng-class="{'mid-h3': !objects}">{{ schema.title }}</h3>
...@@ -10,4 +12,4 @@ ...@@ -10,4 +12,4 @@
</div> </div>
<div ng-show="show_crud === false" class="crud-mask"> <div ng-show="show_crud === false" class="crud-mask">
<span class="loader"></span> <span class="loader"></span>
</div> </div>
\ No newline at end of file
<div class="row academician-dashboard dashboard">
<div class="col-md-12 course-prg-scheduler">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">{{widgetTitle}}</div>
</div>
<div class="panel-body">
<div class="col-xs-3 tabs-container"> <!-- required for floating -->
<ul class="tabs-left">
<li ng-repeat="table in tablesList" ng-click="selectTable(table)" ng-class="{active: currentTable.key == table.key}"><a>{{table.name}}</a></li>
</ul>
</div>
<div class="col-xs-9">
<div class="loader" ng-show="loadingTable">Loading...</div>
<!-- Tab panes -->
<div class="tab-content" ng-hide="loadingTable">
<div class="tab-pane active">
<div class="info-header clearfix">
<div class="info-wrapper">
<img ng-src="{{currentTable.avatar_url}}" class="profile-pic" ng-show="currentTable.avatar_url">
<span class="user-name">{{currentTable.name}}</span>
</div>
<div class="info-wrapper info-wrapper_hours" ng-show="currentTable.totalHours">
<span class="info-title">Ders Yükü:</span> <span>{{currentTable.totalHours}} saat</span>
</div>
</div>
<!-- end of header -->
<div class="table-warning" ng-show="message">
<span class="glyphicon glyphicon-exclamation-sign"></span> {{message.message}}
</div>
<div class="table-container">
<table>
<tbody>
<tr class="headers">
<td></td>
<td>PZT</td>
<td>SAL</td>
<td>ÇAR</td>
<td>PER</td>
<td>CUM</td>
<td>CMT</td>
<td>PAZ</td>
</tr>
<tr ng-repeat="time in timetable">
<td>{{time[0]}}</td>
<td ng-repeat="day in time[1]">
<div timetable-action-selector ng-model="day.durum" readonly="{{currentTable.readonly}}" ng-change="changeValue(day)"></div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="loader pull-right" ng-show="loadingAction">Loading...</div>
<ul class="legend">
<li>
<span class="action-indicator action-indicator_appropriate"></span> Uygun
</li>
<li>
<span class="action-indicator action-indicator_uncertain"></span> Mümkünse boş bırakılmalı
</li>
<li>
<span class="action-indicator action-indicator_busy"></span> Kesinlike boş bırakılmalı
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- end of panel-body -->
</div>
<!-- end of panel -->
</div>
</div>
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
<link rel="icon" type="image/png" href="/img/favicon.ico"> <link rel="icon" type="image/png" href="/img/favicon.ico">
<link rel="stylesheet" href="bower_components/angular-bootstrap/ui-bootstrap-csp.css"> <link rel="stylesheet" href="bower_components/angular-bootstrap/ui-bootstrap-csp.css">
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="bower_components/bootstrap-vertical-tabs/bootstrap.vertical-tabs.css">
<link rel="stylesheet" href="app.css"> <link rel="stylesheet" href="app.css">
<link href="styles/roboto/roboto.css" rel="stylesheet"> <link href="styles/roboto/roboto.css" rel="stylesheet">
<link href="styles/jquery-ui.min.css" rel="stylesheet"> <link href="styles/jquery-ui.min.css" rel="stylesheet">
......
...@@ -707,4 +707,58 @@ angular.module('ulakbus') ...@@ -707,4 +707,58 @@ angular.module('ulakbus')
}); });
} }
}; };
})
.directive('timetableActionSelector', function($timeout){
// Display/hide popover with actions
// global listener used to close popover when user clicks outside of the popover
$('html').on('click', function(e) {
var target = $(e.target);
if (target.parents().is('.action-selector')){
target.parents('.action-selector').children('.popover').toggleClass('ng-hide');
return;
}
if (target.hasClass('action-selector')){
target.children('.popover').toggleClass('ng-hide');
return;
};
$('.course-prg-scheduler .action-selector>.popover').toggleClass('ng-hide', true);
});
return {
templateUrl: 'shared/templates/directives/timetable-action-selector.html',
scope: {
externalModel: '=ngModel',
onChange: "&ngChange"
},
link: function(iScope, iElem, iAttrs){
var valueToClassMap = {
1: 'action-indicator_appropriate',
2: 'action-indicator_uncertain',
3: 'action-indicator_busy'
};
if (iAttrs.hasOwnProperty('readonly')){
iAttrs.$observe('readonly', function(v){
if (v && v == 'false') v = false;
iScope.readonly = v;
});
}
iScope.$watch('externalModel', function(value){
iScope.value = valueToClassMap[value];
});
iScope.setModelValue = function(value){
var oldValue = iScope.externalModel;
iScope.externalModel = value;
// call change in next digest
$timeout(function(){
if (iScope.onChange && value != oldValue) {
iScope.onChange();
}
});
}
}
}
}); });
<div class="action-selector" ng-class="{readonly: readonly}">
<span class="action-indicator" ng-class="value"></span>
<div class="popover bottom ng-hide" ng-if="!readonly">
<div class="arrow"></div>
<div class="popover-content">
<ul class="actions-selector-select">
<li ng-click="setModelValue(1)">
<span class="action-indicator action-indicator_appropriate"></span>
</li>
<li ng-click="setModelValue(2)">
<span class="action-indicator action-indicator_uncertain"></span>
</li>
<li ng-click="setModelValue(3)">
<span class="action-indicator action-indicator_busy"></span>
</li>
</ul>
</div>
</div>
</div>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment