Initial state

This commit is contained in:
2023-05-16 10:16:21 -06:00
commit c3c0108143
167 changed files with 20135 additions and 0 deletions

41
js/barra.js Normal file
View File

@@ -0,0 +1,41 @@
function barra(profesor, retardos) {
profesor.faltas = profesor.total - profesor.asistencias - profesor.retardos - profesor.justificaciones;
if (profesor.total != 0)
var porcentajes = {
"asistencias": profesor.asistencias / profesor.total * 100,
"retardos": profesor.retardos / profesor.total * 100,
"justificaciones": profesor.justificaciones / profesor.total * 100,
"faltas": 100 * profesor.faltas / profesor.total
}
else
var porcentajes = {
"asistencias": 0,
"retardos": 0,
"justificaciones": 0,
"faltas": 0
}
var html = `
<section id="profesor-${profesor.id}">
<div class="row">
<div class="col-12">
<div class="progress">
<div class="progress-bar bg-success" role="progressbar" style="width: ${porcentajes.asistencias}%" aria-valuenow="${porcentajes.asistencias}" aria-valuemin="0" aria-valuemax="100"></div>
<!-- Show retardos only if it's set to true -->
${retardos ? `<div class="progress-bar bg-warning" role="progressbar" style="width: ${porcentajes.retardos}%" aria-valuenow="${porcentajes.retardos}" aria-valuemin="0" aria-valuemax="100"></div>` : ``}
<div class="progress-bar bg-azul" role="progressbar" style="width: ${porcentajes.justificaciones}%" aria-valuenow="${porcentajes.justificaciones}" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: ${porcentajes.faltas}%" aria-valuenow="${porcentajes.faltas}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
<!-- Span Asistencias: # Retardos: # Faltas: # -->
<div class="row justify-content-center">
<span class="mx-3 mt-1">Asistencias: ${profesor.asistencias}</span>
${retardos ? `<span class="mx-3 mt-1">Retardos: ${profesor.retardos}</span>` : `` }
<span class="mx-3 mt-1">Justificaciones: ${profesor.justificaciones}</span>
<span class="mx-3 mt-1">Faltas: ${profesor.faltas}</span>
</div>
</div>
`;
return html;
}

7
js/bootstrap/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

7
js/bootstrap/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

5
js/bootstrap/popper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

731
js/clockpicker.js Normal file
View File

@@ -0,0 +1,731 @@
/*!
* ClockPicker v{package.version} (http://weareoutman.github.io/clockpicker/)
* Copyright 2014 Wang Shenwei.
* Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE)
*/
;(function(){
var $ = window.jQuery,
$win = $(window),
$doc = $(document),
$body;
// Can I use inline svg ?
var svgNS = 'http://www.w3.org/2000/svg',
svgSupported = 'SVGAngle' in window && (function(){
var supported,
el = document.createElement('div');
el.innerHTML = '<svg/>';
supported = (el.firstChild && el.firstChild.namespaceURI) == svgNS;
el.innerHTML = '';
return supported;
})();
// Can I use transition ?
var transitionSupported = (function(){
var style = document.createElement('div').style;
return 'transition' in style ||
'WebkitTransition' in style ||
'MozTransition' in style ||
'msTransition' in style ||
'OTransition' in style;
})();
// Listen touch events in touch screen device, instead of mouse events in desktop.
var touchSupported = 'ontouchstart' in window,
mousedownEvent = 'mousedown' + ( touchSupported ? ' touchstart' : ''),
mousemoveEvent = 'mousemove.clockpicker' + ( touchSupported ? ' touchmove.clockpicker' : ''),
mouseupEvent = 'mouseup.clockpicker' + ( touchSupported ? ' touchend.clockpicker' : '');
// Vibrate the device if supported
var vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null;
function createSvgElement(name) {
return document.createElementNS(svgNS, name);
}
function leadingZero(num) {
return (num < 10 ? '0' : '') + num;
}
// Get a unique id
var idCounter = 0;
function uniqueId(prefix) {
var id = ++idCounter + '';
return prefix ? prefix + id : id;
}
// Clock size
var dialRadius = 100,
outerRadius = 80,
// innerRadius = 80 on 12 hour clock
innerRadius = 54,
tickRadius = 13,
diameter = dialRadius * 2,
duration = transitionSupported ? 350 : 1;
// Popover template
var tpl = [
'<div class="popover clockpicker-popover">',
'<div class="arrow"></div>',
'<div class="popover-title">',
'<span class="clockpicker-span-hours text-azul-ing"></span>',
' : ',
'<span class="clockpicker-span-minutes"></span>',
'<span class="clockpicker-span-am-pm"></span>',
'</div>',
'<div class="popover-content">',
'<div class="clockpicker-plate">',
'<div class="clockpicker-canvas"></div>',
'<div class="clockpicker-dial clockpicker-hours"></div>',
'<div class="clockpicker-dial clockpicker-minutes clockpicker-dial-out"></div>',
'</div>',
'<span class="clockpicker-am-pm-block">',
'</span>',
'</div>',
'</div>'
].join('');
// ClockPicker
function ClockPicker(element, options) {
var popover = $(tpl),
plate = popover.find('.clockpicker-plate'),
hoursView = popover.find('.clockpicker-hours'),
minutesView = popover.find('.clockpicker-minutes'),
amPmBlock = popover.find('.clockpicker-am-pm-block'),
isInput = element.prop('tagName') === 'INPUT',
input = isInput ? element : element.find('input'),
addon = element.find('.input-group-addon'),
self = this,
timer;
this.id = uniqueId('cp');
this.element = element;
this.options = options;
this.isAppended = false;
this.isShown = false;
this.currentView = 'hours';
this.isInput = isInput;
this.input = input;
this.addon = addon;
this.popover = popover;
this.plate = plate;
this.hoursView = hoursView;
this.minutesView = minutesView;
this.amPmBlock = amPmBlock;
this.spanHours = popover.find('.clockpicker-span-hours');
this.spanMinutes = popover.find('.clockpicker-span-minutes');
this.spanAmPm = popover.find('.clockpicker-span-am-pm');
this.amOrPm = "PM";
// Setup for for 12 hour clock if option is selected
if (options.twelvehour) {
var amPmButtonsTemplate = ['<div class="clockpicker-am-pm-block">',
'<button type="button" class="btn btn-sm btn-default clockpicker-button clockpicker-am-button">',
'AM</button>',
'<button type="button" class="btn btn-sm btn-default clockpicker-button clockpicker-pm-button">',
'PM</button>',
'</div>'].join('');
var amPmButtons = $(amPmButtonsTemplate);
//amPmButtons.appendTo(plate);
////Not working b/c they are not shown when this runs
//$('clockpicker-am-button')
// .on("click", function() {
// self.amOrPm = "AM";
// $('.clockpicker-span-am-pm').empty().append('AM');
// });
//
//$('clockpicker-pm-button')
// .on("click", function() {
// self.amOrPm = "PM";
// $('.clockpicker-span-am-pm').empty().append('PM');
// });
$('<button type="button" class="btn btn-sm btn-default clockpicker-button am-button">' + "AM" + '</button>')
.on("click", function() {
self.amOrPm = "AM";
$('.clockpicker-span-am-pm').empty().append('AM');
}).appendTo(this.amPmBlock);
$('<button type="button" class="btn btn-sm btn-default clockpicker-button pm-button">' + "PM" + '</button>')
.on("click", function() {
self.amOrPm = 'PM';
$('.clockpicker-span-am-pm').empty().append('PM');
}).appendTo(this.amPmBlock);
}
if (! options.autoclose) {
// If autoclose is not setted, append a button
$('<button type="button" class="btn btn-sm btn-default btn-block clockpicker-button">' + options.donetext + '</button>')
.click($.proxy(this.done, this))
.appendTo(popover);
}
// Placement and arrow align - make sure they make sense.
if ((options.placement === 'top' || options.placement === 'bottom') && (options.align === 'top' || options.align === 'bottom')) options.align = 'left';
if ((options.placement === 'left' || options.placement === 'right') && (options.align === 'left' || options.align === 'right')) options.align = 'top';
popover.addClass(options.placement);
popover.addClass('clockpicker-align-' + options.align);
this.spanHours.click($.proxy(this.toggleView, this, 'hours'));
this.spanMinutes.click($.proxy(this.toggleView, this, 'minutes'));
// Show or toggle
input.on('focus.clockpicker click.clockpicker', $.proxy(this.show, this));
addon.on('click.clockpicker', $.proxy(this.toggle, this));
// Build ticks
var tickTpl = $('<div class="clockpicker-tick"></div>'),
i, tick, radian, radius;
// Hours view
if (options.twelvehour) {
for (i = 1; i < 13; i += 1) {
tick = tickTpl.clone();
radian = i / 6 * Math.PI;
radius = outerRadius;
//tick.css('font-size', '120%');
tick.css({
left: dialRadius + Math.sin(radian) * radius - tickRadius,
top: dialRadius - Math.cos(radian) * radius - tickRadius
});
tick.html(i === 0 ? '00' : i);
hoursView.append(tick);
tick.on(mousedownEvent, mousedown);
}
} else {
for (i = 0; i < 24; i += 1) {
tick = tickTpl.clone();
radian = i / 6 * Math.PI;
var inner = i > 0 && i < 13;
radius = inner ? innerRadius : outerRadius;
tick.css({
left: dialRadius + Math.sin(radian) * radius - tickRadius,
top: dialRadius - Math.cos(radian) * radius - tickRadius
});
/*if (inner) {
tick.css('font-size', '120%');
}*/
tick.html(i === 0 ? '00' : i);
hoursView.append(tick);
tick.on(mousedownEvent, mousedown);
}
}
// Minutes view
for (i = 0; i < 60; i += 5) {
tick = tickTpl.clone();
radian = i / 30 * Math.PI;
tick.css({
left: dialRadius + Math.sin(radian) * outerRadius - tickRadius,
top: dialRadius - Math.cos(radian) * outerRadius - tickRadius
});
//tick.css('font-size', '120%');
tick.html(leadingZero(i));
minutesView.append(tick);
tick.on(mousedownEvent, mousedown);
}
// Clicking on minutes view space
plate.on(mousedownEvent, function(e){
if ($(e.target).closest('.clockpicker-tick').length === 0) {
mousedown(e, true);
}
});
// Mousedown or touchstart
function mousedown(e, space) {
var offset = plate.offset(),
isTouch = /^touch/.test(e.type),
x0 = offset.left + dialRadius,
y0 = offset.top + dialRadius,
dx = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0,
dy = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0,
z = Math.sqrt(dx * dx + dy * dy),
moved = false;
// When clicking on minutes view space, check the mouse position
if (space && (z < outerRadius - tickRadius || z > outerRadius + tickRadius)) {
return;
}
e.preventDefault();
// Set cursor style of body after 200ms
var movingTimer = setTimeout(function(){
$body.addClass('clockpicker-moving');
}, 200);
// Place the canvas to top
if (svgSupported) {
plate.append(self.canvas);
}
// Clock
self.setHand(dx, dy, ! space, true);
// Mousemove on document
$doc.off(mousemoveEvent).on(mousemoveEvent, function(e){
e.preventDefault();
var isTouch = /^touch/.test(e.type),
x = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0,
y = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0;
if (! moved && x === dx && y === dy) {
// Clicking in chrome on windows will trigger a mousemove event
return;
}
moved = true;
self.setHand(x, y, false, true);
});
// Mouseup on document
$doc.off(mouseupEvent).on(mouseupEvent, function(e){
$doc.off(mouseupEvent);
e.preventDefault();
var isTouch = /^touch/.test(e.type),
x = (isTouch ? e.originalEvent.changedTouches[0] : e).pageX - x0,
y = (isTouch ? e.originalEvent.changedTouches[0] : e).pageY - y0;
if ((space || moved) && x === dx && y === dy) {
self.setHand(x, y);
}
if (self.currentView === 'hours') {
self.toggleView('minutes', duration / 2);
} else {
if (options.autoclose) {
self.minutesView.addClass('clockpicker-dial-out');
setTimeout(function(){
self.done();
}, duration / 2);
}
}
plate.prepend(canvas);
// Reset cursor style of body
clearTimeout(movingTimer);
$body.removeClass('clockpicker-moving');
// Unbind mousemove event
$doc.off(mousemoveEvent);
});
}
if (svgSupported) {
// Draw clock hands and others
var canvas = popover.find('.clockpicker-canvas'),
svg = createSvgElement('svg');
svg.setAttribute('class', 'clockpicker-svg');
svg.setAttribute('width', diameter);
svg.setAttribute('height', diameter);
var g = createSvgElement('g');
g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')');
var bearing = createSvgElement('circle');
bearing.setAttribute('class', 'clockpicker-canvas-bearing');
bearing.setAttribute('cx', 0);
bearing.setAttribute('cy', 0);
bearing.setAttribute('r', 2);
var hand = createSvgElement('line');
hand.setAttribute('x1', 0);
hand.setAttribute('y1', 0);
var bg = createSvgElement('circle');
bg.setAttribute('class', 'clockpicker-canvas-bg');
bg.setAttribute('r', tickRadius);
var fg = createSvgElement('circle');
fg.setAttribute('class', 'clockpicker-canvas-fg');
fg.setAttribute('r', 3.5);
g.appendChild(hand);
g.appendChild(bg);
g.appendChild(fg);
g.appendChild(bearing);
svg.appendChild(g);
canvas.append(svg);
this.hand = hand;
this.bg = bg;
this.fg = fg;
this.bearing = bearing;
this.g = g;
this.canvas = canvas;
}
raiseCallback(this.options.init);
}
function raiseCallback(callbackFunction) {
if (callbackFunction && typeof callbackFunction === "function") {
callbackFunction();
}
}
// Default options
ClockPicker.DEFAULTS = {
'default': '', // default time, 'now' or '13:14' e.g.
fromnow: 0, // set default time to * milliseconds from now (using with default = 'now')
placement: 'bottom', // clock popover placement
align: 'left', // popover arrow align
donetext: 'Aceptar', // done button text
autoclose: false, // auto close when minute is selected
twelvehour: false, // change to 12 hour AM/PM clock from 24 hour
vibrate: true // vibrate the device when dragging clock hand
};
// Show or hide popover
ClockPicker.prototype.toggle = function(){
this[this.isShown ? 'hide' : 'show']();
};
// Set popover position
ClockPicker.prototype.locate = function(){
var element = this.element,
popover = this.popover,
offset = element.offset(),
width = element.outerWidth(),
height = element.outerHeight(),
placement = this.options.placement,
align = this.options.align,
styles = {},
self = this;
popover.show();
// Place the popover
switch (placement) {
case 'bottom':
styles.top = offset.top + height;
break;
case 'right':
styles.left = offset.left + width;
break;
case 'top':
styles.top = offset.top - popover.outerHeight();
break;
case 'left':
styles.left = offset.left - popover.outerWidth();
break;
}
// Align the popover arrow
switch (align) {
case 'left':
styles.left = offset.left;
break;
case 'right':
styles.left = offset.left + width - popover.outerWidth();
break;
case 'top':
styles.top = offset.top;
break;
case 'bottom':
styles.top = offset.top + height - popover.outerHeight();
break;
}
popover.css(styles);
};
// Show popover
ClockPicker.prototype.show = function(e){
// Not show again
if (this.isShown) {
return;
}
raiseCallback(this.options.beforeShow);
var self = this;
// Initialize
if (! this.isAppended) {
// Append popover to body
$body = $(document.body).append(this.popover);
// Reset position when resize
$win.on('resize.clockpicker' + this.id, function(){
if (self.isShown) {
self.locate();
}
});
this.isAppended = true;
}
// Get the time
var value = ((this.input.prop('value') || this.options['default'] || '') + '').split(':');
if (value[0] === 'now') {
var now = new Date(+ new Date() + this.options.fromnow);
value = [
now.getHours(),
now.getMinutes()
];
}
this.hours = + value[0] || 0;
this.minutes = + value[1] || 0;
this.spanHours.html(leadingZero(this.hours));
this.spanMinutes.html(leadingZero(this.minutes));
// Toggle to hours view
this.toggleView('hours');
// Set position
this.locate();
this.isShown = true;
// Hide when clicking or tabbing on any element except the clock, input and addon
$doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, function(e){
var target = $(e.target);
if (target.closest(self.popover).length === 0 &&
target.closest(self.addon).length === 0 &&
target.closest(self.input).length === 0) {
self.hide();
}
});
// Hide when ESC is pressed
$doc.on('keyup.clockpicker.' + this.id, function(e){
if (e.keyCode === 27) {
self.hide();
}
});
raiseCallback(this.options.afterShow);
};
// Hide popover
ClockPicker.prototype.hide = function(){
raiseCallback(this.options.beforeHide);
this.isShown = false;
// Unbinding events on document
$doc.off('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id);
$doc.off('keyup.clockpicker.' + this.id);
this.popover.hide();
raiseCallback(this.options.afterHide);
};
// Toggle to hours or minutes view
ClockPicker.prototype.toggleView = function(view, delay){
var raiseAfterHourSelect = false;
if (view === 'minutes' && $(this.hoursView).css("visibility") === "visible") {
raiseCallback(this.options.beforeHourSelect);
raiseAfterHourSelect = true;
}
var isHours = view === 'hours',
nextView = isHours ? this.hoursView : this.minutesView,
hideView = isHours ? this.minutesView : this.hoursView;
this.currentView = view;
this.spanHours.toggleClass('text-azul-ing', isHours);
this.spanMinutes.toggleClass('text-azul-ing', ! isHours);
// Let's make transitions
hideView.addClass('clockpicker-dial-out');
nextView.css('visibility', 'visible').removeClass('clockpicker-dial-out');
// Reset clock hand
this.resetClock(delay);
// After transitions ended
clearTimeout(this.toggleViewTimer);
this.toggleViewTimer = setTimeout(function(){
hideView.css('visibility', 'hidden');
}, duration);
if (raiseAfterHourSelect) {
raiseCallback(this.options.afterHourSelect);
}
};
// Reset clock hand
ClockPicker.prototype.resetClock = function(delay){
var view = this.currentView,
value = this[view],
isHours = view === 'hours',
unit = Math.PI / (isHours ? 6 : 30),
radian = value * unit,
radius = isHours && value > 0 && value < 13 ? innerRadius : outerRadius,
x = Math.sin(radian) * radius,
y = - Math.cos(radian) * radius,
self = this;
if (svgSupported && delay) {
self.canvas.addClass('clockpicker-canvas-out');
setTimeout(function(){
self.canvas.removeClass('clockpicker-canvas-out');
self.setHand(x, y);
}, delay);
} else {
this.setHand(x, y);
}
};
// Set clock hand to (x, y)
ClockPicker.prototype.setHand = function(x, y, roundBy5, dragging){
var radian = Math.atan2(x, - y),
isHours = this.currentView === 'hours',
unit = Math.PI / (isHours || roundBy5 ? 6 : 30),
z = Math.sqrt(x * x + y * y),
options = this.options,
inner = isHours && z < (outerRadius + innerRadius) / 2,
radius = inner ? innerRadius : outerRadius,
value;
if (options.twelvehour) {
radius = outerRadius;
}
// Radian should in range [0, 2PI]
if (radian < 0) {
radian = Math.PI * 2 + radian;
}
// Get the round value
value = Math.round(radian / unit);
// Get the round radian
radian = value * unit;
// Correct the hours or minutes
if (options.twelvehour) {
if (isHours) {
if (value === 0) {
value = 12;
}
} else {
if (roundBy5) {
value *= 5;
}
if (value === 60) {
value = 0;
}
}
} else {
if (isHours) {
if (value === 12) {
value = 0;
}
value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12;
} else {
if (roundBy5) {
value *= 5;
}
if (value === 60) {
value = 0;
}
}
}
// Once hours or minutes changed, vibrate the device
if (this[this.currentView] !== value) {
if (vibrate && this.options.vibrate) {
// Do not vibrate too frequently
if (! this.vibrateTimer) {
navigator[vibrate](10);
this.vibrateTimer = setTimeout($.proxy(function(){
this.vibrateTimer = null;
}, this), 100);
}
}
}
this[this.currentView] = value;
this[isHours ? 'spanHours' : 'spanMinutes'].html(leadingZero(value));
// If svg is not supported, just add an active class to the tick
//if (! svgSupported) {
this[isHours ? 'hoursView' : 'minutesView'].find('.clockpicker-tick').each(function(){
var tick = $(this);
tick.toggleClass('active', value === + tick.html());
});
//return;
//}
// Place clock hand at the top when dragging
if (dragging || (! isHours && value % 5)) {
this.g.insertBefore(this.hand, this.bearing);
this.g.insertBefore(this.bg, this.fg);
this.bg.setAttribute('class', 'clockpicker-canvas-bg clockpicker-canvas-bg-trans');
} else {
// Or place it at the bottom
this.g.insertBefore(this.hand, this.bg);
this.g.insertBefore(this.fg, this.bg);
this.bg.setAttribute('class', 'clockpicker-canvas-bg');
}
// Set clock hand and others' position
var cx = Math.sin(radian) * radius,
cy = - Math.cos(radian) * radius;
this.hand.setAttribute('x2', cx);
this.hand.setAttribute('y2', cy);
this.bg.setAttribute('cx', cx);
this.bg.setAttribute('cy', cy);
this.fg.setAttribute('cx', cx);
this.fg.setAttribute('cy', cy);
};
// Hours and minutes are selected
ClockPicker.prototype.done = function() {
raiseCallback(this.options.beforeDone);
this.hide();
var last = this.input.prop('value'),
value = leadingZero(this.hours) + ':' + leadingZero(this.minutes);
if (this.options.twelvehour) {
value = value + this.amOrPm;
}
this.input.prop('value', value);
if (value !== last) {
this.input.triggerHandler('change');
if (! this.isInput) {
this.element.trigger('change');
}
}
if (this.options.autoclose) {
this.input.trigger('blur');
}
raiseCallback(this.options.afterDone);
};
// Remove clockpicker from input
ClockPicker.prototype.remove = function() {
this.element.removeData('clockpicker');
this.input.off('focus.clockpicker click.clockpicker');
this.addon.off('click.clockpicker');
if (this.isShown) {
this.hide();
}
if (this.isAppended) {
$win.off('resize.clockpicker' + this.id);
this.popover.remove();
}
};
// Extends $.fn.clockpicker
$.fn.clockpicker = function(option){
var args = Array.prototype.slice.call(arguments, 1);
return this.each(function(){
var $this = $(this),
data = $this.data('clockpicker');
if (! data) {
var options = $.extend({}, ClockPicker.DEFAULTS, $this.data(), typeof option == 'object' && option);
$this.data('clockpicker', new ClockPicker($this, options));
} else {
// Manual operatsions. show, hide, remove, e.g.
if (typeof data[option] === 'function') {
data[option].apply(data, args);
}
}
});
};
}());

