VulpesOS/gaia/apps/calendar/js/utils/overlap.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

135 lines
3.4 KiB
JavaScript
Executable file

/**
* Conflict manager
*/
define(function(require, exports, module) {
'use strict';
/**
* Module dependencies
*/
var ConflictSpan = require('conflict_span');
var IntervalTree = require('interval_tree');
var Timespan = require('common/timespan');
function Overlap() {
this.reset();
}
module.exports = Overlap;
Overlap.prototype = {
reset: function() {
this.tree = new IntervalTree();
this.conflicts = {};
this.elements = {};
},
add: function(myBusytime, element) {
this.tree.add(myBusytime);
this.elements[myBusytime._id] = element;
// Check for conflicts, bail if none
var related = this._findRelated(myBusytime);
if (0 === related.length) {
return;
}
var myID = myBusytime._id;
var myCS = this.conflicts[myID];
var self = this;
related.forEach(function(otherBusytime) {
// Get the other's ID, skip the current
var otherID = otherBusytime._id;
if (otherID === myID) {
return;
}
var otherCS = self.conflicts[otherID];
if (!myCS && !otherCS) {
// This is a brand new conflict.
myCS = new ConflictSpan(self);
myCS.add(myBusytime).add(otherBusytime);
} else if (myCS && !otherCS) {
// Other time can join this one's existing span
myCS.add(otherBusytime);
} else if (!myCS && otherCS) {
// This time can join the other's existing span
myCS = otherCS.add(myBusytime);
} else if (myCS && otherCS && myCS != otherCS) {
// Both already in different spans, so absorb other into this
myCS.absorb(otherCS);
}
});
},
/**
* Remove a busytime from the collection.
* Unlike other methods you must pass a real
* busytime object.
*
* @param {Object} busytime full busytime object.
*/
remove: function(busytime) {
this._clearLayout(busytime);
this.tree.remove(busytime);
delete this.elements[busytime._id];
var myID = busytime._id;
var myCS = this.conflicts[myID];
if (myCS) {
myCS.remove(busytime);
}
},
/**
* Get the ConflictSpan associated with this busytime, if any.
*
* @param {Object|String} busytime id or busytime object.
* @return {Object} associated ConflictSpan, if any.
*/
getConflictSpan: function(busytime) {
var id = this._busytimeId(busytime);
return this.conflicts[id];
},
/**
* @param {Object|String} busytime id or busytime object.
* @return {HTMLElement} associated dom element.
*/
getElement: function(busytime) {
var id = this._busytimeId(busytime);
return this.elements[id];
},
/** private */
_busytimeId: function(busytime) {
return (typeof(busytime) === 'string') ? busytime : busytime._id;
},
/**
* Search tree for busytimes that overlap with the given.
*/
_findRelated: function(busytime) {
//XXX: this is bad encapsulation but
// we generate these when we insert
// the points in the tree.
var span = new Timespan(busytime._startDateMS, busytime._endDateMS);
return this.tree.query(span);
},
/**
* Clear the layout from a busytime element, presumably because it has just
* been removed from conflict.
*
* @param {Object} busytime full busytime object.
*/
_clearLayout: function(busytime) {
var el = this.elements[busytime._id];
el.style.width = '';
el.style.left = '';
el.classList.remove('has-overlaps', 'many-overlaps');
}
};
});