ui.scheduler.agenda.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /**
  2. * DevExtreme (ui/scheduler/workspaces/ui.scheduler.agenda.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var $ = require("../../../core/renderer");
  11. var domAdapter = require("../../../core/dom_adapter");
  12. var noop = require("../../../core/utils/common").noop;
  13. var each = require("../../../core/utils/iterator").each;
  14. var getPublicElement = require("../../../core/utils/dom").getPublicElement;
  15. var registerComponent = require("../../../core/component_registrator");
  16. var SchedulerWorkSpace = require("./ui.scheduler.work_space");
  17. var extend = require("../../../core/utils/extend").extend;
  18. var dateLocalization = require("../../../localization/date");
  19. var tableCreator = require("../ui.scheduler.table_creator");
  20. var AGENDA_CLASS = "dx-scheduler-agenda";
  21. var AGENDA_DATE_CLASS = "dx-scheduler-agenda-date";
  22. var GROUP_TABLE_CLASS = "dx-scheduler-group-table";
  23. var AGENDA_GROUPED_ATTR = "dx-group-column-count";
  24. var TIME_PANEL_ROW_CLASS = "dx-scheduler-time-panel-row";
  25. var TIME_PANEL_CELL_CLASS = "dx-scheduler-time-panel-cell";
  26. var NODATA_CONTAINER_CLASS = "dx-scheduler-agenda-nodata";
  27. var LAST_ROW_CLASS = "dx-scheduler-date-table-last-row";
  28. var INNER_CELL_MARGIN = 5;
  29. var OUTER_CELL_MARGIN = 20;
  30. var SchedulerAgenda = SchedulerWorkSpace.inherit({
  31. _activeStateUnit: void 0,
  32. _getDefaultOptions: function() {
  33. return extend(this.callBase(), {
  34. agendaDuration: 7,
  35. rowHeight: 60,
  36. noDataText: ""
  37. })
  38. },
  39. _optionChanged: function(args) {
  40. var name = args.name;
  41. var value = args.value;
  42. switch (name) {
  43. case "agendaDuration":
  44. break;
  45. case "noDataText":
  46. case "rowHeight":
  47. this._recalculateAgenda(this._rows);
  48. break;
  49. case "groups":
  50. if (!value || !value.length) {
  51. if (this._$groupTable) {
  52. this._$groupTable.remove();
  53. this._$groupTable = null;
  54. this._detachGroupCountAttr()
  55. }
  56. } else {
  57. if (!this._$groupTable) {
  58. this._initGroupTable();
  59. this._dateTableScrollable.$content().prepend(this._$groupTable)
  60. }
  61. }
  62. this.callBase(args);
  63. break;
  64. default:
  65. this.callBase(args)
  66. }
  67. },
  68. _renderFocusState: noop,
  69. _renderFocusTarget: noop,
  70. _cleanFocusState: noop,
  71. supportAllDayRow: function() {
  72. return false
  73. },
  74. _isVerticalGroupedWorkSpace: function() {
  75. return false
  76. },
  77. _getElementClass: function() {
  78. return AGENDA_CLASS
  79. },
  80. _setFirstViewDate: function() {
  81. this._firstViewDate = new Date(this.option("currentDate"));
  82. this._setStartDayHour(this._firstViewDate)
  83. },
  84. _getRowCount: function() {
  85. return this.option("agendaDuration")
  86. },
  87. _getCellCount: function() {
  88. return 1
  89. },
  90. _getTimePanelRowCount: function() {
  91. return this.option("agendaDuration")
  92. },
  93. _getDateByIndex: noop,
  94. _getFormat: function() {
  95. return "d ddd"
  96. },
  97. _renderAllDayPanel: noop,
  98. _toggleAllDayVisibility: noop,
  99. _initWorkSpaceUnits: function() {
  100. this._initGroupTable();
  101. this._$timePanel = $("<table>").addClass(this._getTimePanelClass());
  102. this._$dateTable = $("<table>").addClass(this._getDateTableClass())
  103. },
  104. _initGroupTable: function() {
  105. var groups = this.option("groups");
  106. if (groups && groups.length) {
  107. this._$groupTable = $("<table>").addClass(GROUP_TABLE_CLASS)
  108. }
  109. },
  110. _renderView: function() {
  111. this._setFirstViewDate();
  112. this._rows = [];
  113. this.invoke("getAgendaRows", {
  114. agendaDuration: this.option("agendaDuration"),
  115. currentDate: new Date(this.option("currentDate"))
  116. }).done(function(rows) {
  117. this._recalculateAgenda(rows)
  118. }.bind(this))
  119. },
  120. _recalculateAgenda: function(rows) {
  121. var cellTemplates = [];
  122. this._cleanView();
  123. if (this._rowsIsEmpty(rows)) {
  124. this._renderNoData();
  125. return
  126. }
  127. this._rows = rows;
  128. if (this._$groupTable) {
  129. cellTemplates = this._renderGroupHeader();
  130. this._setGroupHeaderCellsHeight()
  131. }
  132. this._renderTimePanel();
  133. this._renderDateTable();
  134. this.invoke("agendaIsReady", rows, INNER_CELL_MARGIN, OUTER_CELL_MARGIN);
  135. this._applyCellTemplates(cellTemplates);
  136. this._dateTableScrollable.update()
  137. },
  138. _renderNoData: function() {
  139. this._$noDataContainer = $("<div>").addClass(NODATA_CONTAINER_CLASS).html(this.option("noDataText"));
  140. this._dateTableScrollable.$content().append(this._$noDataContainer)
  141. },
  142. _setTableSizes: noop,
  143. _toggleHorizontalScrollClass: noop,
  144. _createCrossScrollingConfig: noop,
  145. _setGroupHeaderCellsHeight: function() {
  146. var $cells = this._getGroupHeaderCells().filter(function(_, element) {
  147. return !element.getAttribute("rowSpan")
  148. });
  149. var rows = this._removeEmptyRows(this._rows);
  150. if (!rows.length) {
  151. return
  152. }
  153. for (var i = 0; i < $cells.length; i++) {
  154. var $cellContent = $cells.eq(i).find(".dx-scheduler-group-header-content");
  155. $cellContent.outerHeight(this._getGroupRowHeight(rows[i]))
  156. }
  157. },
  158. _rowsIsEmpty: function(rows) {
  159. var result = true;
  160. for (var i = 0; i < rows.length; i++) {
  161. var groupRow = rows[i];
  162. for (var j = 0; j < groupRow.length; j++) {
  163. if (groupRow[j]) {
  164. result = false;
  165. break
  166. }
  167. }
  168. }
  169. return result
  170. },
  171. _detachGroupCountAttr: function() {
  172. this.$element().removeAttr(AGENDA_GROUPED_ATTR)
  173. },
  174. _attachGroupCountAttr: function() {
  175. this.$element().attr(AGENDA_GROUPED_ATTR, this.option("groups").length)
  176. },
  177. _removeEmptyRows: function(rows) {
  178. var result = [];
  179. var isEmpty = function(data) {
  180. return !data.some(function(value) {
  181. return value > 0
  182. })
  183. };
  184. for (var i = 0; i < rows.length; i++) {
  185. if (rows[i].length && !isEmpty(rows[i])) {
  186. result.push(rows[i])
  187. }
  188. }
  189. return result
  190. },
  191. _getGroupHeaderContainer: function() {
  192. return this._$groupTable
  193. },
  194. _makeGroupRows: function() {
  195. var tree = this.invoke("createReducedResourcesTree");
  196. var cellTemplate = this.option("resourceCellTemplate");
  197. var getGroupHeaderContentClass = this._getGroupHeaderContentClass();
  198. var cellTemplates = [];
  199. var table = tableCreator.makeGroupedTableFromJSON(tableCreator.VERTICAL, tree, {
  200. cellTag: "th",
  201. groupTableClass: GROUP_TABLE_CLASS,
  202. groupRowClass: this._getGroupRowClass(),
  203. groupCellClass: this._getGroupHeaderClass(),
  204. groupCellCustomContent: function(cell, cellText, index, data) {
  205. var container = domAdapter.createElement("div");
  206. var contentWrapper = domAdapter.createElement("div");
  207. container.className = getGroupHeaderContentClass;
  208. contentWrapper.appendChild(cellText);
  209. container.appendChild(contentWrapper);
  210. container.className = getGroupHeaderContentClass;
  211. if (cellTemplate && cellTemplate.render) {
  212. cellTemplates.push(cellTemplate.render.bind(cellTemplate, {
  213. model: {
  214. data: data.data,
  215. id: data.value,
  216. color: data.color,
  217. text: cellText.textContent
  218. },
  219. container: getPublicElement($(container)),
  220. index: index
  221. }))
  222. } else {
  223. contentWrapper.appendChild(cellText);
  224. container.appendChild(contentWrapper)
  225. }
  226. cell.appendChild(container)
  227. },
  228. cellTemplate: cellTemplate
  229. });
  230. return {
  231. elements: $(table).find("." + this._getGroupRowClass()),
  232. cellTemplates: cellTemplates
  233. }
  234. },
  235. _cleanView: function() {
  236. this._$dateTable.empty();
  237. this._$timePanel.empty();
  238. if (this._$groupTable) {
  239. this._$groupTable.empty()
  240. }
  241. if (this._$noDataContainer) {
  242. this._$noDataContainer.empty();
  243. this._$noDataContainer.remove();
  244. delete this._$noDataContainer
  245. }
  246. },
  247. _createWorkSpaceElements: function() {
  248. this._createWorkSpaceStaticElements()
  249. },
  250. _createWorkSpaceStaticElements: function() {
  251. if (this._$groupTable) {
  252. this._dateTableScrollable.$content().prepend(this._$groupTable)
  253. }
  254. this._dateTableScrollable.$content().append(this._$timePanel, this._$dateTable);
  255. this.$element().append(this._dateTableScrollable.$element())
  256. },
  257. _renderDateTable: function() {
  258. this._renderTableBody({
  259. container: getPublicElement(this._$dateTable),
  260. rowClass: this._getDateTableRowClass(),
  261. cellClass: this._getDateTableCellClass()
  262. })
  263. },
  264. _attachTablesEvents: noop,
  265. _attachEvents: noop,
  266. _cleanCellDataCache: noop,
  267. needRenderDateTimeIndication: function() {
  268. return false
  269. },
  270. _prepareCellTemplateOptions: function(text, date, rowIndex, $cell) {
  271. var groupsOpt = this.option("groups");
  272. var groups = {};
  273. var path = groupsOpt.length && this._getPathToLeaf(rowIndex) || [];
  274. path.forEach(function(resourceValue, resourceIndex) {
  275. var resourceName = groupsOpt[resourceIndex].name;
  276. groups[resourceName] = resourceValue
  277. });
  278. return {
  279. model: {
  280. text: text,
  281. date: date,
  282. groups: groups
  283. },
  284. container: getPublicElement($cell),
  285. index: rowIndex
  286. }
  287. },
  288. _renderTableBody: function(options) {
  289. var cellTemplates = [];
  290. var cellTemplateOpt = options.cellTemplate;
  291. this._$rows = [];
  292. var fillTableBody = function(rowIndex, rowSize) {
  293. if (rowSize) {
  294. var date;
  295. var cellDateNumber;
  296. var cellDayName;
  297. var $row = $("<tr>");
  298. var $td = $("<td>").height(this._getRowHeight(rowSize));
  299. if (options.getStartDate) {
  300. date = options.getStartDate && options.getStartDate(rowIndex);
  301. cellDateNumber = dateLocalization.format(date, "d");
  302. cellDayName = dateLocalization.format(date, this._formatWeekday)
  303. }
  304. if (cellTemplateOpt && cellTemplateOpt.render) {
  305. var templateOptions = this._prepareCellTemplateOptions(cellDateNumber + " " + cellDayName, date, i, $td);
  306. cellTemplates.push(cellTemplateOpt.render.bind(cellTemplateOpt, templateOptions))
  307. } else {
  308. if (cellDateNumber && cellDayName) {
  309. $td.addClass(AGENDA_DATE_CLASS).text(cellDateNumber + " " + cellDayName)
  310. }
  311. }
  312. if (options.rowClass) {
  313. $row.addClass(options.rowClass)
  314. }
  315. if (options.cellClass) {
  316. $td.addClass(options.cellClass)
  317. }
  318. $row.append($td);
  319. this._$rows.push($row)
  320. }
  321. }.bind(this);
  322. for (var i = 0; i < this._rows.length; i++) {
  323. each(this._rows[i], fillTableBody);
  324. this._setLastRowClass()
  325. }
  326. $(options.container).append($("<tbody>").append(this._$rows));
  327. this._applyCellTemplates(cellTemplates)
  328. },
  329. _setLastRowClass: function() {
  330. if (this._rows.length > 1 && this._$rows.length) {
  331. var $lastRow = this._$rows[this._$rows.length - 1];
  332. $lastRow.addClass(LAST_ROW_CLASS)
  333. }
  334. },
  335. _renderTimePanel: function() {
  336. this._renderTableBody({
  337. container: getPublicElement(this._$timePanel),
  338. rowCount: this._getTimePanelRowCount(),
  339. cellCount: 1,
  340. rowClass: TIME_PANEL_ROW_CLASS,
  341. cellClass: TIME_PANEL_CELL_CLASS,
  342. cellTemplate: this.option("dateCellTemplate"),
  343. getStartDate: this._getTimePanelStartDate.bind(this)
  344. })
  345. },
  346. _getTimePanelStartDate: function(rowIndex) {
  347. var current = new Date(this.option("currentDate"));
  348. var cellDate = new Date(current.setDate(current.getDate() + rowIndex));
  349. return cellDate
  350. },
  351. _getRowHeight: function(rowSize) {
  352. var baseHeight = this.option("rowHeight");
  353. var innerOffset = (rowSize - 1) * INNER_CELL_MARGIN;
  354. return rowSize ? baseHeight * rowSize + innerOffset + OUTER_CELL_MARGIN : 0
  355. },
  356. _getGroupRowHeight: function(groupRows) {
  357. if (!groupRows) {
  358. return
  359. }
  360. var result = 0;
  361. for (var i = 0; i < groupRows.length; i++) {
  362. result += this._getRowHeight(groupRows[i])
  363. }
  364. return result
  365. },
  366. getAgendaVerticalStepHeight: function() {
  367. return this.option("rowHeight")
  368. },
  369. getEndViewDate: function() {
  370. var currentDate = new Date(this.option("currentDate"));
  371. var agendaDuration = this.option("agendaDuration");
  372. currentDate.setHours(this.option("endDayHour"));
  373. var result = currentDate.setDate(currentDate.getDate() + agendaDuration - 1) - 6e4;
  374. return new Date(result)
  375. },
  376. getCoordinatesByDate: function() {
  377. return {
  378. top: 0,
  379. left: 0,
  380. max: 0,
  381. groupIndex: 0
  382. }
  383. },
  384. getCellDataByCoordinates: function() {
  385. return {
  386. startDate: null,
  387. endDate: null
  388. }
  389. }
  390. });
  391. registerComponent("dxSchedulerAgenda", SchedulerAgenda);
  392. module.exports = SchedulerAgenda;