288
js/consulta_horarios.js Normal file
View File

@@ -0,0 +1,288 @@
// initial state
const días = ["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"];
const horas_estándar = /* range from 7 to 22 */ Array.from(Array(22 - 7 + 1).keys()).map(x => x + 7);
// fill the table with empty cells
for (let i = 0; i < horas_estándar.length - 1; i++) {
const hora = horas_estándar[i];
const tr = document.createElement("tr");
tr.id = `hora-${hora}-00`;
tr.classList.add(hora > 13 ? "tarde" : "mañana");
const th = document.createElement("th");
th.classList.add("text-center");
th.scope = "row";
th.rowSpan = 4;
th.innerText = `${hora}:00`;
th.style.verticalAlign = "middle";
tr.appendChild(th);
for (let j = 0; j < días.length; j++) {
const día = días[j];
const td = document.createElement("td");
td.id = `hora-${hora}-00-${día}`;
tr.appendChild(td);
}
document.querySelector("tbody#horario")?.appendChild(tr);
// add 7 rows for each hour
const hours = [15, 30, 45];
for (let j = 1; j < 4; j++) {
const tr = document.createElement("tr");
tr.id = `hora-${hora}-${hours[j - 1]}`;
tr.classList.add(hora > 13 ? "tarde" : "mañana");
for (let k = 0; k < días.length; k++) {
const día = días[k];
const td = document.createElement("td");
td.id = `hora-${hora}-${hours[j - 1]}-${día}`;
// td.innerText = `hora-${hora}-${hours[j - 1]}-${día}`;
tr.appendChild(td);
}
document.querySelector("tbody#horario")?.appendChild(tr);
}
}
// add an inital height to the table cells
const tds = document.querySelectorAll("tbody#horario td");
tds.forEach(td => td.style.height = "2rem");
var table = document.querySelector("table");
var empty_table = table?.innerHTML || "";
// hide the table
table.style.display = "none";
document.getElementById('dlProfesor')?.addEventListener('input', function () {
var input = document.getElementById('dlProfesor');
var value = input.value;
var option = document.querySelector(`option[value="${value}"]`);
if (option) {
var id = option.getAttribute('data-id');
const input_profesor = document.getElementById('editor_profesor');
input_profesor.value = id;
// remove is invalid class
input.classList.remove("is-invalid");
// add is valid class
input.classList.add("is-valid");
}
else {
const input_profesor = document.getElementById('editor_profesor');
input_profesor.value = "";
// remove is valid class
input.classList.remove("is-valid");
// add is invalid class
input.classList.add("is-invalid");
}
});
/**
* Functions and Methods
**/
const buscarGrupo = async () => {
// Add loading animation in the button
const btn = document.querySelector("#btn-buscar");
btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Cargando...';
btn.disabled = true;
const carrera = document.querySelector("#filter_carrera")?.value;
const grupo = document.querySelector("#filter_grupo")?.value;
console.log(`Carrera: ${carrera}, Grupo: ${grupo}`);
if (carrera == "" || grupo == "") {
triggerMessage("El nombre del grupo y la carrera son requeridos", "Faltan campos");
// Remove loading animation in the button
btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
btn.disabled = false;
return;
}
const formData = new FormData();
formData.append("carrera", carrera);
formData.append("grupo", grupo);
formData.append("periodo", document.querySelector("#periodo")?.value);
const thisScript = document.currentScript;
const facultad = thisScript.getAttribute("data-facultad");
formData.append('facultad', facultad);
try {
const response = await fetch("action/action_horario.php", {
method: "POST",
body: formData
}).then(res => res.json());
if (response.status == "success") {
let limits = {
min: 22,
max: 7
};
let sábado = false;
const horario = response.horario;
// show the table
table.style.display = "table";
// clear the table
table.innerHTML = empty_table;
// fill the table
for (let i = 0; i < horario.length; i++) {
const dia = horario[i].dia;
if (dia == "sábado")
sábado = true;
const { hora, minutos } = {
hora: parseInt(horario[i].hora.split(":")[0]),
minutos: horario[i].hora.split(":")[1]
};
// update the limits
if (hora < limits.min) {
limits.min = hora;
}
if (hora > limits.max) {
limits.max = hora;
}
const materia = horario[i].materia;
const profesor = horario[i].profesor;
const salon = horario[i].salon;
const id = horario[i].horario_id;
const prof_id = horario[i].profesor_id;
const cell = document.querySelector(`#hora-${hora}-${minutos}-${dia}`);
cell.innerHTML =
`
<div>
<small class="text-gray">${hora}:${minutos}</small>
<b class="title">${materia}</b> <br>
<br><span>Salón: </span>${salon} <br>
<span class="ing ing-formacion mx-1"></span>${profesor}
</div>
`;
const html = `<div class="menu-flotante p-2">
<a
class="mx-2"
href="#"
data-toggle="modal"
data-target="#modal-editar"
data-dia="${dia}"
data-hora="${hora}:${minutos}"
data-materia="${materia}"
data-profesor="${prof_id}"
data-salon="${salon}"
data-id="${id}"
>
<i class="ing-editar ing"></i>
</a>
<a
class="mx-2"
href="#"
data-toggle="modal"
data-target="#modal-borrar"
data-hoario_id="${id}"
>
<i class="ing-basura ing"></i>
</a>
</div>`;
const td = cell.closest("td");
td.innerHTML += html;
td.classList.add("position-relative");
// this cell spans 4 rows
cell.rowSpan = 6;
cell.classList.add("bloque-clase", "overflow");
for (let j = 1; j < 6; j++) {
const minute = (parseInt(minutos) + j * 15);
const next_minute = (minute % 60).toString().padStart(2, "0");
const next_hour = (hora + Math.floor(minute / 60));
const next_cell = document.querySelector(`#hora-${next_hour}-${next_minute}-${dia}`);
next_cell.remove();
}
}
// remove the elements that are not in the limits
const horas = document.querySelectorAll("tbody#horario tr");
for (let i = 0; i < horas.length; i++) {
const hora = horas[i];
const hora_id = parseInt(hora.id.split("-")[1]);
if (hora_id < limits.min || hora_id > limits.max) {
hora.remove();
}
}
// if there is no sábado, remove the column
if (!sábado) {
document.querySelectorAll("tbody#horario td").forEach(td => {
if (td.id.split("-")[3] == "sábado") {
td.remove();
}
});
// remove the header (the last)
const headers = document.querySelector("#headers");
headers.lastElementChild?.remove();
}
// adjust width
const ths = document.querySelectorAll("tr#headers th");
const width = 95 / (ths.length - 1);
ths.forEach((th, key) => th.style.width = (key == 0) ? "5%" : `${width}%`);
// search item animation
const menúFlontantes = document.querySelectorAll(".menu-flotante");
menúFlontantes.forEach((element) => {
element.classList.add("d-none");
element.parentElement?.addEventListener("mouseover", () => {
element.classList.remove("d-none");
});
element.parentElement?.addEventListener("mouseout", () => {
element.classList.add("d-none");
});
});
}
else {
triggerMessage(response.message, "Error");
// Remove loading animation in the button
btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
btn.disabled = false;
}
}
catch (error) {
triggerMessage("Error al cargar el horario", "Error");
triggerMessage(error, "Error");
}
// Remove loading animation in the button
btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
btn.disabled = false;
};
async function guardar(id) {
const btn = document.querySelector("#btn-guardar");
const clone = btn.cloneNode(true);
btn.innerHTML = '<i class="ing-cargando ing"></i> Guardando...';
btn.disabled = true;
const data = {
hora: document.querySelector("#editor_hora"),
dia: document.querySelector("#editor_dia"),
salon: document.querySelector("#editor_salón"),
profesor: document.querySelector("#editor_profesor"),
};
const hora = data.hora.value; // h:mm
const { compareHours } = await import('./date_functions');
const hora_antes = compareHours(hora, "07:15") < 0;
const hora_después = compareHours(hora, "21:30") > 0;
if (hora_antes || hora_después) {
alert(`La hora ${hora} no es válida`);
triggerMessage("Selecciona una hora", "Error");
btn.innerHTML = clone.innerHTML;
btn.disabled = false;
data.hora.focus();
data.hora.classList.add("is-invalid");
return;
}
const dia = data.dia.value;
const salon = data.salon.value;
const profesor = data.profesor.value;
const formData = new FormData();
formData.append("id", id);
formData.append("hora", hora);
formData.append("dia", dia);
formData.append("salon", salon);
formData.append("profesor", profesor);
const response = await fetch("action/action_horario_update.php", {
method: "POST",
body: formData
}).then(res => res.json());
if (response.status == "success") {
triggerMessage(response.message, "Éxito", "success");
btn.innerHTML = '<i class="ing-aceptar ing"></i> Guardado';
btn.classList.add("btn-success");
btn.classList.remove("btn-primary");
// return to the initial state
setTimeout(() => {
buscarGrupo();
btn.replaceWith(clone);
$("#modal-editar").modal("hide");
}, 1000);
}
else {
triggerMessage(response.message, "Error");
btn.replaceWith(clone);
$("#modal-editar").modal("hide");
}
}
function triggerMessage(message, header, colour = "danger") {
throw new Error('Function not implemented.');
}

