2294 lines
62 KiB
JavaScript
2294 lines
62 KiB
JavaScript
require({cache:{
|
|
'url:dojox/calendar/templates/MatrixView.html':"<div data-dojo-attach-events=\"keydown:_onKeyDown\">\n\t<div class=\"dojoxCalendarYearColumnHeader\" data-dojo-attach-point=\"yearColumnHeader\">\n\t\t<table><tr><td><span data-dojo-attach-point=\"yearColumnHeaderContent\"></span></td></tr></table>\t\t\n\t</div>\t\n\t<div data-dojo-attach-point=\"columnHeader\" class=\"dojoxCalendarColumnHeader\">\n\t\t<table data-dojo-attach-point=\"columnHeaderTable\" class=\"dojoxCalendarColumnHeaderTable\" cellpadding=\"0\" cellspacing=\"0\"></table>\n\t</div>\t\t\n\t<div dojoAttachPoint=\"rowHeader\" class=\"dojoxCalendarRowHeader\">\n\t\t<table data-dojo-attach-point=\"rowHeaderTable\" class=\"dojoxCalendarRowHeaderTable\" cellpadding=\"0\" cellspacing=\"0\"></table>\n\t</div>\t\n\t<div dojoAttachPoint=\"grid\" class=\"dojoxCalendarGrid\">\n\t\t<table data-dojo-attach-point=\"gridTable\" class=\"dojoxCalendarGridTable\" cellpadding=\"0\" cellspacing=\"0\"></table>\n\t</div>\t\n\t<div data-dojo-attach-point=\"itemContainer\" class=\"dojoxCalendarContainer\" data-dojo-attach-event=\"mousedown:_onGridMouseDown,mouseup:_onGridMouseUp,ondblclick:_onGridDoubleClick,touchstart:_onGridTouchStart,touchmove:_onGridTouchMove,touchend:_onGridTouchEnd\">\n\t\t<table data-dojo-attach-point=\"itemContainerTable\" class=\"dojoxCalendarContainerTable\" cellpadding=\"0\" cellspacing=\"0\" style=\"width:100%\"></table>\n\t</div>\t\n</div>\n"}});
|
|
define("dojox/calendar/MatrixView", [
|
|
"dojo/_base/declare",
|
|
"dojo/_base/array",
|
|
"dojo/_base/event",
|
|
"dojo/_base/lang",
|
|
"dojo/_base/sniff",
|
|
"dojo/_base/fx",
|
|
"dojo/_base/html",
|
|
"dojo/on",
|
|
"dojo/dom",
|
|
"dojo/dom-class",
|
|
"dojo/dom-style",
|
|
"dojo/dom-geometry",
|
|
"dojo/dom-construct",
|
|
"dojo/query",
|
|
"dojox/html/metrics",
|
|
"dojo/i18n",
|
|
"./ViewBase",
|
|
"dojo/text!./templates/MatrixView.html",
|
|
"dijit/_TemplatedMixin"],
|
|
|
|
function(
|
|
declare,
|
|
arr,
|
|
event,
|
|
lang,
|
|
has,
|
|
fx,
|
|
html,
|
|
on,
|
|
dom,
|
|
domClass,
|
|
domStyle,
|
|
domGeometry,
|
|
domConstruct,
|
|
query,
|
|
metrics,
|
|
i18n,
|
|
ViewBase,
|
|
template,
|
|
_TemplatedMixin){
|
|
|
|
/*=====
|
|
var __HeaderClickEventArgs = {
|
|
// summary:
|
|
// A column click event.
|
|
// index: Integer
|
|
// The column index.
|
|
// date: Date
|
|
// The date displayed by the column.
|
|
// triggerEvent: Event
|
|
// The origin event.
|
|
};
|
|
=====*/
|
|
|
|
/*=====
|
|
var __ExpandRendererClickEventArgs = {
|
|
// summary:
|
|
// A expand renderer click event.
|
|
// columnIndex: Integer
|
|
// The column index of the cell.
|
|
// rowIndex: Integer
|
|
// The row index of the cell.
|
|
// date: Date
|
|
// The date displayed by the cell.
|
|
// triggerEvent: Event
|
|
// The origin event.
|
|
};
|
|
=====*/
|
|
|
|
return declare("dojox.calendar.MatrixView", [ViewBase, _TemplatedMixin], {
|
|
|
|
// summary:
|
|
// The matrix view is a calendar view that displaying a matrix where each cell is a day.
|
|
|
|
templateString: template,
|
|
|
|
baseClass: "dojoxCalendarMatrixView",
|
|
|
|
_setTabIndexAttr: "domNode",
|
|
|
|
// viewKind: String
|
|
// Type of the view. Used by the calendar widget to determine how to configure the view.
|
|
// This view kind is "matrix".
|
|
viewKind: "matrix",
|
|
|
|
// renderData: Object
|
|
// The render data object contains all the data needed to render the widget.
|
|
renderData: null,
|
|
|
|
// startDate: Date
|
|
// The start date of the time interval displayed.
|
|
// If not set at initialization time, will be set to current day.
|
|
startDate: null,
|
|
|
|
// refStartTime: Date?
|
|
// (Optional) Start of the time interval of interest.
|
|
// It is used to style differently the displayed rows out of the
|
|
// time interval of interest.
|
|
refStartTime: null,
|
|
|
|
// refStartTime: Date?
|
|
// (Optional) End of the time interval of interest.
|
|
// It is used to style differently the displayed rows out of the
|
|
// time interval of interest.
|
|
refEndTime: null,
|
|
|
|
// columnCount: Integer
|
|
// The number of column to display (from the startDate).
|
|
columnCount: 7,
|
|
|
|
// rowCount: Integer
|
|
// The number of rows to display (from the startDate).
|
|
rowCount: 5,
|
|
|
|
// horizontalRenderer: Class
|
|
// The class use to create horizontal renderers.
|
|
horizontalRenderer: null,
|
|
|
|
// labelRenderer: Class
|
|
// The class use to create label renderers.
|
|
labelRenderer: null,
|
|
|
|
// expandRenderer: Class
|
|
// The class use to create drill down renderers.
|
|
expandRenderer: null,
|
|
|
|
// percentOverlap: Integer
|
|
// The percentage of the renderer width used to superimpose one item renderers on another
|
|
// when two events are overlapping. By default 0.
|
|
percentOverlap: 0,
|
|
|
|
// verticalGap: Integer
|
|
// The number of pixels between two item renderers that are overlapping each other if the percentOverlap property is 0.
|
|
verticalGap: 2,
|
|
|
|
// horizontalRendererHeight: Integer
|
|
// The height in pixels of the horizontal and label renderers that is applied by the layout.
|
|
horizontalRendererHeight: 17,
|
|
|
|
// horizontalRendererHeight: Integer
|
|
// The height in pixels of the horizontal and label renderers that is applied by the layout.
|
|
labelRendererHeight: 14,
|
|
|
|
// expandRendererHeight: Integer
|
|
// The height in pixels of the expand/collapse renderers that is applied by the layout.
|
|
expandRendererHeight: 15,
|
|
|
|
// cellPaddingTop: Integer
|
|
// The top offset in pixels of each cell applied by the layout.
|
|
cellPaddingTop: 16,
|
|
|
|
// expandDuration: Integer
|
|
// Duration of the animation when expanding or collapsing a row.
|
|
expandDuration: 300,
|
|
|
|
// expandEasing: Function
|
|
// Easing function of the animation when expanding or collapsing a row (null by default).
|
|
expandEasing: null,
|
|
|
|
// layoutDuringResize: Boolean
|
|
// Indicates if the item renderers' position and size is updated or if they are hidden during a resize of the widget.
|
|
layoutDuringResize: false,
|
|
|
|
// roundToDay: Boolean
|
|
// For horizontal renderers that are not filling entire days, whether fill the day or not.
|
|
roundToDay: true,
|
|
|
|
// showCellLabel: Boolean
|
|
// Whether display or not the grid cells label (usually the day of month).
|
|
showCellLabel: true,
|
|
|
|
// scrollable: [private] Boolean
|
|
scrollable: false,
|
|
|
|
// resizeCursor: [private] Boolean
|
|
resizeCursor: "e-resize",
|
|
|
|
constructor: function(){
|
|
this.invalidatingProperties = ["columnCount", "rowCount", "startDate", "horizontalRenderer", "labelRenderer", "expandRenderer",
|
|
"rowHeaderDatePattern", "columnHeaderLabelLength", "cellHeaderShortPattern", "cellHeaderLongPattern", "percentOverlap",
|
|
"verticalGap", "horizontalRendererHeight", "labelRendererHeight", "expandRendererHeight", "cellPaddingTop",
|
|
"roundToDay", "itemToRendererKindFunc", "layoutPriorityFunction", "formatItemTimeFunc", "textDir", "items"];
|
|
|
|
this._ddRendererList = [];
|
|
this._ddRendererPool = [];
|
|
this._rowHeaderHandles = [];
|
|
|
|
// For Dojo 1.8
|
|
// this._viewHandles.push(
|
|
// ViewPort.on("resize", lang.hitch(this, this._resizeHandler)));
|
|
|
|
// pre 1.8 compat code
|
|
this._viewHandles.push(on(window, "resize", lang.hitch(this, this._resizeHandler)));
|
|
|
|
},
|
|
|
|
destroy: function(preserveDom){
|
|
this._cleanupRowHeader();
|
|
this.inherited(arguments);
|
|
},
|
|
|
|
postCreate: function(){
|
|
this.inherited(arguments);
|
|
this._initialized = true;
|
|
if(!this.invalidRendering){
|
|
this.refreshRendering();
|
|
}
|
|
},
|
|
|
|
_createRenderData: function(){
|
|
|
|
var rd = {};
|
|
|
|
rd.dateLocaleModule = this.dateLocaleModule;
|
|
rd.dateClassObj = this.dateClassObj;
|
|
rd.dateModule = this.dateModule; // arithmetics on Dates
|
|
|
|
rd.dates = [];
|
|
|
|
rd.columnCount = this.get("columnCount");
|
|
rd.rowCount = this.get("rowCount");
|
|
|
|
rd.sheetHeight = this.itemContainer.offsetHeight;
|
|
|
|
this._computeRowsHeight(rd);
|
|
|
|
var d = this.get("startDate");
|
|
|
|
if(d == null){
|
|
d = new rd.dateClassObj();
|
|
}
|
|
|
|
d = this.floorToDay(d, false, rd);
|
|
|
|
this.startDate = d;
|
|
|
|
for(var row = 0; row < rd.rowCount ; row++){
|
|
rd.dates.push([]);
|
|
for(var col = 0; col < rd.columnCount ; col++){
|
|
rd.dates[row].push(d);
|
|
d = rd.dateModule.add(d, "day", 1);
|
|
d = this.floorToDay(d, false, rd);
|
|
}
|
|
}
|
|
|
|
rd.startTime = this.newDate(rd.dates[0][0], rd);
|
|
rd.endTime = this.newDate(rd.dates[rd.rowCount-1][rd.columnCount-1], rd);
|
|
rd.endTime = rd.dateModule.add(rd.endTime, "day", 1);
|
|
rd.endTime = this.floorToDay(rd.endTime, true);
|
|
|
|
if(this.displayedItemsInvalidated){
|
|
this.displayedItemsInvalidated = false;
|
|
this._computeVisibleItems(rd);
|
|
|
|
if(this._isEditing){
|
|
this._endItemEditing(null, false);
|
|
}
|
|
|
|
}else if(this.renderData){
|
|
rd.items = this.renderData.items;
|
|
}
|
|
|
|
rd.rtl = !this.isLeftToRight();
|
|
|
|
return rd;
|
|
},
|
|
|
|
_validateProperties: function(){
|
|
|
|
this.inherited(arguments);
|
|
|
|
if(this.columnCount<1 || isNaN(this.columnCount)){
|
|
this.columnCount = 1;
|
|
}
|
|
|
|
if(this.rowCount<1 || isNaN(this.rowCount)){
|
|
this.rowCount = 1;
|
|
}
|
|
|
|
if(isNaN(this.percentOverlap) || this.percentOverlap < 0 || this.percentOverlap > 100){
|
|
this.percentOverlap = 0;
|
|
}
|
|
|
|
if(isNaN(this.verticalGap) || this.verticalGap < 0){
|
|
this.verticalGap = 2;
|
|
}
|
|
|
|
if(isNaN(this.horizontalRendererHeight) || this.horizontalRendererHeight < 1){
|
|
this.horizontalRendererHeight = 17;
|
|
}
|
|
|
|
if(isNaN(this.labelRendererHeight) || this.labelRendererHeight < 1){
|
|
this.labelRendererHeight = 14;
|
|
}
|
|
|
|
if(isNaN(this.expandRendererHeight) || this.expandRendererHeight < 1){
|
|
this.expandRendererHeight = 15;
|
|
}
|
|
|
|
},
|
|
|
|
_setStartDateAttr: function(value){
|
|
this.displayedItemsInvalidated = true;
|
|
this._set("startDate", value);
|
|
},
|
|
|
|
_setColumnCountAttr: function(value){
|
|
this.displayedItemsInvalidated = true;
|
|
this._set("columnCount", value);
|
|
},
|
|
|
|
_setRowCountAttr: function(value){
|
|
this.displayedItemsInvalidated = true;
|
|
this._set("rowCount", value);
|
|
},
|
|
|
|
__fixEvt:function(e){
|
|
e.sheet = "primary";
|
|
e.source = this;
|
|
return e;
|
|
},
|
|
|
|
//////////////////////////////////////////
|
|
//
|
|
// Formatting functions
|
|
//
|
|
//////////////////////////////////////////
|
|
|
|
_formatRowHeaderLabel: function(/*Date*/d){
|
|
// summary:
|
|
// Computes the row header label for the specified time of day.
|
|
// By default the getWeekNumberLabel() function is called.
|
|
// The rowHeaderDatePattern property can be used to set a
|
|
// custom date pattern to the formatter.
|
|
// d: Date
|
|
// The date to format
|
|
// tags:
|
|
// protected
|
|
|
|
if(this.rowHeaderDatePattern){
|
|
return this.renderData.dateLocaleModule.format(d, {
|
|
selector: 'date',
|
|
datePattern: this.rowHeaderDatePattern
|
|
});
|
|
}else{
|
|
return this.getWeekNumberLabel(d);
|
|
}
|
|
|
|
},
|
|
|
|
_formatColumnHeaderLabel: function(d){
|
|
// summary:
|
|
// Computes the column header label for the specified date.
|
|
// By default a formatter is used, optionally the <code>columnHeaderLabelLength</code>
|
|
// property can be used to specify the length of the string.
|
|
// d: Date
|
|
// The date to format
|
|
// tags:
|
|
// protected
|
|
|
|
return this.renderData.dateLocaleModule.getNames('days', this.columnHeaderLabelLength ? this.columnHeaderLabelLength : 'wide', 'standAlone')[d.getDay()];
|
|
},
|
|
|
|
_formatGridCellLabel: function(d, row, col){
|
|
// summary:
|
|
// Computes the column header label for the specified date.
|
|
// By default a formatter is used, optionally the <code>cellHeaderLongPattern</code> and <code>cellHeaderShortPattern</code>
|
|
// properties can be used to set a custom date pattern to the formatter.
|
|
// d: Date
|
|
// The date to format.
|
|
// row: Integer
|
|
// The row that displays the current date.
|
|
// col: Integer
|
|
// The column that displays the current date.
|
|
// tags:
|
|
// protected
|
|
|
|
|
|
var isFirstDayOfMonth = row == 0 && col == 0 || d.getDate() == 1;
|
|
var format, rb;
|
|
if(isFirstDayOfMonth){
|
|
if(this.cellHeaderLongPattern){
|
|
format = this.cellHeaderLongPattern;
|
|
}else{
|
|
rb = i18n.getLocalization("dojo.cldr", this._calendar);
|
|
format = rb["dateFormatItem-MMMd"];
|
|
}
|
|
}else{
|
|
if(this.cellHeaderShortPattern){
|
|
format = this.cellHeaderShortPattern;
|
|
}else{
|
|
rb = i18n.getLocalization("dojo.cldr", this._calendar);
|
|
format = rb["dateFormatItem-d"];
|
|
}
|
|
}
|
|
return this.renderData.dateLocaleModule.format(d, {
|
|
selector: 'date',
|
|
datePattern: format
|
|
});
|
|
},
|
|
|
|
////////////////////////////////////////////
|
|
//
|
|
// HTML structure management
|
|
//
|
|
///////////////////////////////////////////
|
|
|
|
refreshRendering: function(){
|
|
this.inherited(arguments);
|
|
|
|
if(!this.domNode){
|
|
return;
|
|
}
|
|
|
|
this._validateProperties();
|
|
|
|
var oldRd = this.renderData;
|
|
this.renderData = this._createRenderData();
|
|
|
|
this._createRendering(this.renderData, oldRd);
|
|
|
|
this._layoutRenderers(this.renderData);
|
|
},
|
|
|
|
_createRendering: function(renderData, oldRenderData){
|
|
// summary:
|
|
// Creates the HTML structure (grid, place holders, headers, etc)
|
|
// renderData: Object
|
|
// The new render data
|
|
// oldRenderData: Object
|
|
// The previous render data
|
|
// tags:
|
|
// private
|
|
|
|
if(renderData.rowHeight <= 0){
|
|
renderData.columnCount = 0;
|
|
renderData.rowCount = 0;
|
|
return;
|
|
}
|
|
|
|
this._buildColumnHeader(renderData, oldRenderData);
|
|
this._buildRowHeader(renderData, oldRenderData);
|
|
this._buildGrid(renderData, oldRenderData);
|
|
this._buildItemContainer(renderData, oldRenderData);
|
|
|
|
if(this.buttonContainer && this.owner != null && this.owner.currentView == this){
|
|
domStyle.set(this.buttonContainer, {"right":0, "left":0});
|
|
}
|
|
},
|
|
|
|
_buildColumnHeader: function(/*Object*/ renderData, /*Object*/oldRenderData){
|
|
// summary:
|
|
// Creates incrementally the HTML structure of the column header and configures its content.
|
|
//
|
|
// renderData:
|
|
// The render data to display.
|
|
//
|
|
// oldRenderData:
|
|
// The previously render data displayed, if any.
|
|
// tags:
|
|
// private
|
|
var table = this.columnHeaderTable;
|
|
|
|
if(!table){
|
|
return;
|
|
}
|
|
|
|
var count = renderData.columnCount - (oldRenderData ? oldRenderData.columnCount : 0);
|
|
|
|
if(has("ie") == 8){
|
|
// workaround Internet Explorer 8 bug.
|
|
// if on the table, width: 100% and table-layout: fixed are set
|
|
// and columns are removed, width of remaining columns is not
|
|
// recomputed: must rebuild all.
|
|
if(this._colTableSave == null){
|
|
this._colTableSave = lang.clone(table);
|
|
}else if(count < 0){
|
|
this.columnHeader.removeChild(table);
|
|
domConstruct.destroy(table);
|
|
table = lang.clone(this._colTableSave);
|
|
this.columnHeaderTable = table;
|
|
this.columnHeader.appendChild(table);
|
|
count = renderData.columnCount;
|
|
}
|
|
|
|
} // else incremental dom add/remove for real browsers.
|
|
|
|
var tbodies = query("tbody", table);
|
|
var trs = query("tr", table);
|
|
var tbody, tr, td;
|
|
|
|
if(tbodies.length == 1){
|
|
tbody = tbodies[0];
|
|
}else{
|
|
tbody = html.create("tbody", null, table);
|
|
}
|
|
|
|
if(trs.length == 1){
|
|
tr = trs[0];
|
|
}else{
|
|
tr = domConstruct.create("tr", null, tbody);
|
|
}
|
|
|
|
// Build HTML structure (incremental)
|
|
if(count > 0){ // creation
|
|
for(var i=0; i < count; i++){
|
|
td = domConstruct.create("td", null, tr);
|
|
}
|
|
}else{ // deletion
|
|
count = -count;
|
|
for(var i=0; i < count; i++){
|
|
tr.removeChild(tr.lastChild);
|
|
}
|
|
}
|
|
|
|
// fill & configure
|
|
query("td", table).forEach(function(td, i){
|
|
td.className = "";
|
|
var d = renderData.dates[0][i];
|
|
this._setText(td, this._formatColumnHeaderLabel(d));
|
|
if(i == 0){
|
|
domClass.add(td, "first-child");
|
|
}else if(i == this.renderData.columnCount-1){
|
|
domClass.add(td, "last-child");
|
|
}
|
|
this.styleColumnHeaderCell(td, d, renderData);
|
|
}, this);
|
|
|
|
if(this.yearColumnHeaderContent){
|
|
var d = renderData.dates[0][0];
|
|
this._setText(this.yearColumnHeaderContent, renderData.dateLocaleModule.format(d,
|
|
{selector: "date", datePattern:"yyyy"}));
|
|
}
|
|
},
|
|
|
|
styleColumnHeaderCell: function(node, date, renderData){
|
|
// summary:
|
|
// Styles the CSS classes to the node that displays a column header cell.
|
|
// By default this method is setting the "dojoxCalendarWeekend" if the day of week represents a weekend.
|
|
// node: Node
|
|
// The DOM node that displays the column in the grid.
|
|
// date: Date
|
|
// The date displayed by this column
|
|
// renderData: Object
|
|
// The render data.
|
|
// tags:
|
|
// protected
|
|
|
|
if(this.isWeekEnd(date)){
|
|
return domClass.add(node, "dojoxCalendarWeekend");
|
|
}
|
|
},
|
|
|
|
_rowHeaderHandles: null,
|
|
|
|
_cleanupRowHeader: function(){
|
|
// tags:
|
|
// private
|
|
|
|
while(this._rowHeaderHandles.length > 0){
|
|
var list = this._rowHeaderHandles.pop();
|
|
while(list.length>0){
|
|
list.pop().remove();
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
_rowHeaderClick: function(e){
|
|
// tags:
|
|
// private
|
|
|
|
var index = query("td", this.rowHeaderTable).indexOf(e.currentTarget);
|
|
this._onRowHeaderClick({
|
|
index: index,
|
|
date: this.renderData.dates[index][0],
|
|
triggerEvent: e
|
|
});
|
|
},
|
|
|
|
_buildRowHeader: function(renderData, oldRenderData){
|
|
|
|
// summary:
|
|
// Creates incrementally the HTML structure of the row header and configures its content.
|
|
//
|
|
// renderData:
|
|
// The render data to display.
|
|
//
|
|
// oldRenderData:
|
|
// The previously render data displayed, if any.
|
|
// tags:
|
|
// private
|
|
|
|
var rowHeaderTable = this.rowHeaderTable;
|
|
|
|
if(!rowHeaderTable){
|
|
return;
|
|
}
|
|
|
|
var tbodies = query("tbody", rowHeaderTable);
|
|
var tbody, tr, td;
|
|
|
|
if(tbodies.length == 1){
|
|
tbody = tbodies[0];
|
|
}else{
|
|
tbody = domConstruct.create("tbody", null, rowHeaderTable);
|
|
}
|
|
|
|
var count = renderData.rowCount - (oldRenderData ? oldRenderData.rowCount : 0);
|
|
|
|
// Build HTML structure
|
|
if(count>0){ // creation
|
|
for(var i=0; i < count; i++){
|
|
tr = domConstruct.create("tr", null, tbody);
|
|
td = domConstruct.create("td", null, tr);
|
|
|
|
var h = [];
|
|
|
|
h.push(on(td, "click", lang.hitch(this, this._rowHeaderClick)));
|
|
|
|
if(!has("touch")){
|
|
h.push(on(td, "mousedown", function(e){
|
|
domClass.add(e.currentTarget, "Active");
|
|
}));
|
|
|
|
h.push(on(td, "mouseup", function(e){
|
|
domClass.remove(e.currentTarget, "Active");
|
|
}));
|
|
|
|
h.push(on(td, "mouseover", function(e){
|
|
domClass.add(e.currentTarget, "Hover");
|
|
}));
|
|
|
|
h.push(on(td, "mouseout", function(e){
|
|
domClass.remove(e.currentTarget, "Hover");
|
|
}));
|
|
}
|
|
this._rowHeaderHandles.push(h);
|
|
}
|
|
}else{
|
|
count = -count;
|
|
// deletion of existing nodes
|
|
for(var i=0; i < count; i++){
|
|
tbody.removeChild(tbody.lastChild);
|
|
var list = this._rowHeaderHandles.pop();
|
|
while(list.length>0){
|
|
list.pop().remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
// fill labels
|
|
|
|
query("tr", rowHeaderTable).forEach(function(tr, i){
|
|
|
|
domStyle.set(tr, "height", this._getRowHeight(i) + "px");
|
|
|
|
var d = renderData.dates[i][0];
|
|
|
|
var td = query("td", tr)[0];
|
|
td.className = "";
|
|
if(i == 0){
|
|
domClass.add(td, "first-child");
|
|
}
|
|
if(i == this.renderData.rowCount-1){
|
|
domClass.add(td, "last-child");
|
|
}
|
|
|
|
this.styleRowHeaderCell(td, d, renderData);
|
|
|
|
this._setText(td, this._formatRowHeaderLabel(d));
|
|
}, this);
|
|
|
|
},
|
|
|
|
styleRowHeaderCell: function(node, date, renderData){
|
|
// summary:
|
|
// Styles the CSS classes to the node that displays a row header cell.
|
|
// By default this method is doing nothing.
|
|
// node: Node
|
|
// The DOM node that displays the column in the grid.
|
|
// date: Date
|
|
// The date in the week.
|
|
// renderData: Object
|
|
// The render data.
|
|
// tags:
|
|
// protected
|
|
|
|
|
|
},
|
|
|
|
_buildGrid: function (renderData, oldRenderData){
|
|
// summary:
|
|
// Creates incrementally the HTML structure of the grid and configures its content.
|
|
//
|
|
// renderData:
|
|
// The render data to display.
|
|
//
|
|
// oldRenderData:
|
|
// The previously render data displayed, if any.
|
|
// tags:
|
|
// private
|
|
|
|
var table = this.gridTable;
|
|
|
|
if(!table){
|
|
return;
|
|
}
|
|
|
|
var rowDiff = renderData.rowCount - (oldRenderData ? oldRenderData.rowCount : 0);
|
|
var addRows = rowDiff > 0;
|
|
|
|
var colDiff = renderData.columnCount - (oldRenderData ? oldRenderData.columnCount : 0);
|
|
|
|
if(has("ie") == 8){
|
|
// workaround Internet Explorer 8 bug.
|
|
// if on the table, width: 100% and table-layout: fixed are set
|
|
// and columns are removed, width of remaining columns is not
|
|
// recomputed: must rebuild all.
|
|
if(this._gridTableSave == null){
|
|
this._gridTableSave = lang.clone(table);
|
|
}else if(colDiff < 0){
|
|
this.grid.removeChild(table);
|
|
domConstruct.destroy(table);
|
|
table = lang.clone(this._gridTableSave);
|
|
this.gridTable = table;
|
|
this.grid.appendChild(table);
|
|
colDiff = renderData.columnCount;
|
|
rowDiff = renderData.rowCount;
|
|
addRows = true;
|
|
}
|
|
}
|
|
|
|
var tbodies = query("tbody", table);
|
|
var tbody;
|
|
|
|
if(tbodies.length == 1){
|
|
tbody = tbodies[0];
|
|
}else{
|
|
tbody = domConstruct.create("tbody", null, table);
|
|
}
|
|
|
|
// Build rows HTML structure (incremental)
|
|
if(addRows){ // creation
|
|
for(var i=0; i<rowDiff; i++){
|
|
domConstruct.create("tr", null, tbody);
|
|
}
|
|
}else{ // deletion
|
|
rowDiff = -rowDiff;
|
|
for(var i=0; i<rowDiff; i++){
|
|
tbody.removeChild(tbody.lastChild);
|
|
}
|
|
}
|
|
|
|
var rowIndex = renderData.rowCount - rowDiff;
|
|
|
|
var addCols = addRows || colDiff >0;
|
|
colDiff = addCols ? colDiff : -colDiff;
|
|
|
|
query("tr", table).forEach(function(tr, i){
|
|
|
|
if(addCols){ // creation
|
|
var len = i >= rowIndex ? renderData.columnCount : colDiff;
|
|
for(var i=0; i<len; i++){
|
|
var td = domConstruct.create("td", null, tr);
|
|
domConstruct.create("span", null, td);
|
|
}
|
|
}else{ // deletion
|
|
for(var i=0; i<colDiff; i++){
|
|
tr.removeChild(tr.lastChild);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Set the CSS classes
|
|
|
|
query("tr", table).forEach(function (tr, row){
|
|
|
|
domStyle.set(tr, "height", this._getRowHeight(row) + "px");
|
|
|
|
tr.className = "";
|
|
// compatibility layer for IE7 & 8 that does not support :first-child and :last-child pseudo selectors
|
|
if(row == 0){
|
|
domClass.add(tr, "first-child");
|
|
}
|
|
if(row == renderData.rowCount-1){
|
|
domClass.add(tr, "last-child");
|
|
}
|
|
|
|
query("td", tr).forEach(function (td, col){
|
|
|
|
td.className = "";
|
|
|
|
if(col == 0){
|
|
domClass.add(td, "first-child");
|
|
}
|
|
|
|
if(col == renderData.columnCount-1){
|
|
domClass.add(td, "last-child");
|
|
}
|
|
|
|
var d = renderData.dates[row][col];
|
|
|
|
var span = query("span", td)[0];
|
|
this._setText(span, this.showCellLabel ? this._formatGridCellLabel(d, row, col): null);
|
|
|
|
this.styleGridCell(td, d, renderData);
|
|
}, this);
|
|
}, this);
|
|
|
|
},
|
|
|
|
styleGridCell: function(node, date, renderData){
|
|
// summary:
|
|
// Styles the CSS classes to the node that displays a column.
|
|
// By default this method is setting the following CSS classes:
|
|
// - "dojoxCalendarToday" class name if the date displayed is the current date,
|
|
// - "dojoxCalendarWeekend" if the date represents a weekend or
|
|
// - "dojoxCalendarDayDisabled" if the date is out of the [refStartTime, refEndTime] interval.
|
|
// node: Node
|
|
// The DOM node that displays the column in the grid.
|
|
// date: Date
|
|
// The date displayed by this column
|
|
// renderData: Object
|
|
// The render data.
|
|
// tags:
|
|
// protected
|
|
|
|
var cal = renderData.dateModule;
|
|
if(this.isToday(date)){
|
|
domClass.add(node, "dojoxCalendarToday");
|
|
}else if(this.refStartTime != null && this.refEndTime != null &&
|
|
(cal.compare(date, this.refEndTime) >= 0 ||
|
|
cal.compare(cal.add(date, "day", 1), this.refStartTime) <= 0)){
|
|
domClass.add(node, "dojoxCalendarDayDisabled");
|
|
}else if(this.isWeekEnd(date)){
|
|
domClass.add(node, "dojoxCalendarWeekend");
|
|
}
|
|
},
|
|
|
|
_buildItemContainer: function(renderData, oldRenderData){
|
|
// summary:
|
|
// Creates the HTML structure of the item container and configures its content.
|
|
//
|
|
// renderData:
|
|
// The render data to display.
|
|
//
|
|
// oldRenderData:
|
|
// The previously render data displayed, if any.
|
|
// tags:
|
|
// private
|
|
|
|
var table = this.itemContainerTable;
|
|
|
|
if(!table){
|
|
return;
|
|
}
|
|
|
|
var rows = [];
|
|
|
|
var count = renderData.rowCount - (oldRenderData ? oldRenderData.rowCount : 0);
|
|
|
|
if(has("ie") == 8){
|
|
// workaround Internet Explorer 8 bug.
|
|
// if on the table, width: 100% and table-layout: fixed are set
|
|
// and columns are removed, width of remaining columns is not
|
|
// recomputed: must rebuild all.
|
|
if(this._itemTableSave == null){
|
|
this._itemTableSave = lang.clone(table);
|
|
}else if(count < 0){
|
|
this.itemContainer.removeChild(table);
|
|
this._recycleItemRenderers(true);
|
|
this._recycleExpandRenderers(true);
|
|
domConstruct.destroy(table);
|
|
table = lang.clone(this._itemTableSave);
|
|
this.itemContainerTable = table;
|
|
this.itemContainer.appendChild(table);
|
|
count = renderData.columnCount;
|
|
}
|
|
|
|
} // else incremental dom add/remove for real browsers.
|
|
|
|
var tbodies = query("tbody", table);
|
|
var tbody, tr, td, div;
|
|
|
|
if(tbodies.length == 1){
|
|
tbody = tbodies[0];
|
|
}else{
|
|
tbody = domConstruct.create("tbody", null, table);
|
|
}
|
|
|
|
// Build HTML structure (incremental)
|
|
if(count>0){ // creation
|
|
for(var i=0; i < count; i++){
|
|
tr = domConstruct.create("tr", null, tbody);
|
|
domClass.add(tr, "dojoxCalendarItemContainerRow");
|
|
td = domConstruct.create("td", null, tr);
|
|
div = domConstruct.create("div", null, td);
|
|
domClass.add(div, "dojoxCalendarContainerRow");
|
|
}
|
|
}else{ // deletion
|
|
count = -count;
|
|
for(var i=0; i < count; i++){
|
|
tbody.removeChild(tbody.lastChild);
|
|
}
|
|
}
|
|
|
|
query(".dojoxCalendarItemContainerRow", table).forEach(function(tr, i){
|
|
domStyle.set(tr, "height", this._getRowHeight(i) + "px");
|
|
rows.push(tr.childNodes[0].childNodes[0]);
|
|
}, this);
|
|
|
|
renderData.cells = rows;
|
|
},
|
|
|
|
_resizeHandler: function(e, apply){
|
|
// summary:
|
|
// Refreshes and apply the row height according to the widget height.
|
|
// e: Event
|
|
// The resize event (optional)
|
|
// apply: Boolean
|
|
// Whether take into account the layoutDuringResize flag to relayout item while resizing or not.
|
|
// tags:
|
|
// private
|
|
|
|
var rd = this.renderData;
|
|
|
|
if(rd == null){
|
|
this.refreshRendering();
|
|
return;
|
|
}
|
|
|
|
if(rd.sheetHeight != this.itemContainer.offsetHeight){
|
|
// refresh values
|
|
rd.sheetHeight = this.itemContainer.offsetHeight;
|
|
var expRow = this.getExpandedRowIndex();
|
|
if(expRow == -1){
|
|
this._computeRowsHeight();
|
|
this._resizeRows();
|
|
}else{
|
|
this.expandRow(rd.expandedRow, rd.expandedRowCol, 0, null, true);
|
|
}
|
|
}
|
|
|
|
if(this.layoutDuringResize || apply){
|
|
// Use a time for FF (at least). In FF the cell size and position info are not ready yet.
|
|
setTimeout(lang.hitch(this, function(){
|
|
this._layoutRenderers(this.renderData);
|
|
}), 20);
|
|
|
|
}else{
|
|
domStyle.set(this.itemContainer, "opacity", 0);
|
|
this._recycleItemRenderers();
|
|
this._recycleExpandRenderers();
|
|
if(this._resizeTimer != undefined){
|
|
clearTimeout(this._resizeTimer);
|
|
}
|
|
this._resizeTimer = setTimeout(lang.hitch(this, function(){
|
|
delete this._resizeTimer;
|
|
this._resizeRowsImpl(this.itemContainer, "tr");
|
|
this._layoutRenderers(this.renderData);
|
|
if(this.resizeAnimationDuration == 0){
|
|
domStyle.set(this.itemContainer, "opacity", 1);
|
|
}else{
|
|
fx.fadeIn({node:this.itemContainer, curve:[0, 1]}).play(this.resizeAnimationDuration);
|
|
}
|
|
}), 200);
|
|
}
|
|
|
|
},
|
|
|
|
// resizeAnimationDuration: Integer
|
|
// Duration, in milliseconds, of the fade animation showing the item renderers after a widget resize.
|
|
resizeAnimationDuration: 0,
|
|
|
|
/////////////////////////////////////////////
|
|
//
|
|
// Row height management
|
|
//
|
|
//////////////////////////////////////////////
|
|
|
|
getExpandedRowIndex: function(){
|
|
// summary:
|
|
// Returns the index of the expanded row or -1 if there's no row expanded.
|
|
return this.renderData.expandedRow == null ? -1 : this.renderData.expandedRow;
|
|
},
|
|
|
|
collapseRow: function(duration, easing, apply){
|
|
// summary:
|
|
// Collapses the expanded row, if any.
|
|
// duration: Integer
|
|
// Duration in milliseconds of the optional animation.
|
|
// easing: Function
|
|
// Easing function of the optional animation.
|
|
|
|
var rd = this.renderData;
|
|
|
|
if(apply == undefined){
|
|
apply = true;
|
|
}
|
|
if(duration == undefined){
|
|
duration = this.expandDuration;
|
|
}
|
|
|
|
if(rd && rd.expandedRow != null && rd.expandedRow != -1){
|
|
if(apply && duration){
|
|
var index = rd.expandedRow;
|
|
var oldSize = rd.expandedRowHeight;
|
|
delete rd.expandedRow;
|
|
this._computeRowsHeight(rd);
|
|
var size = this._getRowHeight(index);
|
|
rd.expandedRow = index;
|
|
|
|
this._recycleExpandRenderers();
|
|
this._recycleItemRenderers();
|
|
domStyle.set(this.itemContainer, "display", "none");
|
|
|
|
this._expandAnimation = new fx.Animation({
|
|
curve: [oldSize, size],
|
|
duration: duration,
|
|
easing: easing,
|
|
onAnimate: lang.hitch(this, function(size) {
|
|
this._expandRowImpl(Math.floor(size));
|
|
}),
|
|
onEnd: lang.hitch(this, function(size) {
|
|
this._expandAnimation = null;
|
|
this._collapseRowImpl(false);
|
|
this._resizeRows();
|
|
domStyle.set(this.itemContainer, "display", "block");
|
|
setTimeout(lang.hitch(this, function(){
|
|
this._layoutRenderers(rd);
|
|
}), 100);
|
|
this.onExpandAnimationEnd(false);
|
|
})
|
|
});
|
|
|
|
this._expandAnimation.play();
|
|
}else{
|
|
this._collapseRowImpl(apply);
|
|
}
|
|
}
|
|
},
|
|
|
|
_collapseRowImpl: function(apply){
|
|
// tags:
|
|
// private
|
|
|
|
var rd = this.renderData;
|
|
delete rd.expandedRow;
|
|
delete rd.expandedRowHeight;
|
|
this._computeRowsHeight(rd);
|
|
if(apply == undefined || apply){
|
|
this._resizeRows();
|
|
this._layoutRenderers(rd);
|
|
}
|
|
},
|
|
|
|
expandRow: function(rowIndex, colIndex, duration, easing, apply){
|
|
// summary:
|
|
// Expands the specified row.
|
|
// rowIndex: Integer
|
|
// The index of the row to expand.
|
|
// colIndex: Integer?
|
|
// The column index of the expand renderer that triggers the action, optional.
|
|
// duration: Integer?
|
|
// Duration in milliseconds of the optional animation.
|
|
// easing: Function?
|
|
// Easing function of the optional animation.
|
|
|
|
var rd = this.renderData;
|
|
if(!rd || rowIndex < 0 || rowIndex >= rd.rowCount){
|
|
return -1;
|
|
}
|
|
if(colIndex == undefined || colIndex < 0 || colIndex >= rd.columnCount){
|
|
colIndex = -1; // ignore invalid values
|
|
}
|
|
if(apply == undefined){
|
|
apply = true;
|
|
}
|
|
if(duration == undefined){
|
|
duration = this.expandDuration;
|
|
}
|
|
if(easing == undefined){
|
|
easing = this.expandEasing;
|
|
}
|
|
|
|
var oldSize = this._getRowHeight(rowIndex);
|
|
var size = rd.sheetHeight - Math.ceil(this.cellPaddingTop * (rd.rowCount-1));
|
|
|
|
rd.expandedRow = rowIndex;
|
|
rd.expandedRowCol = colIndex;
|
|
rd.expandedRowHeight = size;
|
|
|
|
if(apply){
|
|
if(duration){
|
|
//debugger;
|
|
this._recycleExpandRenderers();
|
|
this._recycleItemRenderers();
|
|
domStyle.set(this.itemContainer, "display", "none");
|
|
|
|
this._expandAnimation = new fx.Animation({
|
|
curve: [oldSize, size],
|
|
duration: duration,
|
|
delay:50,
|
|
easing: easing,
|
|
onAnimate: lang.hitch(this, function(size) {
|
|
this._expandRowImpl(Math.floor(size));
|
|
}),
|
|
onEnd: lang.hitch(this, function(){
|
|
this._expandAnimation = null;
|
|
domStyle.set(this.itemContainer, "display", "block");
|
|
setTimeout(lang.hitch(this, function(){
|
|
this._expandRowImpl(size, true);
|
|
}), 100);
|
|
this.onExpandAnimationEnd(true);
|
|
})
|
|
});
|
|
this._expandAnimation.play();
|
|
}else{
|
|
this._expandRowImpl(size)
|
|
}
|
|
}
|
|
},
|
|
|
|
_expandRowImpl: function(size, layout){
|
|
// tags:
|
|
// private
|
|
|
|
var rd = this.renderData;
|
|
rd.expandedRowHeight = size;
|
|
this._computeRowsHeight(rd, rd.sheetHeight-size);
|
|
this._resizeRows();
|
|
if(layout){
|
|
this._layoutRenderers(rd);
|
|
}
|
|
},
|
|
|
|
onExpandAnimationEnd: function(expand){
|
|
// summary:
|
|
// Event dispatched at the end of an expand or collapse animation.
|
|
// expand: Boolean
|
|
// Whether the finished animation was an expand or a collapse animation.
|
|
// tags:
|
|
// callback
|
|
|
|
},
|
|
|
|
_resizeRows: function(){
|
|
// summary:
|
|
// Refreshes the height of the underlying HTML objects.
|
|
// tags:
|
|
// private
|
|
|
|
if(this._getRowHeight(0) <= 0){
|
|
return;
|
|
}
|
|
|
|
if(this.rowHeaderTable){
|
|
this._resizeRowsImpl(this.rowHeaderTable, "tr");
|
|
}
|
|
if(this.gridTable){
|
|
this._resizeRowsImpl(this.gridTable, "tr");
|
|
}
|
|
if(this.itemContainerTable){
|
|
this._resizeRowsImpl(this.itemContainerTable, "tr");
|
|
}
|
|
},
|
|
|
|
_computeRowsHeight:function(renderData, max){
|
|
// summary:
|
|
// 1. Determine if it's better to add or remove pixels
|
|
// 2. distribute added/removed pixels on first and last rows.
|
|
// if rows are not too small, it is not noticeable.
|
|
// tags:
|
|
// private
|
|
|
|
var rd = renderData == null ? this.renderData : renderData;
|
|
|
|
max = max || rd.sheetHeight;
|
|
|
|
max--;
|
|
|
|
if(has("ie") == 7){
|
|
max -= rd.rowCount;
|
|
}
|
|
|
|
if(rd.rowCount == 1){
|
|
rd.rowHeight = max;
|
|
rd.rowHeightFirst = max;
|
|
rd.rowHeightLast = max;
|
|
return;
|
|
}
|
|
|
|
var count = rd.expandedRow == null ? rd.rowCount : rd.rowCount-1;
|
|
var rhx = max / count;
|
|
var rhf, rhl, rh;
|
|
|
|
var diffMin = max - (Math.floor(rhx) * count);
|
|
var diffMax = Math.abs(max - (Math.ceil(rhx) * count));
|
|
var diff;
|
|
|
|
var sign = 1;
|
|
if(diffMin < diffMax){
|
|
rh = Math.floor(rhx);
|
|
diff = diffMin;
|
|
}else{
|
|
sign = -1;
|
|
rh = Math.ceil(rhx);
|
|
diff = diffMax;
|
|
}
|
|
rhf = rh + sign * Math.floor(diff/2);
|
|
rhl = rhf + sign * (diff%2);
|
|
|
|
rd.rowHeight = rh;
|
|
rd.rowHeightFirst = rhf;
|
|
rd.rowHeightLast = rhl;
|
|
},
|
|
|
|
_getRowHeight: function(index){
|
|
// tags:
|
|
// private
|
|
|
|
var rd = this.renderData;
|
|
if(index == rd.expandedRow){
|
|
return rd.expandedRowHeight;
|
|
} else if(rd.expandedRow == 0 && index == 1 || index == 0){
|
|
return rd.rowHeightFirst;
|
|
} else if(rd.expandedRow == this.renderData.rowCount-1 &&
|
|
index == this.renderData.rowCount-2 ||
|
|
index == this.renderData.rowCount-1){
|
|
return rd.rowHeightLast;
|
|
}else{
|
|
return rd.rowHeight;
|
|
}
|
|
},
|
|
|
|
_resizeRowsImpl: function(tableNode, query){
|
|
// tags:
|
|
// private
|
|
var rd = this.renderData;
|
|
dojo.query(query, tableNode).forEach(function(tr, i){
|
|
domStyle.set(tr, "height", this._getRowHeight(i)+"px");
|
|
}, this);
|
|
},
|
|
|
|
////////////////////////////////////////////
|
|
//
|
|
// Item renderers
|
|
//
|
|
///////////////////////////////////////////
|
|
|
|
_setHorizontalRendererAttr: function(value){
|
|
this._destroyRenderersByKind("horizontal");
|
|
this._set("horizontalRenderer", value);
|
|
},
|
|
|
|
_setLabelRendererAttr: function(value){
|
|
this._destroyRenderersByKind("label");
|
|
this._set("labelRenderer", value);
|
|
},
|
|
|
|
_destroyExpandRenderer: function(renderer){
|
|
// summary:
|
|
// Destroys the expand renderer.
|
|
// renderer: dojox/calendar/_RendererMixin
|
|
// The item renderer to destroy.
|
|
// tags:
|
|
// protected
|
|
|
|
arr.forEach(renderer.__handles, function(handle){
|
|
handle.remove();
|
|
});
|
|
|
|
if(renderer["destroy"]){
|
|
renderer.destroy();
|
|
}
|
|
|
|
html.destroy(renderer.domNode);
|
|
},
|
|
|
|
_setExpandRendererAttr: function(value){
|
|
while(this._ddRendererList.length>0){
|
|
this._destroyExpandRenderer(this._ddRendererList.pop());
|
|
}
|
|
|
|
var pool = this._ddRendererPool;
|
|
if(pool){
|
|
while(pool.length > 0){
|
|
this._destroyExpandRenderer(pool.pop());
|
|
}
|
|
}
|
|
this._set("expandRenderer", value);
|
|
},
|
|
|
|
_ddRendererList: null,
|
|
_ddRendererPool: null,
|
|
|
|
_getExpandRenderer: function(date, items, rowIndex, colIndex, expanded){
|
|
// tags:
|
|
// private
|
|
|
|
if(this.expandRenderer == null){
|
|
return null;
|
|
}
|
|
|
|
var ir = this._ddRendererPool.pop();
|
|
if(ir == null){
|
|
ir = new this.expandRenderer();
|
|
}
|
|
|
|
this._ddRendererList.push(ir);
|
|
|
|
ir.set("owner", this);
|
|
ir.set("date", date);
|
|
ir.set("items", items);
|
|
ir.set("rowIndex", rowIndex);
|
|
ir.set("columnIndex", colIndex);
|
|
ir.set("expanded", expanded);
|
|
return ir;
|
|
},
|
|
|
|
_recycleExpandRenderers: function(remove){
|
|
// tags:
|
|
// private
|
|
|
|
for(var i=0; i<this._ddRendererList.length; i++){
|
|
var ir = this._ddRendererList[i];
|
|
ir.set("Up", false);
|
|
ir.set("Down", false);
|
|
if(remove){
|
|
ir.domNode.parentNode.removeChild(ir.domNode);
|
|
}
|
|
domStyle.set(ir.domNode, "display", "none");
|
|
}
|
|
this._ddRendererPool = this._ddRendererPool.concat(this._ddRendererList);
|
|
this._ddRendererList = [];
|
|
},
|
|
|
|
_defaultItemToRendererKindFunc:function(item){
|
|
// tags:
|
|
// private
|
|
var dur = Math.abs(this.renderData.dateModule.difference(item.startTime, item.endTime, "minute"));
|
|
return dur >= 1440 ? "horizontal" : "label";
|
|
},
|
|
|
|
////////////////////////////////////////////
|
|
//
|
|
// Layout
|
|
//
|
|
///////////////////////////////////////////
|
|
|
|
// naturalRowHeight: Integer[]
|
|
// After an item layout has been done, contains for each row the natural height of the row.
|
|
// Ie. the height, in pixels, needed to display all the item renderers.
|
|
naturalRowsHeight: null,
|
|
|
|
_roundItemToDay: function(item){
|
|
// tags:
|
|
// private
|
|
|
|
var s = item.startTime, e = item.endTime;
|
|
|
|
if(!this.isStartOfDay(s)){
|
|
s = this.floorToDay(s, false, this.renderData);
|
|
}
|
|
if(!this.isStartOfDay(e)){
|
|
e = this.renderData.dateModule.add(e, "day", 1);
|
|
e = this.floorToDay(e, true);
|
|
}
|
|
return {startTime:s, endTime:e};
|
|
},
|
|
|
|
_sortItemsFunction: function(a, b){
|
|
// tags:
|
|
// private
|
|
|
|
if(this.roundToDay){
|
|
a = this._roundItemToDay(a);
|
|
b = this._roundItemToDay(b);
|
|
}
|
|
var res = this.dateModule.compare(a.startTime, b.startTime);
|
|
if(res == 0){
|
|
res = -1 * this.dateModule.compare(a.endTime, b.endTime);
|
|
}
|
|
return res;
|
|
},
|
|
|
|
_overlapLayoutPass3: function(lanes){
|
|
// summary:
|
|
// Third pass of the overlap layout (optional). Compute the number of lanes used by sub interval.
|
|
// lanes: Object[]
|
|
// The array of lanes.
|
|
// tags:
|
|
// private
|
|
|
|
var pos=0, posEnd=0;
|
|
var res = [];
|
|
|
|
var refPos = domGeometry.position(this.gridTable).x;
|
|
|
|
for(var col=0; col<this.renderData.columnCount; col++){
|
|
|
|
var stop = false;
|
|
var colPos = domGeometry.position(this._getCellAt(0, col));
|
|
pos = colPos.x - refPos;
|
|
posEnd = pos + colPos.w;
|
|
|
|
for(var lane=lanes.length-1; lane>=0 && !stop; lane--){
|
|
for (var i=0; i<lanes[lane].length; i++){
|
|
var item = lanes[lane][i];
|
|
stop = item.start < posEnd && pos < item.end;
|
|
if(stop){
|
|
res[col] = lane + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!stop){
|
|
res[col] = 0;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
},
|
|
|
|
applyRendererZIndex: function(item, renderer, hovered, selected, edited, focused){
|
|
// summary:
|
|
// Applies the z-index to the renderer based on the state of the item.
|
|
// This methods is setting a z-index of 20 is the item is selected or edited
|
|
// and the current lane value computed by the overlap layout (i.e. the renderers
|
|
// are stacked according to their lane).
|
|
// item: Object
|
|
// The render item.
|
|
// renderer: Object
|
|
// A renderer associated with the render item.
|
|
// hovered: Boolean
|
|
// Whether the item is hovered or not.
|
|
// selected: Boolean
|
|
// Whether the item is selected or not.
|
|
// edited: Boolean
|
|
// Whether the item is being edited not not.
|
|
// focused: Boolean
|
|
// Whether the item is focused not not.
|
|
// tags:
|
|
// private
|
|
|
|
domStyle.set(renderer.container, {"zIndex": edited || selected ? renderer.renderer.mobile ? 100 : 0: item.lane == undefined ? 1 : item.lane+1});
|
|
},
|
|
|
|
_layoutRenderers: function(renderData){
|
|
// tags:
|
|
// private
|
|
if(renderData == null || renderData.items == null || renderData.rowHeight <= 0){
|
|
return;
|
|
}
|
|
|
|
if(!this.gridTable || this._expandAnimation != null ||
|
|
(this.horizontalRenderer == null && this.labelRenderer == null)){
|
|
this._recycleItemRenderers();
|
|
return;
|
|
}
|
|
|
|
this.renderData.gridTablePosX = domGeometry.position(this.gridTable).x;
|
|
this._layoutStep = renderData.columnCount;
|
|
this._recycleExpandRenderers();
|
|
this._hiddenItems = [];
|
|
this._offsets = [];
|
|
this.naturalRowsHeight = [];
|
|
|
|
this.inherited(arguments);
|
|
},
|
|
|
|
_offsets: null,
|
|
|
|
_layoutInterval: function(/*Object*/renderData, /*Integer*/index, /*Date*/start, /*Date*/end, /*Object[]*/items){
|
|
// tags:
|
|
// private
|
|
|
|
if(this.renderData.cells == null){
|
|
return;
|
|
}
|
|
var horizontalItems = [];
|
|
var labelItems = [];
|
|
|
|
for(var i=0; i<items.length; i++){
|
|
var item = items[i];
|
|
var kind = this._itemToRendererKind(item);
|
|
if(kind == "horizontal"){
|
|
horizontalItems.push(item);
|
|
}else if(kind == "label"){
|
|
labelItems.push(item);
|
|
}
|
|
}
|
|
|
|
var expIndex = this.getExpandedRowIndex();
|
|
|
|
if(expIndex != -1 && expIndex != index){
|
|
return; // when row is expanded, layout only expanded row
|
|
}
|
|
|
|
var offsets;
|
|
|
|
var hiddenItems = [];
|
|
|
|
var hItems;
|
|
var hOffsets = [];
|
|
if(horizontalItems.length > 0 && this.horizontalRenderer){
|
|
var hItems = this._createHorizontalLayoutItems(index, start, end, horizontalItems);
|
|
var hOverlapLayout = this._computeHorizontalOverlapLayout(hItems, hOffsets);
|
|
}
|
|
|
|
var lItems;
|
|
var lOffsets = [];
|
|
if(labelItems.length > 0 && this.labelRenderer){
|
|
lItems = this._createLabelLayoutItems(index, start, end, labelItems);
|
|
this._computeLabelOffsets(lItems, lOffsets);
|
|
}
|
|
|
|
var hasHiddenItems = this._computeColHasHiddenItems(index, hOffsets, lOffsets);
|
|
|
|
if(hItems != null){
|
|
this._layoutHorizontalItemsImpl(index, hItems, hOverlapLayout, hasHiddenItems, hiddenItems);
|
|
}
|
|
|
|
if(lItems != null){
|
|
this._layoutLabelItemsImpl(index, lItems, hasHiddenItems, hiddenItems, hOffsets);
|
|
}
|
|
|
|
this._layoutExpandRenderers(index, hasHiddenItems, hiddenItems);
|
|
|
|
this._hiddenItems[index] = hiddenItems;
|
|
},
|
|
|
|
_createHorizontalLayoutItems: function(/*Integer*/index, /*Date*/startTime, /*Date*/endTime, /*Object[]*/items){
|
|
// tags:
|
|
// private
|
|
|
|
if(this.horizontalRenderer == null){
|
|
return;
|
|
}
|
|
|
|
var rd = this.renderData;
|
|
var cal = rd.dateModule;
|
|
var cell = rd.cells[index];
|
|
var irHeight = this.horizontalRendererHeight;
|
|
var vOverlap = this.percentOverlap / 100;
|
|
var maxW = domGeometry.getMarginBox(this.itemContainer).w;
|
|
var sign = rd.rtl ? -1 : 1;
|
|
var layoutItems = [];
|
|
|
|
// step 1: compute projected position and size
|
|
for(var i = 0; i < items.length; i++){
|
|
|
|
var item = items[i];
|
|
var overlap = this.computeRangeOverlap(rd, item.startTime, item.endTime, startTime, endTime);
|
|
|
|
var startOffset = cal.difference(startTime, this.floorToDay(overlap[0], false, rd), "day");
|
|
var dayStart = rd.dates[index][startOffset];
|
|
|
|
var celPos = domGeometry.position(this._getCellAt(index, startOffset, false));
|
|
var start = celPos.x - rd.gridTablePosX;
|
|
if(rd.rtl){
|
|
start += celPos.w;
|
|
}
|
|
|
|
if(!this.roundToDay && !item.allDay){
|
|
start += sign * this.computeProjectionOnDate(rd, dayStart, overlap[0], celPos.w);
|
|
}
|
|
|
|
start = Math.ceil(start);
|
|
|
|
var endOffset = cal.difference(startTime, this.floorToDay(overlap[1], false, rd), "day");
|
|
|
|
var end;
|
|
if(endOffset > rd.columnCount-1){
|
|
celPos = domGeometry.position(this._getCellAt(index, rd.columnCount-1, false));
|
|
if(rd.rtl){
|
|
end = celPos.x - rd.gridTablePosX;
|
|
}else{
|
|
end = celPos.x - rd.gridTablePosX + celPos.w;
|
|
}
|
|
}else{
|
|
dayStart = rd.dates[index][endOffset];
|
|
celPos = domGeometry.position(this._getCellAt(index, endOffset, false));
|
|
end = celPos.x - rd.gridTablePosX;
|
|
|
|
if(rd.rtl){
|
|
end += celPos.w;
|
|
}
|
|
|
|
if(this.roundToDay){
|
|
if(!this.isStartOfDay(overlap[1])){
|
|
end += sign * celPos.w;
|
|
}
|
|
}else{
|
|
end += sign * this.computeProjectionOnDate(rd, dayStart, overlap[1], celPos.w);
|
|
}
|
|
}
|
|
|
|
end = Math.floor(end);
|
|
|
|
if(rd.rtl){
|
|
var t = end;
|
|
end = start;
|
|
start = t;
|
|
}
|
|
|
|
if(end > start){ // invalid items are not displayed
|
|
var litem = lang.mixin({
|
|
start: start,
|
|
end: end,
|
|
range: overlap,
|
|
item: item,
|
|
startOffset: startOffset,
|
|
endOffset: endOffset
|
|
}, item);
|
|
layoutItems.push(litem);
|
|
}
|
|
}
|
|
return layoutItems;
|
|
},
|
|
|
|
_computeHorizontalOverlapLayout: function(layoutItems, offsets){
|
|
// tags:
|
|
// private
|
|
|
|
var rd = this.renderData;
|
|
var irHeight = this.horizontalRendererHeight;
|
|
var overlapLayoutRes = this.computeOverlapping(layoutItems, this._overlapLayoutPass3);
|
|
var vOverlap = this.percentOverlap / 100;
|
|
|
|
for(i=0; i<rd.columnCount; i++){
|
|
var numLanes = overlapLayoutRes.addedPassRes[i];
|
|
var index = rd.rtl ? rd.columnCount - i - 1 : i;
|
|
if(vOverlap == 0){
|
|
offsets[index] = numLanes == 0 ? 0 : numLanes == 1 ? irHeight : irHeight + (numLanes-1) * (irHeight + this.verticalGap);
|
|
}else{
|
|
offsets[index] = numLanes == 0 ? 0 : numLanes * irHeight - (numLanes-1) * (vOverlap * irHeight) + this.verticalGap;
|
|
}
|
|
offsets[index] += this.cellPaddingTop;
|
|
}
|
|
return overlapLayoutRes;
|
|
},
|
|
|
|
_createLabelLayoutItems: function(/*Integer*/index, /*Date*/startTime, /*Date*/endTime, /*Object[]*/items){
|
|
// tags:
|
|
// private
|
|
|
|
if(this.labelRenderer == null){
|
|
return;
|
|
}
|
|
|
|
var d;
|
|
var rd = this.renderData;
|
|
var cal = rd.dateModule;
|
|
|
|
var layoutItems = [];
|
|
|
|
for(var i = 0; i < items.length; i++){
|
|
var item = items[i];
|
|
|
|
d = this.floorToDay(item.startTime, false, rd);
|
|
|
|
var comp = this.dateModule.compare;
|
|
|
|
// iterate on columns overlapped by this item to create one item per column
|
|
//while(d < item.endTime && d < rd.endTime){
|
|
while(comp(d, item.endTime) == -1 && comp(d, endTime) == -1){
|
|
|
|
var dayEnd = cal.add(d, "day", 1);
|
|
dayEnd = this.floorToDay(dayEnd, true);
|
|
|
|
var overlap = this.computeRangeOverlap(rd, item.startTime, item.endTime, d, dayEnd);
|
|
var startOffset = cal.difference(startTime, this.floorToDay(overlap[0], false, rd), "day");
|
|
|
|
if(startOffset >= this.columnCount){
|
|
// If the offset is greater than the column count
|
|
// the item will be processed in another row.
|
|
break;
|
|
}
|
|
|
|
if(startOffset >= 0){
|
|
var list = layoutItems[startOffset];
|
|
if(list == null){
|
|
list = [];
|
|
layoutItems[startOffset] = list;
|
|
}
|
|
|
|
list.push(lang.mixin(
|
|
{ startOffset: startOffset,
|
|
range: overlap,
|
|
item: item
|
|
}, item));
|
|
}
|
|
|
|
d = cal.add(d, "day", 1);
|
|
this.floorToDay(d, true);
|
|
}
|
|
}
|
|
return layoutItems;
|
|
},
|
|
|
|
_computeLabelOffsets: function(layoutItems, offsets){
|
|
// tags:
|
|
// private
|
|
|
|
for(var i=0; i<this.renderData.columnCount; i++){
|
|
offsets[i] = layoutItems[i] == null ? 0 : layoutItems[i].length * (this.labelRendererHeight + this.verticalGap);
|
|
}
|
|
},
|
|
|
|
_computeColHasHiddenItems: function(index, hOffsets, lOffsets){
|
|
// tags:
|
|
// private
|
|
|
|
var res = [];
|
|
var cellH = this._getRowHeight(index);
|
|
var h;
|
|
var maxH = 0;
|
|
for(var i=0; i<this.renderData.columnCount; i++){
|
|
h = hOffsets == null || hOffsets[i] == null ? this.cellPaddingTop : hOffsets[i];
|
|
h += lOffsets == null || lOffsets[i] == null ? 0 : lOffsets[i];
|
|
if(h > maxH){
|
|
maxH = h;
|
|
}
|
|
res[i] = h > cellH;
|
|
}
|
|
|
|
this.naturalRowsHeight[index] = maxH;
|
|
return res;
|
|
},
|
|
|
|
_layoutHorizontalItemsImpl: function(index, layoutItems, hOverlapLayout, hasHiddenItems, hiddenItems){
|
|
|
|
// tags:
|
|
// private
|
|
|
|
var rd = this.renderData;
|
|
var cal = rd.dateModule;
|
|
var cell = rd.cells[index];
|
|
var cellH = this._getRowHeight(index);
|
|
var irHeight = this.horizontalRendererHeight;
|
|
var vOverlap = this.percentOverlap / 100;
|
|
|
|
for(var i=0; i<layoutItems.length; i++){
|
|
|
|
var item = layoutItems[i];
|
|
var lane = item.lane;
|
|
|
|
var posY = this.cellPaddingTop;
|
|
|
|
if(vOverlap == 0) {
|
|
//no overlap and a padding between each event
|
|
posY += lane * (irHeight + this.verticalGap);
|
|
} else {
|
|
// an overlap
|
|
posY += lane * (irHeight - vOverlap * irHeight);
|
|
}
|
|
|
|
var exp = false;
|
|
var maxH = cellH;
|
|
if(this.expandRenderer){
|
|
for(var off=item.startOffset; off<=item.endOffset; off++){
|
|
if(hasHiddenItems[off]){
|
|
exp = true;
|
|
break;
|
|
}
|
|
}
|
|
maxH = exp ? cellH - this.expandRendererHeight : cellH;
|
|
}
|
|
|
|
if(posY + irHeight <= maxH){
|
|
|
|
var ir = this._createRenderer(item, "horizontal", this.horizontalRenderer, "dojoxCalendarHorizontal");
|
|
|
|
var fullHeight = this.isItemBeingEdited(item) && !this.liveLayout && this._isEditing;
|
|
var h = fullHeight ? cellH - this.cellPaddingTop : irHeight;
|
|
var w = item.end - item.start;
|
|
if (has("ie") >= 9 && item.start + w < this.itemContainer.offsetWidth) {
|
|
w++;
|
|
};
|
|
|
|
domStyle.set(ir.container, {
|
|
"top": (fullHeight ? this.cellPaddingTop : posY) + "px",
|
|
"left": item.start + "px",
|
|
"width": w + "px",
|
|
"height": h + "px"
|
|
});
|
|
|
|
this._applyRendererLayout(item, ir, cell, w, h, "horizontal");
|
|
|
|
}else{
|
|
// The items does not fit in view, fill hidden items per column
|
|
for(var d=item.startOffset;d<item.endOffset;d++){
|
|
if(hiddenItems[d] == null){
|
|
hiddenItems[d] = [item.item];
|
|
}else{
|
|
hiddenItems[d].push(item.item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
_layoutLabelItemsImpl: function(index, layoutItems, hasHiddenItems, hiddenItems, hOffsets){
|
|
// tags:
|
|
// private
|
|
var d, list, posY;
|
|
var rd = this.renderData;
|
|
var cal = rd.dateModule;
|
|
var cell = rd.cells[index];
|
|
var cellH = this._getRowHeight(index);
|
|
var irHeight = this.labelRendererHeight;
|
|
var maxW = domGeometry.getMarginBox(this.itemContainer).w;
|
|
|
|
for(var i=0; i<layoutItems.length; i++){
|
|
list = layoutItems[i];
|
|
|
|
if(list != null){
|
|
|
|
var maxH = this.expandRenderer ? (hasHiddenItems[i] ? cellH - this.expandRendererHeight: cellH) : cellH;
|
|
posY = hOffsets == null || hOffsets[i] == null ? this.cellPaddingTop : hOffsets[i] + this.verticalGap;
|
|
var celPos = domGeometry.position(this._getCellAt(index, i));
|
|
var dayStart = rd.dates[index][i];
|
|
var left = celPos.x - rd.gridTablePosX;
|
|
|
|
for(var j=0; j<list.length; j++){
|
|
|
|
if(posY + irHeight + this.verticalGap <= maxH){
|
|
var item = list[j];
|
|
|
|
lang.mixin(item, {
|
|
start: left,
|
|
end: left + celPos.w
|
|
});
|
|
|
|
var ir = this._createRenderer(item, "label", this.labelRenderer, "dojoxCalendarLabel");
|
|
|
|
var fullHeight = this.isItemBeingEdited(item) && !this.liveLayout && this._isEditing;
|
|
var h = fullHeight ? this._getRowHeight(index) - this.cellPaddingTop : irHeight;
|
|
|
|
if(rd.rtl){
|
|
item.start = maxW - item.end;
|
|
item.end = item.start + celPos.w;
|
|
}
|
|
|
|
domStyle.set(ir.container, {
|
|
"top": (fullHeight ? this.cellPaddingTop : posY) + "px",
|
|
"left": item.start + "px",
|
|
"width": celPos.w + "px",
|
|
"height": h + "px"
|
|
});
|
|
|
|
this._applyRendererLayout(item, ir, cell, celPos.w, h, "label");
|
|
|
|
}else{
|
|
break;
|
|
}
|
|
posY += irHeight + this.verticalGap;
|
|
}
|
|
|
|
for(var j; j<list.length; j++){
|
|
if(hiddenItems[i] == null){
|
|
hiddenItems[i] = [list[j]];
|
|
}else{
|
|
hiddenItems[i].push(list[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
_applyRendererLayout: function(item, ir, cell, w, h, kind){
|
|
// tags:
|
|
// private
|
|
|
|
var edited = this.isItemBeingEdited(item);
|
|
var selected = this.isItemSelected(item);
|
|
var hovered = this.isItemHovered(item);
|
|
var focused = this.isItemFocused(item);
|
|
|
|
var renderer = ir.renderer;
|
|
|
|
renderer.set("hovered", hovered);
|
|
renderer.set("selected", selected);
|
|
renderer.set("edited", edited);
|
|
renderer.set("focused", this.showFocus ? focused : false);
|
|
renderer.set("moveEnabled", this.isItemMoveEnabled(item, kind));
|
|
if(kind != "label"){
|
|
renderer.set("resizeEnabled", this.isItemResizeEnabled(item, kind));
|
|
}
|
|
|
|
this.applyRendererZIndex(item, ir, hovered, selected, edited, focused);
|
|
|
|
if(renderer.updateRendering){
|
|
renderer.updateRendering(w, h);
|
|
}
|
|
|
|
domConstruct.place(ir.container, cell);
|
|
domStyle.set(ir.container, "display", "block");
|
|
},
|
|
|
|
_getCellAt: function(rowIndex, columnIndex, rtl){
|
|
// tags:
|
|
// private
|
|
|
|
if((rtl == undefined || rtl == true) && !this.isLeftToRight()){
|
|
columnIndex = this.renderData.columnCount -1 - columnIndex;
|
|
}
|
|
return this.gridTable.childNodes[0].childNodes[rowIndex].childNodes[columnIndex];
|
|
},
|
|
|
|
_layoutExpandRenderers: function(index, hasHiddenItems, hiddenItems){
|
|
// tags:
|
|
// private
|
|
|
|
if(!this.expandRenderer){
|
|
return;
|
|
}
|
|
var rd = this.renderData;
|
|
if(rd.expandedRow == index){
|
|
if(rd.expandedRowCol != null && rd.expandedRowCol != -1){
|
|
this._layoutExpandRendererImpl(rd.expandedRow, rd.expandedRowCol, null, true);
|
|
}
|
|
}else{
|
|
if(rd.expandedRow == null){
|
|
for(var i=0; i<rd.columnCount; i++){
|
|
if(hasHiddenItems[i]){
|
|
this._layoutExpandRendererImpl(index, rd.rtl ? rd.columnCount -1 -i: i, hiddenItems[i], false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
_layoutExpandRendererImpl: function(rowIndex, colIndex, items, expanded){
|
|
// tags:
|
|
// private
|
|
|
|
var d, ir;
|
|
var rd = this.renderData;
|
|
var cal = rd.dateModule;
|
|
var cell = rd.cells[rowIndex];
|
|
|
|
ir = this._getExpandRenderer(
|
|
lang.clone(rd.dates[rowIndex][colIndex]),
|
|
items, rowIndex, colIndex, expanded);
|
|
|
|
var dim = domGeometry.position(this._getCellAt(rowIndex, colIndex));
|
|
dim.x -= rd.gridTablePosX;
|
|
this.layoutExpandRenderer(ir, d, items, dim, this.expandRendererHeight);
|
|
domConstruct.place(ir.domNode, cell);
|
|
domStyle.set(ir.domNode, "display", "block");
|
|
},
|
|
|
|
layoutExpandRenderer: function(renderer, date, items, cellPosition, height){
|
|
// summary:
|
|
// Computes and sets the position of the expand/collapse renderers.
|
|
// By default the renderer is set to take the width of the cell and is placed at the bottom of the cell.
|
|
// The renderer DOM node is in a row that takes all the grid width.
|
|
// renderer: Object
|
|
// The renderer used in specified cell that indicates that some items cannot be displayed.
|
|
// date: Date
|
|
// The date displayed by the cell.
|
|
// items: Object[]
|
|
// The list of non visible items.
|
|
// cellPosition: Object
|
|
// An object that contains the position (x and y properties) and size of the cell (w and h properties).
|
|
// tags:
|
|
// private
|
|
domStyle.set(renderer.domNode, {
|
|
"left": cellPosition.x + "px",
|
|
"width": cellPosition.w + "px",
|
|
"height": height + "px",
|
|
"top": (cellPosition.h - height -1) + "px"
|
|
});
|
|
},
|
|
|
|
/////////////////////////////////////////////
|
|
//
|
|
// Editing
|
|
//
|
|
//////////////////////////////////////////////
|
|
|
|
_onItemEditBeginGesture: function(e){
|
|
// tags:
|
|
// private
|
|
var p = this._edProps;
|
|
|
|
var item = p.editedItem;
|
|
var dates = e.dates;
|
|
|
|
var refTime = this.newDate(p.editKind == "resizeEnd" ? item.endTime : item.startTime);
|
|
|
|
if(p.rendererKind == "label"){
|
|
// noop
|
|
}else if(e.editKind == "move" && (item.allDay || this.roundToDay)){
|
|
var cal = this.renderData.dateModule;
|
|
p.dayOffset = cal.difference(
|
|
this.floorToDay(dates[0], false, this.renderData),
|
|
refTime, "day");
|
|
} // else managed in super
|
|
|
|
this.inherited(arguments);
|
|
},
|
|
|
|
_computeItemEditingTimes: function(item, editKind, rendererKind, times, eventSource){
|
|
// tags:
|
|
// private
|
|
var cal = this.renderData.dateModule;
|
|
var p = this._edProps;
|
|
|
|
if(rendererKind == "label"){ // noop
|
|
}else if(item.allDay || this.roundToDay){
|
|
var isStartOfDay = this.isStartOfDay(times[0]);
|
|
switch(editKind){
|
|
case "resizeEnd":
|
|
if(!isStartOfDay && item.allDay){
|
|
times[0] = cal.add(times[0], "day", 1); // no break;
|
|
}
|
|
case "resizeStart":
|
|
if(!isStartOfDay){
|
|
times[0] = this.floorToDay(times[0], true);
|
|
}
|
|
break;
|
|
case "move":
|
|
times[0] = cal.add(times[0], "day", p.dayOffset);
|
|
break;
|
|
case "resizeBoth":
|
|
if(!isStartOfDay){
|
|
times[0] = this.floorToDay(times[0], true);
|
|
}
|
|
if(!this.isStartOfDay(times[1])){
|
|
times[1] = this.floorToDay(cal.add(times[1], "day", 1), true);
|
|
}
|
|
break;
|
|
}
|
|
|
|
}else{
|
|
times = this.inherited(arguments);
|
|
}
|
|
|
|
return times;
|
|
},
|
|
|
|
|
|
/////////////////////////////////////////////
|
|
//
|
|
// Pixel to Time projection
|
|
//
|
|
//////////////////////////////////////////////
|
|
|
|
getTime: function(e, x, y, touchIndex){
|
|
// summary:
|
|
// Returns the time displayed at the specified point by this component.
|
|
// e: Event
|
|
// Optional mouse event.
|
|
// x: Number
|
|
// Position along the x-axis with respect to the sheet container used if event is not defined.
|
|
// y: Number
|
|
// Position along the y-axis with respect to the sheet container (scroll included) used if event is not defined.
|
|
// touchIndex: Integer
|
|
// If parameter 'e' is not null and a touch event, the index of the touch to use.
|
|
// returns: Date
|
|
|
|
var rd = this.renderData;
|
|
|
|
if(e != null){
|
|
var refPos = domGeometry.position(this.itemContainer, true);
|
|
|
|
if(e.touches){
|
|
|
|
touchIndex = touchIndex==undefined ? 0 : touchIndex;
|
|
|
|
x = e.touches[touchIndex].pageX - refPos.x;
|
|
y = e.touches[touchIndex].pageY - refPos.y;
|
|
|
|
}else{
|
|
|
|
x = e.pageX - refPos.x;
|
|
y = e.pageY - refPos.y;
|
|
}
|
|
}
|
|
|
|
var r = domGeometry.getContentBox(this.itemContainer);
|
|
|
|
if(x < 0){
|
|
x = 0;
|
|
}else if(x > r.w){
|
|
x = r.w-1;
|
|
}
|
|
|
|
if(y < 0){
|
|
y = 0;
|
|
}else if(y > r.h){
|
|
y = r.h-1;
|
|
}
|
|
|
|
// compute the date from column the time in day instead of time from start date of row to prevent DST hour offset.
|
|
|
|
var w = domGeometry.getMarginBox(this.itemContainer).w;
|
|
var colW = w / rd.columnCount;
|
|
|
|
var row;
|
|
if(rd.expandedRow == null){
|
|
row = Math.floor(y / (domGeometry.getMarginBox(this.itemContainer).h / rd.rowCount));
|
|
}else{
|
|
row = rd.expandedRow; //other rows are not usable
|
|
}
|
|
|
|
var r = domGeometry.getContentBox(this.itemContainer);
|
|
|
|
if(rd.rtl){
|
|
x = r.w - x;
|
|
}
|
|
|
|
var col = Math.floor(x / colW);
|
|
|
|
var tm = Math.floor((x-(col*colW)) * 1440 / colW);
|
|
|
|
var date = null;
|
|
if(row < rd.dates.length && col < this.renderData.dates[row].length){
|
|
date = this.newDate(this.renderData.dates[row][col]);
|
|
date = this.renderData.dateModule.add(date, "minute", tm);
|
|
}
|
|
|
|
return date;
|
|
},
|
|
|
|
/////////////////////////////////////////////
|
|
//
|
|
// Event management
|
|
//
|
|
//////////////////////////////////////////////
|
|
|
|
_onGridMouseUp: function(e){
|
|
// tags:
|
|
// private
|
|
|
|
this.inherited(arguments);
|
|
|
|
if(this._gridMouseDown){
|
|
this._gridMouseDown = false;
|
|
|
|
this._onGridClick({
|
|
date: this.getTime(e),
|
|
triggerEvent: e
|
|
});
|
|
}
|
|
},
|
|
|
|
_onGridTouchEnd: function(e){
|
|
// tags:
|
|
// private
|
|
this.inherited(arguments);
|
|
|
|
var g = this._gridProps;
|
|
|
|
if(g){
|
|
|
|
if(!this._isEditing){
|
|
|
|
// touched on grid and on touch start editing was ongoing.
|
|
if(!g.fromItem && !g.editingOnStart){
|
|
this.selectFromEvent(e, null, null, true);
|
|
}
|
|
|
|
if(!g.fromItem){
|
|
|
|
if(this._pendingDoubleTap && this._pendingDoubleTap.grid){
|
|
|
|
this._onGridDoubleClick({
|
|
date: this.getTime(this._gridProps.event),
|
|
triggerEvent: this._gridProps.event
|
|
});
|
|
|
|
clearTimeout(this._pendingDoubleTap.timer);
|
|
|
|
delete this._pendingDoubleTap;
|
|
|
|
}else{
|
|
|
|
this._onGridClick({
|
|
date: this.getTime(this._gridProps.event),
|
|
triggerEvent: this._gridProps.event
|
|
});
|
|
|
|
this._pendingDoubleTap = {
|
|
grid: true,
|
|
timer: setTimeout(lang.hitch(this, function(){
|
|
delete this._pendingDoubleTap;
|
|
}), this.doubleTapDelay)
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
this._gridProps = null;
|
|
}
|
|
},
|
|
|
|
|
|
/////////////////////////////////////////////
|
|
//
|
|
// Events
|
|
//
|
|
//////////////////////////////////////////////
|
|
|
|
_onRowHeaderClick: function(e){
|
|
this._dispatchCalendarEvt(e, "onRowHeaderClick");
|
|
// tags:
|
|
// private
|
|
},
|
|
|
|
onRowHeaderClick: function(e){
|
|
// summary:
|
|
// Event dispatched when a row header cell is clicked.
|
|
// e: __HeaderClickEventArgs
|
|
// Header click event.
|
|
// tags:
|
|
// callback
|
|
},
|
|
|
|
expandRendererClickHandler: function(e, renderer){
|
|
// summary:
|
|
// Default action when an expand renderer is clicked.
|
|
// e: Event
|
|
// The mouse event.
|
|
// renderer: Object
|
|
// The expand renderer.
|
|
// tags:
|
|
// protected
|
|
|
|
event.stop(e);
|
|
|
|
var ri = renderer.get("rowIndex");
|
|
var ci = renderer.get("columnIndex");
|
|
|
|
this._onExpandRendererClick(lang.mixin(this._createItemEditEvent(), {
|
|
rowIndex: ri,
|
|
columnIndex: ci,
|
|
renderer: renderer,
|
|
triggerEvent: e,
|
|
date: this.renderData.dates[ri][ci]
|
|
}));
|
|
},
|
|
|
|
onExpandRendererClick: function(e){
|
|
// summary:
|
|
// Event dispatched when an expand renderer is clicked.
|
|
// e: __ExpandRendererClickEventArgs
|
|
// Expand renderer click event.
|
|
// tags:
|
|
// callback
|
|
},
|
|
|
|
_onExpandRendererClick: function(e){
|
|
|
|
this._dispatchCalendarEvt(e, "onExpandRendererClick");
|
|
|
|
if(!e.isDefaultPrevented()){
|
|
|
|
if(this.getExpandedRowIndex() != -1){
|
|
this.collapseRow();
|
|
}else{
|
|
this.expandRow(e.rowIndex, e.columnIndex);
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
////////////////////////////////////////////
|
|
//
|
|
// Editing
|
|
//
|
|
///////////////////////////////////////////
|
|
|
|
snapUnit: "minute",
|
|
snapSteps: 15,
|
|
minDurationUnit: "minute",
|
|
minDurationSteps: 15,
|
|
triggerExtent: 3,
|
|
liveLayout: false,
|
|
stayInView: true,
|
|
allowStartEndSwap: true,
|
|
allowResizeLessThan24H: false
|
|
|
|
});
|
|
});
|