No Description

main.js 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*!
  2. FullCalendar List View Plugin v4.3.0
  3. Docs & License: https://fullcalendar.io/
  4. (c) 2019 Adam Shaw
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fullcalendar/core')) :
  8. typeof define === 'function' && define.amd ? define(['exports', '@fullcalendar/core'], factory) :
  9. (global = global || self, factory(global.FullCalendarList = {}, global.FullCalendar));
  10. }(this, function (exports, core) { 'use strict';
  11. /*! *****************************************************************************
  12. Copyright (c) Microsoft Corporation. All rights reserved.
  13. Licensed under the Apache License, Version 2.0 (the "License"); you may not use
  14. this file except in compliance with the License. You may obtain a copy of the
  15. License at http://www.apache.org/licenses/LICENSE-2.0
  16. THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17. KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  18. WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  19. MERCHANTABLITY OR NON-INFRINGEMENT.
  20. See the Apache Version 2.0 License for specific language governing permissions
  21. and limitations under the License.
  22. ***************************************************************************** */
  23. /* global Reflect, Promise */
  24. var extendStatics = function(d, b) {
  25. extendStatics = Object.setPrototypeOf ||
  26. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  27. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  28. return extendStatics(d, b);
  29. };
  30. function __extends(d, b) {
  31. extendStatics(d, b);
  32. function __() { this.constructor = d; }
  33. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  34. }
  35. var ListEventRenderer = /** @class */ (function (_super) {
  36. __extends(ListEventRenderer, _super);
  37. function ListEventRenderer(listView) {
  38. var _this = _super.call(this, listView.context) || this;
  39. _this.listView = listView;
  40. return _this;
  41. }
  42. ListEventRenderer.prototype.attachSegs = function (segs) {
  43. if (!segs.length) {
  44. this.listView.renderEmptyMessage();
  45. }
  46. else {
  47. this.listView.renderSegList(segs);
  48. }
  49. };
  50. ListEventRenderer.prototype.detachSegs = function () {
  51. };
  52. // generates the HTML for a single event row
  53. ListEventRenderer.prototype.renderSegHtml = function (seg) {
  54. var _a = this.context, view = _a.view, theme = _a.theme;
  55. var eventRange = seg.eventRange;
  56. var eventDef = eventRange.def;
  57. var eventInstance = eventRange.instance;
  58. var eventUi = eventRange.ui;
  59. var url = eventDef.url;
  60. var classes = ['fc-list-item'].concat(eventUi.classNames);
  61. var bgColor = eventUi.backgroundColor;
  62. var timeHtml;
  63. if (eventDef.allDay) {
  64. timeHtml = core.getAllDayHtml(view);
  65. }
  66. else if (core.isMultiDayRange(eventRange.range)) {
  67. if (seg.isStart) {
  68. timeHtml = core.htmlEscape(this._getTimeText(eventInstance.range.start, seg.end, false // allDay
  69. ));
  70. }
  71. else if (seg.isEnd) {
  72. timeHtml = core.htmlEscape(this._getTimeText(seg.start, eventInstance.range.end, false // allDay
  73. ));
  74. }
  75. else { // inner segment that lasts the whole day
  76. timeHtml = core.getAllDayHtml(view);
  77. }
  78. }
  79. else {
  80. // Display the normal time text for the *event's* times
  81. timeHtml = core.htmlEscape(this.getTimeText(eventRange));
  82. }
  83. if (url) {
  84. classes.push('fc-has-url');
  85. }
  86. return '<tr class="' + classes.join(' ') + '">' +
  87. (this.displayEventTime ?
  88. '<td class="fc-list-item-time ' + theme.getClass('widgetContent') + '">' +
  89. (timeHtml || '') +
  90. '</td>' :
  91. '') +
  92. '<td class="fc-list-item-marker ' + theme.getClass('widgetContent') + '">' +
  93. '<span class="fc-event-dot"' +
  94. (bgColor ?
  95. ' style="background-color:' + bgColor + '"' :
  96. '') +
  97. '></span>' +
  98. '</td>' +
  99. '<td class="fc-list-item-title ' + theme.getClass('widgetContent') + '">' +
  100. '<a' + (url ? ' href="' + core.htmlEscape(url) + '"' : '') + '>' +
  101. core.htmlEscape(eventDef.title || '') +
  102. '</a>' +
  103. '</td>' +
  104. '</tr>';
  105. };
  106. // like "4:00am"
  107. ListEventRenderer.prototype.computeEventTimeFormat = function () {
  108. return {
  109. hour: 'numeric',
  110. minute: '2-digit',
  111. meridiem: 'short'
  112. };
  113. };
  114. return ListEventRenderer;
  115. }(core.FgEventRenderer));
  116. /*
  117. Responsible for the scroller, and forwarding event-related actions into the "grid".
  118. */
  119. var ListView = /** @class */ (function (_super) {
  120. __extends(ListView, _super);
  121. function ListView(context, viewSpec, dateProfileGenerator, parentEl) {
  122. var _this = _super.call(this, context, viewSpec, dateProfileGenerator, parentEl) || this;
  123. _this.computeDateVars = core.memoize(computeDateVars);
  124. _this.eventStoreToSegs = core.memoize(_this._eventStoreToSegs);
  125. var eventRenderer = _this.eventRenderer = new ListEventRenderer(_this);
  126. _this.renderContent = core.memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer));
  127. _this.el.classList.add('fc-list-view');
  128. var listViewClassNames = (_this.theme.getClass('listView') || '').split(' '); // wish we didn't have to do this
  129. for (var _i = 0, listViewClassNames_1 = listViewClassNames; _i < listViewClassNames_1.length; _i++) {
  130. var listViewClassName = listViewClassNames_1[_i];
  131. if (listViewClassName) { // in case input was empty string
  132. _this.el.classList.add(listViewClassName);
  133. }
  134. }
  135. _this.scroller = new core.ScrollComponent('hidden', // overflow x
  136. 'auto' // overflow y
  137. );
  138. _this.el.appendChild(_this.scroller.el);
  139. _this.contentEl = _this.scroller.el; // shortcut
  140. context.calendar.registerInteractiveComponent(_this, {
  141. el: _this.el
  142. // TODO: make aware that it doesn't do Hits
  143. });
  144. return _this;
  145. }
  146. ListView.prototype.render = function (props) {
  147. var _a = this.computeDateVars(props.dateProfile), dayDates = _a.dayDates, dayRanges = _a.dayRanges;
  148. this.dayDates = dayDates;
  149. this.renderContent(this.eventStoreToSegs(props.eventStore, props.eventUiBases, dayRanges));
  150. };
  151. ListView.prototype.destroy = function () {
  152. _super.prototype.destroy.call(this);
  153. this.renderContent.unrender();
  154. this.scroller.destroy(); // will remove the Grid too
  155. this.calendar.unregisterInteractiveComponent(this);
  156. };
  157. ListView.prototype.updateSize = function (isResize, viewHeight, isAuto) {
  158. _super.prototype.updateSize.call(this, isResize, viewHeight, isAuto);
  159. this.eventRenderer.computeSizes(isResize);
  160. this.eventRenderer.assignSizes(isResize);
  161. this.scroller.clear(); // sets height to 'auto' and clears overflow
  162. if (!isAuto) {
  163. this.scroller.setHeight(this.computeScrollerHeight(viewHeight));
  164. }
  165. };
  166. ListView.prototype.computeScrollerHeight = function (viewHeight) {
  167. return viewHeight -
  168. core.subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller
  169. };
  170. ListView.prototype._eventStoreToSegs = function (eventStore, eventUiBases, dayRanges) {
  171. return this.eventRangesToSegs(core.sliceEventStore(eventStore, eventUiBases, this.props.dateProfile.activeRange, this.nextDayThreshold).fg, dayRanges);
  172. };
  173. ListView.prototype.eventRangesToSegs = function (eventRanges, dayRanges) {
  174. var segs = [];
  175. for (var _i = 0, eventRanges_1 = eventRanges; _i < eventRanges_1.length; _i++) {
  176. var eventRange = eventRanges_1[_i];
  177. segs.push.apply(segs, this.eventRangeToSegs(eventRange, dayRanges));
  178. }
  179. return segs;
  180. };
  181. ListView.prototype.eventRangeToSegs = function (eventRange, dayRanges) {
  182. var _a = this, dateEnv = _a.dateEnv, nextDayThreshold = _a.nextDayThreshold;
  183. var range = eventRange.range;
  184. var allDay = eventRange.def.allDay;
  185. var dayIndex;
  186. var segRange;
  187. var seg;
  188. var segs = [];
  189. for (dayIndex = 0; dayIndex < dayRanges.length; dayIndex++) {
  190. segRange = core.intersectRanges(range, dayRanges[dayIndex]);
  191. if (segRange) {
  192. seg = {
  193. component: this,
  194. eventRange: eventRange,
  195. start: segRange.start,
  196. end: segRange.end,
  197. isStart: eventRange.isStart && segRange.start.valueOf() === range.start.valueOf(),
  198. isEnd: eventRange.isEnd && segRange.end.valueOf() === range.end.valueOf(),
  199. dayIndex: dayIndex
  200. };
  201. segs.push(seg);
  202. // detect when range won't go fully into the next day,
  203. // and mutate the latest seg to the be the end.
  204. if (!seg.isEnd && !allDay &&
  205. dayIndex + 1 < dayRanges.length &&
  206. range.end <
  207. dateEnv.add(dayRanges[dayIndex + 1].start, nextDayThreshold)) {
  208. seg.end = range.end;
  209. seg.isEnd = true;
  210. break;
  211. }
  212. }
  213. }
  214. return segs;
  215. };
  216. ListView.prototype.renderEmptyMessage = function () {
  217. this.contentEl.innerHTML =
  218. '<div class="fc-list-empty-wrap2">' + // TODO: try less wraps
  219. '<div class="fc-list-empty-wrap1">' +
  220. '<div class="fc-list-empty">' +
  221. core.htmlEscape(this.opt('noEventsMessage')) +
  222. '</div>' +
  223. '</div>' +
  224. '</div>';
  225. };
  226. // called by ListEventRenderer
  227. ListView.prototype.renderSegList = function (allSegs) {
  228. var segsByDay = this.groupSegsByDay(allSegs); // sparse array
  229. var dayIndex;
  230. var daySegs;
  231. var i;
  232. var tableEl = core.htmlToElement('<table class="fc-list-table ' + this.calendar.theme.getClass('tableList') + '"><tbody></tbody></table>');
  233. var tbodyEl = tableEl.querySelector('tbody');
  234. for (dayIndex = 0; dayIndex < segsByDay.length; dayIndex++) {
  235. daySegs = segsByDay[dayIndex];
  236. if (daySegs) { // sparse array, so might be undefined
  237. // append a day header
  238. tbodyEl.appendChild(this.buildDayHeaderRow(this.dayDates[dayIndex]));
  239. daySegs = this.eventRenderer.sortEventSegs(daySegs);
  240. for (i = 0; i < daySegs.length; i++) {
  241. tbodyEl.appendChild(daySegs[i].el); // append event row
  242. }
  243. }
  244. }
  245. this.contentEl.innerHTML = '';
  246. this.contentEl.appendChild(tableEl);
  247. };
  248. // Returns a sparse array of arrays, segs grouped by their dayIndex
  249. ListView.prototype.groupSegsByDay = function (segs) {
  250. var segsByDay = []; // sparse array
  251. var i;
  252. var seg;
  253. for (i = 0; i < segs.length; i++) {
  254. seg = segs[i];
  255. (segsByDay[seg.dayIndex] || (segsByDay[seg.dayIndex] = []))
  256. .push(seg);
  257. }
  258. return segsByDay;
  259. };
  260. // generates the HTML for the day headers that live amongst the event rows
  261. ListView.prototype.buildDayHeaderRow = function (dayDate) {
  262. var dateEnv = this.dateEnv;
  263. var mainFormat = core.createFormatter(this.opt('listDayFormat')); // TODO: cache
  264. var altFormat = core.createFormatter(this.opt('listDayAltFormat')); // TODO: cache
  265. return core.createElement('tr', {
  266. className: 'fc-list-heading',
  267. 'data-date': dateEnv.formatIso(dayDate, { omitTime: true })
  268. }, '<td class="' + (this.calendar.theme.getClass('tableListHeading') ||
  269. this.calendar.theme.getClass('widgetHeader')) + '" colspan="3">' +
  270. (mainFormat ?
  271. core.buildGotoAnchorHtml(this, dayDate, { 'class': 'fc-list-heading-main' }, core.htmlEscape(dateEnv.format(dayDate, mainFormat)) // inner HTML
  272. ) :
  273. '') +
  274. (altFormat ?
  275. core.buildGotoAnchorHtml(this, dayDate, { 'class': 'fc-list-heading-alt' }, core.htmlEscape(dateEnv.format(dayDate, altFormat)) // inner HTML
  276. ) :
  277. '') +
  278. '</td>');
  279. };
  280. return ListView;
  281. }(core.View));
  282. ListView.prototype.fgSegSelector = '.fc-list-item'; // which elements accept event actions
  283. function computeDateVars(dateProfile) {
  284. var dayStart = core.startOfDay(dateProfile.renderRange.start);
  285. var viewEnd = dateProfile.renderRange.end;
  286. var dayDates = [];
  287. var dayRanges = [];
  288. while (dayStart < viewEnd) {
  289. dayDates.push(dayStart);
  290. dayRanges.push({
  291. start: dayStart,
  292. end: core.addDays(dayStart, 1)
  293. });
  294. dayStart = core.addDays(dayStart, 1);
  295. }
  296. return { dayDates: dayDates, dayRanges: dayRanges };
  297. }
  298. var main = core.createPlugin({
  299. views: {
  300. list: {
  301. class: ListView,
  302. buttonTextKey: 'list',
  303. listDayFormat: { month: 'long', day: 'numeric', year: 'numeric' } // like "January 1, 2016"
  304. },
  305. listDay: {
  306. type: 'list',
  307. duration: { days: 1 },
  308. listDayFormat: { weekday: 'long' } // day-of-week is all we need. full date is probably in header
  309. },
  310. listWeek: {
  311. type: 'list',
  312. duration: { weeks: 1 },
  313. listDayFormat: { weekday: 'long' },
  314. listDayAltFormat: { month: 'long', day: 'numeric', year: 'numeric' }
  315. },
  316. listMonth: {
  317. type: 'list',
  318. duration: { month: 1 },
  319. listDayAltFormat: { weekday: 'long' } // day-of-week is nice-to-have
  320. },
  321. listYear: {
  322. type: 'list',
  323. duration: { year: 1 },
  324. listDayAltFormat: { weekday: 'long' } // day-of-week is nice-to-have
  325. }
  326. }
  327. });
  328. exports.ListView = ListView;
  329. exports.default = main;
  330. Object.defineProperty(exports, '__esModule', { value: true });
  331. }));