981
js/consultar_horarios.js Normal file
View File

@@ -0,0 +1,981 @@
import {
triggerMessage
} from './module/messages.js';
var gHorarios = [];
/**@Auxiliary functions */
function listProfesor({
id,
grado,
profesor,
clave
}) {
const li = document.createElement('li');
li.setAttribute('data-id', id);
li.classList.add('list-group-item', 'd-flex', 'justify-content-between', 'align-items-center');
li.innerHTML = `${clave} | ${grado} ${profesor}`
const btn = document.createElement('button');
btn.setAttribute('type', 'button');
btn.classList.add('badge', 'badge-danger', 'badge-pill', 'border-0');
btn.onclick = _ => li.remove();
const i = document.createElement('i');
i.classList.add('ing-cancelar');
btn.appendChild(i);
li.appendChild(btn);
document.getElementById("profesores").appendChild(li);
}
// function for comparing two hours in format hh:mm (24 hours) and return the spaceship operator
function compareHours(hora1, hora2) {
// parseInt each hour and minute
const [h1, m1, ] = hora1.split(":").map(x => parseInt(x));
const [h2, m2, ] = hora2.split(":").map(x => parseInt(x));
if (h1 > h2)
return 1;
else if (h1 < h2)
return -1;
else if (m1 > m2)
return 1;
else if (m1 < m2)
return -1;
else
return 0;
}
async function buscarGrupo() {
// Add loading animation in the button
const btn = document.querySelector("#btn-buscar");
btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Cargando...';
btn.disabled = true;
const carrera = document.querySelector("#filter_carrera").value;
const grupo = document.querySelector("#filter_grupo").value;
if (carrera == "" || grupo == "") {
triggerMessage("El nombre del grupo y la carrera son requeridos", "Faltan campos");
// Remove loading animation in the button
btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
btn.disabled = false;
return;
}
const formData = new FormData();
formData.append("carrera", carrera);
formData.append("grupo", grupo);
formData.append("periodo", document.querySelector("#periodo").value);
formData.append('facultad', '<?= $user->facultad['facultad_id'] ?>');
try {
gHorarios = [];
const {
status,
horario: horarios,
} = await fetch("action/action_horario.php", {
method: "POST",
body: formData
}).then(res => res.json());
if (status != "success") {
triggerMessage(response.message, "Error");
// Remove loading animation in the button
btn.innerHTML = /* HTML */ `<i class="ing-buscar ing"></i> Buscar`;
btn.disabled = false;
}
// show the table
table.style.display = "table";
document.querySelectorAll('.hidden').forEach(element => element.style.display = "block");
// clear the table
table.innerHTML = empty_table;
if (horarios.length == 0) {
// reload window
window.location.reload();
return;
}
// fill the table
gHorarios = horarios;
function conflicts(horario1, horario2) {
const {
hora: hora_inicio1,
hora_final: hora_final1,
dia: dia1,
} = horario1;
const {
hora: hora_inicio2,
hora_final: hora_final2,
dia: dia2,
} = horario2;
// if the days are different, there is no conflict
if (dia1 != dia2) {
return false;
}
const compareInicios = compareHours(hora_inicio1, hora_inicio2);
const compareFinales = compareHours(hora_final1, hora_final2);
const compareInicioFinal = compareHours(hora_inicio1, hora_final2);
const compareFinalInicio = compareHours(hora_final1, hora_inicio2);
// if the horario is inside the other
if (compareInicios === 0 || compareFinales === 0)
return true
if (compareInicios === 1 && compareInicioFinal === -1)
return true
if (compareFinales === -1 && compareFinalInicio === 1)
return true
// if the horario is outside the other
if (compareInicios === -1 && compareFinales === 1)
return true
return false;
}
// remove the next 5 cells
function removeNextCells(horas, minutos, dia, cells = 5) {
[...Array(cells).keys()].map(i => i + 1).forEach(i => {
const minute = (minutos + i * 15)
const next_minute = (minute % 60).toString().padStart(2, "0");
const next_hour = (horas + Math.floor(minute / 60))
document.getElementById(`hora-${next_hour}:${next_minute}-${dia}`).remove()
});
}
function newBlock(horario, edit = false) {
function move(horario, cells) {
const {
hora: hora_inicio,
dia,
} = horario;
const [horas, minutos] = hora_inicio.split(":").map(x => parseInt(x));
const cell = document.getElementById(`hora-${horas}:${minutos.toString().padStart(2, "0")}-${dia}`);
const {
top,
left
} = cell.getBoundingClientRect();
const block = document.getElementById(`block-${horario.id}`);
block.style.top = `${top}px`;
block.style.left = `${left}px`;
removeNextCells(horas, minutos, dia, cells);
}
const {
id,
materia,
salon,
profesores,
hora: hora_inicio,
dia,
bloques
} = horario;
const [horas, minutos] = hora_inicio.split(":").map(x => parseInt(x));
const hora = `${horas}:${minutos.toString().padStart(2, "0")}`;
horario.hora = hora;
const cell = document.getElementById(`hora-${hora}-${dia}`);
cell.dataset.ids = id;
cell.innerHTML = /*html*/ `
<small class="text-gray">${hora}</small>
<b class="title">${materia}</b> <br>
<br><span>Salón: </span>${salon} <br>
<small class="overflow-auto my-2" style="max-height: 3rem; display: block;">
${profesores.map(({grado, profesor}) => /*html*/ ` <span class = "ing ing-formacion mx-1" > </span> ${grado} ${profesor}`).join("<br>")}
</small>`
if (edit)
cell.innerHTML += /*html*/
`<div class="menu-flotante p-2" style="opacity: .7;" >
<a class="mx-2" href="#" data-toggle="modal" data-target="#modal-editar">
<i class="ing-editar ing"></i>
</a>
<a class="mx-2" href="#" data-toggle="modal" data-target="#modal-borrar">
<i class="ing-basura ing" > </i>
</a>
</div>
`
cell.classList.add("bloque-clase", "position-relative");
cell.rowSpan = bloques;
// draggable
cell.draggable = <?= $write ? "true" : "false" ?>;
bloques > 0 ? removeNextCells(horas, minutos, dia, bloques - 1) : null;
}
function newConflictBlock(horarios, edit = false) {
const first_horario = horarios[0];
const [horas, minutos] = first_horario.hora.split(":").map(x => parseInt(x));
const hora = `${horas}:${minutos.toString().padStart(2, "0")}`;
const ids = horarios.map(horario => horario.id);
const cell = document.getElementById(`hora-${hora}-${first_horario.dia}`);
if (cell == null) {
console.error(`Error: No se encontró la celda: hora-${hora}-${first_horario.dia}`);
return;
}
cell.dataset.ids = ids.join(",");
// replace the content of the cell
cell.innerHTML = /* HTML */ `
<small class = 'text-danger'>
${hora}
</small>
<div class="d-flex justify-content-center align-items-center mt-4">
<div class="d-flex flex-column justify-content-center align-items-center">
<span class="ing ing-importante text-danger" style="font-size: 2rem;"></span>
<b class='text-danger'>
Empalme de ${ids.length} horarios
</b> <hr>
<i class="text-danger">Ver horarios &#8230;</i>
</div>
</div>
`;
// the text must be centered
// cell.style.backgroundColor = "#f6cfd6";
cell.classList.add("conflict", "bloque-clase");
// add cursor clickable role = "button"
cell.setAttribute("role", "button");
// add the event listener for the cell
cell.addEventListener("click", () => {
$("#modal-choose").modal("show");
const ids = cell.getAttribute("data-ids").split(",").map(x => parseInt(x));
const horarios = gHorarios.filter(horario => ids.includes(horario.id));
const tbody = document.querySelector("#modal-choose tbody");
tbody.innerHTML = "";
horarios.sort((a, b) => compareHours(a.hora, b.hora)).forEach(horario => {
const {
materia,
dia,
hora,
hora_final,
profesores,
salon,
id,
} = horario;
// remove the last 00 of the hour
const [horaFmt, hora_finalFmt] = [hora, hora_final].map(hora => hora.slice(0, -3))
const buttons = /* HTML */ `
<td class="text-center">
<button class="btn btn-sm btn-primary dismiss-editar" data-toggle="modal" data-target="#modal-editar">
<i class="ing-editar ing"></i>
</button>
</td>
<td class="text-center">
<button class="btn btn-sm btn-danger dismiss-editar" data-toggle="modal" data-target="#modal-borrar">
<i class="ing-basura ing"></i>
</button>
</td>`
tbody.innerHTML += /* HTML */ `
<tr data-ids="${id}">
<td><small>${horaFmt}-${hora_finalFmt}</small></td>
<td>${materia}</td>
<td>
${profesores.map(({ grado, profesor }) => `${grado} ${profesor}`).join(", ")}
</td>
<td>${salon}</td>
${edit ? buttons : ""}
</tr>`;
});
document.querySelectorAll(".dismiss-editar").forEach(btn => {
btn.addEventListener("click", () => $("#modal-choose").modal("hide"));
});
});
// blocks is (firsthour - lasthour) / 15 minutes
// sum the duracion_bloques of each horario
function getDuration(hora_i, hora_f) {
const [horas_i, minutos_i] = hora_i.split(":").map(x => parseInt(x));
const [horas_f, minutos_f] = hora_f.split(":").map(x => parseInt(x));
const date_i = new Date(0, 0, 0, horas_i, minutos_i);
const date_f = new Date(0, 0, 0, horas_f, minutos_f);
const diff = date_f - date_i;
return diff / (1000 * 60 * 15);
}
const lastHorario = horarios[horarios.length - 1];
// remove the next cells
// get the max hora_final
const maxHoraFinal = horarios.reduce((max, horario) => {
const [horas, minutos] = horario.hora_final.split(":").map(x => parseInt(x));
const date = new Date(0, 0, 0, horas, minutos);
return date > max ? date : max;
}, new Date(0, 0, 0, 0, 0));
const blocks = getDuration(first_horario.hora, `${maxHoraFinal.getHours()}:${maxHoraFinal.getMinutes()}`);
cell.rowSpan = blocks
removeNextCells(horas, minutos, first_horario.dia, blocks - 1);
}
const conflictBlocks = horarios.filter((horario, index, arrayHorario) =>
arrayHorario.filter((_, i) => i != index).some(horario2 =>
conflicts(horario, horario2)))
.sort((a, b) => compareHours(a.hora, b.hora));
const classes = horarios.filter(horario => !conflictBlocks.includes(horario));
const conflictBlocksPacked = []; // array of sets
conflictBlocks.forEach(horario => {
const setIndex = conflictBlocksPacked.findIndex(set => set.some(horario2 => conflicts(horario, horario2)));
if (setIndex === -1) {
conflictBlocksPacked.push([horario]);
} else {
conflictBlocksPacked[setIndex].push(horario);
}
})
classes.forEach(horario =>
newBlock(horario, <?= $write ?>)
)
conflictBlocksPacked.forEach(horarios =>
newConflictBlock(horarios, <?= $write ?>)
)
// remove the elements that are not in the limits
let max_hour = Math.max(...horarios.map(horario => {
const lastMoment = moment(horario.hora, "HH:mm").add(horario.bloques * 15, "minutes");
const lastHour = moment(`${lastMoment.hours()}:00`, "HH:mm");
const hourInt = parseInt(lastMoment.format("HH"));
return lastMoment.isSame(lastHour) ? hourInt - 1 : hourInt;
}));
let min_hour = Math.min(...horarios.map(horario => parseInt(horario.hora.split(":")[0])));
document.querySelectorAll("tbody#horario tr").forEach(hora => {
const hora_id = parseInt(hora.id.split("-")[1].split(":")[0]);
(hora_id < min_hour || hora_id > max_hour) ? hora.remove(): null;
})
// if there is no sábado, remove the column
if (!horarios.some(horario => horario.dia == "sábado")) {
document.querySelectorAll("tbody#horario td").forEach(td => {
if (td.id.split("-")[2] == "sábado") {
td.remove();
}
});
// remove the header (the last)
document.querySelector("#headers").lastElementChild.remove();
}
// adjust width
const ths = document.querySelectorAll("tr#headers th");
ths.forEach((th, key) =>
th.style.width = (key == 0) ? "5%" : `${95 / (ths.length - 1)}%`
);
// search item animation
const menúFlontantes = document.querySelectorAll(".menu-flotante");
menúFlontantes.forEach((element) => {
element.classList.add("d-none");
element.parentElement.addEventListener("mouseover", () =>
element.classList.remove("d-none")
);
element.parentElement.addEventListener("mouseout", (e) =>
element.classList.add("d-none")
);
});
} catch (error) {
triggerMessage("Error al cargar el horario", "Error");
triggerMessage(error, "Error");
}
// droppables
// forall the .bloque-elements add the event listeners for drag and drop
<?php if ($write) : ?>
document.querySelectorAll(".bloque-clase").forEach(element => {
function dragStart() {
this.classList.add("dragging");
}
function dragEnd() {
this.classList.remove("dragging");
}
element.addEventListener("dragstart", dragStart);
element.addEventListener("dragend", dragEnd);
});
// forall the cells that are not .bloque-clase add the event listeners for drag and drop
document.querySelectorAll("td:not(.bloque-clase)").forEach(element => {
function dragOver(e) {
e.preventDefault();
this.classList.add("dragging-over");
}
function dragLeave() {
this.classList.remove("dragging-over");
}
function drop() {
this.classList.remove("dragging-over");
const dragging = document.querySelector(".dragging");
const id = /* for data-ids */ dragging.getAttribute("data-ids");
const hora = /* for data-hora */ this.id.split("-")[1];
const días = ["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"];
let día = /* for data-dia */ this.id.split("-")[2];
día = días.indexOf(día) + 1;
// rowspan
const bloques = parseInt(dragging.getAttribute("rowspan"));
const horaMoment = moment(hora, "HH:mm");
const horaFin = horaMoment.add(bloques * 15, "minutes");
const limit = moment('22:00', 'HH:mm');
if (horaFin.isAfter(limit)) {
triggerMessage("No se puede mover el bloque a esa hora", "Error");
// scroll to the top
window.scrollTo(0, 0);
return;
}
moveHorario(id, día, hora);
}
element.addEventListener("dragover", dragOver);
element.addEventListener("dragleave", dragLeave);
element.addEventListener("drop", drop);
});
<?php endif; ?>
// Remove loading animation in the button
btn.innerHTML = '<i class="ing-buscar ing"></i> Buscar';
btn.disabled = false;
// console.table(gHorarios);
}
async function guardar(id) {
const btn = document.querySelector("#btn-guardar");
const clone = btn.cloneNode(true);
btn.innerHTML = '<i class="ing-cargando ing"></i> Guardando...';
btn.disabled = true;
const data = {
dia: document.querySelector("#editor_dia"),
salon: document.querySelector("#editor_salón"),
//vprofesor: document.querySelector("#editor_profesor"),
duración: document.querySelector("#editor_duración")
};
const dia = data.dia.value;
const salon = data.salon.value;
if (salon == "") {
btn.innerHTML = clone.innerHTML;
btn.disabled = false;
return;
}
const hora = document.querySelector("#selector_horas").value;
const minutos = document.querySelector("#selector_minutos").value;
const bloques = document.querySelector("#dlduración li.selected").getAttribute("data-bloques");
const start = moment(`${hora}:${minutos}`, "HH:mm").add(bloques * 15, "minutes");
const end = moment("22:00", "HH:mm");
if (start.isAfter(end)) {
btn.innerHTML = clone.innerHTML;
btn.disabled = false;
document.querySelector("#dlduración").classList.add("is-invalid");
return;
}
const profesoresList = [...document.querySelectorAll("#profesores li")];
if (profesoresList.length == 0) {
btn.innerHTML = clone.innerHTML;
btn.disabled = false;
return;
}
const formData = new FormData();
// const id = btn.getAttribute("data-id");
formData.append("id", id);
const horas = document.querySelectorAll("#selector_horas, #selector_minutos")
formData.append("hora", `${horas[0].value}:${horas[1].value}`);
formData.append("día", dia);
formData.append("salón", salon);
const profesores = profesoresList.map(li => li.getAttribute("data-id"));
formData.append("duración", data.duración.value);
formData.append("profesores", profesores.join(","));
const response = await fetch("action/action_horario_update.php", {
method: "POST",
body: formData
}).then(res => res.json());
if (response.status == "success") {
triggerMessage("Horario actualizado", "Éxito", "success");
btn.innerHTML = '<i class="ing-aceptar ing"></i> Guardado';
btn.classList.add("btn-success");
btn.classList.remove("btn-primary");
// return to the initial state
setTimeout(() => {
buscarGrupo();
btn.replaceWith(clone);
$("#modal-editar").modal("hide");
}, 100);
} else {
triggerMessage(response.message, "Error");
btn.replaceWith(clone);
$("#modal-editar").modal("hide");
}
}
async function borrarHorario(id) {
const btn = document.querySelector("#btn-borrar");
const clone = btn.cloneNode(true);
btn.innerHTML = '<i class="ing-cargando ing"></i> Borrando...';
btn.disabled = true;
const formData = new FormData();
formData.append("id", id);
const response = await fetch("action/action_horario_delete.php", {
method: "POST",
body: formData
}).then(res => res.json());
if (response.status == "success") {
triggerMessage('Horario borrado', "Éxito", "success");
btn.innerHTML = '<i class="ing-aceptar ing"></i> Borrado';
btn.classList.add("btn-success");
btn.classList.remove("btn-danger");
// return to the initial state
setTimeout(() => {
buscarGrupo();
btn.replaceWith(clone);
$("#modal-borrar").modal("hide");
}, 1000);
} else {
triggerMessage(response.message, "Error");
btn.replaceWith(clone);
$("#modal-borrar").modal("hide");
}
}
function guardarHorario() {
let goBack = false;
const btn = document.querySelector("#btn-guardar-horario");
const clone = btn.cloneNode(true);
btn.innerHTML = '<i class="ing-cargando ing"></i> Guardando...';
btn.disabled = true;
const data = {
dia: document.querySelector("#new_dia"),
salon: document.querySelector("#new_salón"),
profesor: document.querySelector("#new_profesor"),
duración: document.querySelector("#new_duración"),
materia: document.querySelector("#new_materia")
};
const dia = data.dia.value;
const salon = data.salon.value;
const profesor = data.profesor.value;
const materia = data.materia.value;
const duración = data.duración.value;
if (duración == "") {
invalidDatalist("#new_duración");
goBack = true;
}
if (profesor == "") {
data.profesor.classList.add("is-invalid");
goBack = true;
}
if (salon == "") {
data.salon.classList.add("is-invalid");
goBack = true;
}
if (dia == "") {
invalidDatalist("#new_dia");
goBack = true;
}
if (materia == "") {
data.materia.classList.add("is-invalid");
goBack = true;
}
const hora = document.querySelector("#new_horas").value;
if (hora == "") {
invalidDatalist("#new_horas");
goBack = true;
}
const minutos = document.querySelector("#new_minutos").value;
if (minutos == "") {
invalidDatalist("#new_minutos");
goBack = true;
}
const bloques = document.querySelector("#dlNewDuración li.selected")?.getAttribute("data-bloques");
const start = moment(`${hora}:${minutos}`, "HH:mm").add(bloques * 15, "minutes");
const end = moment("22:00", "HH:mm");
if (start.isAfter(end)) {
document.querySelector("#dlNewDuración").classList.add("is-invalid");
goBack = true;
}
if (goBack) {
btn.innerHTML = clone.innerHTML;
btn.disabled = false;
return;
}
const formData = new FormData();
formData.append("grupo", document.querySelector("#filter_grupo").value);
formData.append("hora", `${hora}:${minutos}`);
formData.append("día", dia);
formData.append("salón", salon);
formData.append("profesor", profesor);
formData.append("duración", data.duración.value);
formData.append("periodo", "<?= $user->periodo ?>");
formData.append("materia", materia);
formData.append("facultad", "<?= $user->facultad['facultad_id'] ?>");
fetch("action/action_horario_create.php", {
method: "POST",
body: formData
}).then(res => res.json()).then(response => {
if (response.status == "success") {
triggerMessage("Horario guardado", "Éxito", "success");
btn.innerHTML = /* html */ `<i class="ing-aceptar ing"></i> Guardado`;
btn.classList.add("btn-success");
btn.classList.remove("btn-primary");
// return to the initial state
setTimeout(() => {
btn.innerHTML = clone.innerHTML;
btn.disabled = false;
btn.classList.remove("btn-success");
btn.classList.add("btn-primary");
// this modal
$("#modal-nuevo").modal("hide");
const modalNuevo = document.querySelector("#modal-nuevo");
modalNuevo.querySelectorAll("input").forEach(input => {
input.value = "";
});
// reset the datalist
modalNuevo.querySelectorAll(".datalist").forEach(datalist => {
const cloneDatalist = modalNuevoClone.querySelector(`#${datalist.id}`).cloneNode(true);
// log
datalist.replaceWith(cloneDatalist);
});
// remove all is-valid and is-invalid
modalNuevo.querySelectorAll(".is-valid, .is-invalid").forEach(el => {
el.classList.remove("is-valid", "is-invalid");
});
}, 100);
} else {
triggerMessage(response.message, "Error");
btn.innerHTML = clone.innerHTML;
btn.disabled = false;
$("#modal-nuevo").modal("hide");
}
}).then(() => {
buscarGrupo();
}).catch(err => {
triggerMessage(err, "Error");
btn.innerHTML = clone.innerHTML;
btn.disabled = false;
$("#modal-nuevo").modal("hide");
});
// buscarGrupo();
}
function moveHorario(id, día, hora) {
const formData = new FormData();
formData.append("id", id);
formData.append("hora", hora);
formData.append("día", día);
fetch("action/action_horario_update.php", {
method: "POST",
body: formData
}).then(res => res.json()).then(response => {
if (response.status == "success") {
triggerMessage("Horario movido", "Éxito", "success");
} else {
triggerMessage(response.message, "Error");
}
}).then(() => {
buscarGrupo();
}).catch(err => {
triggerMessage(err, "Error");
});
}
// initial state
{
// fill the table with empty cells
[...Array(16).keys()].map(x => x + 7).forEach(hora => {
// add 7 rows for each hour
[0, 15, 30, 45].map(minute => minute.toString().padStart(2, '0')).forEach(minute => {
const tr = document.createElement("tr");
tr.id = `hora-${hora}:${minute}`;
tr.classList.add(hora > 13 ? "tarde" : "mañana");
if (minute == 0) {
const th = document.createElement("th");
th.classList.add("text-center");
th.scope = "row";
th.rowSpan = 4;
th.innerText = `${hora}:00`;
th.style.verticalAlign = "middle";
tr.appendChild(th);
}
["lunes", "martes", "miércoles", "jueves", "viernes", "sábado"].forEach(día => {
const td = document.createElement("td");
td.id = `hora-${hora}:${minute}-${día}`;
tr.appendChild(td);
});
document.querySelector("tbody#horario").appendChild(tr);
});
})
// add an inital height to the table cells
// query selector All tds and ths inside the tbody#horario
// previous query selector: "tbody#horario td, tbody#horario tr"
document.querySelectorAll("tbody#horario td, tbody#horario tr").forEach(element => element.style.height = "2rem");
document.getElementById('btn-buscar').addEventListener('click', buscarGrupo);
document.getElementById('dlProfesor').addEventListener('input', function(e) {
var input = document.getElementById('dlProfesor');
var value = input.value;
var option = document.querySelector(`option[value="${value}"]`);
if (!option) {
document.getElementById('editor_profesor').value = "";
// remove is valid class
input.classList.remove("is-valid");
// add is invalid class
input.classList.add("is-invalid");
return
}
var id = option.getAttribute('data-id');
if (!document.querySelector(`li[data-id="${id}"]`))
listProfesor({
id: id,
grado: option.getAttribute('data-grado'),
profesor: option.getAttribute('data-profesor'),
clave: option.getAttribute('data-clave')
});
e.target.value = "";
});
}
// state
const table = document.querySelector("table");
const empty_table = table.innerHTML;
document.querySelectorAll('.hidden').forEach(element => element.style.display = "none");
// hide the table
table.style.display = "none";
disableDatalist("#filter_grupo");
document.getElementById("btn-excel-horario").addEventListener("click", () => {
const formData = new FormData();
const grupo = document.getElementById("filter_grupo").value;
formData.append("grupo", grupo);
formData.append('sábado', gHorarios.some(horario => horario.dia == "sábado"));
formData.append("horarios", JSON.stringify(gHorarios));
// min and max hour
formData.append("min", gHorarios.reduce((min, horario) => {
const hora = horario.hora.split(":").map(x => parseInt(x))[0]
return Math.min(hora, min);
}, 24));
formData.append("max", gHorarios.reduce((max, horario) => {
const {
hora,
bloques
} = horario;
// after hour
const lastHour = moment(hora, "HH:mm").add(bloques * 15, "minutes");
const lastMoment = moment(`${lastHour.format("HH")}:00`, "HH:mm");
const intHour = parseInt(lastHour.format("HH"));
return Math.max(lastMoment.isSame(lastHour) ? intHour - 1 : intHour, max);
}, 0));
fetch("export/horario_excel.php", {
method: "POST",
body: formData
})
.then(response => response.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.setAttribute('href', url);
a.setAttribute('download', `horario-${grupo}.xlsx`);
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
})
.catch(() => triggerMessage("error", "Error al exportar el horario"));
});
// on click the li element, inside datalist #dlcarera
document.querySelectorAll("#dlcarrera li").forEach(async li => {
li.addEventListener("click", async () => {
// get the data-id from the li element
const carrera = li.getAttribute("data-id");
const facultad = '<?= $user->facultad['facultad_id'] ?>';
const periodo = '<?= $user->periodo ?>';
const formData = new FormData();
formData.append("carrera", carrera);
formData.append("facultad", facultad);
formData.append("periodo", periodo);
try {
const {
status,
grupos
} = await fetch("action/action_grupo.php", {
method: "POST",
body: formData
}).then(res => res.json());
if (status != "success") {
throw new Error("Error al cargar los grupos");
} else if (grupos.length == 0) {
throw new Error("No hay grupos para esta carrera");
}
const dlgrupo = document.querySelector("#dlgrupo ul");
const prompt = document.querySelector("#dlgrupo .datalist-input");
dlgrupo.innerHTML = "";
grupos.forEach(grupo => {
const li = document.createElement("li");
// data-id is the id of the group
li.setAttribute("data-id", grupo);
li.textContent = grupo;
dlgrupo.appendChild(li);
});
// write Seleccionar grupo
prompt.textContent = "Seleccionar grupo";
disableDatalist("#filter_grupo", false);
// to #filter_grupo input value
const filter_grupo = document.querySelector("#filter_grupo");
filter_grupo.value = "";
} catch (error) {
// remove Error: from the error message
error = error.toString().replace("Error: ", "");
triggerMessage(error, "Error");
console.error(error);
}
const datalist = document.querySelector("#materias");
const materias = await fetch("action/action_materias.php", {
method: "POST",
body: formData
}).then(res => res.json());
});
})
// on modal edit, show the data
$("#modal-editar").on("show.bs.modal", async function(event) {
document.querySelectorAll("#modal-editar .is-invalid, #modal-editar .is-valid")?.forEach(element => element.classList.remove("is-invalid", "is-valid"));
const button = event.relatedTarget;
const parentId = button.parentElement.parentElement.getAttribute("data-ids");
const {
id,
dia,
hora,
materia,
salon,
profesores,
duracion
} = gHorarios?.find(horario => horario.id == parentId);
// search the data-id of the day and click it
const númeroDía = ['domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado'].reduce((acc, curr, key) => (curr == dia) ? key : acc);
document.querySelector(`#dldia li[data-id="${númeroDía}"]`)?.click();
document.querySelector(`#dlduración li[data-id="${duracion}"]`)?.click();
const horas = hora.split(":")[0];
const minutos = hora.split(":")[1];
setDatalist("#selector_horas", horas);
setDatalist("#selector_minutos", minutos);
document.getElementById('editor_salón').value = salon;
// get the option with data-id profesor
document.getElementById("profesores").innerHTML = "";
profesores.forEach(listProfesor);
const btnGuardar = document.getElementById('btn-guardar');
btnGuardar.onclick = () => guardar(id);
})
$("#modal-borrar").modal({
show: false,
backdrop: "static",
keyboard: false,
})
$("#modal-borrar").on("show.bs.modal", async function(event) {
const button = event.relatedTarget;
const id = button.parentElement.parentElement.getAttribute("data-ids");
const btnBorrar = document.getElementById('btn-borrar');
btnBorrar.onclick = () => borrarHorario(id);
})

