mirror of https://github.com/nextcloud/calendar
Merge pull request #4305 from nextcloud/fix/4290/color-dot
Fix color dot and event alignment
This commit is contained in:
commit
c3f6da5e43
|
@ -233,6 +233,10 @@
|
|||
word-break: break-all;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
:not(.fc-timegrid-event-short) > .fc-event-main .fc-event-title-container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.fc-v-event {
|
||||
|
|
|
@ -20,23 +20,24 @@
|
|||
-
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<div class="fc-event-main-frame">
|
||||
<div class="fc-event-time">
|
||||
{{ eventDetails.timeText }}
|
||||
</div>
|
||||
<div class="fc-event-title-container fc-event-main-frame--icons">
|
||||
<div class="fc-event-title fc-sticky">
|
||||
<span class="fc-event-title">{{ eventDetails.event.title }}</span>
|
||||
</div>
|
||||
<Bell v-if="hasAlarms"
|
||||
class="icon-event-reminder"
|
||||
:size="14"
|
||||
:style="{ color: iconColor }" />
|
||||
<AccountMultiple v-if="hasAttendees"
|
||||
:size="14"
|
||||
:style="{ color: iconColor }" />
|
||||
<div class="fc-event-main-frame">
|
||||
<div v-if="!allDay && viewType === 'dayGridMonth'"
|
||||
class="fc-daygrid-event-dot"
|
||||
:style="{'border-color': borderColor }" />
|
||||
<div class="fc-event-time">
|
||||
{{ eventDetails.timeText }}
|
||||
</div>
|
||||
<div class="fc-event-title-container fc-event-main-frame--icons">
|
||||
<div class="fc-event-title fc-sticky">
|
||||
<span class="fc-event-title">{{ eventDetails.event.title }}</span>
|
||||
</div>
|
||||
<Bell v-if="hasAlarms"
|
||||
class="icon-event-reminder"
|
||||
:size="14"
|
||||
:style="{ color: iconColor }" />
|
||||
<AccountMultiple v-if="hasAttendees"
|
||||
:size="14"
|
||||
:style="{ color: iconColor }" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -73,16 +74,45 @@ export default {
|
|||
isDarkText() {
|
||||
return this.eventDetails?.event?._def?.extendedProps?.darkText
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {string|undefined}
|
||||
*/
|
||||
borderColor() {
|
||||
return this.eventDetails?.event?.borderColor ?? undefined
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
allDay() {
|
||||
return this.eventDetails?.event?.allDay ?? false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fc-event-title.fc-sticky {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.fc-event-main-frame--icons {
|
||||
<style lang="scss" scoped>
|
||||
.fc-event-main-frame {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
|
||||
.fc-daygrid-event-dot {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
&--icons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.fc-event-title-container {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.fc-event-title.fc-sticky {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -150,13 +150,12 @@ export function eventSourceFunction(calendarObjects, calendar, start, end, timez
|
|||
},
|
||||
}
|
||||
|
||||
if (object.color) {
|
||||
const customColor = getHexForColorName(object.color)
|
||||
if (customColor) {
|
||||
fcEvent.backgroundColor = customColor
|
||||
fcEvent.borderColor = customColor
|
||||
fcEvent.textColor = generateTextColorForHex(customColor)
|
||||
}
|
||||
// Color of event object is a name while calendar color already is a hex value
|
||||
const customColor = getHexForColorName(object.color) ?? calendar.color
|
||||
if (customColor) {
|
||||
fcEvent.backgroundColor = customColor
|
||||
fcEvent.borderColor = customColor
|
||||
fcEvent.textColor = generateTextColorForHex(customColor)
|
||||
}
|
||||
|
||||
fcEvents.push(fcEvent)
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2022 Richard Steinmetz <richard@steinmetz.cloud>
|
||||
*
|
||||
* @author Richard Steinmetz <richard@steinmetz.cloud>
|
||||
*
|
||||
* @license AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import { eventSourceFunction } from '../../../../../src/fullcalendar/eventSources/eventSourceFunction.js'
|
||||
import {
|
||||
generateTextColorForHex,
|
||||
getHexForColorName, hexToRGB,
|
||||
isLight,
|
||||
} from '../../../../../src/utils/color.js'
|
||||
import { getAllObjectsInTimeRange } from '../../../../../src/utils/calendarObject.js'
|
||||
|
||||
jest.mock('../../../../../src/utils/color.js')
|
||||
jest.mock('../../../../../src/utils/calendarObject.js')
|
||||
|
||||
describe('fullcalendar/eventSourceFunction test suite', () => {
|
||||
beforeEach(() => {
|
||||
generateTextColorForHex.mockClear()
|
||||
getAllObjectsInTimeRange.mockClear()
|
||||
getHexForColorName.mockClear()
|
||||
hexToRGB.mockClear()
|
||||
isLight.mockClear()
|
||||
})
|
||||
|
||||
it('should prefer the event color', () => {
|
||||
const calendar = {
|
||||
id: 'calendar-id-123',
|
||||
color: '#ff00ff',
|
||||
readOnly: false,
|
||||
}
|
||||
|
||||
const start = new Date()
|
||||
start.setHours(start.getHours() - 24)
|
||||
const end = new Date()
|
||||
end.setHours(end.getHours() + 24)
|
||||
const timezone = { calendarJsTimezone: true, tzid: 'America/New_York' }
|
||||
|
||||
const calendarObjects = [
|
||||
{
|
||||
calendarObject: true,
|
||||
dav: {
|
||||
url: 'url1',
|
||||
},
|
||||
id: '1',
|
||||
},
|
||||
]
|
||||
|
||||
const eventComponents = [
|
||||
{
|
||||
name: 'VEVENT',
|
||||
id: '1-1',
|
||||
status: 'CONFIRMED',
|
||||
isAllDay: jest.fn().mockReturnValue(false),
|
||||
getReferenceRecurrenceId: jest.fn().mockReturnValue({ unixTime: 123 }),
|
||||
canModifyAllDay: jest.fn().mockReturnValue(true),
|
||||
startDate: {
|
||||
getInTimezone: jest.fn().mockReturnValue({
|
||||
jsDate: new Date(start),
|
||||
}),
|
||||
},
|
||||
endDate: {
|
||||
getInTimezone: jest.fn().mockReturnValue({
|
||||
jsDate: new Date(end),
|
||||
}),
|
||||
},
|
||||
hasComponent: jest.fn().mockReturnValue(false),
|
||||
hasProperty: jest.fn().mockReturnValue(false),
|
||||
color: 'red',
|
||||
},
|
||||
]
|
||||
|
||||
getAllObjectsInTimeRange
|
||||
.mockReturnValueOnce(eventComponents)
|
||||
hexToRGB
|
||||
.mockReturnValueOnce({ red: 255, green: 0, blue: 255 })
|
||||
isLight
|
||||
.mockReturnValueOnce(false)
|
||||
getHexForColorName
|
||||
.mockReturnValueOnce('#ff0000')
|
||||
generateTextColorForHex
|
||||
.mockReturnValueOnce('#eeeeee')
|
||||
|
||||
expect(eventSourceFunction(calendarObjects, calendar, new Date(start), new Date(end), timezone)).toEqual([
|
||||
{
|
||||
id: '1###1-1',
|
||||
title: 'Untitled event',
|
||||
allDay: false,
|
||||
start,
|
||||
end,
|
||||
classNames: [],
|
||||
extendedProps: {
|
||||
objectId: '1',
|
||||
recurrenceId: 123,
|
||||
canModifyAllDay: true,
|
||||
calendarId: 'calendar-id-123',
|
||||
davUrl: 'url1',
|
||||
objectType: 'VEVENT',
|
||||
percent: null,
|
||||
hasAlarms: false,
|
||||
hasAttendees: false,
|
||||
darkText: false,
|
||||
},
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
},
|
||||
])
|
||||
|
||||
expect(hexToRGB).toHaveBeenCalledTimes(1)
|
||||
expect(hexToRGB).toHaveBeenNthCalledWith(1, '#ff00ff')
|
||||
expect(isLight).toHaveBeenCalledTimes(1)
|
||||
expect(isLight).toHaveBeenNthCalledWith(1, { red: 255, green: 0, blue: 255 })
|
||||
expect(getAllObjectsInTimeRange).toHaveBeenCalledTimes(1)
|
||||
expect(getAllObjectsInTimeRange).toHaveBeenNthCalledWith(1, calendarObjects[0], start, end)
|
||||
expect(getHexForColorName).toHaveBeenCalledTimes(1)
|
||||
expect(getHexForColorName).toHaveBeenNthCalledWith(1, 'red')
|
||||
expect(generateTextColorForHex).toHaveBeenCalledTimes(1)
|
||||
expect(generateTextColorForHex).toHaveBeenNthCalledWith(1, '#ff0000')
|
||||
})
|
||||
|
||||
it('should fallback to the calendar color', () => {
|
||||
const calendar = {
|
||||
id: 'calendar-id-123',
|
||||
color: '#ff00ff',
|
||||
readOnly: false,
|
||||
}
|
||||
|
||||
const start = new Date()
|
||||
start.setHours(start.getHours() - 24)
|
||||
const end = new Date()
|
||||
end.setHours(end.getHours() + 24)
|
||||
const timezone = { calendarJsTimezone: true, tzid: 'America/New_York' }
|
||||
|
||||
const calendarObjects = [
|
||||
{
|
||||
calendarObject: true,
|
||||
dav: {
|
||||
url: 'url1',
|
||||
},
|
||||
id: '1',
|
||||
},
|
||||
]
|
||||
|
||||
const eventComponents = [
|
||||
{
|
||||
name: 'VEVENT',
|
||||
id: '1-1',
|
||||
status: 'CONFIRMED',
|
||||
isAllDay: jest.fn().mockReturnValue(false),
|
||||
getReferenceRecurrenceId: jest.fn().mockReturnValue({ unixTime: 123 }),
|
||||
canModifyAllDay: jest.fn().mockReturnValue(true),
|
||||
startDate: {
|
||||
getInTimezone: jest.fn().mockReturnValue({
|
||||
jsDate: new Date(start),
|
||||
}),
|
||||
},
|
||||
endDate: {
|
||||
getInTimezone: jest.fn().mockReturnValue({
|
||||
jsDate: new Date(end),
|
||||
}),
|
||||
},
|
||||
hasComponent: jest.fn().mockReturnValue(false),
|
||||
hasProperty: jest.fn().mockReturnValue(false),
|
||||
},
|
||||
]
|
||||
|
||||
getAllObjectsInTimeRange
|
||||
.mockReturnValueOnce(eventComponents)
|
||||
hexToRGB
|
||||
.mockReturnValueOnce({ red: 255, green: 0, blue: 255 })
|
||||
isLight
|
||||
.mockReturnValueOnce(false)
|
||||
getHexForColorName
|
||||
.mockReturnValueOnce(null)
|
||||
generateTextColorForHex
|
||||
.mockReturnValueOnce('#eeeeee')
|
||||
|
||||
expect(eventSourceFunction(calendarObjects, calendar, new Date(start), new Date(end), timezone)).toEqual([
|
||||
{
|
||||
id: '1###1-1',
|
||||
title: 'Untitled event',
|
||||
allDay: false,
|
||||
start,
|
||||
end,
|
||||
classNames: [],
|
||||
extendedProps: {
|
||||
objectId: '1',
|
||||
recurrenceId: 123,
|
||||
canModifyAllDay: true,
|
||||
calendarId: 'calendar-id-123',
|
||||
davUrl: 'url1',
|
||||
objectType: 'VEVENT',
|
||||
percent: null,
|
||||
hasAlarms: false,
|
||||
hasAttendees: false,
|
||||
darkText: false,
|
||||
},
|
||||
backgroundColor: '#ff00ff',
|
||||
borderColor: '#ff00ff',
|
||||
textColor: '#eeeeee',
|
||||
},
|
||||
])
|
||||
|
||||
expect(hexToRGB).toHaveBeenCalledTimes(1)
|
||||
expect(hexToRGB).toHaveBeenNthCalledWith(1, '#ff00ff')
|
||||
expect(isLight).toHaveBeenCalledTimes(1)
|
||||
expect(isLight).toHaveBeenNthCalledWith(1, { red: 255, green: 0, blue: 255 })
|
||||
expect(getAllObjectsInTimeRange).toHaveBeenCalledTimes(1)
|
||||
expect(getAllObjectsInTimeRange).toHaveBeenNthCalledWith(1, calendarObjects[0], start, end)
|
||||
expect(getHexForColorName).toHaveBeenCalledTimes(1)
|
||||
expect(getHexForColorName).toHaveBeenNthCalledWith(1, undefined)
|
||||
expect(generateTextColorForHex).toHaveBeenCalledTimes(1)
|
||||
expect(generateTextColorForHex).toHaveBeenNthCalledWith(1, '#ff00ff')
|
||||
})
|
||||
})
|
|
@ -2,6 +2,7 @@
|
|||
* @copyright Copyright (c) 2019 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
* @author Richard Steinmetz <richard@steinmetz.cloud>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
|
@ -227,6 +228,9 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
hasAlarms: false,
|
||||
hasAttendees: false,
|
||||
},
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
},
|
||||
{
|
||||
id: '1###1-2',
|
||||
|
@ -249,6 +253,9 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
hasAlarms: false,
|
||||
hasAttendees: false,
|
||||
},
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
},
|
||||
{
|
||||
id: '1###1-3',
|
||||
|
@ -271,6 +278,9 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
hasAlarms: true,
|
||||
hasAttendees: false,
|
||||
},
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
},
|
||||
{
|
||||
id: '2###2-1',
|
||||
|
@ -293,6 +303,9 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
hasAlarms: false,
|
||||
hasAttendees: false,
|
||||
},
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
},
|
||||
{
|
||||
id: '4###3-1',
|
||||
|
@ -358,11 +371,14 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
expect(getAllObjectsInTimeRange).toHaveBeenNthCalledWith(3, calendarObjects[2], start, end)
|
||||
expect(getAllObjectsInTimeRange).toHaveBeenNthCalledWith(4, calendarObjects[3], start, end)
|
||||
|
||||
expect(getHexForColorName).toHaveBeenCalledTimes(1)
|
||||
expect(getHexForColorName).toHaveBeenNthCalledWith(1, 'red')
|
||||
expect(getHexForColorName).toHaveBeenCalledTimes(5)
|
||||
for (let i = 1; i < 5; i++) {
|
||||
expect(getHexForColorName).toHaveBeenNthCalledWith(i, undefined)
|
||||
}
|
||||
expect(getHexForColorName).toHaveBeenNthCalledWith(5, 'red')
|
||||
|
||||
expect(generateTextColorForHex).toHaveBeenCalledTimes(1)
|
||||
expect(generateTextColorForHex).toHaveBeenNthCalledWith(1, '#ff0000')
|
||||
expect(generateTextColorForHex).toHaveBeenCalledTimes(5)
|
||||
expect(generateTextColorForHex).toHaveBeenCalledWith('#ff0000')
|
||||
|
||||
// Make sure the following dates have not been touched
|
||||
expect(event11Start.getFullYear()).toEqual(2020)
|
||||
|
@ -617,6 +633,9 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
id: '1###1',
|
||||
start: event1End,
|
||||
title: 'Untitled task',
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
}, {
|
||||
allDay: false,
|
||||
classNames: [
|
||||
|
@ -640,6 +659,9 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
id: '1###2',
|
||||
start: event2End,
|
||||
title: 'Untitled task',
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
}, {
|
||||
allDay: false,
|
||||
classNames: [
|
||||
|
@ -663,6 +685,9 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
id: '1###3',
|
||||
start: event3End,
|
||||
title: 'Untitled task (99%)',
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
}, {
|
||||
allDay: false,
|
||||
classNames: [
|
||||
|
@ -681,11 +706,14 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
percent: null,
|
||||
recurrenceId: 123,
|
||||
hasAlarms: false,
|
||||
hasAttendees: false
|
||||
hasAttendees: false,
|
||||
},
|
||||
id: '1###4',
|
||||
start: event4End,
|
||||
title: 'This task has a title',
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
}, {
|
||||
allDay: false,
|
||||
classNames: [
|
||||
|
@ -709,6 +737,9 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
id: '1###5',
|
||||
start: event5End,
|
||||
title: 'This task has a title and percent (99%)',
|
||||
backgroundColor: '#ff0000',
|
||||
borderColor: '#ff0000',
|
||||
textColor: '#eeeeee',
|
||||
}])
|
||||
|
||||
expect(eventComponentSet[0].startDate.getInTimezone).toHaveBeenCalledTimes(0)
|
||||
|
@ -740,8 +771,10 @@ describe('fullcalendar/freeBusyResourceEventSourceFunction test suite', () => {
|
|||
expect(getAllObjectsInTimeRange).toHaveBeenCalledTimes(1)
|
||||
expect(getAllObjectsInTimeRange).toHaveBeenNthCalledWith(1, calendarObjects[0], start, end)
|
||||
|
||||
expect(getHexForColorName).toHaveBeenCalledTimes(0)
|
||||
expect(generateTextColorForHex).toHaveBeenCalledTimes(0)
|
||||
expect(getHexForColorName).toHaveBeenCalledTimes(5)
|
||||
expect(getHexForColorName).toHaveBeenCalledWith(undefined)
|
||||
expect(generateTextColorForHex).toHaveBeenCalledTimes(5)
|
||||
expect(getHexForColorName).toHaveBeenCalledWith(undefined)
|
||||
})
|
||||
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue