TimeGridEventRenderUtils.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. var TimeGridEventRenderUtils = {
  2. /*
  3. Returns a boolean.
  4. TODO: check isStart/isEnd.
  5. */
  6. checkEventRendering: function(start, end) {
  7. start = $.fullCalendar.moment.parseZone(start);
  8. end = $.fullCalendar.moment.parseZone(end);
  9. var expectedRects = this.computeSpanRects(start, end);
  10. var eventEls = $('.fc-event'); // sorted by DOM order. not good for RTL
  11. var isMatch = this.checkEventRenderingMatch(expectedRects, eventEls);
  12. return {
  13. rects: expectedRects,
  14. els: eventEls,
  15. length: eventEls.length,
  16. isMatch: isMatch
  17. };
  18. },
  19. checkEventRenderingMatch: function(expectedRects, eventEls) {
  20. var expectedLength = expectedRects.length;
  21. var i, expectedRect;
  22. var elRect;
  23. if (eventEls.length != expectedLength) {
  24. console.log('does not match element count');
  25. return false;
  26. }
  27. for (i = 0; i < expectedLength; i++) {
  28. expectedRect = expectedRects[i];
  29. elRect = eventEls[i].getBoundingClientRect();
  30. // horizontally contained AND vertically really similar?
  31. if (!(
  32. elRect.left >= expectedRect.left &&
  33. elRect.right <= expectedRect.right &&
  34. Math.abs(elRect.top - expectedRect.top) < 1 &&
  35. Math.abs(elRect.bottom - expectedRect.bottom) < 1
  36. )) {
  37. console.log('rects do not match');
  38. return false;
  39. }
  40. }
  41. return true;
  42. },
  43. computeSpanRects: function(start, end) {
  44. var dayStructs = this.computeDays();
  45. var slotStructs = this.computeSlots();
  46. var dayI, dayStruct;
  47. var slotI, slotStruct;
  48. var coverage;
  49. var startTop = null;
  50. var endTop = null;
  51. var rects = [];
  52. for (dayI = 0; dayI < dayStructs.length; dayI++) {
  53. dayStruct = dayStructs[dayI];
  54. for (slotI = 0; slotI < slotStructs.length; slotI++) {
  55. slotStruct = slotStructs[slotI];
  56. slotStart = dayStruct.date.clone().time(0)
  57. .add(slotStruct.dayOffset, 'days')
  58. .add(slotStruct.startTime);
  59. slotEnd = dayStruct.date.clone().time(0)
  60. .add(slotStruct.dayOffset, 'days')
  61. .add(slotStruct.endTime);
  62. if (startTop === null) { // looking for the start
  63. coverage = (start - slotStart) / (slotEnd - slotStart);
  64. startTop = (coverage > 0 && coverage <= 1) ?
  65. (slotStruct.top + slotStruct.height * coverage) :
  66. null;
  67. }
  68. else { // looking for the end
  69. coverage = (end - slotStart) / (slotEnd - slotStart);
  70. endTop = (coverage >= 0 && coverage < 1) ? // exclusive
  71. (slotStruct.top + slotStruct.height * coverage) :
  72. null;
  73. if (endTop !== null) { // found end
  74. rects.push({
  75. left: dayStruct.left,
  76. right: dayStruct.right,
  77. top: startTop,
  78. bottom: endTop,
  79. width: dayStruct.right - dayStruct.left,
  80. height: endTop - startTop
  81. });
  82. startTop = null;
  83. }
  84. }
  85. }
  86. if (startTop !== null) { // could not find the start in this day
  87. rects.push({
  88. left: dayStruct.left,
  89. right: dayStruct.right,
  90. top: startTop,
  91. bottom: slotStruct.bottom,
  92. width: dayStruct.right - dayStruct.left,
  93. height: slotStruct.bottom - startTop
  94. });
  95. startTop = slotStructs[0].top; // top of next column
  96. }
  97. }
  98. return rects;
  99. },
  100. computeDays: function() {
  101. var dayEls = $('.fc-day-header[data-date]');
  102. var days = dayEls.map(function(i, node) {
  103. var rect = node.getBoundingClientRect();
  104. return $.extend({}, rect, {
  105. date: $.fullCalendar.moment.parseZone(
  106. $(node).data('date')
  107. )
  108. });
  109. }).get();
  110. return days;
  111. },
  112. computeSlots: function() {
  113. var slotEls = $('.fc-time-grid .fc-slats tr[data-time]');
  114. var slots = slotEls.map(function(i, node) {
  115. var rect = node.getBoundingClientRect();
  116. return $.extend({}, rect, {
  117. startTime: moment.duration(
  118. $(node).data('time')
  119. )
  120. });
  121. }).get();
  122. var len = slots.length;
  123. if (len < 3) {
  124. console.log('need at least 3 slots');
  125. return [];
  126. }
  127. var mid = Math.floor(len / 2);
  128. var i = mid - 1;
  129. var standardMs = slots[mid + 1].startTime - slots[mid].startTime;
  130. var ms;
  131. var dayOffset = 0;
  132. // iterate from one-before middle to beginning
  133. for (i = mid - 1; i >= 0; i--) {
  134. ms = slots[i + 1].startTime - slots[i].startTime;
  135. // big deviation? assume moved to previous day (b/c of special minTime)
  136. if (Math.abs(ms - standardMs) > standardMs * 2) {
  137. dayOffset--;
  138. slots[i].endTime = moment.duration(slots[i].startTime).add(standardMs);
  139. }
  140. else { // otherwise, current slot's end is next slot's beginning
  141. slots[i].endTime = moment.duration(slots[i + 1].startTime);
  142. }
  143. slots[i].dayOffset = dayOffset;
  144. }
  145. dayOffset = 0;
  146. // iterate from middle to one-before last
  147. for (i = mid; i < len - 1; i++) {
  148. ms = slots[i + 1].startTime - slots[i].startTime;
  149. slots[i].dayOffset = dayOffset;
  150. // big deviation? assume moved to next day (b/c of special maxTime)
  151. if (Math.abs(ms - standardMs) > standardMs * 2) {
  152. dayOffset++; // will apply to the next slotStruct
  153. slots[i].endTime = moment.duration(slots[i].startTime).add(standardMs);
  154. }
  155. else { // otherwise, current slot's end is next slot's beginning
  156. slots[i].endTime = moment.duration(slots[i + 1].startTime);
  157. }
  158. }
  159. // assume last slot has the standard duration
  160. slots[i].endTime = moment.duration(slots[i].startTime).add(standardMs);
  161. slots[i].dayOffset = dayOffset;
  162. // if last slot went over the day threshold
  163. if (slots[i].endTime.as('days') > 1) {
  164. slots[i].endTime.subtract(1, 'day');
  165. slots[i].dayOffset++;
  166. }
  167. return slots;
  168. }
  169. };