View File

@@ -0,0 +1,75 @@
/*
jQuery Custom Input File Plugin - version 1.0
Copyright 2014, Ángel Espro, www.aesolucionesweb.com.ar,
Licence : GNU General Public License
Site: www.aesolucionesweb.com.ar/plugins/custom-input-file
You must not remove these lines. Read gpl.txt for further legal information.
*/
(function($){CustomFile=function(elem,options){this.elem=$(elem);this.itemFileList=[];this.defaults={type:'all',allowed:'all',notAllowed:[],addContainerAfter:$(elem),multiple:true,maxFiles:5,maxMB:0,maxKBperFile:2048,fileWrapper:'<div class="cif-parent"></div>',filePicker:'<h3>Soltar archivos aquí</h3><p>o clic para seleccionar desde carpeta</p><div class="cif-icon-picker"></div>',image:{crop:false,preview:{display:true,maxWidth:300},cropSize:[320,225],minSize:[0,0],maxSize:[0,0]},messages:{errorType:"Tipo de archivo no permitido",errorMaxMB:"Peso máximo de archivos acumulado excedido",errorFileKB:"Archivo muy pesado",errorMaxFiles:"Cantidad máxima de archivos alcanzada",errorBigImage:"Imagen muy grande",errorSmallImage:"Imagen muy pequeña",errorOnReading:"Aplicación ocupada. Inténtelo más tarde.",errorMultipleDisable:"Suelte un archivo por vez."},popup:{active:true,autoclose:true,delay:10000},callbacks:{onComplete:function(app){},beforeRead:function(file){},onSuccess:function(item,callback){},onError:function(file,msg){},beforeRemove:function(item){},}}
this.settings=$.extend(true,{},this.defaults,options);this.status='stop';this.init();}
CustomFile.prototype={init:function(){var attnm=this.elem.attr("name");if(attnm=='')var attnm="inputfile";this.name=(attnm.indexOf("[]",attnm-2)===-1)?attnm+"[]":attnm;this.form=this.elem.parents('form');this.container=$('<div class="cif-file-container cif-container-'+this.settings.type+'-type">');var image=this.settings.image;image.minSize=(typeof(image.minSize)!=='object'||image.minSize.length!==2)?[0,0]:image.minSize;if(image.crop){var minSize=[];for(i=0;i<image.minSize.length;i++){var value=(image.minSize[i]>image.cropSize[i])?image.minSize[i]:image.cropSize[i];minSize.push(value);}
image.minSize=minSize}
this.setFileWrapper();this.appendContainer();this.filePicker=new FilePicker(this);$.customFile.elements.push(this);},onSuccess:function(item,callback){this.itemFileList.push(item);if(this.settings.callbacks.onSuccess(item,callback)===false)return;callback();},onError:function(file,msg){this.settings.callbacks.onError(file,msg);var popupSet=this.settings.popup;if(popupSet.active)
for(k=0;k<msg.length;k++){var fileExt=file.name.substr(file.name.lastIndexOf('.')+1);var fileName=file.name.substr(0,file.name.lastIndexOf('.'));if(fileName.length>42)var fileName=fileName.substr(0,40)+"...";msg[k]+=' ('+fileName+'.'+fileExt+')';$.customFile.popup.add(msg[k],popupSet.autoclose,popupSet.delay,'error');}},onComplete:function(){this.status="completed";if(this.settings.multiple){var response=this.checkMaxFiles()
var popupSet=this.settings.popup;if(response&&popupSet.active)$.customFile.popup.add(response,popupSet.autoclose,popupSet.delay,'ok');}else{if(this.itemFileList.length>1)this.itemFileList[0].destroy();}
this.settings.callbacks.onComplete(this);},read:function(fileList,currentItem){var i=currentItem;if(i+1>fileList.length)this.status='completed';if(this.status==='completed'){this.onComplete();return false;}
var beforeRead=this.settings.callbacks.beforeRead(fileList[i]);if(beforeRead===false)return this.read(fileList,i+1);app=this;var response=app.checkMaxFiles(fileList[i]);if(typeof(response)==='string'){this.onError(fileList[i],[response]);return this.read(fileList,i+1);}
var msg=[];var checklist=["checkFileKB","checkFileType","checkTotalMB"]
for(j=0;j<checklist.length;j++){var response=app[checklist[j]](fileList[i]);if(response)msg.push(response)}
if(msg.length>0){this.onError(fileList[i],msg);return this.read(fileList,i+1);}
new FileItem(this,fileList,i);},appendContainer:function(){var sett=this.settings;if(sett.fileWrapper.parent().length!=0&&sett.appendAfter!=this.elem){sett.addContainerAfter=sett.fileWrapper;}
sett.addContainerAfter.after(this.container);},setFileWrapper:function(){var app=this;var fwr=this.settings.fileWrapper;if(typeof(fwr)==='string')this.settings.fileWrapper=$(fwr);this.settings.fileWrapper=$('<div>',{class:"cif-file-row"}).append(this.settings.fileWrapper);var fwr=this.settings.fileWrapper;fwr.find(':input').each(function(index){var $this=$(this);var attnm=$this.attr("name");if(!attnm)var attnm=app.name.substr(0,app.name.indexOf("[]",-2))+"-"+index;if(attnm.indexOf("[]",-2)===-1){$this.attr("name",attnm+"[]");}});if(fwr.find('.cif-img').length==0&&this.settings.type=='image'){var parent=fwr.find('.cif-parent');if(parent.length===0){var $img=fwr.find('img');var parent=$('<div>',{class:'cif-parent'});parent.append($img);fwr.append(parent);}
if(parent.find('img').length===0)parent.append('<img>')
parent.find('img').addClass("cif-img");}
if(fwr.find('.cif-parent').length==0){fwr.prepend('<div class="cif-parent"></div>');}},checkFileKB:function(file){if(file.size>this.settings.maxKBperFile*1024&&this.settings.maxKBperFile!=0){var msg=this.settings.messages.errorFileKB;}
return msg;},checkFileType:function(file){var ext=file.name.substr(file.name.lastIndexOf('.')+1);var ext=ext.toLowerCase();var imageCropAllowed=["jpeg","jpg","png"]
if((this.settings.type=='image'&&this.settings.image.crop&&imageCropAllowed.indexOf(ext)==-1)||(this.settings.type=='image'&&!file.type.match(/image\//))||(this.settings.allowed!='all'&&this.settings.allowed.indexOf(ext)==-1)||(this.settings.notAllowed.indexOf(ext)!=-1))
{var msg=this.settings.messages.errorType;}
return msg;},checkMaxFiles:function(file){if(this.settings.maxFiles<=this.itemFileList.length&&this.settings.maxFiles){var msg=this.settings.messages.errorMaxFiles;this.filePicker.btn.addClass('inactive');}else{this.filePicker.btn.removeClass('inactive');}
return msg;},checkTotalMB:function(file){var fileSize=(typeof(file)!=='undefined')?file.size:0;var totalSize=0;for(var obj in this.itemFileList){totalSize+=this.itemFileList[obj].file.size;}
if(fileSize+totalSize>this.settings.maxMB*1024*1024&&this.settings.maxMB!=0){var msg=this.settings.messages.errorMaxMB;}
return msg;},checkImageSize:function(img,file){var stt=this.settings.image
if((stt.minSize[0]&&img.width<stt.minSize[0])||(stt.minSize[1]&&img.height<stt.minSize[1])){var msg=this.settings.messages.errorSmallImage;if(stt.minSize[0])msg+=' Ancho mínimo:'+stt.minSize[0]+'px.';if(stt.minSize[1])msg+=' Alto mínimo: '+stt.minSize[1]+'px.';}
if((stt.maxSize[0]&&img.width>stt.maxSize[0])||(stt.maxSize[1]&&img.height>stt.maxSize[1])){var msg=this.settings.messages.errorBigImage;if(stt.maxSize[0])msg+=' Ancho máximo:'+stt.maxSize[0]+'px.';if(stt.maxSize[1])msg+=' Alto máximo: '+stt.maxSize[1]+'px.';}
return msg;},}
FilePicker=function(app){this.btn=$('<div class="cif-file-picker"></div>').append(app.settings.filePicker);this.init(app);}
FilePicker.prototype={init:function(app){var multiple=(app.settings.multiple||app.elem.attr("multiple")=="multiple")?'multiple="multiple"':' ';this.inputHidden=$('<input type="file" '+multiple+'/>');app.elem.after(this.btn);var elem=app.elem.clone();app.elem.detach();app.elem=elem;this.btn.addClass("cif-pkr-"+app.elem.attr("name"));var btn=this.btn;var inputHidden=this.inputHidden;inputHidden.change(function(){var popupSet=app.settings.popup;if(app.status=='reading')return $.customFile.popup.add(app.settings.messages.errorOnReading,popupSet.autoclose,popupSet.delay,'error');$.customFile.popup.close();fileList=$(this)[0].files;app.status='reading';app.read(fileList,0);});btn.on({click:function(){if(!$(this).is('.inactive'))inputHidden.click();return false;},dragover:function(e){e=e||window.event;e.preventDefault();if($(this).is('.inactive'))e.dataTransfer.dropEffect='none';btn.addClass('dragover');return false;},dragleave:function(e){btn.removeClass('dragover');return false;},drop:function(e){e=window.event;e.preventDefault();btn.removeClass('dragover');var popupSet=app.settings.popup;if(app.status=='reading')return $.customFile.popup.add(app.settings.messages.errorOnReading,popupSet.autoclose,popupSet.delay,'error');$.customFile.popup.close();var fileList=e.dataTransfer.files;if(fileList.length>1&&!app.settings.multiple)return $.customFile.popup.add(app.settings.messages.errorMultipleDisable,popupSet.autoclose,popupSet.delay,'error');app.status='reading';app.read(fileList,0);}});},};FileItem=function(app,fileList,currentItem){this.file=fileList[currentItem];this.app=app;this.fileList=fileList;this.currentItem=currentItem;this.init();}
FileItem.prototype={init:function(){this.jcropObj=null;this.node=this.app.settings.fileWrapper.clone();this.img=null;this.btnClose=$('<div class="cif-close" title="Remove">close</div>');this.btnClose.click(function(){fileObj.destroy();});this.fr=new FileReader;var fr=this.fr;var app=this.app;var fileObj=this;var fileList=this.fileList;var currentItem=this.currentItem;var callback=function(){app.onSuccess(fileObj,function(){app.read(fileList,currentItem+1);});delete fileObj.fr;delete fileObj.fileList;delete fileObj.currentItem;}
fr.onload=function(){switch(app.settings.type){case"image":fileObj.readImage(callback);break;default:fileObj.readAllTypes(callback);break;}}
fr.readAsDataURL(this.file);},destroy:function(){this.app.settings.callbacks.beforeRemove(this);if(this.node)this.node.remove();var i=this.app.itemFileList.indexOf(this);this.app.itemFileList.splice(i,1);this.app.checkMaxFiles();},serialize:function(){return $.customFile.serialize([{key:this.app.name,value:this.file}]);},readImage:function(callback){var fileObj=this;var fr=this.fr;var app=this.app;var imgNode=fileObj.node.find("img.cif-img");fileObj.img=new Image;fileObj.img.src=fr.result;fileObj.img.onload=function(){msg=app.checkImageSize(fileObj.img,fileObj.file);if(msg){app.onError(fileObj.file,[msg]);return app.read(fileObj.fileList,fileObj.currentItem+1);}
imgNode.attr("src",fr.result);imgNode.parent().prepend(fileObj.btnClose);app.container.append(fileObj.node);if(app.settings.image.crop===true){fileObj.jcropObj=fileObj.initJcrop(app.settings.image,imgNode.parent(),fileObj.img,app.name);}
callback();}},readAllTypes:function(callback){fileObj=this;var parent=fileObj.node.find('.cif-parent');var FileExt=fileObj.file.name.substr(fileObj.file.name.lastIndexOf('.')+1);var FileName=fileObj.file.name.substr(0,fileObj.file.name.lastIndexOf('.'));if(FileName.length>42)var FileName=FileName.substr(0,40)+"...";var fileSize=(fileObj.file.size<102400)?(fileObj.file.size/1024).toFixed(2):Math.round(fileObj.file.size/1024);parent.append($('<div class="cif-all-type">'+FileName+'.'+FileExt+' <span class="cif-file-size">('+fileSize+'KB)</span><div>')).append(fileObj.btnClose);this.app.container.append(fileObj.node)
callback();},initJcrop:function(options,parent,img,appName){var jcrop_api,boundx,boundy;if(options.preview.display){appName=appName.replace("[]","");prevMaxWidth=options.preview.maxWidth;prevSize=(options.cropSize[0]>prevMaxWidth)?[prevMaxWidth,options.cropSize[1]/options.cropSize[0]*prevMaxWidth]:options.cropSize;parent.append('<div class="preview-pane" style="width:'+prevSize[0]+'px;height:'+prevSize[1]+'px;"><div class="preview-container" style="width:'+prevSize[0]+'px;height:'+prevSize[1]+'px; overflow:hidden"><img src="'+img.src+'" class="jcrop-preview im-prv" /></div></div> '
+'<input type="hidden" class="jcropx" name="'+appName+'-x[]" /><input type="hidden" class="jcropy" name="'+appName+'-y[]" /><input type="hidden" class="jcropw" name="'+appName+'-w[]" /><input type="hidden" class="jcroph" name="'+appName+'-h[]" />');parent.css("min-height",prevSize[1]+20+"px");}
var $preview=parent.find('.preview-pane'),$pcnt=$preview.find('.preview-container'),$pimg=$preview.find('.preview-container img'),xsize=$pcnt.width(),ysize=$pcnt.height();api=parent.find('.cif-img').Jcrop({keySupport:false,onChange:updatePreview,onSelect:updatePreview,aspectRatio:options.cropSize[0]/options.cropSize[1],minSize:options.cropSize,trueSize:[img.width,img.height]},function(){var bounds=this.getBounds();boundx=bounds[0];boundy=bounds[1];jcrop_api=this;jcrop_api.animateTo([0,0,options.cropSize[0]]);$preview.appendTo(jcrop_api.ui.holder);});function updatePreview(c){if(parseInt(c.w)>0&&options.preview.display){var rx=xsize / c.w;var ry=ysize / c.h;$pimg.css({width:Math.round(rx*boundx)+'px',height:Math.round(ry*boundy)+'px',marginLeft:'-'+Math.round(rx*c.x)+'px',marginTop:'-'+Math.round(ry*c.y)+'px'});}
updateCoords(c);};function updateCoords(c){parent.find('.jcropx').val(c.x);parent.find('.jcropy').val(c.y);parent.find('.jcropw').val(c.w);parent.find('.jcroph').val(c.h);}
return jcrop_api;}}
$.customFile={elements:[],getElements:function(selector){var elements=[];var selector=selector.split(",");var el=$.customFile.elements;for(k=0;k<selector.length;k++){selector[k]=selector[k].trim()
for(i=0;i<el.length;i++){if(el[i].name===selector[k]+"[]"||el[i].name===selector[k])
elements.push({type:"pseudoinput",obj:el[i]});if($(selector[k]).is('form')){$(selector[k]).each(function(){elements.push({type:"form",obj:$(this),pseudoChild:(el[i].form[0]===$(this)[0])});});}
if($(selector[k]).is(':input')){$(selector[k]).not(':submit').each(function(){elements.push({type:"input",obj:$(this)});});}}}
var indexToRemove=[]
for(i=0;i<elements.length;i++){if(indexToRemove.indexOf(i)!==-1)continue;for(j=0;j<elements.length;j++){if(j===i||indexToRemove.indexOf(j)!==-1)continue;switch(elements[i].type){case"form":var el=elements[i].obj[0];if(el===elements[j].obj[0]||(elements[j].type==="pseudoinput"&&el==elements[j].obj.form[0])||(elements[j].type==="input"&&el==elements[j].obj.parents('form')[0])){indexToRemove.push(j);}
break;case"input":var el=elements[i].obj[0];if(el===elements[j].obj[0])
indexToRemove.push(j);break;case"pseudoinput":var el=elements[i].obj.name;if(el===elements[j].obj.name||el+"[]"===elements[j].obj.name)
indexToRemove.push(j);break;}}}
var result=[];for(i=0;i<elements.length;i++){if(indexToRemove.indexOf(i)===-1)result.push(elements[i]);}
return result;},serialize:function(elements){formData=null;if(typeof(elements)==='object'){formData=formData||new FormData();if(!elements.length)var elements=[elements]
for(j=0;j<elements.length;j++){if(elements[j].hasOwnProperty("key")&&elements[j].hasOwnProperty("value")){formData.append(elements[j].key,elements[j].value);}}}
if(typeof(elements)==='string'){elements=this.getElements(elements);for(j=0;j<elements.length;j++){formData=formData||new FormData();var elem=elements[j];switch(elem.type){case'pseudoinput':$.each(elem.obj.itemFileList,function(index,element){formData.append(elem.obj.name,element.file);});break;case"form":$.each(elem.obj.find(':input'),function(){if($(this).not(':submit'))
formData.append($(this).attr("name"),$(this).val());});var app=elem.obj.data("appCustomFile");if(typeof(app)=="undefined"){elem.obj.data("appCustomFile",[]);}
$.each(app,function(){appThis=this;$.each(appThis.itemFileList,function(index,element){formData.append(appThis.name,element.file);});});break;case"input":formData.append(elem.obj.attr("name"),elem.obj.val());break;}}}
return formData},ajax:function(el,options){if(typeof(el)==='string'){var element=this.getElements(el)[0];switch(element.type){case"form":var action=element.obj.attr("action");break;case"input":var action=element.obj.parents("form").attr("action");break;case"pseudoinput":var action=element.obj.form.attr("action");break;}
var formData=$.customFile.serialize(el);}
if(typeof(el)==='object'&&el instanceof FileItem){var formData=el.serialize();var action=el.app.form.attr("action");}
var defaults={cache:false,contentType:false,data:formData,processData:false,url:action,type:'POST',progressBar:{active:true,markup:'<div class="cf-progressbar-wr"><div class="cf-progressbar"><span width="0"></span></div></div>',appendTo:$('body'),removeAfterComplete:true,node:null},progress:function(e,total,position,percent){this.progressBar.node.find("span").width(percent+'%');},xhr:function(){var ax=this;var xhr=$.ajaxSettings.xhr();xhr.upload.onprogress=function(e){var e=e||window.event;var position=e.position||e.loaded;var total=e.totalSize||e.total;var percent=((e.loaded/e.total)*100)+"";ax.progress(e,total,position,percent);};xhr.upload.onload=function(){ax.progressBar.node.find("span").width('100%');if(ax.progressBar.removeAfterComplete)
ax.progressBar.node.fadeOut(function(){$(this).remove();});};return xhr;},beforeSend:function(){},complete:function(){},success:function(xml){},}
var settings=$.extend(true,{},defaults,options);if(!settings.progressBar.active)settings.progress=function(){};settings.progressBar.node=$(settings.progressBar.markup);var settBefore=settings.beforeSend;if(settings.progressBar.active){settings.beforeSend=function(){settBefore();settings.progressBar.appendTo.append(settings.progressBar.node);};}
$.ajax(settings);},validate:function(elements,options){elements=this.getElements(elements);for(j=0;j<elements.length;j++){el=elements[j];switch(el.type){case"form":break;case"input":break;case"pseudoinput":break;}}},popup:{wrapper:$('<div id="cif-msg-wr"><div class="cif-msg-close">close</div></div>'),open:function(){var popup=this;this.wrapper.find('.cif-msg-close').click(function(){popup.close()});$('body').append(popup.wrapper);},add:function(msg,autoclose,delay,type){if(!delay)delay=3000;switch(type){case"error":var icon='<span class="cif-msg-icon cif-msg-icon-error"></span>';break;case"ok":var icon='<span class="cif-msg-icon cif-msg-icon-ok"></span>';break;default:var icon='';}
var popup=this;if($('body').find(popup.wrapper).length<1)popup.open();this.wrapper.append('<div class="cif-msg">'+icon+msg+'</div>');if(typeof(fftimeout)!=='undefined')clearTimeout(fftimeout);if(autoclose)
fftimeout=setTimeout(function(){popup.close();},delay);},close:function(){this.wrapper.find(".cif-msg").remove();this.wrapper.detach();}}}
$.fn.customFile=function(options){return this.each(function(){var element=$(this);var tagName=element[0].tagName.toLowerCase();if(tagName=='input'){var customFile=new CustomFile(this,options);var prop=customFile.form
if(typeof(customFile.form.data("appCustomFile"))!="undefined"){var formData=customFile.form.data("appCustomFile");formData.push(customFile);}else{var formData=new Array(customFile);}
customFile.form.data("appCustomFile",formData);}});};})(jQuery);

264
js/datalist.js Normal file
View File

@@ -0,0 +1,264 @@
/*
* Selects con datalist
*/
var click_in_process = false;
var visible = false;
$('.datalist-text .datalist-input').on('focusin', function () {
var elementRoot = $(this).parents('.datalist');
elementRoot.find(".icono").show();
elementRoot.find("ul").show();
elementRoot.find(".datalist-input").trigger("keyup");
});
function ocultaList(e) {
(e.data.padre).find('.icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
(e.data.padre).find('ul').hide();
// $('.datalist .icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
// $('.datalist ul').hide();
}
function ocultaTodos() {
$('.datalist .icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
$('.datalist ul').hide();
}
//$('.datalist-input').click(function(){
$(document).on('click', '.datalist-input', function () {
var elementRoot = $(this).parent();
limpiaInput({ "data": { "padre": elementRoot } });
const alreadyOpen = elementRoot.find('ul').is(':visible');
if (alreadyOpen) {
setTimeout(() => {
ocultaTodos();
}, 0);
// stop all jquery animations
return;
}
if (!elementRoot.hasClass("disabled")) {
elementRoot.find('ul').show();
elementRoot.find('.datalist-input').focus();
elementRoot.find('ul').show();
elementRoot.find('.icono').removeClass('ing-buscar').addClass('ing-cancelar iconoAzul pointer');
elementRoot.find('.icono').on('click', { "padre": elementRoot }, limpiaInput);
elementRoot.find('.icono').on('click', { "padre": elementRoot }, ocultaList);
}
// if other datalist is open, close it
$('.datalist').each(function () {
// get the input hidden from the datalist
var inputHidden = $(this).find('input[type="hidden"]').attr('id');
// get the input hidden from the datalist that was clicked
var inputHiddenClicked = elementRoot.find('input[type="hidden"]').attr('id');
if ($(this).find('ul').is(':visible') && inputHidden != inputHiddenClicked) {
$(this).find('ul').hide();
$(this).find('.icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
}
});
});
//usar class="selected" para marcar seleccioando por default
$(function () {
$.each($(".datalist").find('ul li:not(.not-selectable)'), function () {
if ($(this).hasClass("selected")) {
var elementRoot = $(this).parents('.datalist');
elementRoot.find('.datalist-input').text($(this).html().replace(/[\t\n]+/g, ' ').trim());
var cid = $(this).data('id');
elementRoot.find("input[type=hidden]").val(cid);
}
});
// add not-selectable class to all li elements and the .datalist-input element
$('.datalist-input ul li, .datalist-input').addClass('user-select-none');
});
$(document).on('click', '.datalist-select > ul li:not(.not-selectable)', function () {
var elementRoot = $(this).parents('.datalist');
elementRoot.find('.datalist-input').text($(this).html().replace(/[\t\n]+/g, ' ').trim());
// $(this).parent('ul').siblings('input[type="text"]').blur();
ocultaList({ "data": { "padre": elementRoot } });
var cid = $(this).data('id');
elementRoot.find("input[type=hidden]").val(cid);
elementRoot.find("li").removeClass("selected");
$(this).addClass("selected");
elementRoot.removeClass("datalist-invalid");
});
$('.modal').on('hide.bs.modal', function (e) {
$('.datalist .icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
$('.datalist ul').hide();
});
function setDatalist(selector, value = -1) {
var elementRoot = $(selector).parents('.datalist');
$.each(elementRoot.find('ul li:not(.not-selectable)'), function () {
if ($(this).data("id") == value) {
elementRoot.find('.datalist-input').text($(this).html().replace(/[\t\n]+/g, ' ').trim());
$(selector).val(value);
elementRoot.find("li").removeClass("selected");
$(this).addClass("selected");
}
});
}
function setDatalistFirst(selector) {
var index = 1;
var elementRoot = $(selector).parents('.datalist');
var num = elementRoot.find('ul li:not(.not-selectable)').length;
if (index <= num) {
while (elementRoot.find('ul li:nth-child(' + index + ')').hasClass("not-selectable") && index <= num) {
index++;
}
var element = elementRoot.find('ul li:nth-child(' + index + ')');
elementRoot.find('.datalist-input').text(element.html().replace(/[\t\n]+/g, ' ').trim());
$(selector).val(element.data("id"));
elementRoot.find("li").removeClass("selected");
element.addClass("selected");
}
}
function disableDatalist(selector, disabled = true) {
var elementRoot = $(selector).parents('.datalist');
if (disabled) {
elementRoot.addClass("disabled");
ocultaList({ "data": { "padre": elementRoot } });
} else
elementRoot.removeClass("disabled");
}
function invalidDatalist(selector, invalid = true) {
var elementRoot = $(selector).parents('.datalist');
if (invalid) {
elementRoot.addClass("datalist-invalid");
} else
elementRoot.removeClass("datalist-invalid");
}
function buscaDatalist(selector, valor) {
selector.find('ul li').each(function () {
var elem = $(this);
if ($(this).parent().is('li'))
elem = $(this).parent();
if (!$(this).html().toUpperCase().includes(valor.toUpperCase())) {
$(elem).hide();
selector.find('.datalist-input').val("");
selector.find("input[type=hidden]").val("");
} else
$(elem).show();
});
}
function getDatalistText(selector, valor) {
var elementRoot = $(selector).parents('.datalist');
var text = "";
$.each(elementRoot.find('ul li:not(.not-selectable)'), function () {
if ($(this).data("id") == valor) {
text = $(this).html();
}
});
return text;
}
//---
$('.datalist-text .datalist-input').keyup(function () {
var elementRoot = $(this).parents('.datalist');
var input = $(this);
elementRoot.find('ul li').each(function () {
var elem = $(this);
if ($(this).parent().is('li'))
elem = $(this).parent();
if (!$(this).html().toUpperCase().includes(input.val().toUpperCase()))
$(elem).hide();
else
$(elem).show();
});
});
/*
$('.datalist-text input').blur(function() {
var elementRoot = $(this).parents('.datalist');
console.log("Click? "+click_in_process);
if(!click_in_process) {
buscaDatalist(elementRoot, elementRoot.find('.datalist-input').val());
elementRoot.find('.icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar');
elementRoot.find('ul').children('li').show();
elementRoot.find('ul').hide();
}
click_in_process = false;
});
*/
$('.datalist-text > ul li:not(.not-selectable)').click(function () {
console.log("Li click!" + $(this).html());
var elementRoot = $(this).parents('.datalist');
elementRoot.find('.datalist-input').val($(this).html().replace(/[\t\n]+/g, ' ').trim());
//$(this).parent('ul').siblings('input[type="text"]').blur();
var cid = $(this).data('id');
elementRoot.find("input[type=hidden]").val(cid);
elementRoot.find("li").removeClass("selected");
$(this).addClass("selected");
click_in_process = true;
//elementRoot.find('.datalist-input').blur();
ocultaList({ "data": { "padre": elementRoot } });
});
/* $('.datalist-text .datalist-input').click(function () {
var elementRoot = $(this).parents('.datalist');
limpiaInput({ "data": { "padre": elementRoot } });
const alreadyOpen = elementRoot.find('ul').is(':visible');
console.log("Click! " + alreadyOpen);
elementRoot.find('ul').show();
elementRoot.find('input').focus();
elementRoot.find('ul').show();
elementRoot.find('.icono').removeClass('ing-buscar').addClass('ing-cancelar iconoAzul pointer');
elementRoot.find('.icono').on('click', { "padre": elementRoot }, limpiaInput);
}); */
$(document).on('click', function (e) {
var target = $(e.target);
// or if you click in the .datalist-input and the datalist is visible
let isDatalist = target.parents().addBack().is('.datalist');
// alert(isDatalist);
if (!isDatalist)
ocultaList({ "data": { "padre": $('.datalist') } });
// if the data list is visible and you click in the input, hide the list
});
function limpiaInput(e) {
(e.data.padre).find('.datalist-input').val('');
(e.data.padre).find('.datalist-input').parent().children('ul').children('li').show();
(e.data.padre).find('li:first').focus();
(e.data.padre).find('.datalist-input').focus();
}
// function make required
function makeRequiredDatalist(selector, required = true) {
var elementRoot = $(selector).parents('.datalist');
if (required)
elementRoot.addClass("required");
else
elementRoot.removeClass("required");
}
// function validate
function validateDatalist(selector) {
var elementRoot = $(selector).parents('.datalist');
if (elementRoot.hasClass("required") && $(selector).val() == "") {
invalidDatalist(selector, true);
return false;
}
invalidDatalist(selector, false);
return true;
}

14
js/date_functions.js Normal file
View File

@@ -0,0 +1,14 @@
// function that receives two hours in hh:mm format and compares as a spaceship operator
export function compareHours(h1, h2) {
const [h1h, h1m] = h1.split(":").map(Number);
const [h2h, h2m] = h2.split(":").map(Number);
if (h1h > h2h)
return 1;
if (h1h < h2h)
return -1;
if (h1m > h2m)
return 1;
if (h1m < h2m)
return -1;
return 0;
}

37
js/datepicker-es.js Normal file
View File

@@ -0,0 +1,37 @@
/* Inicialización en español para la extensión 'UI date picker' para jQuery. */
/* Traducido por Vester (xvester@gmail.com). */
( function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define( [ "../widgets/datepicker" ], factory );
} else {
// Browser globals
factory( jQuery.datepicker );
}
}( function( datepicker ) {
datepicker.regional.es = {
closeText: "Cerrar",
prevText: "&#x3C;Ant",
nextText: "Sig&#x3E;",
currentText: "Hoy",
monthNames: [ "enero","febrero","marzo","abril","mayo","junio",
"julio","agosto","septiembre","octubre","noviembre","diciembre" ],
monthNamesShort: [ "ene","feb","mar","abr","may","jun",
"jul","ago","sep","oct","nov","dic" ],
dayNames: [ "domingo","lunes","martes","miércoles","jueves","viernes","sábado" ],
dayNamesShort: [ "dom","lun","mar","mié","jue","vie","sáb" ],
dayNamesMin: [ "D","L","M","X","J","V","S" ],
weekHeader: "Sm",
dateFormat: "dd/mm/yy",
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: "" };
datepicker.setDefaults( datepicker.regional.es );
return datepicker.regional.es;
} ) );

BIN
js/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

44
js/fetchlib.js Normal file
View File

@@ -0,0 +1,44 @@
var submit = function (url, data) {
// create a form
var form = document.createElement('form');
form.method = 'POST';
form.action = url;
form.style.display = 'none';
// add the form data to the form
for (var key in data) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = key;
input.value = data[key];
form.appendChild(input);
}
// submit the form
document.body.appendChild(form);
form.submit();
}
var toFormData = function (obj) {
var formData = new FormData();
for (var key in obj) {
formData.append(key, obj[key]);
}
return formData;
}
var fetchPHP = async function (url, data = {}) {
return response = await fetch(
url,
{ method: 'POST', body: toFormData(data) }
)
.then(response => {
try {
return response.json()
}
catch (e) {
var message = 'Error en la respuesta del servidor';
Promise.reject(message)
}
})
.then(response => response.error ? Promise.reject(response.error) : Promise.resolve(response))
}

20
js/horarios_profesor.js Normal file
View File

@@ -0,0 +1,20 @@
document.getElementById('form').addEventListener('submit', async function (e) {
e.preventDefault();
const formData = new FormData(this);
try {
const response = await fetch('action/action_horario_profesor.php', {
method: 'POST',
body: formData,
});
const data = await response.json();
if (data.status == 'ok') {
}
else {
triggerMessage(data.message, 'Error en la consulta', 'warning');
}
} catch (error) {
triggerMessage('Fallo al consutar los datos ', 'Error', 'danger');
}
});

13
js/jquery-ui.js vendored Normal file

File diff suppressed because one or more lines are too long

2
js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

36
js/messages.js Normal file
View File

@@ -0,0 +1,36 @@
function triggerMessage(message, header, color = "danger", selector = "message") {
const container = document.getElementById(selector);
container.innerHTML = '';
/* Template message_tmp */
var node = /* html */`
<article class="alert alert-${color} alert-dismissible fade show" role="alert" id="alert-color">
<h4 class="alert-heading"><span class="ing-${(color !== 'success') ? 'importante' : 'aceptar'}"></span> ${header}</h4>
<span id="message-alert">${message}</span>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</article>
`
setTimeout(function () {
container.innerHTML = node;
}, 100);
/* setTimeout(function () {
container.innerHTML = '';
}, 5000); */
}
function messageMissingInputs(required) {
var message = 'Faltan los siguientes campos: ';
required.forEach(function (item, index) {
let last = required.length - 1;
if (index == last)
message += item;
else if (index == last - 1)
message += item + ' y ';
else
message += item + ', ';
});
triggerMessage(message, 'Error', 'danger');
}

39
js/messages.php Normal file
View File

@@ -0,0 +1,39 @@
<script>
function triggerMessage(message, header, color = "danger", selector = "message") {
const container = document.getElementById(selector);
let logo;
container.innerHTML = '';
/* Template message_tmp */
var node = /* html */`
<article class="alert alert-${color} alert-dismissible fade show" role="alert" id="alert-color">
<h4 class="alert-heading"><span class="ing-${(color !== 'success') ? 'importante' : 'aceptar'}"></span> ${header}</h4>
<span id="message-alert">${message}</span>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</article>
`
setTimeout(function() {
container.innerHTML = node;
}, 100);
/* setTimeout(function() {
container.innerHTML = '';
}, 5000); */
}
function messageMissingInputs(required) {
var message = 'Faltan los siguientes campos: ';
required.forEach(function(item, index) {
let last = required.length - 1;
if (index == last)
message += item;
else if (index == last - 1)
message += item + ' y ';
else
message += item + ', ';
});
triggerMessage(message, 'Error', 'danger');
}
</script>

2
js/moment.js Normal file

File diff suppressed because one or more lines are too long

1947
js/richtext.js Normal file

File diff suppressed because it is too large Load Diff

31
js/scrollables.js Normal file
View File

@@ -0,0 +1,31 @@
const scrollButtons = `
<a href="#up" id="scroll-up" class="btn btn-primary btn-sm" role="button" aria-pressed="true" style="display: sticky; position: fixed; bottom: 3rem; right: 1rem;">
<span class="ing-caret ing-rotate-180 ing-fw"></span>
</a>
<a href="#down" id="scroll-down" class="btn btn-primary btn-sm" role="button" aria-pressed="true" style="display: sticky; position: fixed; bottom: 1rem; right: 1rem;">
<span class="ing-caret ing-fw"></span>
</a>
`
document.body.insertAdjacentHTML('beforeend', scrollButtons);
const scroll_up = document.querySelector('#scroll-up');
const scroll_down = document.querySelector('#scroll-down');
scroll_up.style.transition = scroll_down.style.transition = 'display 1.5s ease-in-out';
scroll_up.style.display = scroll_down.style.display = 'none';
scroll_up.addEventListener('click', () =>
window.scrollTo({ top: 0, behavior: 'smooth' }))
scroll_down.addEventListener('click', () =>
window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }))
const check = () => {
scroll_down.style.display = (window.scrollY + window.innerHeight) > document.body.scrollHeight * .8 ? 'none' : 'block'
scroll_up.style.display = (window.scrollY) < document.body.scrollHeight * .2 ? 'none' : 'block'
}
['scroll', 'resize'].forEach(e => window.addEventListener(e, check))

49
js/sidebarmenu.js Normal file
View File

@@ -0,0 +1,49 @@
/*
* JQuery para el manejo de menu
*/
$('#dismiss, .overlay').on('click', function () {
// hide sidebar
$('#sidebar').removeClass('active');
// hide overlay
$('.overlay').removeClass('active');
$('.menu').css('visibility', 'visible');
});
$('#sidebarCollapse').on('click', function () {
// open sidebar
$('#sidebar').addClass('active');
// fade in the overlay
$('.overlay').addClass('active');
$('.menu').css('visibility', 'hidden');
//$('.collapse.in').toggleClass('in');
$('a[aria-expanded=true]').attr('aria-expanded', 'false');
});
/*
var Nightly = new Nightly(true, {
//body: "backgorund color", // Default: #282828
//texts: "texts color", // Default: #f5f5f5
//inputs: {
// color: "text color inside inputs", // Default: #f5f5f5
// backgroundColor: "background color" // Default #313131
//},
//buttons: {
// color: "button's text color", // Default: #f5f5f5
// backgroundColor: "button's backgournd color" // #757575
//},
links: "#ffffff", // Default: #009688
classes: [// Classes to apply when enabling the dark mode on certain elements
{ apply: 'bg-head-dark', to: 'bg-head', },
{ apply: 'form-control-dark', to: 'form-control', },
{ apply: 'subMenu-dark', to: 'subMenu', },
{ apply: 'sistema.text-white', to: 'sistema.text-secondary', },
]
});
if($(".fa-adjust")){
$(".fa-adjust").click(function(){
Nightly.toggle();
});
}*/

187
js/toggle.js Normal file
View File

@@ -0,0 +1,187 @@
/*\
|*| ========================================================================
|*| Bootstrap Toggle: bootstrap4-toggle.js v3.6.1
|*| https://gitbrent.github.io/bootstrap4-toggle/
|*| ========================================================================
|*| Copyright 2018-2019 Brent Ely
|*| Licensed under MIT
|*| ========================================================================
\*/
+function ($) {
'use strict';
// TOGGLE PUBLIC CLASS DEFINITION
// ==============================
var Toggle = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, this.defaults(), options)
this.render()
}
Toggle.VERSION = '3.7.0-beta'
Toggle.DEFAULTS = {
on: 'On',
off: 'Off',
onstyle: 'primary',
offstyle: 'light',
size: 'normal',
style: '',
width: null,
height: null
}
Toggle.prototype.defaults = function() {
return {
on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
}
}
Toggle.prototype.render = function () {
this._onstyle = 'btn-' + this.options.onstyle
this._offstyle = 'btn-' + this.options.offstyle
var size
= this.options.size === 'large' || this.options.size === 'lg' ? 'btn-lg'
: this.options.size === 'small' || this.options.size === 'sm' ? 'btn-sm'
: this.options.size === 'mini' || this.options.size === 'xs' ? 'btn-xs'
: ''
var $toggleOn = $('<label for="'+ this.$element.prop('id') +'" class="btn">').html(this.options.on)
.addClass(this._onstyle + ' ' + size)
var $toggleOff = $('<label for="'+ this.$element.prop('id') +'" class="btn">').html(this.options.off)
.addClass(this._offstyle + ' ' + size)
var $toggleHandle = $('<span class="toggle-handle btn btn-light">')
.addClass(size)
var $toggleGroup = $('<div class="toggle-group">')
.append($toggleOn, $toggleOff, $toggleHandle)
var $toggle = $('<div class="toggle btn" data-toggle="toggle" role="button">')
.addClass( this.$element.prop('checked') ? this._onstyle : this._offstyle+' off' )
.addClass(size).addClass(this.options.style)
this.$element.wrap($toggle)
$.extend(this, {
$toggle: this.$element.parent(),
$toggleOn: $toggleOn,
$toggleOff: $toggleOff,
$toggleGroup: $toggleGroup
})
this.$toggle.append($toggleGroup)
var width = this.options.width || Math.max($toggleOn.outerWidth(), $toggleOff.outerWidth())+($toggleHandle.outerWidth()/2)
var height = this.options.height || Math.max($toggleOn.outerHeight(), $toggleOff.outerHeight())
$toggleOn.addClass('toggle-on')
$toggleOff.addClass('toggle-off')
this.$toggle.css({ width: width, height: height })
if (this.options.height) {
$toggleOn.css('line-height', $toggleOn.height() + 'px')
$toggleOff.css('line-height', $toggleOff.height() + 'px')
}
this.update(true)
this.trigger(true)
}
Toggle.prototype.toggle = function () {
if (this.$element.prop('checked')) this.off()
else this.on()
}
Toggle.prototype.on = function (silent) {
if (this.$element.prop('disabled')) return false
this.$toggle.removeClass(this._offstyle + ' off').addClass(this._onstyle)
this.$element.prop('checked', true)
if (!silent) this.trigger()
}
Toggle.prototype.off = function (silent) {
if (this.$element.prop('disabled')) return false
this.$toggle.removeClass(this._onstyle).addClass(this._offstyle + ' off')
this.$element.prop('checked', false)
if (!silent) this.trigger()
}
Toggle.prototype.enable = function () {
this.$toggle.removeClass('disabled')
this.$toggle.removeAttr('disabled')
this.$element.prop('disabled', false)
}
Toggle.prototype.disable = function () {
this.$toggle.addClass('disabled')
this.$toggle.attr('disabled', 'disabled')
this.$element.prop('disabled', true)
}
Toggle.prototype.update = function (silent) {
if (this.$element.prop('disabled')) this.disable()
else this.enable()
if (this.$element.prop('checked')) this.on(silent)
else this.off(silent)
}
Toggle.prototype.trigger = function (silent) {
this.$element.off('change.bs.toggle')
if (!silent) this.$element.change()
this.$element.on('change.bs.toggle', $.proxy(function() {
this.update()
}, this))
}
Toggle.prototype.destroy = function() {
this.$element.off('change.bs.toggle')
this.$toggleGroup.remove()
this.$element.removeData('bs.toggle')
this.$element.unwrap()
}
// TOGGLE PLUGIN DEFINITION
// ========================
function Plugin(option) {
var optArg = Array.prototype.slice.call( arguments, 1 )[0]
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.toggle')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
if (typeof option === 'string' && data[option] && typeof optArg === 'boolean') data[option](optArg)
else if (typeof option === 'string' && data[option]) data[option]()
//else if (option && !data[option]) console.log('bootstrap-toggle: error: method `'+ option +'` does not exist!');
})
}
var old = $.fn.bootstrapToggle
$.fn.bootstrapToggle = Plugin
$.fn.bootstrapToggle.Constructor = Toggle
// TOGGLE NO CONFLICT
// ==================
$.fn.toggle.noConflict = function () {
$.fn.bootstrapToggle = old
return this
}
// TOGGLE DATA-API
// ===============
$(function() {
$('input[type=checkbox][data-toggle^=toggle]').bootstrapToggle()
})
$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
var $checkbox = $(this).find('input[type=checkbox]')
$checkbox.bootstrapToggle('toggle')
e.preventDefault()
})
}(jQuery);

