diff -r 058bb3dc685f -r 0b59724cb3f2 cubicweb/web/data/cubicweb.calendar.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cubicweb/web/data/cubicweb.calendar.js Sat Jan 16 13:48:51 2016 +0100 @@ -0,0 +1,361 @@ +/** + * This file contains Calendar utilities + * :organization: Logilab + * :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. + * :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr + */ + +// IMPORTANT NOTE: the variables DAYNAMES AND MONTHNAMES will be added +// by cubicweb automatically +// dynamically computed (and cached) +var _CAL_HEADER = null; + +TODAY = new Date(); + +/** + * .. class:: Calendar + * + * Calendar (graphical) widget + * + * public methods are : + * + * __init__ : + * :attr:`containerId`: the DOM node's ID where the calendar will be displayed + * :attr:`inputId`: which input needs to be updated when a date is selected + * :attr:`year`, :attr:`month`: year and month to be displayed + * :attr:`cssclass`: CSS class of the calendar widget (default is 'commandCal') + * + * show() / hide(): + * show or hide the calendar widget + * + * toggle(): + * show (resp. hide) the calendar if it's hidden (resp. displayed) + * + * displayNextMonth(): (resp. displayPreviousMonth()) + * update the calendar to display next (resp. previous) month + */ +Calendar = function(containerId, inputId, year, month, cssclass) { + this.containerId = containerId; + this.inputId = inputId; + this.year = year; + this.month = month - 1; // Javascript's counter starts at 0 for january + this.cssclass = cssclass || "popupCalendar"; + this.visible = false; + this.domtable = null; + + this.cellprops = { + 'onclick': function() { + dateSelected(this, containerId); + }, + 'onmouseover': function() { + this.style.fontWeight = 'bold'; + }, + 'onmouseout': function() { + this.style.fontWeight = 'normal'; + } + }; + + this.todayprops = jQuery.extend({}, + this.cellprops, { + 'class': 'today' + }); + + this._rowdisplay = function(row) { + var _td = function(elt) { + return TD(this.cellprops, elt); + }; + return TR(null, $.map(row, _td)); + }; + + this._makecell = function(cellinfo) { + return TD(cellinfo[0], cellinfo[1]); + }; + + /** + * .. function:: Calendar._uppercaseFirst(s) + * + * utility function (the only use for now is inside the calendar) + */ + this._uppercaseFirst = function(s) { + return s.charAt(0).toUpperCase(); + }; + + /** + * .. function:: Calendar._domForRows(rows) + * + * accepts the cells data and builds the corresponding TR nodes + * + * * `rows`, a list of list of couples (daynum, cssprops) + */ + this._domForRows = function(rows) { + var lines = []; + for (i = 0; i < rows.length; i++) { + lines.push(TR(null, $.map(rows[i], this._makecell))); + } + return lines; + }; + + /** + * .. function:: Calendar._headdisplay(row) + * + * builds the calendar headers + */ + this._headdisplay = function(row) { + if (_CAL_HEADER) { + return _CAL_HEADER; + } + var self = this; + var _th = function(day) { + return TH(null, self._uppercaseFirst(day)); + }; + return TR(null, $.map(DAYNAMES, _th)); + }; + + this._getrows = function() { + var rows = []; + var firstday = new Date(this.year, this.month, 1); + var stopdate = firstday.nextMonth(); + var curdate = firstday.sub(firstday.getRealDay()); + while (curdate.getTime() < stopdate) { + var row = []; + for (var i = 0; i < 7; i++) { + if (curdate.getMonth() == this.month) { + props = curdate.equals(TODAY) ? this.todayprops: this.cellprops; + row.push([props, curdate.getDate()]); + } else { + row.push([this.cellprops, ""]); + } + curdate.iadd(1); + } + rows.push(row); + } + return rows; + }; + + this._makecal = function() { + var rows = this._getrows(); + var monthname = MONTHNAMES[this.month] + " " + this.year; + var prevlink = "javascript: togglePreviousMonth('" + this.containerId + "');"; + var nextlink = "javascript: toggleNextMonth('" + this.containerId + "');"; + this.domtable = TABLE({ + 'class': this.cssclass + }, + THEAD(null, TR(null, TH(null, A({ + 'href': prevlink + }, + "<<")), + // IE 6/7 requires colSpan instead of colspan + TH({ + 'colSpan': 5, + 'colspan': 5, + 'style': "text-align: center;" + }, + monthname), TH(null, A({ + 'href': nextlink + }, + ">>")))), TBODY(null, this._headdisplay(), this._domForRows(rows))); + return this.domtable; + }; + + this._updateDiv = function() { + if (!this.domtable) { + this._makecal(); + } + cw.jqNode(this.containerId).empty().append(this.domtable); + // replaceChildNodes($(this.containerId), this.domtable); + }; + + this.displayNextMonth = function() { + this.domtable = null; + if (this.month == 11) { + this.year++; + } + this.month = (this.month + 1) % 12; + this._updateDiv(); + }; + + this.displayPreviousMonth = function() { + this.domtable = null; + if (this.month == 0) { + this.year--; + } + this.month = (this.month + 11) % 12; + this._updateDiv(); + }; + + this.show = function() { + if (!this.visible) { + var container = cw.jqNode(this.containerId); + if (!this.domtable) { + this._makecal(); + } + container.empty().append(this.domtable); + toggleVisibility(container); + this.visible = true; + } + }; + + this.hide = function(event) { + var self; + if (event) { + self = event.data.self; + } else { + self = this; + } + if (self.visible) { + toggleVisibility(self.containerId); + self.visible = false; + } + }; + + this.toggle = function() { + if (this.visible) { + this.hide(); + } + else { + this.show(); + } + }; + + // call hide() when the user explicitly sets the focus on the matching input + cw.jqNode(inputId).bind('focus', { + 'self': this + }, + this.hide); // connect(inputId, 'onfocus', this, 'hide'); +}; + +/** + * .. data:: Calendar.REGISTRY + * + * keep track of each calendar created + */ +Calendar.REGISTRY = {}; + +/** + * .. function:: toggleCalendar(containerId, inputId, year, month) + * + * popup / hide calendar associated to `containerId` + */ +function toggleCalendar(containerId, inputId, year, month) { + var cal = Calendar.REGISTRY[containerId]; + if (!cal) { + cal = new Calendar(containerId, inputId, year, month); + Calendar.REGISTRY[containerId] = cal; + } + /* hide other calendars */ + for (containerId in Calendar.REGISTRY) { + var othercal = Calendar.REGISTRY[containerId]; + if (othercal !== cal) { + othercal.hide(); + } + } + cal.toggle(); +} + +/** + * .. function:: toggleNextMonth(containerId) + * + * ask for next month to calendar displayed in `containerId` + */ +function toggleNextMonth(containerId) { + var cal = Calendar.REGISTRY[containerId]; + cal.displayNextMonth(); +} + +/** + * .. function:: togglePreviousMonth(containerId) + * + * ask for previous month to calendar displayed in `containerId` + */ +function togglePreviousMonth(containerId) { + var cal = Calendar.REGISTRY[containerId]; + cal.displayPreviousMonth(); +} + +/** + * .. function:: dateSelected(cell, containerId) + * + * callback called when the user clicked on a cell in the popup calendar + */ +function dateSelected(cell, containerId) { + var cal = Calendar.REGISTRY[containerId]; + var input = cw.getNode(cal.inputId); + // XXX: the use of innerHTML might cause problems, but it seems to be + // the only way understood by both IE and Mozilla. Otherwise, + // IE accepts innerText and mozilla accepts textContent + var selectedDate = new Date(cal.year, cal.month, cell.innerHTML, 12); + input.value = remoteExec("format_date", cw.utils.toISOTimestamp(selectedDate)); + cal.hide(); +} + +function whichElement(e) { + var targ; + if (!e) { + e = window.event; + } + if (e.target) { + targ = e.target; + } + else if (e.srcElement) { + targ = e.srcElement; + } + if (targ.nodeType == 3) // defeat Safari bug + { + targ = targ.parentNode; + } + return targ; +} + +function getPosition(element) { + var left; + var top; + var offset; + // TODO: deal scrollbar positions also! + left = element.offsetLeft; + top = element.offsetTop; + + if (element.offsetParent != null) { + offset = getPosition(element.offsetParent); + left = left + offset[0]; + top = top + offset[1]; + + } + return [left, top]; +} + +function getMouseInBlock(event) { + var elt = event.target; + var x = event.clientX; + var y = event.clientY; + var w = elt.clientWidth; + var h = elt.clientHeight; + var offset = getPosition(elt); + + x = 1.0 * (x - offset[0]) / w; + y = 1.0 * (y - offset[1]) / h; + return [x, y]; +} +function getHourFromMouse(event, hmin, hmax) { + var pos = getMouseInBlock(event); + var y = pos[1]; + return Math.floor((hmax - hmin) * y + hmin); +} + +function addCalendarItem(event, hmin, hmax, year, month, day, duration, baseurl) { + var hour = getHourFromMouse(event, hmin, hmax); + + if (0 <= hour && hour < 24) { + baseurl += "&start=" + year + "%2F" + month + "%2F" + day + "%20" + hour + ":00"; + baseurl += "&stop=" + year + "%2F" + month + "%2F" + day + "%20" + (hour + duration) + ":00"; + + stopPropagation(event); + window.location.assign(baseurl); + return false; + } + return true; +} + +function stopPropagation(event) { + event.cancelBubble = true; + if (event.stopPropagation) event.stopPropagation(); +}