Просмотр исходного кода

fixes, make dnd tests works, and other tests

Adam Shaw 7 лет назад
Родитель
Сommit
c25eed2b90

+ 2 - 4
src/agenda/TimeGrid.ts

@@ -12,7 +12,7 @@ import TimeGridHelperRenderer from './TimeGridHelperRenderer'
 import TimeGridFillRenderer from './TimeGridFillRenderer'
 import { Duration, createDuration, addDurations, wholeDivideDurations, asRoughMs } from '../datelib/duration'
 import { startOfDay, DateMarker, addMs } from '../datelib/marker'
-import { createFormatter, DateFormatter } from '../datelib/formatting'
+import { DateFormatter, createFormatter, formatIsoTimeString } from '../datelib/formatting'
 
 /* A component that renders one or more columns of vertical time slots
 ----------------------------------------------------------------------------------------------------------------------*/
@@ -28,8 +28,6 @@ const AGENDA_STOCK_SUB_DURATIONS = [
   { seconds: 15 }
 ]
 
-const HMS_FORMAT = createFormatter({ hour: '2-digit', minute: '2-digit', second: '2-digit' })
-
 export default class TimeGrid extends InteractiveDateComponent {
 
   dayDates: DayTableInterface['dayDates']
@@ -275,7 +273,7 @@ export default class TimeGrid extends InteractiveDateComponent {
         '</td>'
 
       html +=
-        '<tr data-time="' + dateEnv.format(slotDate, HMS_FORMAT) + '"' +
+        '<tr data-time="' + formatIsoTimeString(slotDate) + '"' +
           (isLabeled ? '' : ' class="fc-minor"') +
           '>' +
           (!isRTL ? axisHtml : '') +

+ 17 - 5
src/datelib/formatting.ts

@@ -66,17 +66,29 @@ export function buildIsoString(marker: DateMarker, timeZoneOffset?: number, stri
   let s = marker.toISOString()
 
   s = s.replace('.000', '')
-  s = s.replace('Z', '')
 
-  if (timeZoneOffset != null) { // provided?
-    s += timeZoneOffset ? formatTimeZoneOffset(timeZoneOffset, true) : 'Z'
-  } else if (stripZeroTime) {
-    s = s.replace('T00:00:00', '')
+  if (stripZeroTime) {
+    s = s.replace('T00:00:00Z', '')
+  }
+
+  if (s.length > 10) { // time part wasn't stripped, can add timezone info
+    if (timeZoneOffset == null) {
+      s = s.replace('Z', '')
+    } else if (timeZoneOffset !== 0) {
+      s = s.replace('Z', formatTimeZoneOffset(timeZoneOffset, true))
+    }
+    // otherwise, its UTC-0 and we want to keep the Z
   }
 
   return s
 }
 
+export function formatIsoTimeString(marker: DateMarker) {
+  return padStart(marker.getUTCHours(), 2) + ':' +
+    padStart(marker.getUTCMinutes(), 2) + ':' +
+    padStart(marker.getUTCSeconds(), 2)
+}
+
 export function formatTimeZoneOffset(minutes: number, doIso = false) {
   let sign = minutes < 0 ? '+' : '-' // whaaa
   let abs = Math.abs(minutes)

+ 2 - 1
src/exports.ts

@@ -123,10 +123,11 @@ export { DateProfile } from './DateProfileGenerator'
 export { DateMarker, addDays, startOfDay, addMs, diffWholeWeeks, diffWholeDays, diffDayAndTime } from './datelib/marker'
 export {
   Duration, createDuration,
-  isSingleDay, multiplyDuration,
+  isSingleDay, multiplyDuration, addDurations,
   asRoughMinutes, asRoughSeconds, asRoughMs,
   wholeDivideDurations, greatestDurationDenominator
 } from './datelib/duration'
 export { DateEnv } from './datelib/env'
 export { defineLocale, getLocale, getLocaleCodes } from './datelib/locale'
 export { DateFormatter, createFormatter } from './datelib/formatting'
+export { parse as parseMarker } from './datelib/parsing'

+ 2 - 1
src/models/event/EventDateProfile.ts

@@ -50,7 +50,8 @@ export default class EventDateProfile {
     }
 
     if (endMarker && endMarker <= startMarker) {
-      return false
+      endMarker = null
+      // TODO: warning?
     }
 
     if (forcedAllDay == null) {

+ 1 - 1
src/util/misc.ts

@@ -297,7 +297,7 @@ export function capitaliseFirstLetter(str) {
 
 export function padStart(val, len) { // doesn't work with total length more than 3
   let s = String(val)
-  return '000'.substr(0, val.length - len) + s
+  return '000'.substr(0, len - s.length) + s
 }
 
 

+ 5 - 31
tests/automated/datelib/main.js

@@ -1,5 +1,6 @@
+import { formatPrettyTimeZoneOffset, formatIsoTimeZoneOffset } from './utils'
 
-fdescribe('datelib', function() {
+describe('datelib', function() {
   var DateEnv = FullCalendar.DateEnv
   var createFormatter = FullCalendar.createFormatter
   var createDuration = FullCalendar.createDuration
@@ -523,7 +524,7 @@ fdescribe('datelib', function() {
     it('outputs ISO8601 formatting', function() {
       var marker = env.createMarker('2018-06-08T00:00:00')
       var s = env.formatIso(marker)
-      var realTzo = getFormattedTimzoneOffset(new Date(2018, 5, 8))
+      var realTzo = formatIsoTimeZoneOffset(new Date(2018, 5, 8))
       expect(s).toBe('2018-06-08T00:00:00' + realTzo)
     })
 
@@ -537,14 +538,14 @@ fdescribe('datelib', function() {
         timeZoneName: 'short'
       })
       var s = env.format(marker, formatter)
-      expect(s).toBe('Friday, June 8, 2018, ' + getFormattedTimzoneOffset2(new Date(2018, 5, 8)))
+      expect(s).toBe('Friday, June 8, 2018, ' + formatPrettyTimeZoneOffset(new Date(2018, 5, 8)))
     })
 
     it('can output a timezone only', function() {
       var marker = env.createMarker('2018-06-08')
       var formatter = createFormatter({ timeZoneName: 'short' })
       var s = env.format(marker, formatter)
-      expect(s).toBe(getFormattedTimzoneOffset2(new Date(2018, 5, 8)))
+      expect(s).toBe(formatPrettyTimeZoneOffset(new Date(2018, 5, 8)))
     })
 
 
@@ -656,31 +657,4 @@ fdescribe('datelib', function() {
 
   })
 
-
-  // utils
-
-  function getFormattedTimzoneOffset(date) {
-    let minutes = date.getTimezoneOffset()
-    let sign = minutes < 0 ? '+' : '-' // whaaa
-    let abs = Math.abs(minutes)
-    let hours = Math.floor(abs / 60)
-    let mins = Math.round(abs % 60)
-
-    return sign + pad(hours) + ':' + pad(mins)
-  }
-
-  function getFormattedTimzoneOffset2(date) {
-    let minutes = date.getTimezoneOffset()
-    let sign = minutes < 0 ? '+' : '-' // whaaa
-    let abs = Math.abs(minutes)
-    let hours = Math.floor(abs / 60)
-    let mins = Math.round(abs % 60)
-
-    return 'GMT' + sign + hours + (mins ? ':' + pad(mins) : '')
-  }
-
-  function pad(n) {
-    return n < 10 ? '0' + n : '' + n
-  }
-
 })

+ 10 - 4
tests/automated/event-drag/TimeGridEventDragUtils.js

@@ -4,16 +4,22 @@ import { computeSpanRects } from '../event-render/TimeGridEventRenderUtils'
 
 export function drag(startDate, endDate, debug) {
 
-  startDate = FullCalendar.moment.parseZone(startDate)
-  endDate = FullCalendar.moment.parseZone(endDate)
+  if (typeof startDate === 'string') {
+    startDate = FullCalendar.parseMarker(startDate).marker
+  }
+
+  if (typeof endDate === 'string') {
+    endDate = FullCalendar.parseMarker(endDate).marker
+  }
 
   var startRect = computeSpanRects(
     startDate,
-    startDate.clone().add({ minutes: 30 }) // hardcoded 30 minute slot :(
+    FullCalendar.addMs(startDate, 1000 * 60 * 30) // hardcoded 30 minute slot :(
   )[0]
+
   var endRect = computeSpanRects(
     endDate,
-    endDate.clone().add({ minutes: 30 }) // hardcoded 30 minute slot :(
+    FullCalendar.addMs(endDate, 1000 * 60 * 30) // hardcoded 30 minute slot :(
   )[0]
 
   return EventDragUtils.drag(

+ 35 - 18
tests/automated/event-render/TimeGridEventRenderUtils.js

@@ -12,8 +12,8 @@ TODO: check isStart/isEnd.
 */
 export function checkEventRendering(start, end) {
 
-  start = FullCalendar.moment.parseZone(start)
-  end = FullCalendar.moment.parseZone(end)
+  start = FullCalendar.parseMarker(start).marker
+  end = FullCalendar.parseMarker(end).marker
 
   var expectedRects = computeSpanRects(start, end)
   var eventEls = $('.fc-event') // sorted by DOM order. not good for RTL
@@ -63,6 +63,7 @@ export function computeSpanRects(start, end) {
   var slotStructs = computeSlots()
   var dayI, dayStruct
   var slotI, slotStruct
+  var slotDayStart
   var slotStart
   var slotEnd
   var coverage
@@ -76,13 +77,20 @@ export function computeSpanRects(start, end) {
     for (slotI = 0; slotI < slotStructs.length; slotI++) {
       slotStruct = slotStructs[slotI]
 
-      slotStart = dayStruct.date.clone().time(0)
-        .add(slotStruct.dayOffset, 'days')
-        .add(slotStruct.startTime)
+      slotDayStart = FullCalendar.addDays(
+        dayStruct.date,
+        slotStruct.dayOffset
+      )
+
+      slotStart = FullCalendar.addMs(
+        slotDayStart,
+        slotStruct.startTime.time
+      )
 
-      slotEnd = dayStruct.date.clone().time(0)
-        .add(slotStruct.dayOffset, 'days')
-        .add(slotStruct.endTime)
+      slotEnd = FullCalendar.addMs(
+        slotDayStart,
+        slotStruct.endTime.time
+      )
 
       if (startTop === null) { // looking for the start
         coverage = (start - slotStart) / (slotEnd - slotStart)
@@ -132,9 +140,9 @@ function computeDays() {
   var days = dayEls.map(function(i, node) {
     var rect = node.getBoundingClientRect()
     return $.extend({}, rect, {
-      date: FullCalendar.moment.parseZone(
+      date: FullCalendar.parseMarker(
         $(node).data('date')
-      )
+      ).marker
     })
   }).get()
 
@@ -148,7 +156,7 @@ function computeSlots() {
   var slots = slotEls.map(function(i, node) {
     var rect = node.getBoundingClientRect()
     return $.extend({}, rect, {
-      startTime: moment.duration(
+      startTime: FullCalendar.createDuration(
         $(node).data('time')
       )
     })
@@ -173,9 +181,12 @@ function computeSlots() {
     // big deviation? assume moved to previous day (b/c of special minTime)
     if (Math.abs(ms - standardMs) > standardMs * 2) {
       dayOffset--
-      slots[i].endTime = moment.duration(slots[i].startTime).add(standardMs)
+      slots[i].endTime = FullCalendar.addDurations(
+        slots[i].startTime,
+        FullCalendar.createDuration(standardMs)
+      )
     } else { // otherwise, current slot's end is next slot's beginning
-      slots[i].endTime = moment.duration(slots[i + 1].startTime)
+      slots[i].endTime = slots[i + 1].startTime
     }
 
     slots[i].dayOffset = dayOffset
@@ -192,19 +203,25 @@ function computeSlots() {
     // big deviation? assume moved to next day (b/c of special maxTime)
     if (Math.abs(ms - standardMs) > standardMs * 2) {
       dayOffset++ // will apply to the next slotStruct
-      slots[i].endTime = moment.duration(slots[i].startTime).add(standardMs)
+      slots[i].endTime = FullCalendar.addDurations(
+        slots[i].startTime,
+        FullCalendar.createDuration(standardMs)
+      )
     } else { // otherwise, current slot's end is next slot's beginning
-      slots[i].endTime = moment.duration(slots[i + 1].startTime)
+      slots[i].endTime = slots[i + 1].startTime
     }
   }
 
   // assume last slot has the standard duration
-  slots[i].endTime = moment.duration(slots[i].startTime).add(standardMs)
+  slots[i].endTime = FullCalendar.addDurations(
+    slots[i].startTime,
+    FullCalendar.createDuration(standardMs)
+  )
   slots[i].dayOffset = dayOffset
 
   // if last slot went over the day threshold
-  if (slots[i].endTime.as('days') > 1) {
-    slots[i].endTime.subtract(1, 'day')
+  if (slots[i].endTime.time > 1000 * 60 * 60 * 24) {
+    slots[i].endTime.time -= 1000 * 60 * 60 * 24
     slots[i].dayOffset++
   }
 

+ 14 - 5
tests/automated/event-render/timeText.js

@@ -1,3 +1,4 @@
+import { formatIsoTimeZoneOffset } from '../datelib/utils'
 import { getTimeTexts } from './TimeGridEventRenderUtils'
 
 describe('the time text on events', function() {
@@ -10,9 +11,11 @@ describe('the time text on events', function() {
     })
 
     it('renders segs with correct local timezone', function() {
+      var FORMAT = { hour: 'numeric', minute: '2-digit', timeZoneName: 'short' }
+
       initCalendar({
         timezone: 'local',
-        timeFormat: 'h:mm Z',
+        timeFormat: FORMAT,
         events: [
           { start: '2017-07-03T23:00:00', end: '2017-07-04T13:00:00' }
         ]
@@ -21,10 +24,16 @@ describe('the time text on events', function() {
       expect(
         getTimeTexts()
       ).toEqual([
-        moment('2017-07-03T23:00:00').format('h:mm Z') + ' - ' +
-        moment('2017-07-04T00:00:00').format('h:mm Z'),
-        moment('2017-07-04T00:00:00').format('h:mm Z') + ' - ' +
-        moment('2017-07-04T13:00:00').format('h:mm Z')
+        currentCalendar.formatRange(
+          new Date('2017-07-03T23:00:00'),
+          new Date('2017-07-04T00:00:00'),
+          FORMAT
+        ),
+        currentCalendar.formatRange(
+          new Date('2017-07-04T00:00:00'),
+          new Date('2017-07-04T13:00:00'),
+          FORMAT
+        )
       ])
     })
   })

+ 2 - 2
tests/automated/legacy/constraint.js

@@ -37,8 +37,8 @@ describe('event constraint', function() {
             } ]
             testEventDrag(options, '2014-11-14', true, function() {
               var event = currentCalendar.clientEvents()[0]
-              expect(event.start).toEqualMoment('2014-11-14T05:00:00')
-              expect(event.end).toEqualMoment('2014-11-14T07:00:00')
+              expect(event.start).toEqualDate('2014-11-14T05:00:00Z')
+              expect(event.end).toEqualDate('2014-11-14T07:00:00Z')
               done()
             })
           })

+ 34 - 14
tests/automated/lib/dnd-resize-utils.js

@@ -1,3 +1,5 @@
+import { formatIsoDay } from '../datelib/utils'
+
 
 // this function has been mangled to work with external jqui draggables as well
 export function testEventDrag(options, dropDate, expectSuccess, callback, eventClassName) {
@@ -18,20 +20,29 @@ export function testEventDrag(options, dropDate, expectSuccess, callback, eventC
     if (eventsRendered) { return }
     eventsRendered = true
 
-    dropDate = calendar.moment(dropDate)
+    var dropDateMeta
+    var dropDateHasTime
+    if (typeof dropDate === 'string') {
+      dropDateMeta = FullCalendar.parseMarker(dropDate)
+      dropDateHasTime = !dropDateMeta.isTimeUnspecified
+      dropDate = dropDateMeta.marker
+    } else {
+      dropDateHasTime = true
+    }
+
     eventEl = $('.' + (eventClassName || 'fc-event') + ':first')
     expect(eventEl.length).toBe(1)
 
-    if (dropDate.hasTime()) {
+    if (dropDateHasTime) {
       dragEl = eventEl.find('.fc-time')
-      dayEl = $('.fc-time-grid .fc-day[data-date="' + dropDate.format('YYYY-MM-DD') + '"]')
-      slatIndex = dropDate.hours() * 2 + (dropDate.minutes() / 30) // assumes slotDuration:'30:00'
+      dayEl = $('.fc-time-grid .fc-day[data-date="' + formatIsoDay(dropDate) + '"]')
+      slatIndex = dropDate.getUTCHours() * 2 + (dropDate.getUTCMinutes() / 30) // assumes slotDuration:'30:00'
       slatEl = $('.fc-slats tr:eq(' + slatIndex + ')')
       expect(slatEl.length).toBe(1)
       dy = slatEl.offset().top - eventEl.offset().top
     } else {
       dragEl = eventEl.find('.fc-title')
-      dayEl = $('.fc-day-grid .fc-day[data-date="' + dropDate.format('YYYY-MM-DD') + '"]')
+      dayEl = $('.fc-day-grid .fc-day[data-date="' + formatIsoDay(dropDate) + '"]')
       dy = dayEl.offset().top - eventEl.offset().top
     }
 
@@ -65,11 +76,11 @@ export function testEventDrag(options, dropDate, expectSuccess, callback, eventC
             eventObj = calendar.clientEvents()[0]
           }
 
-          if (dropDate.hasTime()) { // dropped on a slot
-            successfulDrop = eventObj.start.format() === dropDate.format() // compare exact times
+          if (dropDateHasTime) { // dropped on a slot
+            successfulDrop = eventObj.start.valueOf() === dropDate.valueOf() // compare exact times
           } else { // dropped on a whole day
             // only compare days
-            successfulDrop = eventObj.start.format('YYYY-MM-DD') === dropDate.format('YYYY-MM-DD')
+            successfulDrop = formatIsoDay(eventObj.start) === formatIsoDay(dropDate)
           }
 
           expect(successfulDrop).toBe(allowed)
@@ -101,18 +112,27 @@ export function testEventResize(options, resizeDate, expectSuccess, callback, ev
     if (eventsRendered) { return }
     eventsRendered = true
 
-    resizeDate = calendar.moment(resizeDate)
+    var resizeDateMeta
+    var resizeDateHasTime
+    if (typeof resizeDate === 'string') {
+      resizeDateMeta = FullCalendar.parseMarker(resizeDate)
+      resizeDateHasTime = !resizeDateMeta.isTimeUnspecified
+      resizeDate = resizeDateMeta.marker
+    } else {
+      resizeDateHasTime = true
+    }
+
     eventEl = $('.' + (eventClassName || 'fc-event') + ':last')
     dragEl = eventEl.find('.fc-resizer')
 
-    if (resizeDate.hasTime()) {
-      lastDayEl = $('.fc-time-grid .fc-day[data-date="' + resizeDate.clone().format('YYYY-MM-DD') + '"]')
-      lastSlatIndex = resizeDate.hours() * 2 + (resizeDate.minutes() / 30) // assumes slotDuration:'30:00'
+    if (resizeDateHasTime) {
+      lastDayEl = $('.fc-time-grid .fc-day[data-date="' + formatIsoDay(resizeDate) + '"]')
+      lastSlatIndex = resizeDate.getUTCHours() * 2 + (resizeDate.getUTCMinutes() / 30) // assumes slotDuration:'30:00'
       lastSlatEl = $('.fc-slats tr:eq(' + (lastSlatIndex - 1) + ')')
       expect(lastSlatEl.length).toBe(1)
       dy = lastSlatEl.offset().top + lastSlatEl.outerHeight() - (eventEl.offset().top + eventEl.outerHeight())
     } else {
-      lastDayEl = $('.fc-day-grid .fc-day[data-date="' + resizeDate.clone().add(-1, 'day').format('YYYY-MM-DD') + '"]')
+      lastDayEl = $('.fc-day-grid .fc-day[data-date="' + formatIsoDay(FullCalendar.addDays(resizeDate, -1)) + '"]')
       dy = lastDayEl.offset().top - eventEl.offset().top
     }
 
@@ -140,7 +160,7 @@ export function testEventResize(options, resizeDate, expectSuccess, callback, ev
           eventObj = calendar.clientEvents()[0]
         }
 
-        successfulDrop = eventObj.end && eventObj.end.format() === resizeDate.format()
+        successfulDrop = eventObj.end && eventObj.end.valueOf() === resizeDate.valueOf()
 
         expect(allowed).toBe(successfulDrop)
         expect(allowed).toBe(expectSuccess)