105
js/util.js Normal file
View File

@@ -0,0 +1,105 @@
/*
* utilidades js
*/
function trim(cadena){
for(i=0; i<cadena.length; ){
if(cadena.charAt(i)==" ")
cadena=cadena.substring(i+1, cadena.length);
else
break;
}
for(i=cadena.length-1; i>=0; i=cadena.length-1){
if(cadena.charAt(i)==" ")
cadena=cadena.substring(0,i);
else
break;
}
return cadena;
}
function getDiaNombre(num){
switch(parseInt(num)){
case 0: return "Domingo";
case 1: return "Lunes";
case 2: return "Martes";
case 3: return "Miércoles";
case 4: return "Jueves";
case 5: return "Viernes";
case 6: return "Sábado";
}
}
function fechaGuion(fechaTxt){//de dd/mm/aaaa a aaaa-mm-dd
fechaTxt = trim(fechaTxt);
if(fechaTxt.substr(2,1) == "/" && fechaTxt.substr(5,1) == "/"){// dd/mm/aaaa
var fechaArr = fechaTxt.split("/");
return fechaArr[2]+"-"+fechaArr[1]+"-"+fechaArr[0];
}
if(fechaTxt.substr(4,1) == "-" && fechaTxt.substr(7,1) == "-")// aaaa-mm-dd
return fechaTxt;
return "";
}
function fechaObjeto(fechaTxt){//de dd/mm/aaaa a aaaa-mm-dd
fechaTxt = trim(fechaTxt);
if(fechaTxt.substr(2,1) == "/" && fechaTxt.substr(5,1) == "/"){// dd/mm/aaaa
var fechaArr = fechaTxt.split("/");
return new Date(parseInt(fechaArr[2]), parseInt(fechaArr[1])-1, parseInt(fechaArr[0]) );
}
if(fechaTxt.substr(4,1) == "-" && fechaTxt.substr(7,1) == "-"){// aaaa-mm-dd
var fechaArr = fechaTxt.split("-");
return new Date(parseInt(fechaArr[0]), parseInt(fechaArr[1])-1, parseInt(fechaArr[2]) );
}
return false;
}
function validaFecha(fechaTxt){
if(fechaTxt.charAt(4) == "-" && fechaTxt.charAt(7) == "-"){//yyyy-mm-dd
var fechaArr = fechaTxt.split("-");
var ano= fechaArr[0];
var mes= fechaArr[1];
var dia= fechaArr[2];
}
if(fechaTxt.charAt(2) == "/" && fechaTxt.charAt(5) == "/"){//dd-mm-aaaa
var fechaArr = fechaTxt.split("/");
var ano= fechaArr[2];
var mes= fechaArr[1];
var dia= fechaArr[0];
}
var d = new Date();
var anoActual = d.getFullYear();
if (isNaN(ano) || ano.length < 4 || parseInt(ano, 10) < (anoActual-1)){ return false; }
if (isNaN(mes) || parseInt(mes, 10) < 1 || parseInt(mes, 10) > 12){ return false; }
if (isNaN(dia) || parseInt(dia, 10) < 1 || parseInt(dia, 10) > 31){ return false; }
if (mes == 4 || mes == 6 || mes == 9 || mes== 11) {
if (dia > 30) { return false; }
} else{
if (mes == 2) {
if(dia <= 28 )
return true;
else{
if ((ano % 4 == 0) && dia == 29) return true;
else return false;
}
}
}
return true;
}
function validaPass(str, vacio = false){
if(vacio && str == "") return true;
return str.match(/\S*(?=\S{5,})(?=\S*[a-zA-Z])(?=\S*[\d])(?=\S*[\W])\S*$/);
}
/*
$('.toggle-password').click(function(){
var campo = $(this).parents(".form-group").find(".toggle-field");
if (campo.prop('type') === "password") {
campo.prop('type', 'text');
} else {
campo.prop('type', 'password');
}
});*/

65
js/vista_forms.js Normal file
View File

@@ -0,0 +1,65 @@
$(".date-picker").datepicker($.datepicker.regional["es"]);
$(".date-picker").datepicker({
dateFormat: "dd/mm/yyyy",
changeMonth: true,
});
$("#fecha_inicial").datepicker("option", "minDate", fecha_inicial);
$("#fecha_inicial").datepicker("option", "maxDate", limit);
$("#fecha_final").datepicker("option", "minDate", fecha_inicial);
$("#fecha_final").datepicker("option", "maxDate", limit);
var today = new Date();
var fecha_inicial = new Date(<?= isset($fecha_inicial) ? $fecha_inicial->format("Y, m-1, d") : date("Y, m-1, d", strtotime($periodo['inicio'])) ?>);
var fecha_final = new Date(<?= isset($fecha_final) ? $fecha_final->format("Y, m-1, d") : date("Y, m-1, d", strtotime($periodo['fin'])) ?>);
var limit = new Date(Math.min(today, fecha_final));
// if today is in the period, set the initial date to today
$("#fecha_inicial").datepicker("setDate", fecha_inicial);
$("#fecha_final").datepicker("setDate", today <= fecha_final ? today : fecha_final);
function reset_form() {
$("#fecha_inicial").datepicker("setDate", fecha_inicial);
$("#fecha_final").datepicker("setDate", today <= fecha_final ? today : fecha_final);
$("#dlcarrera").find("li").removeClass("selected");
$("#dlcarrera").find("li[data-value='0']").addClass("selected");
$("#dlmateria").find("li").removeClass("selected");
$("#dlmateria").find("li[data-value='0']").addClass("selected");
$("#filter_carrera").val("");
$("#filter_materia").val("");
console.log(`Todos los campos han sido limpiados.`);
}
<?php if (empty($carrera)) { ?>
disableDatalist("#filter_materia", true);
<?php } ?>
reset_form();
// $("#fecha_inicial").on("change", function() {
// var fecha_inicial = $("#fecha_inicial").datepicker("getDate");
// var fecha_final = $("#fecha_final").datepicker("getDate");
// if (fecha_final < fecha_inicial) {
// $("#fecha_final").datepicker("setDate", fecha_inicial);
// }
// $("#fecha_final").datepicker("option", "minDate", fecha_inicial);
// });
// $("#fecha_final").on("change", function() {
// var fecha_inicial = $("#fecha_inicial").datepicker("getDate");
// var fecha_final = $("#fecha_final").datepicker("getDate");
// if (fecha_final < fecha_inicial) {
// $("#fecha_inicial").datepicker("setDate", fecha_final);
// }
// $("#fecha_inicial").datepicker("option", "maxDate", fecha_final);
// });
// Datalist carrera then select materia
$(document).on('click', '#dlcarrera li', function() {
// if this is empty
// console.log($(this).attr('data-value'));
if ($(this).attr('data-value') == '0')
disableDatalist("#filter_materia", true);
});