{
  "documentation": [
    {
      "id": "faq",
      "title": "FAQ",
      "path": "FAQ.md",
      "content": "Q: The Calendar is not fully recognized / I get JavaScript errors like \"setOption is not a function\" or \"addEvents is not a function\".\n\nA: This may hapen, when not including the addon packages into Vaadin's whitelisting. Please check, if your 'application.properties' contain the property \"vaadin.whitelist\" and if it does, if the whitelist includes \"org.vaadin.stefan\".\n```\nvaadin.whitelisted-packages=com.vaadin,org.vaadin.stefan,some.other.addon,etc.etc.etc\n```\n\nPlease also see [Build problems / JS (client side) errors with V14+](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Known-Issues#build-problems--js-client-side-errors-v14) for more details. If the issue still occurs, please [check](https://github.com/stefanuebe/vaadin-fullcalendar/issues/), if there might be an open issue already or create a new one.\n\nQ: The `DatesRenderedEvent` is not fired when setting an option, that changes the view.\n\nA: I deactivated the forwarding of the datesRendered event from the client side when an option is set, since\nthat would lead otherwise to a huge amount of datesRendered events. When setting options before the client side\nis fully attached, the queueing messes up the event handling here.\n\nWhen needed, you can activate or deactivate that by using the method `allowDatesRenderEventOnOptionChange(boolean)`.\nBy default this value is `false`, simply set it to true to also receive date render events on setOption.\n",
      "category": "docs",
      "tags": [
        "faq",
        "datesrenderedevent"
      ]
    },
    {
      "id": "features",
      "title": "Features",
      "path": "Features.md",
      "content": "This page shows a summary of the most important features of the FullCalendar library, that this addon provides. It is\nnot a full list of all features. If you find any library features missing, please create a [feature request](https://github.com/stefanuebe/vaadin-fullcalendar/issues/new?template=BLANK_ISSUE).\n\n## FullCalendar features\n- Adding, updating, and removing calendar entries using a data provider pattern\n- Switching between displayed intervals (next month, previous month, etc.)\n- Navigating to a specific date or today\n- Switching the calendar view (month, basic day/week, agenda day/week, list views, multi-month)\n- Setting a locale for week days, number formatting, and first-day-of-week calculation\n- Overriding the first day of the week independently of the locale\n- Limiting the maximum number of stacked entries per day (except basic views)\n- Activating day/week numbers as navigation links\n- Setting business hours with multiple time ranges per week\n- Creating recurring events (simple recurrence and RFC 5545 RRule)\n- Setting a client-side timezone\n- Optional Vaadin/Lumo theme\n- Custom native JS event handlers for entries\n- Client-side event sources (JSON feeds, Google Calendar, iCalendar)\n\n### Entry model\nThe `Entry` class supports the following properties:\n\n| Property | Method | Description |\n|---|---|---|\n| Title | `setTitle(String)` | Displayed label on the calendar |\n| Start / End | `setStart(LocalDate)` / `setStart(LocalDateTime)` / `setStart(Instant)` and equivalently `setEnd(LocalDate)` / `setEnd(LocalDateTime)` / `setEnd(Instant)` | `LocalDate`, `LocalDateTime`, or `Instant`; `LocalDate` implies all-day. `setEnd` is optional — omitting it creates a single-day (or point-in-time) entry |\n| All-day | `setAllDay(boolean)` | Force all-day rendering regardless of time part |\n| Color | `setColor(String)` | HTML color string (`\"#ff3333\"`, `\"red\"`) |\n| URL | `setUrl(String)` | FC renders the entry as an `<a>` tag and navigates on click |\n| Interactive | `setInteractive(Boolean)` | Per-entry keyboard-focusability; `null` = inherit global `eventInteractive` |\n| Editable | `setEditable(boolean)` | Enable/disable drag and resize for this entry |\n| Display mode | `setDisplayMode(DisplayMode)` | `AUTO`, `BLOCK`, `LIST_ITEM`, `BACKGROUND`, `INVERSE_BACKGROUND`, `NONE` |\n| Overlap | `setOverlap(Boolean)` | Whether this entry may overlap others; `null` = inherit global setting |\n| Constraint | `setConstraint(String)` | Group id or `\"businessHours\"` restricting when this entry may be placed |\n| Recurring (simple) | `setRecurringDaysOfWeek` / `setRecurringStartTime` / `setRecurringEndTime` | Built-in day-of-week recurrence |\n| Recurring duration | `setRecurringDuration(String)` | ISO 8601 duration for multi-day recurring all-day events (e.g. `\"P2D\"`) |\n| RRule | `setRRule(RRule)` | RFC 5545 recurrence rule for complex patterns |\n| Exclusion dates | `rrule.excludeDates(LocalDate...)` | Dates excluded from an RRule recurrence — set on the `RRule` builder instance, transferred automatically to the entry |\n| Custom properties | `setCustomProperty(String, Object)` | Arbitrary data accessible in JS callbacks |\n\n### RRule — rich recurrence patterns\n\n`RRule` provides a fluent Java API for RFC 5545 recurrence rules, backed by the `@fullcalendar/rrule` plugin (bundled automatically).\n\n```java\n// Weekly on Monday, Wednesday, Friday\nEntry standup = new Entry();\nstandup.setTitle(\"Weekly Standup\");\nstandup.setRRule(RRule.weekly()\n    .byWeekday(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)\n    .dtstart(LocalDate.of(2025, 1, 1))\n    .until(LocalDate.of(2025, 12, 31)));\n\n// Last Friday of each month\n// byWeekday accepts RFC 5545 BYDAY strings: \"-1fr\" = last Friday, \"1mo\" = first Monday,\n// \"-2tu\" = second-to-last Tuesday. Positive/negative numbers select the nth occurrence from\n// the start/end of the period.\nEntry endOfMonth = new Entry();\nendOfMonth.setTitle(\"Monthly Review\");\nendOfMonth.setRRule(RRule.monthly().byWeekday(\"-1fr\"));\n\n// Raw RFC 5545 string (for patterns not supported by the fluent builder)\nEntry custom = new Entry();\ncustom.setRRule(RRule.ofRaw(\"FREQ=WEEKLY;BYDAY=MO,WE;INTERVAL=2\"));\n```\n\n**When to use RRule vs. built-in recurrence:**\n- Use the built-in `recurringDaysOfWeek` / `recurringStartTime` / `recurringEndTime` for simple weekly patterns — less setup, no plugin required.\n- Use `RRule` for richer patterns: bi-weekly, monthly-by-weekday, yearly, exclusion dates, limited counts, etc.\n- The two mechanisms are mutually exclusive per entry: setting an `RRule` overrides built-in recurrence fields.\n\n### Entry URL behaviour\n\nWhen `entry.setUrl(url)` is set, FullCalendar renders the entry as an `<a>` tag and navigates to the URL when clicked. The server-side `EntryClickedEvent` **is still fired** when the entry is clicked.\n\n### Accessibility\n\nSet `setOption(Option.ENTRY_INTERACTIVE, true)` to make all entries keyboard-focusable (`tabindex=\"0\"`), enabling keyboard-only users to Tab to entries and activate them with Enter or Space. By default, only entries with a `url` property are focusable. Enabling this globally is recommended for WCAG 2.1 AA, Success Criterion 2.1.1. For per-entry control, use `Entry.setInteractive(Boolean)` (pass `null` to inherit the global setting).\n\nAdditional accessibility options (set via `setOption`):\n- `Option.NATIVE_TOOLBAR_BUTTON_HINTS` — `Map<String, String>` of `aria-label` values for toolbar buttons\n- `Option.NAV_LINK_HINT` / `Option.MORE_LINK_HINT` / `Option.NATIVE_TOOLBAR_VIEW_HINT` — screen-reader labels for navigation links, \"+N more\" overflow links, and view-switcher buttons (use `$0` as a runtime placeholder for the count or date value, e.g. `\"$0 more events\"`)\n- `Option.CLOSE_HINT` / `Option.TIME_HINT` / `Option.ENTRY_HINT` — labels for popover close buttons, time displays, and entries\n\n### Event handling\n\nServer-side events fired by the calendar:\n\n| Event | When fired |\n|---|---|\n| `TimeslotClickedEvent` | User clicks an empty time slot |\n| `TimeslotsSelectedEvent` | User selects a range of time slots |\n| `EntryClickedEvent` | User clicks an entry (including keyboard activation when `Option.ENTRY_INTERACTIVE` is true) |\n| `EntryDroppedEvent` | User drops an entry after dragging (includes new start/end) |\n| `EntryResizedEvent` | User resizes an entry (includes new start/end) |\n| `EntryDragStartEvent` | User begins dragging an entry |\n| `EntryDragStopEvent` | User releases an entry after dragging (fires regardless of whether a valid drop occurred) |\n| `EntryResizeStartEvent` | User begins resizing an entry |\n| `EntryResizeStopEvent` | User releases after resizing (fires regardless of whether a valid resize occurred) |\n| `EntryMouseEnterEvent` / `EntryMouseLeaveEvent` | Mouse enters/leaves an entry |\n| `DatesRenderedEvent` | The current view interval is rendered (use to update labels, refresh data, etc.) |\n| `MoreLinkClickedEvent` | User clicks the \"+N more\" overflow link |\n| `DayNumberClickedEvent` / `WeekNumberClickedEvent` | User clicks a day/week number (when `navLinks` is enabled) |\n| `BrowserTimezoneObtainedEvent` | The client's local timezone is detected on first load |\n| `EventSourceFailureEvent` | A client-side event source (JSON feed, Google Calendar, iCal) failed to load |\n| `ExternalEntryDroppedEvent` | An entry from a client-side event source is dropped into the calendar |\n| `ExternalEntryResizedEvent` | An entry from a client-side event source is resized |\n\n### Event sources (client-side)\n\nIn addition to the server-managed `EntryProvider`, the calendar supports client-side event sources that load data directly in the browser:\n\n```java\n// JSON feed — FC fetches from your REST endpoint with start/end query parameters\nJsonFeedEventSource jsonFeed = new JsonFeedEventSource(\"https://example.com/events\");\n// .withEditable(true)  // optional: enable drag/drop for entries from this source\ncalendar.addClientSideEventSource(jsonFeed);\n\n// Google Calendar\nGoogleCalendarEventSource google = new GoogleCalendarEventSource(\"calendarId@gmail.com\");\ngoogle.withApiKey(\"YOUR_API_KEY\");  // or set globally: calendar.setOption(Option.EXTERNAL_EVENT_SOURCE_GOOGLE_CALENDAR_API_KEY, key)\ncalendar.addClientSideEventSource(google);\n\n// iCalendar (.ics) feed\nICalendarEventSource ical = new ICalendarEventSource(\"https://example.com/calendar.ics\");\ncalendar.addClientSideEventSource(ical);\n```\n\nClient-side event source entries are read-only by default (`editable = false`). To enable drag/drop and resize for a source, call `.withEditable(true)` on the source instance before adding it to the calendar. When a drag-drop occurs, an `ExternalEntryDroppedEvent` is fired; when a resize occurs, an `ExternalEntryResizedEvent` is fired (both instead of their server-managed counterparts `EntryDroppedEvent` / `EntryResizedEvent`).\n\n\n### View-specific options\n\nOverride any option for a specific view type only. The view type string is the FullCalendar view name\n(e.g. `\"dayGridMonth\"`, `\"dayGridWeek\"`, `\"timeGridWeek\"`, `\"timeGridDay\"`, `\"listWeek\"`) or a\nprefix that matches multiple views (e.g. `\"timeGrid\"` matches both `timeGridWeek` and `timeGridDay`).\nYou can also pass a `CalendarView` enum value instead of a raw string.\n\n```java\n// Limit event rows to 3 in month view, no limit in other views\ncalendar.setViewSpecificOption(\"dayGridMonth\", Option.DAY_MAX_EVENT_ROWS, 3);\n\n// Custom slot duration only in time-grid views\n// All three forms work thanks to the DurationConverter:\ncalendar.setViewSpecificOption(\"timeGrid\", Option.SLOT_DURATION, \"00:30:00\");     // string\ncalendar.setViewSpecificOption(\"timeGrid\", Option.SLOT_DURATION, Duration.ofMinutes(30));  // Duration\ncalendar.setViewSpecificOption(\"timeGrid\", Option.SLOT_DURATION, LocalTime.of(0, 30));    // LocalTime\n```\n\n### Navigation\n\n```java\ncalendar.next();           // next interval\ncalendar.previous();       // previous interval\ncalendar.today();          // jump to today\ncalendar.gotoDate(date);   // jump to a specific date\n```\n\n## Scheduler features\nThe scheduler extension integrates the features of the commercial FullCalendar Scheduler plugin.\nA valid license key is required for production use (see [Scheduler license](Scheduler-license)).\n\n- Adding and removing resources (including hierarchical resource trees)\n- Linking one or multiple resources to entries (`ResourceEntry`)\n- Resource grouping by field value (`setOption(SchedulerOption.RESOURCE_GROUP_FIELD, ...)`) with customisable group headers\n- Multiple resource area columns with support for static text and interactive Vaadin components (`setResourceAreaColumns`)\n- Timeline views and vertical resource views (`SchedulerView`)\n- Filtering and ordering resources on the server side\n\nEvent handling:\n- Timeslot clicked / selected\n- Entry dropped (including the resource assignment after drop)\n\n### Component Resource Area Columns\n\nIn addition to static text columns, the resource area sidebar can display interactive Vaadin components (DatePicker, TextField, ComboBox, etc.) — one component instance per resource. This pattern mirrors Vaadin Grid's `ComponentColumn` and is useful for:\n\n- Inline editing of resource metadata (deadlines, priority, owner, notes)\n- One-way binding to entry properties (display entry start/end dates, duration)\n- Two-way binding (component change updates entry; entry change updates component)\n\nComponents are created by a callback that receives the `Resource` and returns a component instance. They are fully interactive — users can type, select, open dropdowns, etc. — and survive FullCalendar view changes and re-renders. Type-safe runtime access is provided at any time via `getComponent(resource)`.\n\n```java\n// Define a component column with a callback\nComponentResourceAreaColumn<DatePicker> deadlineCol = new ComponentResourceAreaColumn<>(\n    \"deadline\", \"Deadline\",\n    resource -> {\n        DatePicker picker = new DatePicker();\n        picker.setWidth(\"130px\");\n        return picker;\n    }\n);\n\n// Mix with regular text columns\nscheduler.setResourceAreaColumns(\n    new ResourceAreaColumn(\"title\", \"Name\").withWidth(\"200px\"),\n    deadlineCol.withWidth(\"160px\")\n);\n\n// Update a component at any time (type-safe, no casting)\ndeadlineCol.getComponent(resource).ifPresent(picker ->\n    picker.setValue(LocalDate.now())\n);\n```\n\n## Developer Tools\n\n- **[MCP Server](MCP-Server)**: Model Context Protocol server for AI assistants (Claude Code, GitHub Copilot, etc.) providing searchable documentation, Java API reference, code examples, and model schemas.\n",
      "category": "docs",
      "tags": [
        "features",
        "entry",
        "localdate",
        "localdatetime",
        "instant",
        "auto",
        "block",
        "background",
        "none",
        "rrule",
        "entryclickedevent",
        "timeslotclickedevent",
        "timeslotsselectedevent",
        "entrydroppedevent",
        "entryresizedevent",
        "entrydragstartevent",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "fullcalendar-examples",
      "title": "Introduction",
      "path": "FullCalendar-Examples.md",
      "content": "# Introduction\nThis page contains some samples to get you started with the FullCalendar addon. The samples are always based on the\nlatest version of the addon.\n\nSome samples use an in-memory entry provider when modifiying the calendar data to keep things simple. You may\nneed to adapt those parts, if you use a different entry provider.\n\nAlso we tried to keep things short. So you may see variables like `calendar`, `entry` or `entryProvider`\nwithout any declaration. In those cases these represent the basic types `FullCalendar`, `Entry` or `EntryProvider`.\n\n> **Note for 7.2.x readers:** several samples below still use the pre-7.2 API\n> (`FullCalendarBuilder.create()`, `event.createCopyBasedOnChanges()`). Both\n> remain functional in 7.2 as `@Deprecated(since = \"7.2.0\")` with no removal\n> scheduled for 7.x. For the equivalents, see\n> [Migration guide 7.1 → 7.2](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-7.1-to-7.2).\n\nIf you find an outdated sample, please create an issue for that.\n\n# Creating a basic calendar instance and add an entry\n\nThe FullCalendar is a normal Vaadin component, that can be added to your view as any other component. By default it uses\nan eager loading in memory entry provider, with which you simply can add, update or remove calendar entries.\n\n```java\n// Create a new calendar instance and attach it to our layout\nFullCalendar calendar = FullCalendarBuilder.create().build();\ncontainer.add(calendar);\ncontainer.setFlexGrow(1, calendar);\n\n// Create a initial sample entry\nEntry entry = new Entry();\nentry.setTitle(\"Some event\");\nentry.setColor(\"#ff3333\");\n\n// the given times will be interpreted as utc based - useful when the times are fetched from your database\nentry.setStart(LocalDate.now().withDayOfMonth(3).atTime(10, 0));\n        entry.setEnd(entry.getStart().plusHours(2));\n\n// FC uses a data provider concept similar to the Vaadin default's one, with some differences\n// By default the FC uses a in-memory data provider, which is sufficient for most basic use cases.\n        calendar.getEntryProvider().asInMemory().addEntries(entry);\n```\n\n# Add, update or remove a calendar entry\n\n```java\nInMemoryEntryProvider<Entry> entryProvider = calendar.getEntryProvider().asInMemory();\n\nHorizontalLayout buttons = new HorizontalLayout();\nButton buttonSave;\nif (newInstance) {\nbuttonSave = new Button(\"Create\", e -> {\n        if (binder.validate().isOk()) {\n        // add the entry to the calendar instance\n        entryProvider.addEntry(entry);\n           entryProvider.refreshAll();\n       }\n               });\n               } else {\nbuttonSave = new Button(\"Save\", e -> {\n        if (binder.validate().isOk()) {\n        // update an existing entry in the client side\n        // this will only send changed data\n        entryProvider.refreshItem(entry);\n       }\n               });\n               }\n               buttons.add(buttonSave);\n\nif (!newInstance) {\nButton buttonRemove = new Button(\"Remove\", e -> {\n   entryProvider.removeEntry(entry);\n   entryProvider.refreshAll();\n});\n   buttons.add(buttonRemove);\n}\n```\n\n# Calendar event handling\nThis sample shows how to react on calendar events, that are triggered by the user or the calendar lifecycle.\n\n```java\n/*\n * The day click event listener is called when a user clicks in an empty space inside of the\n * calendar. Depending of if the clicked point was a day or time slot the event will provide the\n * time details of the clicked point. With this info you can show a dialog to create a new entry.\n */\ncalendar.addTimeslotsSelectedListener((event) -> {\n// react on the selected timeslot, for instance create a new instance and let the user edit it\nEntry entry = new Entry();\n   \n   entry.setStart(event.getStart()); // also event times are always utc based\n        entry.setEnd(event.getEnd());\n        entry.setAllDay(event.isAllDay());\n\n        entry.setColor(\"dodgerblue\");\n\n// ... show an editor\n});\n\n        /*\n         * The entry click event listener is called when the user clicks on an existing entry.\n         * The event provides the clicked event which might be then opened in a dialog.\n         */\n        calendar.addEntryClickedListener((event) -> {\n// react on the clicked entry, for instance let the user edit it\nEntry entry = event.getEntry();\n\n// ... show an editor\n});\n```\n\n# Entry providers\n\n> Introduced in version 4.1\n\nEntry providers allow you to minimize the memory footprint by activating lazy loading for calendar entries. The only\nexception from that is the `EagerInMemoryEntryProvider`, which simulates the old behavior of the FullCalendar.\n\nThe following examples show the different types of `EntryProvider`s and how to use them. The eager variant is the way\nto get rid of the deprecated API in the `FullCalendar`.\n\n## In memory entry provider\n\nThe `InMemoryEntryProvider` caches all registered entries on the server side, but provides only a subset of them to\nthe client (i. e. the entries of the current shown period). This way you can use the CRUD API on the server side\nwithout the need of implementing it yourself. On the other hand the client will be kept free of unnecessary information.\n\n```java\n// load items from backend\nList<Entry> entryList = backend.streamEntries().collect(Collectors.toList());\n\n// init lazy loading provider based on given collection - does NOT use the collection as backend as ListDataProvider does\nLazyInMemoryEntryProvider<Entry> entryProvider = EntryProvider.lazyInMemoryFromItems(entryList);\n\n// set entry provider\ncalendar.setEntryProvider(entryProvider);\n\n// CRUD operations\n// to add\nEntry entry = new Entry();       // ... plus some init\nentryProvider.addEntries(entry); // register in data provider\nentryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch\n\n// after some change\nentryProvider.refreshItem(entry); // call refresh to inform the client about the data change and trigger a refetch\n\n// to remove\nentryProvider.removeEntry(entry);\nentryProvider.refreshAll(); // call refresh to inform the client about the data change and trigger a refetch\n```\n\n## Using callbacks\n\nThe callback entry provider is a base implementation of the `EntryProvider` interface. It does care about how the\nbackend creates or stores the entry data, but only fetches the entries to show from it by passing a query. The backend\nis responsible for providing the entries and handle any changes to the data (e. g. due to calendar entry events).\n\n```java\n// the callback provider uses the given callback to fetch entries when necessary\nCallbackEntryProvider<Entry> entryProvider = EntryProvider.fromCallbacks(\n        query -> backend.streamEntries(query),\n        entryId -> backend.getEntry(entryId).orElse(null)\n);\n\n// set entry provider\ncalendar.setEntryProvider(entryProvider);\n\n// CRUD operations\n// to add\nEntry entry = new Entry();          // ... plus some init\nbackend.addEntry(entry);            // register in your backend\nentryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch\n\n// after some change\nbackend.updateEntry(entry);         // inform your backend\nentryProvider.refreshItem(entry);   // call refresh to inform the client about the data change and trigger a refetch\n\n// to remove\nbackend.removeEntry(entry);         // remove from your backend\nentryProvider.refreshAll();   // call refresh to inform the client about the \n```\n\n## Custom implementation\n\nFeel free to create your own custom implementation, for instance to provide advanced internal caching on the server\nside. We recommend to extend the `AbstractEntryProvider` to start with.\n\nThe simples variant is similar to the callback variant, but with its own class:\n\n```java\nprivate static class BackendEntryProvider extends AbstractEntryProvider<Entry> {\n   private final EntryService service;\n\n   public BackendEntryProvider(EntryService service) {\n      this.service = service;\n   }\n\n   @Override\n   public Stream<Entry> fetch(@NonNull EntryQuery query) {\n      return service.streamEntries(query);\n   }\n\n   @Override\n   public Optional<Entry> fetchById(@NonNull String id) {\n      return service.getEntry(id);\n   }\n}\n```\n\n## Activate prefetch mode (experimental)\n\nBy default the entry provider will always fetch data for the current period. Switching to an adjacent one can\nlead to flickering, since the calendar will resize itself due to the shown entries.\n\nTo prevent that flickering, the calendar can be set to \"prefetch mode\". When activated, the calendar will always\nfetch the previous and next period together with the current one. This means, that on switching to an adjacent\nperiod will initially show the previously fetched entries and update those with the latest state from the server.\nThis leads to an increased amount of data transported between server and client, but will lead to a better\nuser experience as the above mentioned flickering will be prevented.\n\nThe prefetch mode tries to obtain the necessary period based on the current view range unit. The supported units\nare \"day\", \"month\" and \"year\". If no range unit could be determined, a warning will show up. If the range unit\nis not supported, prefetch will not work (in this case the calendar behaves as if prefetch has been disabled).\n\nPlease note, that this functionality is still experimental, but should work fine in most use cases. Thus ee recommend\nto activate it to improve the user experience.\n\n```java\ncalendar.setPrefetchEnabled(true);\n```\n\n# Setting the calendar's dimensions\n\nYou may set the dimensions as with every other Vaadin component. The FC library also brings in some additional\nsettings for content height or an aspect ratio, that can be taken into account. These can be set\nvia the Options API.\n\nSee https://fullcalendar.io/docs/sizing for details.\n\n# Using timezones\n\n```java\n// FC allows to show entries in a specifc timezone. Setting a timezone only affects the client side\n// and might be interesting, when editing those entries in some kind of edit form\n\nTimezone tzBerlinGermany = new Timezone(ZoneId.of(\"Europe/Berlin\"));\ncalendar.setTimezone(tzBerlinGermany); // will rerender the client side and show all times 1-2 hours \"later\".\n\n// We can also reset the timezone to default.\ncalendar.setTimezone(Timezone.UTC);\n\n// We can also read the browsers timezone, after the component has been attached to the client side.\n// There are other ways to obtain the browser's timezone, so you are not obliged to use the listener.\ncalendar.addBrowserTimezoneObtainedListener(event -> calendar.setTimezone(event.getTimezone()));\n\n// If you want to let the calendar obtain the browser time zone automatically, you may simply use the builder.\n// In that case as soon as the client connected, it will set it's timezone in the server side instance.\n        FullCalendarBuilder.create().withAutoBrowserTimezone().build();\n\n// Entries use internally utc to define times. The LocalDateTime and Instant methods setStart/End have the same effect.\nentry.setStart(Instant.now()); // UTC\n        entry.setEnd(LocalDateTime.now()); // UTC\n\n// Entry provides some additional convenience methods to handle the current calendar's timezone's offset, e.g. to allow easy\n// integration into edit forms.\n        calendar.setTimezone(tzBerlinGermany); // times are now 1-2 hours \"ahead\" (depending on daylight saving)\nentry.setStart(LocalDate.of(2000, 1, 1).atStartOfDay());\n\nLocalDateTime utcStart = entry.getStart(); // will be 2000-01-01, 00:00\nLocalDateTime offsetStart = entry.getStartWithOffset(); // will be 2000-01-01, 01:00\n\n// ... modify the offset start, for instance in a date picker\n// e.g. modifiedOffsetStart = offsetStart.plusHours(5);\nLocalDateTime modifiedOffsetStart = offsetStart.plusHours(5);\n\nentry.setStartWithOffset(modifiedOffsetStart); // automatically takes care of conversion back to utc\nutcStart = entry.getStart(); // will be 2000-01-01, 04:00\noffsetStart = entry.getStartWithOffset(); // will be 2000-01-01, 05:00\n```\n\n# Passing custom initial options in Java\n\nYou can fully customize the client side options in Java by passing a JsonObject when creating the FullCalendar.\nPlease be aware, that some options are always set, regardless of the values you set. Please check the\nApiDocs of the withInitialOptions method (or respective constructors) for details\n\nThe following example shows the default initial options as they are set internally by the web component.\n\n```java\nJsonObject initialOptions = Json.createObject();\ninitialOptions.put(\"height\", \"100%\");\ninitialOptions.put(\"timeZone\", \"UTC\");\ninitialOptions.put(\"header\", false);\ninitialOptions.put(\"weekNumbers\", true);\ninitialOptions.put(\"eventLimit\", false); // pass an int value to limit the entries per day\ninitialOptions.put(\"navLinks\", true); \ninitialOptions.put(\"selectable\", true);\ncalendar = FullCalendarBuilder.create().withScheduler().withInitialOptions(initialOptions).build();\n```\n\n# Style the calendar\n\n## Lumo Theme\nSince 6.1 the calendar provides a built-in Lumo theme, that changes minor parts of it to use Lumo variables, like\nsizes, colors, etc. At this point, the theme is not applied automatically, but you have to opt-in to use it.\n\nPlease also be aware, that with 6.1, it still is considered experimental, so there might be parts, that have been\nforgotten or not looking as expected. Also any additional custom stylings may override the Lumo stylings.\n\nTo activate the Lumo theme, simply add the respective theme variant, as you would do with other Vaadin components.\n\n```java\ncalendar.addThemeVariant(FullCalendarVariant.LUMO);\n```\n\n## Global styles\n\nSince 6.0 the component is part of the light dom and thus can be styles via plain css. For any details\non styling the FC please refer to the FC docs (regarding css properties, classes, etc.).\n\nThe styles can be defined as you are used to using the Vaadin theme mechanism or `@CssImport`s.\n\nSample styles.css\n\n```css\n/* change the border color of the fc in a global way*/\n.fc {\n   --fc-border-color: #ddd;\n}\n\n/* change the border color of the fc for dark themes*/\n[theme~=\"dark\"] .fc {\n   --fc-border-color: #333;\n}\n\n\n/* change the appearance of the week and day number to a more button like style when hovering */\n.fc a:is(.fc-daygrid-week-number, .fc-daygrid-day-number) {\n   background: transparent;\n   font-size: 12px;\n   transition: background 200ms ;\n   border-radius: 3px;\n}\n\n.fc a:is(.fc-daygrid-week-number, .fc-daygrid-day-number):hover {\n   background: var(--lumo-primary-color-10pct);\n   text-decoration: none;\n}\n\n.fc a.fc-daygrid-day-number {\n   padding-left: 6px;\n   padding-right: 6px;\n}\n```\n\n# Show the current shown time interval (e. g. month) with Vaadin components\n\n```java\nprivate void init() {\n   // The element that should show the current interval.\n   HasText intervalLabel = new Span();\n\n   // combo box to select a view for the calendar, like \"monthly\", \"weekly\", ...\n   ComboBox<CalendarView> viewBox = new ComboBox<>(\"\", CalendarViewImpl.values());\n   viewBox.addValueChangeListener(e -> {\n      CalendarView value = e.getValue();\n      calendar.changeView(value == null ? CalendarViewImpl.DAY_GRID_MONTH : value);\n   });\n   viewBox.setValue(CalendarViewImpl.DAY_GRID_MONTH);\n\n   /*\n    * The view rendered listener is called when the view has been rendererd on client side\n    * and FC is aware of the current shown interval. Might be accessible more directly in\n    * future.\n    */\n   calendar.addDatesRenderedListener(event -> {\n      LocalDate intervalStart = event.getIntervalStart();\n      CalendarView cView = viewBox.getValue();\n\n      String formattedInterval = ... // format the intervalStart based on cView. See the demos for examples.\n\n      intervalLabel.setText(formattedInterval);\n   });\n}\n```\n\n# Creating a background entry\nA background entry is an entry, that is rendered behind all other entries. It is not clickable and\nhas no tooltip. It is useful for marking a time range, e. g. for marking a vacation.\n\n```java\nEntry entry = new Entry();\n// ... setup entry details\n        \nentry.setDisplayMode(DisplayMode.BACKGROUND);\ncalendar.addEntry(entry);\n```\n\n# Adding business hours\nYou can define business hours for each day of the week. If you don't define any business hours, the calendar will\nassume, that the business hours are from 0:00 to 24:00 for each day.\n\nNon-business hours are grayed out in the calendar.\n\n```java\n// Single instance for \"normal\" business week (mo-fr)\ncalendar.setBusinessHours(new BusinessHours(LocalTime.of(9, 0), LocalTime.of(17, 0),BusinessHours.DEFAULT_BUSINESS_WEEK));\n\n// Multiple instances\n        calendar.setBusinessHours(\nnew BusinessHours(LocalTime.of(9, 0), LocalTime.of(17, 0),BusinessHours.DEFAULT_BUSINESS_WEEK),\n        new BusinessHours(LocalTime.of(12, 0), LocalTime.of(15, 0), DayOfWeek.SATURDAY)\n        );\n\n// Single instance for \"each day from 9am to midnight\"\n        calendar.setBusinessHours(new BusinessHours(LocalTime.of(9, 0)));\n```\n\n# Using tippy.js for description tooltips\nBy default the calendar does not provide tooltips for entries. However, you can easily integrate any type of\ntooltip mechanism or library, for instance by simply applying an html title or using a matured tooltip library\nlike tippy.js.\n\nThis sample shows how to easy integrate tippy.js into a custom subclass of FullCalendar to show an entry's description\nas a tooltip when hovering the entry inside the FC. Please customize the example as needed.\n\n1. Create a new TypeScript file inside the frontend folder of your project. It needs to extend either FullCalendar or\n   FullCalendarScheduler. This example utilized FullCalendarScheduler. If you want to use the normal FC, simply remove\n   all the -Scheduler parts. You may also have a simply JavaScript file, in that case you need to change the\n   following script a bit.\n\nfull-calendar-with-tooltips.ts\n\n```typescript\nimport {FullCalendarScheduler} from '@vaadin/flow-frontend/vaadin-full-calendar/full-calendar-scheduler';\nimport tippy from 'tippy.js';\n\n\nexport class FullCalendarWithTooltip extends FullCalendarScheduler {\n   initCalendar() {\n      super.initCalendar();\n\n      this.calendar!.setOption(\"eventDidMount\", e => {\n         this.initTooltip(e);\n      });\n   }\n\n   initTooltip(e: any) {\n      if (e.event.title && !e.isMirror) {\n         e.el.addEventListener(\"mouseenter\", () => {\n            let tooltip = e.event.getCustomProperty(\"description\", e.event.title);\n\n            e.el._tippy = tippy(e.el, {\n               theme: 'light',\n               content: tooltip,\n               trigger: 'manual'\n            });\n\n            e.el._tippy.show();\n         })\n\n         e.el.addEventListener(\"mouseleave\", () => {\n            if (e.el._tippy) {\n               e.el._tippy.destroy();\n            }\n         })\n      }\n   }\n}\n\ncustomElements.define(\"full-calendar-with-tooltip\", FullCalendarWithTooltip);\n\n```\n\n2. Now create a simple JavaClass, that utilizes your js file. This Java class also imports the needed CSS files.\n\n```java\n@Tag(\"full-calendar-with-tooltip\")\n@JsModule(\"./full-calendar-with-tooltip.js\")\n@CssImport(\"tippy.js/dist/tippy.css\")\n@CssImport(\"tippy.js/themes/light.css\")\npublic class FullCalendarWithTooltip extends FullCalendarScheduler {\n\n   public FullCalendarWithTooltip() {\n   }\n}\n```\n\nAs shown in the subclass sample, you may also use the FullCalendarBuilder to create your custom class.\n\n# Customize the entry content\n\nFC allows you to modify the content of an entry. The given string will be interpreted as js function on client side\nand attached as `eventContent` callback. See https://fullcalendar.io/docs/content-injection (\"...a function\") for\ndetails.\n\n```java\ncalendar.setEntryDidMountCallback(\n   \"function(info) {\" +\n           \"   info.el.style.color = 'red';\" +\n           \"   return info.el; \" +\n           \"}\"\n);\n\n```\n\nInside the javascript callback you may access the entry's default properties or custom ones, that\nyou can set beforehand, using the custom property api (e. g.`setCustomProperty(String, Object)`).\nIn the callback you can access the custom property in a similar way, using `getCustomProperty(key)`\nor `getCustomProperty(key, defaultValue)`.\n\nPlease be aware, that the entry content callback has to be set before the client side is attached. Setting it afterwards\nhas no effect.\n\nAlso make sure, that your callback function does not contain any harmful code or allow cross side scripting.\n\n```java\n// set the custom property beforehand\nentry.setCustomProperty(Entry.EntryCustomProperties.DESCRIPTION, \"some description\");\n\n// use the custom property\ncalendar = FullCalendarBuilder.create()\n        .withEntryContent(\n                \"function(info) {\" +\n                        \"   let entry = info.event;\" +\n                        \"   console.log(entry.title);\" + // standard property\n                        \"   console.log(entry.getCustomProperty('\" + Entry.EntryCustomProperties.DESCRIPTION+ \"'));\" + // custom property\n                        \"   /* ... do something with the event content ...*/\" +\n                        \"   return info.el; \" +\n                        \"}\"\n)\n// ... other settings\n        .build();\n\n// or use the custom property in the entryDidMountCallback\n```\n\n# Use native javascript events for entries\nWith 6.2 custom native event handlers for entries have been added. These allow you to setup JavaScript events for\neach entry, e.g. a mouse over event handler. Inside these event handlers you may also access the created entry dom\nelement.\n\nCustom native event handlers are added to the FullCalender object. They will then be applied to each created\nentry object (using the entryDidMount callback).\n\nTo add an event handler, simply call the method `addEntryNativeEventListener` on the calendar. The first parameter\nis the JavaScript event name (e.g. \"mouseover\"), the second parameter is the callback, that shall be used for\nthat event. Please be aware, that we do NOT check or sanitize the given JavaScript. It is up to you to prevent\nmalicious code from being sent to your users.\n\nInside the event callback, you may access the entryDidMount argument object, that contains additional information\nabout the current entry. See the official docs (https://fullcalendar.io/docs/event-render-hooks)\nfor more details about which details it provide.\n\n```java\nFullCalendar calendar = new FullCalendar();\n\n// ... other configurations\n\n// write the js event, the current entry info and the current entry's element to the browser console.\ncalendar.addEntryNativeEventListener(\"mouseover\", \"e => console.warn(e, info.event, info.el)\");\n\nadd(calendar);\n```\n\nPlease be aware, that due to the design of the used library, these event handlers have to be setup before the\ncalendar is initialized on the client side.\n\nThis sample will change the element style, when the mouse moves over it and changes back, when leaving the element.\n\n```java\ncalendar.addEntryNativeEventListener(\"mouseover\", \"e => info.el.style.opacity = '0.5'\");\ncalendar.addEntryNativeEventListener(\"mouseout\", \"e => info.el.style.opacity = ''\");\n```\n\nYou can also access the client side dom to utilize other elements, like the parents. With this you may for instance\ncall a server side method.\n\nThe following sample shows, how a client callable method in the current view, containing the FullCalendar object, can\nbe called, when right clicking the entry. With this info you can for instance open a custom popup as a context menu.\n\n```java\n@Route(...)\npublic void MyCalendarView extends VerticalLayout {\n    public MyCalendarView() {\n\n      FullCalendar calender = new FullCalendar();\n      // adds a contextmenu / right client event listener, that calls our openContextMenu. \n      // \"this\" is the fc object, \"this.el\" is the Flow element and \"this.el.parentElement\" is our current view.\n      // This hierarchy access may changed, when you nest the FC into other containers. \n\n      calendar.addEntryNativeEventListener(\"contextmenu\",\n              \"e => this.el.parentElement.$server.openContextMenu(info.event, e.clientX, e.clientY)\");\n\n      add(calender);\n   }\n\n   @ClientCallable\n   public void openContextMenu(JsonObject e, int pointerX, int pointerY) {\n      System.out.println(e);\n      System.out.println(pointerX);\n      System.out.println(pointerY);\n   }\n} \n```\n\nYou can combine the event handlers with a custom entryDidMount callback, if you want additional customizations\nof the entries. The FC will take care of combining the event handlers and you EDM callback\n```java\ncalendar.setEntryDidMountCallback(\"\"\"\n       function(info) {\n           console.warn(\"my custom callback\");\n       }\"\"\");\n\ncalendar.addEntryNativeEventListener(\"mouseover\", \"e => info.el.style.opacity = '0.5'\");\ncalendar.addEntryNativeEventListener(\"mouseout\", \"e => info.el.style.opacity = ''\");\n```\n\nThe following sample shows how to utilize the entryDidMount callback, the native event handlers and the\n[Popup addon](https://vaadin.com/directory/component/popup) to show a context menu. In this sample, the context\nmenu is based on a ListBox.\n\n```java\n@Route(...)\npublic void MyCalendarView extends VerticalLayout {\n    \n    private Popup popup;\n   \n    public MyCalendarView() {\n\n        FullCalendar calender = new FullCalendar();\n        // adds a contextmenu / right client event listener, that calls our openContextMenu. \n        // \"this\" is the fc object, \"this.el\" is the Flow element and \"this.el.parentElement\" is our current view.\n        // This hierarchy access may changed, when you nest the FC into other containers. \n\n        calendar.addEntryNativeEventListener(\"contextmenu\",\n                \"e => {\" +\n                \"   e.preventDefault(); \" +\n                \"   this.el.parentElement.$server.openContextMenu(info.event.id);\" +\n                \"}\");\n\n        // by default, the entry element has no id attribute. Therefore we have to add it ourselves, using the \n        // entry id, that is by default an auto generated UUID\n        calendar.setEntryDidMountCallback(\"\"\"\n                function(info) {\n                    info.el.id = \"entry-\" + info.event.id;\n                }\"\"\");\n\n    }\n\n    @ClientCallable\n    public void openContextMenu (String id){\n        initPopup(); // init the popp\n\n        popup.removeAll(); // remove old content\n\n\n        // setup the context menu\n        // (side note: the list box shows a checkmark, when selecting an item, therefore you may want to use a different \n        // component for a real application or hide the checkmark with CSS)\n        ListBox<String> listBox = new ListBox<>();\n        listBox.setItems(\"Option A\", \"Option B\", \"Option C\");\n        listBox.addValueChangeListener(event -> {\n            Notification.show(\"Selected \" + event.getValue());\n            popup.hide();\n        });\n\n        popup.add(listBox);\n        popup.setFor(\"entry-\" + id);\n\n        popup.show();\n    }\n\n    private void initPopup () {\n        if (popup == null) {\n            popup = new Popup();\n            popup.setFocusTrap(true);\n            add(popup);\n        }\n    }\n} \n```\n\n# Creating a subclass of FullCalendar for custom mods\nSince version 6.0.0, the client side component is based on a simple HTMLElement and thus there is\nno framework lifecycle to hook into. The main entry points for your components are therefore:\n* connectedCallback() - called when the component is attached to the dom\n* initCalendar() - called when the calendar is initialized - only called once\n* createInitOptions(initialOptions) - called when the calendar is initialized. You can modify the initial options here.\n* createEventHandlers() - called when the calendar is initialized. You can modify the event handlers here.\n\nBe aware, that during `connectedCallback()` and before calling `initCalendar()` no internal calendar\nobject is available. Calling `this.calendar` will automatically infer `initCalendar()` and thus can lead\nto unwanted side effects. Therefore, if you want to set options, add entries or do other things with the\ncalendar object, do it after `super.initCalendar()` has been called.\n\nIf you want to modifiy options, that are passed into the calendar object, you can extend the method\n`createInitOptions(initialOptions)` and return a modified options object.\n\nIf you want to modify or extend the event handlers, you can override the method `createEventHandlers()`-\n\nWe recommend to use the `override` modifier on overridden methods to make sure, that the method is\nalways up-to-date.\n\n1. Create a custom web component\n   Create a custom component, that extends FullCalendar or FullCalendarScheduler.\n\n\n```typescript\nimport {FullCalendar} from '@vaadin/flow-frontend/vaadin-full-calendar/full-calendar';\n\nexport class MyFullCalendar extends FullCalendar {\n   connectedCallback() {\n      super.connectedCallback();\n\n      // do something with this.calendar\n      // ...\n   }\n\n   initCalendar() {\n      super.initCalendar();\n\n      // do something with this.calendar\n      // ...\n   }\n\n   createInitOptions(initialOptions) {\n      // modify the initial options\n      // attention: this.calendar is not available here!\n      // ...\n\n      return initialOptions;\n   }\n\n   createEventHandlers() {\n      // modify the event handlers\n      // attention: this.calendar is not available here!\n      // ...\n\n      return super.createEventHandlers();\n   }\n}\n\ncustomElements.define(\"my-full-calendar\", MyFullCalendar);\n```\n\n2. Create a subclass of FullCalendar\n\n```java\nimport com.vaadin.flow.component.Tag;\nimport com.vaadin.flow.component.dependency.JsModule;\nimport org.vaadin.stefan.fullcalendar.FullCalendar;\n\n@Tag(\"my-full-calendar\")\n@JsModule(\"./my-full-calendar.js\")\npublic class MyFullCalendar extends FullCalendar {\n\n   public MyFullCalendar() {\n   }\n}\n```\n\n3. Use this class in your code\n\n```java\ncalendar = new MyFullCalendar();\n```\n\nYou can even use the FullCalendarBuilder to create your custom class. Be aware, that in the current version your\ncustom class needs to provide all constructors, that the extended FC class has. This will be fixed in future versions.\n\n```java\ncalendar = FullCalendarBuilder.create().withCustomType(MyFullCalendar.class).build();\n```   \n\n\n# Entry data utilities\n\n## Handling data changes in events\n\nWhen an event occurs, you may want to check or apply the event's changes against the related calendar item.\n\nYou may either do this manually or use the provided utility functions, that are part of the `EntryDataEvent` classe\n(and subclasses).\n\nIt might come in handy, that you get changes from an event in form of an `Entry` object instead of the different\nchanged values of the event itself.\n\nTo do so, you can simply call the method `createCopyBasedOnChanges()` method, that the `EntryDataEvent` provides.\nThis will create complete copy of the entry but with the changes of the event applied. This copy will not be added to\nthe calendar and is simply intended for data checks.\n\nTo apply any incoming changes to the related `Entry`, the event class provides the method `applyChangesOnEntry()`.\nThis will override the entry with the event data, but not automatically update the client side. This is up to you\nto do with an `refreshItem()` or `refreshAll()` call. Also any backend updates (except for the in memory provider)\nneeds to be handled by your logic.\n\n```java\n// directly apply the changes\ncalendar.addEntryDroppedListener(event -> {\n        event.applyChangesOnEntry(); // includes now the allDay attribute if sent by client\n});\n\n// create a copy to do some business logic checks\n        calendar.addEntryDroppedListener(event -> {\nEntry copy = event.createCopyBasedOnChanges();\n\n    if(copy.getStartAsLocalDate().isBefore(someRequiredMinimalDate) /* do some background checks on the changed data */){\n        event.applyChangesOnEntry();\n        event.getSource().getEntryProvider().refreshItem(event.getEntry()); // refresh the entry to update the UI\n        }\n        });\n```\n\n## Create a temporary copy\n\nThe `Entry` class provides a copy API, that allows you to create a copy of an entry or from a given entry. With this you\ncan easily create temporary instances for an edit dialog without needing to write a lot of \"get-set\" calls. This is\nuseful, when your binders work with the `setBean` api\n\nPlease be aware, that this api is considered \"experimental\" and might not work in every special use case or with every\ncustom property key.\n\n```java\nEntry tmpEntry = entry.copy(); // create a temporary copy\n// you may also call copyAsType to allow the copy to be of a different type\n\nBinder<Entry> binder = new Binder<>();\n\n// ... init binder\n\nbinder.setBean(tmpEntry); // you can of course also use the read/writeBean api\n\n// modify the bound fields\n\nif (binder.validate().isOk()) {\n        entry.copyFrom(tmpEntry); // this will overwrite the entry with the values of the tmpEntry\n// ... update the backend as needed, e.g. by calling refreshItem on the entry provider\n}\n```\n\nAlternatively you can use the copy API in a JPA fashion, where new instances are created on changes.\n\n```java\nEntry tmpEntry = entry.copy(); // create a temporary copy\n\n// ... modify the temporary copy\n\n// return a new copy at the end without changing the initial entry\nreturn tmpEntry.copy();\n```",
      "category": "docs",
      "tags": [
        "fullcalendar-examples",
        "fullcalendar",
        "entry",
        "entryprovider",
        "eagerinmemoryentryprovider",
        "inmemoryentryprovider",
        "abstractentryprovider",
        "entrydataevent",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "fullcalendar-functionality",
      "title": "FullCalendar-Functionality",
      "path": "FullCalendar-Functionality.md",
      "content": "This addon uses a 3rd party library called FullCalendar. We try to integrate all features the library provides. Therefore\nthe following list might not include all available features, but should list the most important ones. If you find\na feature in the FC library, that this addon not yet supports, please create an feature request in the issues page.\n\nSupported features are\n- adding / updating / removing calendar entries using a data provider like mechanism,\n- switching between shown intervals (next month, previous month, etc.),\n- goto a specific date or today,\n- switch the calendar view (month, basic views for days and weeks, agenda views for days and weeks, list views for day to year),\n- setting a locale to be used for displaying week days, formatting values, calculating the first day of the week, etc. (supported locales are provided as constant list)\n- setting the first day of week to be shown (overrides the locale setting),\n- limit max shown entries per day (except basic views)\n- activating day / week numbers / names to be links\n- setting a eventRender JS function from server side\n- setting business hours information (multiple entries possible)\n- creating recurring events\n- setting a client side timezone\n- optional Lumo theme\n- custom native js event handlers for entries\n\n- Event handling for\n    - clicking an empty time spot in the calendar,\n    - selecting a block of empty time spots in the calendar,\n    - clicking an entry,\n    - moving an entry via drag and drop (event is fired on drop + changed time),\n    - resizing an entry (event is fired after resize + changed time),\n    - view rendered (i. e. to update a label of the shown interval)\n    - clicking on limited entries link \"+ X more\"\n    - clicking on a day's or week's number link (when activated)\n\n- Model supports setting\n    - title,\n    - start / end / all day flag,\n    - color (html colors, like \"#f00\" or \"red\"),\n    - description (not shown via FC),\n    - editable / read only\n    - rendering mode (normal, background, inversed background)\n    - recurring data (day of week, start / end date and time)\n    - etc.",
      "category": "docs",
      "tags": [
        "fullcalendar-functionality",
        "entry",
        "event"
      ]
    },
    {
      "id": "fullcalendar-migrationguides",
      "title": "Index",
      "path": "FullCalendar-MigrationGuides.md",
      "content": "We know that migrations suck. Not only developers fear the appearance of a new major version but also every\nproduct or project manager of an application, that uses 3rd party software, knows, that it can be a stressful and time consuming horror to\nintegrate a new major version.\n\nUnfortunately this applies also for this addon. There will be breaking changes here and  there, that requires you to get back\ninto your code and review everything. Nevertheless, we hope, that this migration guide helps you as good as possible\nto get a detailed insight of what has changed and what needs to be done to get you back on track.\n\nIf we missed something or anything is unclear, please ping us on GitHub. We hope, that your upgrade goes through\nas smoothly as possible.\n\n# Index\n* [4.1 > 6.0](#migrating-from-41--60)\n* [4.0 > 4.1](#migrating-from-40--41)\n* [3.x > 4.0](#migrating-from-3x--40)\n\n# Migrating from 4.1 > 6.0\nDepending on your Vaadin version you may need to update also other things, related to Vaadin core and Spring Boot.\nSteps to be taken there, will not be covered here.\n\n## Removed polymer\nSince Polymer has been removed from Vaadin 24, we decided to convert the JS elements to plain, HTML element based\nweb components. Thus, this version should work with Vaadin 23 and 24. \n\nFor most cases this should not affect your application. However, if you subclasses the javascript classes, you may need\nto adapt some of the changes. Any Polymer related feature needs to be converted to plain javascript. If you used\nproperties, you should still be able to set those via the Flow Java API, but you simply have to declare them as normal\nJS class fields. \n\nAlso please note, that the content of the component is now part of the light dom. This will most likely affect\nany custom stylings you may have defined. See the next part for details.\n\n## Styling\nSince the component is now part of the light dom, you have the advantages and disadvantages of it. \n\nAny custom styles you may have defined via overriding the JS class or via using the Java method `addCustomStyles` \ncan now be simply defined via plain css style files. So simply take your css snippets and move them to your global\ncss styles (however they are strucutred :) ).\n\nPlease be aware, that due to being part of the light dom, any other stylings may bleed into the FC now or vice versa.\nBut our experience showed, that the majority of our user base preferred the light dom variant, thus we decided to\ngo this way.\n\nAlso since we moved to a new major of the FC library, it might be, that css selectors have changed in their \nprovided styles and thus your custom styles might not work out of the box.\n\n## Folder structure and tags\nWe changed the folder structure and tag names a bit to better represent the Vaadin nature of this addon and to\nprevent potential naming conflicts. Therefore the the files will now be placed inside a folder named\n`vaadin-full-calendar`. The file names themselves have not changed.\n\nIf you subclasses one of the FC JavaScript classes, simply update the folder structure to be something like\n`@vaadin/flow-frontend/vaadin-full-calendar/full-calendar`. You may need to add the file suffix \".ts\".\n\nAdditionally we prefixed the element tag names with a `vaadin-`, so that the FC itself now has the tag \n`vaadin-full-calendar`. This is relevant, if you used the old tag names for styling or dom querying purposes.\nIn that case update the tag names.\n\n## TypeScript\nWe migrated the old JS files to TypeScript. But this process is not yet done and thus there are many things still in\nprogress (mainly the definition of custom types and some code refinement). \n\nNevertheless, for the normal use case, this has no effect. If you subclassed the JS classes, feel free to convert\nit to TypeScript, but be aware, we do not yet have any fancy TypeScript stuff. But it will come somewhere in future ;)\n\nThings to have in mind when migrating: We use protected and private modifiers of typescript now. Any underscores \nhave been removed and the methods / fields have become private or protected. For instance the `_initCalendar()` method\nis now named `initCalendar()`. This is one of the most important ones - if you have subclassed the FC, you most likely\nhave overridden this method and have to update your code. We recommend to use the `override` modifier, so that the \ncompiler marks any issues regarding such cases.\n\n### Issues with webpack\nThere is a known issue with webpack, that will most likely lead to issues, when starting the application.\n\nCheck the \"Known Issues\" page for details (> Startup issue when using webpack (Vaadin 14-23)).\n\n## No more EagerInMemoryEntryProvider\nTo make maintenance of the client side a bit easier and less error prone, we decided to remove the \n`EagerInMemoryEntryProvider` and thus have the client side always be in \"lazy loading\" mode. This means, that there is \nno official way anymore to move all entries to the client side at once.\n\nOf course you still can override this behavior by using simple JS, but we do not recommend to do\nthat as all infrastructure is built around the fetching mechanisms.\n\nThe `LazyInMemoryEntryProvider` has been renamed to `InMemoryEntryProvider`. Rename all imports and class occurrences.\nAlso the static methods inside EntryProvider have been renamed from `lazyInMemoryFromItems` to `inMemoryFrom`.\n\nReplace any usage of the eager variant with the (now) default one. You also need to call `refreshAll`/`refreshItem` \nafter you changed the data in the provider. This behavior aligns to the behavior to the normal Vaadin data provider.\n\nThe `updateMethod` of the eager variant has no replacement in the default one, as items are not pushed to the client,\nbut fetched. When the client shall be updated, call the refresh methods instead.\n\nThere are also other methods, that where some variant of `Eager`. Simply replace them with the now default one and\ncheck, if refreshs are necessary in your use cases.\n\n### Prefetch mode\nThere is now a prefetch mode, that allows fetching adjacent periods. This shall prevent flickering, when switching\nto the previous/next period. See the samples page for details.\n\n## Custom views\nUp to now custom views had to be created as a Java class but could only be registered via initial options. To\nmake life a bit easier here, the interface `CustomCalendarView` has been added plus methods to register those. \n\nIt is recommended to convert your views and use this new interface. While the old way should still work\nand lead to `AnonymousCustomCalendarView` instances, a warning will be printed onto the error console.\n\nCheck the `CustomCalendarView` docs for additional information. The relevant method is `getViewSettings()`.\n\nPlease note, that due to limitations of the FC library, views can only be set at initialization time.\n\n## Entry is \"static\" again, JsonItem is gone\nThis part describes a rare use case and should not be affecting most of the FC users.\n\nWith 4.x we tried to make the `Entry` structure more dynamic to allow easier definition of new properties and automate\nthe update mechanism a bit. Unfortunately the approach we took was not practicable in all use cases and we even had\nsome issues with proxying and mocking mechanisms.\n\nDue to that we decided to go back to the POJO approach as we had it prior to 4.x. This means, if you had extended\nthe `Entry` class to add properties using the `Key` mechanism, we are sorry, but you will have to convert your\nsubclass. \n\n### Json annotations\nNevertheless, some ideas have survived this rollback. Especially automating the conversion and update process is still\nsomething we do not want to miss. To make life a bit easier, there are now annotations to mark class fields for\nautomated conversion and allow them to be updated. Check the `Entry` source code and annotations in the `json` \nsubpackage, if you want or need to use those annotations.\n\n## Deprecated methods have been removed\n### Calendar Entry CRUD\nReplace Calendar Entry CRUD calls with `getEntryProvider().asInMemoryProvider()`, e.g. \n```java\n// before\ncalendar.addEntry(entry);\n\ncalendar.getEntryProvider().asInMemoryProvider().addEntry(entry)\n```\n\nWe know, this might be cumbersome for use cases, where you only use the in memory provider, but with having a cleaner\napi in mind this is a step we need to take. Sorry for the inconvenience.\n\n### Entry Resource API\nResource methods in `Entry` are now more aligned to other Vaadin item api, so replace for instance `assignResources`\nwith `addResources`.\n\n### Other changes\n* RenderingMode has been renamed to DisplayMode to align with the FC library and is a top class now. \n  Replace it and related methods respectively.\n* Entry's method `copy(Class<T>)` has been renamed to `copyAsType(Class<T>)`.\n* Entry's method `getResources` now may return `null`. Use `getOrCreateResources`. We wanted to have the names here being aligned to other namings in Entry.\n* `CalendarLocale` is now an enum. This should not affect you in most use cases.\n* The option \"week numbers within days\" is no longer available, week numbers are now always display inside days by the FC library. Simply remove any calls to that setting.\n* Since we used the javax @NotNull annotation a lot for better dx, but Vaadin 24 will no longer support that due to Spring Boot 3, we decided to add our own annotation to provide additional information without potential naming conflicts. \n\n\n# Migrating from 4.0 > 4.1\n## Entry Provider and old CRUD operations\n4.1 most important change is the introduction of EntryProviders. Please see the [examples](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples#entry-providers) for details regarding the different new variants.\n\nBy default the FullCalendar uses an `EagerInMemoryEntryProvider`, which behaves the same way as the FullCalendar did before. This means, this should not be a breaking change for your application. Yet we recommend to change to either the `LazyInMemoryEntryProvider` or a callback variant to use the advantages of the new entry providers.\n\nPlease note, that the Entry CRUD API on the FullCalendar has been marked as deprecated. It is recommended to replace it with the respective API of the eager in memory provider, if you want to stay with that implementation. See the [examples page](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples#in-memory-eager-loading) for an example on how that could look like.\n\n# Migrating from 3.x > 4.0\n## Introduction\n### Timezones\nThe most breaking change when migrating from version 3.x to 4.0 will be that the server side got\nrid of any timezone inclusion regarding date times. You still may set a timezone for the calendar\nor set/get offsetted local date times, but the regular api is now always UTC based and we try to keep\nanything as clear as possible regarding whether a local date time represents a UTC time or a time with offset.\n\nPart of this change is\n* Getter and Setter of Entry start and end have changed in name and meaning\n* Timezones are not applied anymore to the server side times\n* Calendar and event time related api is also now UTC based (e.g. finding entries in a timespan)\n\n### JsonItem\nWith this version also the foundation of the `Entry` type has changed to a more dynamic, automated way of handling and converting properties, when communicating with the client. This is done in a new class `JsonItem` which `Entry` now extends.\n\nIn theory, this should not break your code, unless you have extended the Entry class. In that case please have a look into the examples page or the implementation of Entry to get an idea what has changed. We hope, that we have covered now all basic properties of the client side FullCalendar items and that subclasses are not necessary anymore.\n\nIf you still need your subclass, you may have to overhaul the conversion part. For this case it is not really possible to foresee any implementation details and give advices on those, unfortunately.\n\n## Migration steps / manual in detail\n### Timezone\nBefore heading into all UTC and timezone related changes, the first thing to mention is, that the Timezone class now\nhas some simple methods to apply or remove the offset of the timezone it represents from a local date time to create\nanother ((un)offsetted) local date time to help doing things manual. Just to keep in mind, when one of the following\nthings might seem to be a too breaking change.\n\n### Entry start / end and timezone.\nIf are using the `Instant` based start / end api only, theoretically you do not need to change your code.\nPlease notify that `getStartUTC / getEndUTC` have been deprecated. Replace them at some point with `getStartAsInstant / getEndAsInstant`.\n\nIf are using the `LocalDateTime` based versions, you will most likely need to change your code as the `LocalDateTime` based `getStart / getEnd` and\n`setStart / setEnd` methods are now always referring to UTC and never to the timezones. If you want to set or get the date time including\nthe calendar timezone's offset, please use the newly introduced `getStartWithOffset / getEndWithOffset` and `setStartWithOffset / setEndWithOffset`.\nThey take care of adding/subtracting the timezone's offset - either from the assigned calendar or as parameter.\n\nSince some methods seem to do the same as before, it might feel a bit unnecessary to have the method names changed, but we wanted to assure, that it is always clear, what \"kind\" of date time the respective method is working with. Either with the default (UTC) or some explicit offset.\n\n```java\n// Reading and writing the UTC based backend\n\nTimezone calendarTimezone = ...;\nLocalDateTime utcBasedStartDate = ...\n\n// old\nentry.setStart(utcBasedStartDate, calendarTimezone);\n\n// new\nentry.setStart(utcBasedStartDate);\n```\n\n```java\n// Editing an existing entry inside an edit form\n\nDatePicker datePicker = ...\n\n// old\ndatePicker.setValue(entry.getStart());\n\n// ...value changed by date picker\n\nentry.setStart(datePicker.getValue());\n\n\n// new\ndatePicker.setValue(entry.getStartWithOffset());\n\n// ...value changed by date picker\n\nentry.setStartWithOffset(datePicker.getValue());\n```\n\nThe offset variants with the timezone parameter are intended to be used, when working on a new entry, that\nis not yet added to a calendar. Here the entry cannot access the calendar's timezone. In this case you should use these methods. In all\nother cases we recommend to let the entry handle the timezone conversion internally by using the offset variants without timezone parameter.\n\n```java\n// Creating a new entry and let the user fill it inside an edit form\nTimezone timezone = ...;\nDatePicker datePicker = ...\n\n// old\ndatePicker.setValue(entry.getStart(timezone));\n\n// ...value changed by date picker\n\nentry.setStart(datePicker.getValue(), timezone);\n\n\n// new\ndatePicker.setValue(entry.getStartWithOffset(timezone));\n\n// ...value changed by date picker\n\nentry.setStartWithOffset(datePicker.getValue(), timezone);\n```\n\nSummarized we recommend: when working with your backend (persisting, etc), use the UTC variants. When working with some kind\nof edit form, where the user can modify his/her entry based on the calendar's timezone, use the offset variants. For new entries, that have not yet been added to the calendar, use the offset variants with timezone parameter (in the .\n\n### Entry related events date time\n#### Events and timezones\nAs with the entries also event times are now always UTC based. We tried to align the api the the entry's one in naming and behavior, so that the \"default\" date time is always UTC based, while the offset variant api provides the data with the calendar timezone's offset applied.\n\n```java\n// old\ncalendar.addTimeslotSelectedEvent(event -> {\n    Entry entry = new Entry()\n    entry.setStart(event.getStartDateTimeUTC());\n    entry.setEnd(event.getEndDateTimeUTC());\n\n    // if you need the offset variant, use for instance event.getStartDateTime();\n});\n\n// new\ncalendar.addTimeslotSelectedEvent(event -> {\n    Entry entry = new Entry()\n    entry.setStart(event.getStart());\n    entry.setEnd(event.getEnd());\n\n    // if you need the offset variant, use for instance event.getStartWithOffset();\n});\n```\n\n#### Renamed getters\nGetters in `TimeslotsSelectedEvent` have changed to be more aligned to the entry's and other events names to simplify the code to read a bit (e. g. from `getStartDateTime` to `getStart`). We added respective methods for getting the Instant and the offsetted variant.\n\n#### Removed getters in all-day related events\nSee chapter [**All-day behavior**](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-MigrationGuides#all-day-behavior) for details.\n\n### Recurrence\n`setRecurring(boolean)` is gone. There is no replacement for this method, since recurrence is now detected automatically\nbased on if you have set any relevant recurrence property in the entry. See isRecurring() for details, which properties are relevant. This behavior has been taken over from the client side library.\n\n```java\n// old\nentry.setRecurring(recurring);\n\n// new\n// entry.setRecurring(recurring); // not needed anymore, is calculated automatically\n```\n\n`setRecurringStartDate / setRecurringEndDate` has lost the timezone parameter. Remove the timezone parameter. See chapter **All-day behavior** for details.\n\n```java\n// old\nentry.setRecurringStartDate(start.toLocalDate(), timezone);\n\n// new\nentry.setRecurringStartDate(start.toLocalDate());\n```\n\n### All-day behavior\nThe displayment / interpretion of all-day entries and changing timezones has changed. In version 3.x an all-day entry was not bound to the day alone, but\nalso influenced by the timezone. This could lead to effects, that a holiday, which is on a specific day (e. g. New Year),\nspans two days, when switching the timezone. While it might somehow appear to be technically correct, it simply is not from the perspective of a calendar.\nA holiday - or in general an all-day event - is bound to the day, not the time. If you need a day spanning event, that\nis bound to the timezone and \"moves\", when changing the timezone, please create a time based event going over the whole\nday. With this change we align the server side behavior to the client side library and other big calendar providers (for instance Google Calendar).\n\nThis change also affects code at some points. You may have compilation errors for missing `Instant` or `LocalDateTime`\nbased methods, e. g. at `MoreLinkClickedEvent`. Those events provide a `LocalDate` based getter, which you\nshould use instead.\n\nOther events still may provide a date time based getter, where the returned value \"behaves\" now differently for all-day events\nas described above, e. g. all subclasses of `DateTimeEvent`, for instance the `TimeslotClickedEvent`. In 3.x when clicking\nthe 1st of March, the returned date may have been pointing to the 28th of February due to applied timezone\nconversion. Now the returned timestamp will always be the correct day at 00:00 UTC time. Simply ignore the\ntime part in this case or use the `LocalDate` getter.\n\n### Accessing custom properties in eventDidMount or eventContent\nNot a required but a recommended change. If you have customized the appearance of your entries using one of the\ncallbacks `setEntryDidMount()` or `setEntryContent()` (or the respective client side variants) and you access\ncustom properties of an entry (for instance `description`), you should change the access to the newly introduced\n`getCustomProperty()` method. This method takes the custom property key and allows to define a fallback default value\nas second parameter.\n\n```java\n// set the custom property beforehand\nEntry someEntry = ...;\nsomeEntry.setCustomProperty(EntryCustomProperties.DESCRIPTION, \"some description\");\n\ncalendar.setEntryContentCallback(\"\" +\n    \"function(info) {\" +\n\n    // old\n    \"if(info.event.extendedProps && info.eventExtendedProps.customProperty && info.eventExtendedProps.customProperty.description) \"+\n    \"   console.log(info.event.extendedProps.customProperty.description);\" +\n    \"else \" +\n    \"   console.log('no description set');\" +\n\n    // new\n    \"   console.log(info.event.getCustomProperty('\" +EntryCustomProperties.DESCRIPTION+ \"', 'no description set'));\" + // get custom property with fallback\n\n    \"   /* ... do something with the event content ...*/\" +\n    \"   return info.el; \" +\n    \"}\"\n);\n```\n\nYou can use that method also in javascript subclasses of the FullCalendar. Please note, that this method is a custom javascript, which is added\nby us as soon as the client side `eventDidMount` or `eventContent` option has been set. Beforehand the method is not present\nand using it will lead to javascript errors.\n\n\n### Deprecation\nSome methods have been deprecated due to typos or ambigious meaning. Please check any compiler warnings and apidocs\nregarding deprecated methods. They might be removed in any upcoming minor or major release without additional\nwarning.\n\n## Removed features\nIf you used a feature in your calendar, that an entry could have a different timezone for start and end:\nthis is not supported anymore out of the box. We know, that this is a step back regarding functionality,\nbut at this point we thing having a straight way of storing the times internally is a bigger and more\ncommon advantage, since this spares a lot of network overhead (entries do not need to be resend on\ntimezone change anymore). Implementing this would have taken too much time now without us knowing, if it is needed at all.\nInstead we wanted to bring you the new version as fast as possible.\n\nIf you need this feature again, please contact us and we will check how to bring it back in one or another way.",
      "category": "docs",
      "tags": [
        "fullcalendar-migrationguides",
        "eagerinmemoryentryprovider",
        "lazyinmemoryentryprovider",
        "inmemoryentryprovider",
        "eager",
        "customcalendarview",
        "anonymouscustomcalendarview",
        "entry",
        "key",
        "calendarlocale",
        "jsonitem",
        "instant",
        "localdatetime",
        "migration",
        "upgrade",
        "event"
      ]
    },
    {
      "id": "fullcalendar-releasenotes",
      "title": "Index",
      "path": "FullCalendar-ReleaseNotes.md",
      "content": "# Index\n* [6.2.x](#62x)\n* [6.1.x](#61x)\n* [6.0.x](#60x)\n* [4.1.x](#41x)\n* [4.0.x](#40x)\n\n\n# 6.2.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-Notes-6.2.x)\n- added custom native event handlers for entries\n\n# 6.1.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-Notes-6.1.x)\n- added an optional Lumo theme for the addon\n\n# 6.0.x\n- updated to FullCalendar 6.1.6\n- Migrated from Polymer 3 to simple HTML Element based web component (no Lit nor Polymer)\n- Migrated source code from JavaScript to TypeScript (ongoing process, not yet finished)\n- Folder structures changed\n- Tag names prefixed with \"vaadin-\"\n- Content is now part of the light dom, thus styling will be easier\n- Client side eager loading removed, items will now always be fetched\n- Added prefetch mode to allow smoother transition between periods\n- Breaking changes regarding methods and fields (client side and server side). Also usage of private / protected modifiers in TS.\n- Added support for FC's \"multi-month\" views.\n- Added proper API for creating and registering custom views. Also added an internal handling of \"anonymous\" custom views created by initial options.\n- Deprecated code from previous versions has been removed\n- JsonItem has been removed, Entry is a \"normal field\" class again due to issues with proxying frameworks\n- setHeight has been minimalized to be more aligned with Vaadin standards. FC internal height settings / options are not\n  supported anymore. Calendar content will take only as much space as needed.\n- added type `RecurringTime` to allow setting an entry recurrence of more than 24h\n\n\nMinor changes:\n- getResources now may return null. Use getOrCreateResources.\n- CalendarLocale is now an enum. Use getLocale() to obtain the contained locale value.\n- week numbers within days is no longer available, weeknumbers are now always display inside days.\n- RenderingMode and alike namings have been named to DisplayMode / display to match the FC library naming. Also DisplayMode is now a top level class.\n- added resize observer to client side to automatically take care of resizes\n- added our own @NotNull annotation to allow support for Vaadin 23 and 24\n- Entry's method `copy(Class<T>)` has been renamed to `copyAsType(Class<T>)`.\n\nOther things that we may have overseen :)\n\nDue to lack of time, we have no release note details at this time. We tried to provide additional info as part of the migration page.\n\n# 4.1.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-Notes-4.1.x)\n- added EntryProvider, a data provider like callback based class to allow lazy loading entries based on the actual displayed timespan\n\n# 4.0.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-Notes-4.0.x)\n- introduced a new type JsonItem for creating item classes with dynamic property handling and automated conversion from and to json\n- integrated json item api into Entry types for dynamic type conversion. Due to that entries will not send all data to the client, when updating existing ones\n- changed date time handling on server side and communication to be always utc\n- entries are not resent to server anymore when changing timezone on server\n- entry data changes are now sent at once the the client\n- client side entries (\"event\") have now a getCustomProperty method inside eventDidMount or eventContent callbacks\n- removed official support of custom timezones for entries\n- renamed several methods\n- recurrence has some changes regarding enable recurrence and timezones\n",
      "category": "docs",
      "tags": [
        "fullcalendar-releasenotes",
        "recurringtime",
        "migration",
        "upgrade",
        "entry",
        "event"
      ]
    },
    {
      "id": "fullcalendar-scheduler-examples",
      "title": "Activating the scheduler",
      "path": "FullCalendar-Scheduler-Examples.md",
      "content": "# Activating the scheduler\n**using the builder**\n```java\nFullCalendar calendar = FullCalendarBuilder.create().withScheduler().build();\n```\n\n**setSchedulerLicenseKey*\n```java\n// scheduler options\n((Scheduler) calendar).setSchedulerLicenseKey(...);\n```\n\n# Adding a resource to a calendar and link it with entries\n```java\nResource resource = new Resource(null, s, color);\ncalendar.addResource(resource);\n\n// When we want to link an entry with a resource, we need to use ResourceEntry\n// (a subclass of Entry)\nResourceEntry entry = new ResourceEntry(null, title, start.atStartOfDay(), start.plusDays(days).atStartOfDay(), true, true, color, \"Some description...\");\nentry.setResource(resource);\ncalendar.addEntry(entry);\n```\n\n# Handling change of an entry's assigned resource by drag and drop\n```java\ncalendar.addEntryDroppedListener(event -> {\n    event.applyChangesOnEntry();\n\n    Entry entry = event.getEntry();\n\n    if(entry instanceof ResourceEntry) {\n        Set<Resource> resources = ((ResourceEntry) entry).getResources();\n        if(!resources.isEmpty()) {\n            // do something with the resource info\n        }\n    }\n});\n```\n\n# Switching to a timeline view\n```java\ncalendar.changeView(SchedulerView.TIMELINE_DAY);\n```\n\n# Activate vertical resource view\n```java\ncalendar.setGroupEntriesBy(GroupEntriesBy.RESOURCE_DATE);\n```\n\n# Creating a resource bases background event\nResourceEntry entry = new ResourceEntry();\n// ... setup entry details, including addResource()\n\nentry.setDisplayMode(DisplayMode.BACKGROUND);\ncalendar.addEntry(entry);\n\n# Creating hierarchical resources\n```java\n// Create a parent resource. When adding the sub resources first before adding the parent to the calendar,\n// the sub resources are registered automatically on client side and server side.\n\nResource parent = new Resource();\nparent.addChildren(new Resource(), new Resource(), new Resource());\n\ncalendar.addResource(parent); // will add the resource and also it's children to server and client\n\n// add new resources to already registered parents\nResource child = new Resource()\nparent.addChild(child);\ncalendar.addResource(child); // this will update the client side\n\n// or remove them from already registered ones\ncalendar.removeResource(child); \nparent.removeChild(child); \n```\n\n# Making a resource entry draggable between resources\n```java\n// activate for the client to have an entry being draggable between resources\nresourceEntry.setResourceEditableOnClientSide(true);\n\n// update the entry on the client side, if it is already added to the calendar\ncalendar.refreshAll();\n```",
      "category": "docs",
      "tags": [
        "fullcalendar-scheduler-examples",
        "scheduler",
        "resource",
        "entry",
        "event"
      ]
    },
    {
      "id": "fullcalendar-scheduler-functionality",
      "title": "FullCalendar-Scheduler-Functionality",
      "path": "FullCalendar-Scheduler-Functionality.md",
      "content": "This addon uses a 3rd party library called FullCalendar Scheduler. We try to integrate all features the library provides. Therefore\nthe following list might not include all available features, but should list the most important ones. If you find\na feature in the FC library, that this addon not yet supports, please create an feature request in the issues page.\n\n- adding / removing resources (hierarchies of resources are supported)\n- Link one or multiple resources with entries.\n- Activation of the Scheduler by method in the FullCalendarBuilder.\n- List of possible Scheduler based views (timeline).\n- List of possible Scheduler entries grouping.\n\n- Event handling for\n    - Timeslot clicked\n    - Timeslots slected\n    - Entry dropped\n\n*Info:* Entries are linked to calendar internally. The calendar instance is used to resolve resources by after updating an\nentry on the client side.",
      "category": "docs",
      "tags": [
        "fullcalendar-scheduler-functionality",
        "scheduler",
        "resource",
        "entry",
        "event"
      ]
    },
    {
      "id": "fullcalendar-scheduler-license",
      "title": "Activating the Scheduler - [Example](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Scheduler-Examples#activating-the-scheduler)",
      "path": "FullCalendar-Scheduler-License.md",
      "content": "The FullCalendar Scheduler library has a different license model then the basic FullCalendar.\n\nFor more details please visit https://fullcalendar.io/license and https://fullcalendar.io/docs/plugin-index\n\n**This addon does not provide any commercial license for the Scheduler. The license model of MIT does only affect the additional files of this addon, not the used original files.**\n\n# Activating the Scheduler - [Example](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Scheduler-Examples#activating-the-scheduler)\n\nBy default the scheduler is not active, when you use a FullCalendar instance. To have an instance with scheduler activated, use the `.withScheduler(...)` method of the `FullCalendarBuilder`.\n\nThis method will throw an exception, if the scheduler extension is not on the class path.\n\nTo link a resource with entries, use the Entry subclass `ResourceEntry`.",
      "category": "docs",
      "tags": [
        "fullcalendar-scheduler-license",
        "fullcalendarbuilder",
        "resourceentry",
        "scheduler",
        "resource",
        "entry",
        "event"
      ]
    },
    {
      "id": "fullcalendar-scheduler",
      "title": "FullCalendar-Scheduler",
      "path": "FullCalendar-Scheduler.md",
      "content": "This addon extends the **FullCalendar for Flow** addon with the **FullCalendar Scheduler**, which provides\nadditional resource based views (Timeline View and Vertical Resource View) for Vaadin 23+.\n\nIt is based on the latest version of the FullCalendar Scheduler library 6.x.\n\nIt needs the [basic addon](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar) to work.\nSince this addon is not always updated when the basis gets an update, I suggest, that you add both dependencies\n(basis and extension) to always use the latest versions. This extension is compatible as long as the readme\ndoes not tells anything else.\n\n## Requirements / versions / support\nThe addon is built against Vaadin 14.x and Java 8, but is intended to be used with the latest major Vaadin version\nand thus also supports Vaadin 23 and 24 / Java 11+.\n\nAddon versions prior to the current major version are not supported anymore. If you need a fix for such a version\nfeel free to fork the project. You may create an issue, but due to limited time it is very unlikely, that we will fix\nit.\n\nPlease also have a look at the demo for some basic examples and source code of how to integrate the FC.\nFor more examples please have a look into the example section.",
      "category": "docs",
      "tags": [
        "fullcalendar-scheduler",
        "scheduler",
        "resource"
      ]
    },
    {
      "id": "getting-started",
      "title": "Getting Started",
      "path": "Getting-Started.md",
      "content": "# Getting Started\n\nThis guide will help you add FullCalendar for Vaadin Flow to your project.\n\n## Requirements\n\n- **Version 7.x**: Vaadin 25+ / Java 21+\n- **Version 6.x**: Vaadin 14-24 / Java 11+\n\n## Maven Dependency\n\nAdd the Vaadin Directory repository to your `pom.xml`:\n\n```xml\n<repositories>\n    <repository>\n        <id>vaadin-addons</id>\n        <url>https://maven.vaadin.com/vaadin-addons</url>\n    </repository>\n</repositories>\n```\n\nAdd the core dependency:\n\n```xml\n<dependency>\n    <groupId>org.vaadin.stefan</groupId>\n    <artifactId>fullcalendar2</artifactId>\n    <version>7.1.5-SNAPSHOT</version>\n</dependency>\n```\n\n### Scheduler Extension (Optional)\n\nIf you need resource-based views (Timeline, Vertical Resource), add the Scheduler extension:\n\n```xml\n<dependency>\n    <groupId>org.vaadin.stefan</groupId>\n    <artifactId>fullcalendar2-scheduler</artifactId>\n    <version>7.1.5-SNAPSHOT</version>\n</dependency>\n```\n\n**Note**: The Scheduler extension requires a separate [commercial license](https://fullcalendar.io/pricing) from FullCalendar LLC for production use. The MIT license of this addon only covers the Java integration code.\n\n## Basic Usage\n\nCreate a simple calendar and add it to your view:\n\n```java\n// Create the calendar\nFullCalendar calendar = FullCalendarBuilder.create().build();\ncalendar.setSizeFull();\n\n// Add it to your layout\nadd(calendar);\n\n// Create and add an entry\nEntry entry = new Entry();\nentry.setTitle(\"My Event\");\nentry.setStart(LocalDate.now().atTime(10, 0));\nentry.setEnd(LocalDate.now().atTime(12, 0));\n\ncalendar.getEntryProvider().asInMemory().addEntry(entry);\n```\n\n## Next Steps\n\n- Check the [Samples](Samples) for more code examples\n- Review [Features](Features) for a full feature overview\n- See the [FAQ](FAQ) for common questions and troubleshooting\n- If you use AI tools like Claude, Cursor, or Copilot, check out our [MCP Server](MCP-Server) for enhanced assistance with the addon\n",
      "category": "docs",
      "tags": [
        "getting-started",
        "scheduler",
        "resource",
        "entry",
        "event"
      ]
    },
    {
      "id": "home",
      "title": "Home",
      "path": "Home.md",
      "content": "Welcome to the FullCalendar for Flow documentation. Here you will find different information about\nthe Flow integration of the [FullCalendar library](https://fullcalendar.io).\n\n## Quick Links\n\n- [Getting Started](Getting-Started) - Installation and basic setup\n- [Samples](Samples) - Code examples\n- [Features](Features) - Feature overview\n- [FAQ](FAQ) - Common questions and troubleshooting\n- [Migration Guides](Migration-guides) - Upgrading between versions\n\nFor general information about the project, please check to the\n[project's readme](https://github.com/stefanuebe/vaadin-fullcalendar).",
      "category": "docs",
      "tags": [
        "home"
      ]
    },
    {
      "id": "known-issues",
      "title": "Known-Issues",
      "path": "Known-Issues.md",
      "content": "## Known Issues\n\n### Multiline events drag & drop cause the scrollbar to lose position\nThe problem appears when you remove the events and add them back. When you remove all the events from the calendar it resizes itself. When the calendar has no events, it is much shorter which explains why the scroll position is changing.\n\nTake a look here for a workaround https://github.com/stefanuebe/vaadin-fullcalendar/issues/76\n\nAnother good way to fix it is to provide the resources/events as JSON feed and refetch the events instead of removing and adding them back.\n\n### Build problems / JS (client side) errors\nIt might be that the transitive dependencies are not resolved correctly. This mostly happens in Spring Boot due to its built-in class path scanning, which is adapted by Vaadin.\n\nPlease ensure that, if you are using the `vaadin.allowed-packages` property, it lists the addon's package `org.vaadin.stefan` (or simply `org.vaadin`).\n\nIf you are not using any allowed or blocking list in the properties and still have the issue, please check if you have added the `@EnableVaadin` annotation to your Spring application class. If that is the case, check if there are packages listed. If yes, add the package `org.vaadin.stefan` to it.\n\nIf the annotation is not added or added without any parameter and the issue occurs, please add the package `org.vaadin.stefan` plus other necessary packages that have to be scanned, as parameters.\n\nThis should enable Spring to analyze all relevant npm dependencies at runtime. Other CDI versions should work the same.\n\n### Entry cache limits\nThe calendar maintains an internal cache of entries limited to 10,000 items (LRU eviction). This is to prevent unbounded memory growth when using lazy-loaded entry providers with large datasets. If you need more entries cached, consider implementing a custom caching strategy.\n\n### Server-defined JavaScript callbacks\nThe addon uses `new Function()` to evaluate server-defined JavaScript callbacks (e.g., for entry render hooks). This is intentional and allows the server to define client-side behavior dynamically. See [FullCalendar Event Render Hooks](https://fullcalendar.io/docs/event-render-hooks) for the underlying feature.\n\n## Notes for Custom Subclasses\n\nWhen creating custom TypeScript/JavaScript subclasses of FullCalendar:\n\n1. **Prevent duplicate event handler registration**: Use a flag (e.g., `_tooltipInitialized`) to ensure event handlers are only registered once, even if `initCalendar()` is called multiple times.\n\n2. **Clean up resources**: If you add ResizeObservers or other resources, clean them up in `disconnectedCallback()` to prevent memory leaks.",
      "category": "docs",
      "tags": [
        "known-issues",
        "entry",
        "event"
      ]
    },
    {
      "id": "mcp-server",
      "title": "FullCalendar Vaadin MCP Server",
      "path": "MCP-Server.md",
      "content": "# FullCalendar Vaadin MCP Server\n\nModel Context Protocol (MCP) server providing documentation, API reference, and code examples for the [FullCalendar Vaadin Flow](https://github.com/stefanuebe/vaadin-fullcalendar) addon.\n\nUse this MCP server to help AI assistants (Claude, GitHub Copilot, etc.) understand and work with FullCalendar in your Vaadin projects.\n\n## Quick Start\n\nAdd the MCP server to your AI assistant's configuration:\n\n### Claude Code / Claude Desktop\n\nAdd to your MCP configuration (`.mcp.json`, `claude_desktop_config.json`, or settings):\n\n```json\n{\n  \"mcpServers\": {\n    \"fullcalendar\": {\n      \"type\": \"http\",\n      \"url\": \"https://v-herd.eu/vaadin-fullcalendar-mcp/mcp\"\n    }\n  }\n}\n```\n\n### Project-Level Configuration (CLAUDE.md)\n\nAdd this to your project's `CLAUDE.md` to automatically enable the server for that project:\n\n```markdown\n## MCP Servers\n\nFullCalendar Vaadin documentation server:\n\n\\`\\`\\`json\n{\n  \"mcpServers\": {\n    \"fullcalendar\": {\n      \"type\": \"http\",\n      \"url\": \"https://v-herd.eu/vaadin-fullcalendar-mcp/mcp\"\n    }\n  }\n}\n\\`\\`\\`\n```\n\n### Other MCP Clients\n\nPoint your MCP client to:\n- **MCP endpoint**: `https://v-herd.eu/vaadin-fullcalendar-mcp/mcp`\n- **Health check**: `https://v-herd.eu/vaadin-fullcalendar-mcp/health`\n\n## What You Can Do\n\nOnce configured, your AI assistant can:\n\n- **Set up new projects** - Get correct Maven dependencies and repository configuration\n- **Search documentation** - Find relevant docs, examples, and API references\n- **Explore the API** - Get detailed class documentation with methods and fields\n- **Find code examples** - Get working code for common use cases\n- **Understand the data model** - Learn Entry and Resource properties\n- **Migrate between versions** - Get migration guides for version upgrades\n\n## Available Tools\n\n### `get_maven_dependency`\nGet Maven coordinates, repository config, and pom.xml snippets for project setup.\n\n```json\n{ \"name\": \"get_maven_dependency\", \"arguments\": { \"includeScheduler\": true } }\n```\n\nReturns ready-to-use configuration:\n- Artifact IDs: `org.vaadin.stefan:fullcalendar2` and `fullcalendar2-scheduler`\n- Repository: Vaadin Directory (`https://maven.vaadin.com/vaadin-addons`)\n- Version compatibility (v7 for Vaadin 25+, v6 for Vaadin 14-24)\n\n### `search_docs`\nSearch across all documentation, API reference, and code examples.\n\n```json\n{ \"name\": \"search_docs\", \"arguments\": { \"query\": \"how to add entries\", \"limit\": 10 } }\n```\n\n### `get_api_reference`\nGet detailed API reference for a Java class.\n\n```json\n{ \"name\": \"get_api_reference\", \"arguments\": { \"className\": \"FullCalendar\" } }\n```\n\n### `list_classes`\nList all available Java classes, optionally filtered.\n\n```json\n{ \"name\": \"list_classes\", \"arguments\": { \"filter\": \"Entry\", \"source\": \"addon\" } }\n```\n\n### `get_code_example`\nGet code examples for specific use cases.\n\n```json\n{ \"name\": \"get_code_example\", \"arguments\": { \"search\": \"drag and drop\", \"category\": \"events\" } }\n```\n\n### `get_entry_schema`\nGet the Entry model schema with all properties, types, and descriptions.\n\n### `get_resource_schema`\nGet the Resource model schema (Scheduler extension) with all properties.\n\n### `list_calendar_views`\nList all available calendar views (DayGrid, TimeGrid, List, Timeline, etc.).\n\n```json\n{ \"name\": \"list_calendar_views\", \"arguments\": { \"includeScheduler\": true } }\n```\n\n### `list_event_types`\nList all server-side event types that can be listened to.\n\n```json\n{ \"name\": \"list_event_types\", \"arguments\": { \"source\": \"core\" } }\n```\n\n### `get_migration_guide`\nGet migration guide for upgrading between versions.\n\n```json\n{ \"name\": \"get_migration_guide\", \"arguments\": { \"toVersion\": \"7\" } }\n```\n\n### `get_documentation`\nGet full documentation page content.\n\n```json\n{ \"name\": \"get_documentation\", \"arguments\": { \"path\": \"Getting-Started.md\" } }\n```\n\nAvailable pages: `Getting-Started.md`, `Samples.md`, `Features.md`, `FAQ.md`, `Migration-guides.md`, `Known-issues.md`, `Scheduler-license.md`\n\n## Features\n\n- **Hybrid Search**: Semantic search (OpenAI embeddings) with keyword search fallback\n- **Complete API Reference**: All Java classes with methods, fields, and constructors\n- **Code Examples**: 50+ examples extracted from documentation and demo sources\n- **Model Schemas**: Entry and Resource property definitions with types\n- **Calendar Views**: All 44 views with descriptions (including Scheduler views)\n- **Event Types**: Server-side event documentation\n- **Migration Guides**: Version upgrade instructions\n- **Maven Setup**: Dependency coordinates and pom.xml snippets\n\n---\n\n## Self-Hosting\n\nIf you need to run your own instance of the MCP server (e.g., for custom modifications or offline use), follow the instructions below.\n\n### Using Docker\n\n```bash\ncd mcp-server\ndocker build -t fullcalendar-mcp .\ndocker run -p 3000:3000 fullcalendar-mcp\n```\n\nFor semantic search (optional), pass an OpenAI API key:\n\n```bash\ndocker run -p 3000:3000 -e OPENAI_API_KEY=sk-... fullcalendar-mcp\n```\n\n### Local Development\n\n```bash\ncd mcp-server\n\n# Install dependencies\nnpm install\n\n# Extract data from source files\nnpm run extract\n\n# Start development server\nnpm run dev\n\n# Or build and start production server\nnpm run build\nnpm start\n```\n\n### Configuration\n\n| Environment Variable | Description | Default |\n|---------------------|-------------|---------|\n| `PORT` | Server port | `3000` |\n| `OPENAI_API_KEY` | OpenAI API key for semantic search | (keyword search only) |\n| `DATA_PATH` | Path to extracted data JSON | `./data/extracted.json` |\n| `PROJECT_ROOT` | Root of FullCalendar project (for extraction) | `../` |\n\n### Endpoints\n\n| Endpoint | Description |\n|----------|-------------|\n| `POST /mcp` | MCP JSON-RPC endpoint |\n| `POST /` | Alternative MCP endpoint |\n| `GET /health` | Health check |\n| `GET /info` | Server statistics |\n\n### Architecture\n\n```\nsrc/\n├── index.ts              # Express HTTP server with MCP protocol\n├── types.ts              # TypeScript type definitions\n├── tools/\n│   └── index.ts          # Tool handler implementations\n├── search/\n│   ├── index.ts          # Hybrid search orchestration\n│   ├── keyword-search.ts # FlexSearch-based keyword search\n│   └── semantic-search.ts# OpenAI embeddings search\n└── extractors/\n    ├── extract-all.ts    # Main extraction script\n    ├── java-extractor.ts # Java source parser\n    ├── docs-extractor.ts # Markdown documentation parser\n    └── model-extractor.ts# Model schema extractor\n```\n\n### Updating Documentation\n\nThe server extracts documentation at build time. To update:\n\n1. Pull latest changes to the FullCalendar repository\n2. Run `npm run extract` or rebuild the Docker image\n3. Restart the server\n\n---\n\n## License\n\nMIT License - see the main project LICENSE file.\n\nThe FullCalendar Scheduler extension requires a separate [commercial license](https://fullcalendar.io/pricing) from FullCalendar LLC for production use.\n",
      "category": "docs",
      "tags": [
        "mcp-server",
        "port",
        "migration",
        "upgrade",
        "scheduler",
        "resource",
        "entry",
        "event"
      ]
    },
    {
      "id": "migration-guide-3.x-to-4.0",
      "title": "Migration-guide-3.x-to-4.0",
      "path": "Migration-guide-3.x-to-4.0.md",
      "content": "## Introduction\n### Timezones\nThe most breaking change when migrating from version 3.x to 4.0 will be that the server side got\nrid of any timezone inclusion regarding date times. You still may set a timezone for the calendar\nor set/get offsetted local date times, but the regular api is now always UTC based and we try to keep\nanything as clear as possible regarding whether a local date time represents a UTC time or a time with offset.\n\nPart of this change is\n* Getter and Setter of Entry start and end have changed in name and meaning\n* Timezones are not applied anymore to the server side times\n* Calendar and event time related api is also now UTC based (e.g. finding entries in a timespan)\n\n### JsonItem\nWith this version also the foundation of the `Entry` type has changed to a more dynamic, automated way of handling and converting properties, when communicating with the client. This is done in a new class `JsonItem` which `Entry` now extends.\n\nIn theory, this should not break your code, unless you have extended the Entry class. In that case please have a look into the examples page or the implementation of Entry to get an idea what has changed. We hope, that we have covered now all basic properties of the client side FullCalendar items and that subclasses are not necessary anymore.\n\nIf you still need your subclass, you may have to overhaul the conversion part. For this case it is not really possible to foresee any implementation details and give advices on those, unfortunately.\n\n## Migration steps / manual in detail\n### Timezone\nBefore heading into all UTC and timezone related changes, the first thing to mention is, that the Timezone class now\nhas some simple methods to apply or remove the offset of the timezone it represents from a local date time to create\nanother ((un)offsetted) local date time to help doing things manual. Just to keep in mind, when one of the following\nthings might seem to be a too breaking change.\n\n### Entry start / end and timezone.\nIf you are using the `Instant` based start / end api only, theoretically you do not need to change your code.\nPlease notify that `getStartUTC / getEndUTC` have been deprecated. Replace them at some point with `getStartAsInstant / getEndAsInstant`.\n\nIf you are using the `LocalDateTime` based versions, you will most likely need to change your code as the `LocalDateTime` based `getStart / getEnd` and\n`setStart / setEnd` methods are now always referring to UTC and never to the timezones. If you want to set or get the date time including\nthe calendar timezone's offset, please use the newly introduced `getStartWithOffset / getEndWithOffset` and `setStartWithOffset / setEndWithOffset`.\nThey take care of adding/subtracting the timezone's offset - either from the assigned calendar or as parameter.\n\nSince some methods seem to do the same as before, it might feel a bit unnecessary to have the method names changed, but we wanted to assure, that it is always clear, what \"kind\" of date time the respective method is working with. Either with the default (UTC) or some explicit offset.\n\n```java\n// Reading and writing the UTC based backend\n\nTimezone calendarTimezone = ...;\nLocalDateTime utcBasedStartDate = ...\n\n// old\nentry.setStart(utcBasedStartDate, calendarTimezone);\n\n// new\nentry.setStart(utcBasedStartDate);\n```\n\n```java\n// Editing an existing entry inside an edit form\n\nDatePicker datePicker = ...\n\n// old\ndatePicker.setValue(entry.getStart());\n\n// ...value changed by date picker\n\nentry.setStart(datePicker.getValue());\n\n\n// new\ndatePicker.setValue(entry.getStartWithOffset());\n\n// ...value changed by date picker\n\nentry.setStartWithOffset(datePicker.getValue());\n```\n\nThe offset variants with the timezone parameter are intended to be used, when working on a new entry, that\nis not yet added to a calendar. Here the entry cannot access the calendar's timezone. In this case you should use these methods. In all\nother cases we recommend to let the entry handle the timezone conversion internally by using the offset variants without timezone parameter.\n\n```java\n// Creating a new entry and let the user fill it inside an edit form\nTimezone timezone = ...;\nDatePicker datePicker = ...\n\n// old\ndatePicker.setValue(entry.getStart(timezone));\n\n// ...value changed by date picker\n\nentry.setStart(datePicker.getValue(), timezone);\n\n\n// new\ndatePicker.setValue(entry.getStartWithOffset(timezone));\n\n// ...value changed by date picker\n\nentry.setStartWithOffset(datePicker.getValue(), timezone);\n```\n\nSummarized we recommend: when working with your backend (persisting, etc), use the UTC variants. When working with some kind\nof edit form, where the user can modify his/her entry based on the calendar's timezone, use the offset variants. For new entries, that have not yet been added to the calendar, use the offset variants with the calendar's timezone parameter.\n\n### Entry related events date time\n#### Events and timezones\nAs with the entries also event times are now always UTC based. We tried to align the api the the entry's one in naming and behavior, so that the \"default\" date time is always UTC based, while the offset variant api provides the data with the calendar timezone's offset applied.\n\n```java\n// old\ncalendar.addTimeslotSelectedEvent(event -> {\n    Entry entry = new Entry()\n    entry.setStart(event.getStartDateTimeUTC());\n    entry.setEnd(event.getEndDateTimeUTC());\n\n    // if you need the offset variant, use for instance event.getStartDateTime();\n});\n\n// new\ncalendar.addTimeslotSelectedEvent(event -> {\n    Entry entry = new Entry()\n    entry.setStart(event.getStart());\n    entry.setEnd(event.getEnd());\n\n    // if you need the offset variant, use for instance event.getStartWithOffset();\n});\n```\n\n#### Renamed getters\nGetters in `TimeslotsSelectedEvent` have changed to be more aligned to the entry's and other events names to simplify the code to read a bit (e. g. from `getStartDateTime` to `getStart`). We added respective methods for getting the Instant and the offsetted variant.\n\n#### Removed getters in all-day related events\nSee chapter [All-day behavior](#all-day-behavior) for details.\n\n### Recurrence\n`setRecurring(boolean)` is gone. There is no replacement for this method, since recurrence is now detected automatically\nbased on if you have set any relevant recurrence property in the entry. See isRecurring() for details, which properties are relevant. This behavior has been taken over from the client side library.\n\n```java\n// old\nentry.setRecurring(recurring);\n\n// new\n// entry.setRecurring(recurring); // not needed anymore, is calculated automatically\n```\n\n`setRecurringStartDate / setRecurringEndDate` has lost the timezone parameter. Remove the timezone parameter. See chapter [All-day behavior](#all-day-behavior) for details.\n\n```java\n// old\nentry.setRecurringStartDate(start.toLocalDate(), timezone);\n\n// new\nentry.setRecurringStartDate(start.toLocalDate());\n```\n\n### All-day behavior\nThe displayment / interpretion of all-day entries and changing timezones has changed. In version 3.x an all-day entry was not bound to the day alone, but\nalso influenced by the timezone. This could lead to effects, that a holiday, which is on a specific day (e. g. New Year),\nspans two days, when switching the timezone. While it might somehow appear to be technically correct, it simply is not from the perspective of a calendar.\nA holiday - or in general an all-day event - is bound to the day, not the time. If you need a day spanning event, that\nis bound to the timezone and \"moves\", when changing the timezone, please create a time based event going over the whole\nday. With this change we align the server side behavior to the client side library and other big calendar providers (for instance Google Calendar).\n\nThis change also affects code at some points. You may have compilation errors for missing `Instant` or `LocalDateTime`\nbased methods, e. g. at `MoreLinkClickedEvent`. Those events provide a `LocalDate` based getter, which you\nshould use instead.\n\nOther events still may provide a date time based getter, where the returned value \"behaves\" now differently for all-day events\nas described above, e. g. all subclasses of `DateTimeEvent`, for instance the `TimeslotClickedEvent`. In 3.x when clicking\nthe 1st of March, the returned date may have been pointing to the 28th of February due to applied timezone\nconversion. Now the returned timestamp will always be the correct day at 00:00 UTC time. Simply ignore the\ntime part in this case or use the `LocalDate` getter.\n\n### Accessing custom properties in eventDidMount or eventContent\nNot a required but a recommended change. If you have customized the appearance of your entries using one of the\ncallbacks `setEntryDidMountCallback(...)` or `setEntryContentCallback(...)`\nand you access custom properties of an entry (for instance `description`), you should change the access to the newly\nintroduced `getCustomProperty()` method. This method takes the custom property key and allows to define a fallback\ndefault value as second parameter.\n\n> **Note (7.1):** The `setEntryContentCallback` and `setEntryDidMountCallback` methods shown below are\n> deprecated as of 7.1. Use `setOption(Option.ENTRY_CONTENT, JsCallback.of(...))` instead.\n> The `getCustomProperty()` access pattern inside the callback remains the same.\n\n```java\n// set the custom property beforehand\nEntry someEntry = ...;\nsomeEntry.setCustomProperty(EntryCustomProperties.DESCRIPTION, \"some description\");\n\ncalendar.setEntryContentCallback(\"\" +\n    \"function(info) {\" +\n\n    // old\n    \"if(info.event.extendedProps && info.eventExtendedProps.customProperty && info.eventExtendedProps.customProperty.description) \"+\n    \"   console.log(info.event.extendedProps.customProperty.description);\" +\n    \"else \" +\n    \"   console.log('no description set');\" +\n\n    // new\n    \"   console.log(info.event.getCustomProperty('\" +EntryCustomProperties.DESCRIPTION+ \"', 'no description set'));\" + // get custom property with fallback\n\n    \"   /* ... do something with the event content ...*/\" +\n    \"   return info.el; \" +\n    \"}\"\n);\n```\n\nYou can use that method also in javascript subclasses of the FullCalendar. Please note, that this method is a custom javascript, which is added\nby us as soon as the client side `eventDidMount` or `eventContent` option has been set. Beforehand the method is not present\nand using it will lead to javascript errors.\n\n\n### Deprecation\nSome methods have been deprecated due to typos or ambigious meaning. Please check any compiler warnings and apidocs\nregarding deprecated methods. They might be removed in any upcoming minor or major release without additional\nwarning.\n\n## Removed features\nIf you used a feature in your calendar, that an entry could have a different timezone for start and end:\nthis is not supported anymore out of the box. We know, that this is a step back regarding functionality,\nbut at this point we thing having a straight way of storing the times internally is a bigger and more\ncommon advantage, since this spares a lot of network overhead (entries do not need to be resend on\ntimezone change anymore). Implementing this would have taken too much time now without us knowing, if it is needed at all.\nInstead we wanted to bring you the new version as fast as possible.\n\nIf you need this feature again, please contact us and we will check how to bring it back in one or another way.\n",
      "category": "docs",
      "tags": [
        "migration-guide-3.x-to-4.0",
        "entry",
        "jsonitem",
        "instant",
        "localdatetime",
        "timeslotsselectedevent",
        "morelinkclickedevent",
        "localdate",
        "datetimeevent",
        "timeslotclickedevent",
        "migration",
        "upgrade",
        "event"
      ]
    },
    {
      "id": "migration-guide-4.0-to-4.1",
      "title": "Migration-guide-4.0-to-4.1",
      "path": "Migration-guide-4.0-to-4.1.md",
      "content": "## Entry Provider and old CRUD operations\n\n4.1's most important change is the introduction of `EntryProvider`. The direct entry CRUD API on `FullCalendar` is deprecated; use an `EntryProvider` instead.\n\n```java\n// Old (4.0)\ncalendar.addEntry(entry);\ncalendar.removeEntry(entry);\ncalendar.getEntries();\n```\n\n```java\n// New (4.1) — eager in-memory variant (same behavior as before 4.1)\nEagerInMemoryEntryProvider<Entry> provider = new EagerInMemoryEntryProvider<>();\ncalendar.setEntryProvider(provider);\n\nprovider.addEntry(entry);\nprovider.removeEntry(entry);\nprovider.getEntries();\n```\n\nBy default the `FullCalendar` still uses an `EagerInMemoryEntryProvider`, so the old behavior is preserved if you do not explicitly set a provider. The old CRUD API on `FullCalendar` keeps working but is marked `@Deprecated`.\n\n## Recommended: lazy or callback variant\n\nFor larger data sets, we recommend switching to `LazyInMemoryEntryProvider` or a callback-based provider:\n\n```java\n// Callback variant — backend fetches entries on demand per time range\nCallbackEntryProvider<Entry> provider = EntryProvider.fromCallbacks(\n    query -> myRepository.findByRange(query.getStart(), query.getEnd()).stream(),\n    id -> myRepository.findById(id).orElse(null)\n);\ncalendar.setEntryProvider(provider);\n```\n\nSee the [FullCalendar Examples wiki page](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples#entry-providers) for complete code samples of each variant.\n\n> **Note:** `EagerInMemoryEntryProvider` was removed in v6.0. If you skip v5.x and jump to 6.x, see the [4.1 → 6.0 guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-4.1-to-6.0) for the replacement (`InMemoryEntryProvider`, now lazy-only).\n",
      "category": "docs",
      "tags": [
        "migration-guide-4.0-to-4.1",
        "entryprovider",
        "fullcalendar",
        "eagerinmemoryentryprovider",
        "lazyinmemoryentryprovider",
        "inmemoryentryprovider",
        "migration",
        "upgrade",
        "entry",
        "event"
      ]
    },
    {
      "id": "migration-guide-4.1-to-6.0",
      "title": "Migration-guide-4.1-to-6.0",
      "path": "Migration-guide-4.1-to-6.0.md",
      "content": "Depending on your Vaadin version you may need to update also other things, related to Vaadin core.\nSteps to be taken there, will not be covered here.\n\n## Removed polymer\nSince Polymer has been removed from Vaadin 24, we decided to convert the JS elements to plain, HTML element based\nweb components. Thus, this version should work with Vaadin 23 and 24. \n\nFor most cases this should not affect your application. However, if you subclasses the javascript classes, you may need\nto adapt some of the changes. Any Polymer related feature needs to be converted to plain javascript. If you used\nproperties, you should still be able to set those via the Flow Java API, but you simply have to declare them as normal\nJS class fields. \n\nAlso please note, that the content of the component is now part of the light dom. This will most likely affect\nany custom stylings you may have defined. See the next part for details.\n\n## Styling\nSince the component is now part of the light dom, you have the advantages and disadvantages of it. \n\nAny custom styles you may have defined via overriding the JS class or via using the Java method `addCustomStyles`\ncan now be simply defined via plain css style files. So simply take your css snippets and move them to your global\ncss styles (however they are structured).\n\nPlease be aware, that due to being part of the light dom, any other stylings may bleed into the FC now or vice versa.\nBut our experience showed, that the majority of our user base preferred the light dom variant, thus we decided to\ngo this way.\n\nAlso since we moved to a new major of the FC library, it might be, that css selectors have changed in their \nprovided styles and thus your custom styles might not work out of the box.\n\n## Folder structure and tags\nWe changed the folder structure and tag names a bit to better represent the Vaadin nature of this addon and to\nprevent potential naming conflicts. Therefore the the files will now be placed inside a folder named\n`vaadin-full-calendar`. The file names themselves have not changed.\n\nIf you subclasses one of the FC JavaScript classes, simply update the folder structure to be something like\n`@vaadin/flow-frontend/vaadin-full-calendar/full-calendar`. You may need to add the file suffix \".ts\".\n\nAdditionally we prefixed the element tag names with a `vaadin-`, so that the FC itself now has the tag \n`vaadin-full-calendar`. This is relevant, if you used the old tag names for styling or dom querying purposes.\nIn that case update the tag names.\n\n## TypeScript\nWe migrated the old JS files to TypeScript. But this process is not yet done and thus there are many things still in\nprogress (mainly the definition of custom types and some code refinement). \n\nNevertheless, for the normal use case, this has no effect. If you subclassed the JS classes, feel free to convert\nit to TypeScript, but be aware, we do not yet have any fancy TypeScript stuff. But it will come somewhere in future ;)\n\nThings to have in mind when migrating: We use protected and private modifiers of typescript now. Any underscores \nhave been removed and the methods / fields have become private or protected. For instance the `_initCalendar()` method\nis now named `initCalendar()`. This is one of the most important ones - if you have subclassed the FC, you most likely\nhave overridden this method and have to update your code. We recommend to use the `override` modifier, so that the \ncompiler marks any issues regarding such cases.\n\n### Issues with webpack\nThere is a known issue with webpack, that will most likely lead to issues, when starting the application.\n\nCheck the \"Known Issues\" page for details (> Startup issue when using webpack (Vaadin 14-23)).\n\n## No more EagerInMemoryEntryProvider\nTo make maintenance of the client side a bit easier and less error prone, we decided to remove the \n`EagerInMemoryEntryProvider` and thus have the client side always be in \"lazy loading\" mode. This means, that there is \nno official way anymore to move all entries to the client side at once.\n\nOf course you still can override this behavior by using simple JS, but we do not recommend to do\nthat as all infrastructure is built around the fetching mechanisms.\n\nThe `LazyInMemoryEntryProvider` has been renamed to `InMemoryEntryProvider`. Rename all imports and class occurrences.\nAlso the static methods inside EntryProvider have been renamed from `lazyInMemoryFromItems` to `inMemoryFrom`.\n\nReplace any usage of the eager variant with the (now) default one. You also need to call `refreshAll`/`refreshItem` \nafter you changed the data in the provider. This behavior aligns to the behavior to the normal Vaadin data provider.\n\nThe `updateMethod` of the eager variant has no replacement in the default one, as items are not pushed to the client,\nbut fetched. When the client shall be updated, call the refresh methods instead.\n\nThere are also other methods, that where some variant of `Eager`. Simply replace them with the now default one and\ncheck, if refreshs are necessary in your use cases.\n\n### Prefetch mode\nThere is now a prefetch mode, that allows fetching adjacent periods. This shall prevent flickering, when switching\nto the previous/next period. See the samples page for details.\n\n## Custom views\nUp to now custom views had to be created as a Java class but could only be registered via initial options. To\nmake life a bit easier here, the interface `CustomCalendarView` has been added plus methods to register those. \n\nIt is recommended to convert your views and use this new interface. While the old way should still work\nand lead to `AnonymousCustomCalendarView` instances, a warning will be printed onto the error console.\n\nCheck the `CustomCalendarView` docs for additional information. The relevant method is `getViewSettings()`.\n\nPlease note, that due to limitations of the FC library, views can only be set at initialization time.\n\n## Entry is \"static\" again, JsonItem is gone\nThis part describes a rare use case and should not be affecting most of the FC users.\n\nWith 4.x we tried to make the `Entry` structure more dynamic to allow easier definition of new properties and automate\nthe update mechanism a bit. Unfortunately the approach we took was not practicable in all use cases and we even had\nsome issues with proxying and mocking mechanisms.\n\nDue to that we decided to go back to the POJO approach as we had it prior to 4.x. This means, if you had extended\nthe `Entry` class to add properties using the `Key` mechanism, we are sorry, but you will have to convert your\nsubclass. \n\n### Json annotations\nNevertheless, some ideas have survived this rollback. Especially automating the conversion and update process is still\nsomething we do not want to miss. To make life a bit easier, there are now annotations to mark class fields for\nautomated conversion and allow them to be updated. Check the `Entry` source code and annotations in the `json` \nsubpackage, if you want or need to use those annotations.\n\n## Deprecated methods have been removed\n### Calendar Entry CRUD\nReplace Calendar Entry CRUD calls with `getEntryProvider().asInMemory()`, e.g. \n```java\n// before\ncalendar.addEntry(entry);\n\n// after\ncalendar.getEntryProvider().asInMemory().addEntry(entry);\n```\n\nWe know, this might be cumbersome for use cases, where you only use the in memory provider, but with having a cleaner\napi in mind this is a step we need to take. Sorry for the inconvenience.\n\n### Entry Resource API\nResource methods in `Entry` are now more aligned to other Vaadin item api, so replace for instance `assignResources`\nwith `addResources`.\n\n### Other changes\n* RenderingMode has been renamed to DisplayMode to align with the FC library and is a top class now. \n  Replace it and related methods respectively.\n* Entry's method `copy(Class<T>)` has been renamed to `copyAsType(Class<T>)`.\n* Entry's method `getResources` now may return `null`. Use `getOrCreateResources`. We wanted to have the names here being aligned to other namings in Entry.\n* `CalendarLocale` is now an enum. This should not affect you in most use cases.\n* The option \"week numbers within days\" is no longer available, week numbers are now always display inside days by the FC library. Simply remove any calls to that setting.\n* Since we used the javax @NotNull annotation a lot for better dx, but Vaadin 24 will no longer support that due to Spring Boot 3, we decided to add our own annotation to provide additional information without potential naming conflicts. \n",
      "category": "docs",
      "tags": [
        "migration-guide-4.1-to-6.0",
        "eagerinmemoryentryprovider",
        "lazyinmemoryentryprovider",
        "inmemoryentryprovider",
        "eager",
        "customcalendarview",
        "anonymouscustomcalendarview",
        "entry",
        "key",
        "calendarlocale",
        "migration",
        "upgrade",
        "event"
      ]
    },
    {
      "id": "migration-guide-6.3-to-6.4",
      "title": "Migrating from 6.3 to 6.4",
      "path": "Migration-guide-6.3-to-6.4.md",
      "content": "# Migrating from 6.3 to 6.4\n\nVersion 6.4 modernizes the addon for Vaadin 24.10 while backporting v7 features. This guide covers the upgrade path and breaking changes.\n\n> For earlier versions (6.2 or 6.1), see the [v6.0 migration guide](Migration-guides.md#migrating-from-41--60) first.\n\n## Prerequisites\n\nBefore upgrading to 6.4, ensure your project meets this requirement:\n\n| Requirement | Minimum Version |\n|-------------|-----------------|\n| **Vaadin** | 24.10.x |\n\n**Note**: Vaadin 14 is no longer supported. If you're on Vaadin 14, you must upgrade to Vaadin 24.10 first.\n\n## Step 1: Update Maven Dependencies\n\nIn your `pom.xml`, update the FullCalendar addon version:\n\n```xml\n<dependency>\n    <groupId>org.vaadin.stefan</groupId>\n    <artifactId>fullcalendar2</artifactId>\n    <version>6.4.0</version>\n</dependency>\n\n<!-- For Scheduler support -->\n<dependency>\n    <groupId>org.vaadin.stefan</groupId>\n    <artifactId>fullcalendar2-scheduler</artifactId>\n    <version>6.4.0</version>\n</dependency>\n```\n\nRun Maven to fetch the new version:\n\n```bash\nmvn clean dependency:tree\n```\n\n## Step 2: Handle Breaking Changes\n\n### Overlap Field Type Change\n\nThe `Entry.overlap` field has changed from `boolean` (primitive) to `Boolean` (nullable):\n\n**Before (6.3)**:\n```java\nentry.setOverlap(true);\nboolean overlap = entry.isOverlap();  // Returns primitive boolean\n```\n\n**After (6.4)**:\n```java\nentry.setOverlap(true);\nBoolean overlap = entry.getOverlap();  // Returns nullable Boolean\n```\n\n**What changed**:\n- `isOverlap()` is deprecated in 6.4; `getOverlap()` is the non-deprecated replacement\n- `boolean` → `Boolean` (type changed to nullable)\n- `null` is now a distinct state: when null, the entry inherits the calendar-level `eventOverlap` setting; when `false`, overlap is always denied for this entry\n\n**Migration**:\n- Replace `isOverlap()` calls with `getOverlap()`. `isOverlap()` still compiles but is deprecated and coalesces `null` to `true`; `getOverlap()` gives you the raw nullable value\n- If you need a primitive, use: `Boolean overlap = entry.getOverlap(); boolean value = overlap != null && overlap;`\n- Update any comparisons: `if (overlap != null && overlap)` instead of `if (overlap)`\n\n**Recompilation against the 6.4 JAR is required.**\n\n## Step 3: Update Deprecated Method Calls (Optional)\n\nWhile deprecated methods still work, consider replacing them with the unified `setOption()` API for consistency.\n\n### Common Deprecated Methods → Replacements\n\n| Deprecated Method | Replacement |\n|-------------------|-------------|\n| `setFirstDay(DayOfWeek)` | `setOption(Option.FIRST_DAY, DayOfWeek.MONDAY)` |\n| `setWeekends(boolean)` | `setOption(Option.WEEKENDS, true)` |\n| `setEntryDidMountCallback(String)` | `setOption(Option.ENTRY_DID_MOUNT, JsCallback.of(...))` |\n\n**Example**:\n\n```java\n// Before (6.3)\ncalendar.setFirstDay(DayOfWeek.MONDAY);\ncalendar.setWeekends(false);\n\n// After (6.4) — preferred approach\ncalendar.setOption(Option.FIRST_DAY, DayOfWeek.MONDAY);\ncalendar.setOption(Option.WEEKENDS, false);\n```\n\nDeprecated methods are still functional and have `@Deprecated` annotations visible in your IDE. Replace them at your convenience — they remain supported in 6.4.\n\n## Step 4: Optional — Adopt New v7 Features\n\n### Use RRule for Recurring Entries\n\nIf you were using the legacy recurrence fields (`recurringDaysOfWeek`, `recurringStartDate`, `recurringEndDate`), consider switching to RRule:\n\n**Before (6.3 — legacy approach)**:\n```java\nEntry entry = new Entry(\"Weekly Meeting\");\nentry.setStart(LocalDateTime.of(2025, 3, 24, 10, 0));\nentry.setEnd(LocalDateTime.of(2025, 3, 24, 11, 0));\nentry.setRecurringDaysOfWeek(DayOfWeek.MONDAY, DayOfWeek.FRIDAY);\nentry.setRecurringStartDate(LocalDate.of(2025, 3, 1));\nentry.setRecurringEndDate(LocalDate.of(2025, 12, 31));\ncalendar.getEntryProvider().asInMemory().addEntry(entry);\n```\n\n**After (6.4 — RRule approach)**:\n```java\nEntry entry = new Entry(\"Weekly Meeting\");\nentry.setStart(LocalDateTime.of(2025, 3, 24, 10, 0));\nentry.setEnd(LocalDateTime.of(2025, 3, 24, 11, 0));\n\nRRule rule = RRule.weekly()\n    .byWeekday(DayOfWeek.MONDAY, DayOfWeek.FRIDAY)\n    .until(LocalDate.of(2025, 12, 31));\n\nentry.setRRule(rule);\ncalendar.getEntryProvider().asInMemory().addEntry(entry);\n```\n\nBoth approaches work, but RRule is more powerful (supports exclusions, complex patterns, RFC 5545 import).\n\n### Adopt New Entry Fields\n\nThe new fields (`url`, `interactive`) are optional but recommended:\n\n```java\nEntry entry = new Entry(\"Conference Talk\");\nentry.setUrl(\"https://conference.example.com/talks/opening-keynote\");\nentry.setInteractive(true);  // Allows dragging and resizing\ncalendar.getEntryProvider().asInMemory().addEntry(entry);\n```\n\n## Step 5: Handle New NPM Dependencies\n\nThe following npm packages are automatically loaded:\n\n- `@fullcalendar/rrule`\n- `@fullcalendar/google-calendar`\n- `@fullcalendar/icalendar`\n- `ical.js`\n\n**You don't need to do anything** — they're bundled automatically in the addon JAR. If you have a custom npm build process, no changes are required.\n\n## Step 6: Recompile and Test\n\n```bash\nmvn clean verify\n```\n\nRestart your development server and verify.\n\nTest the following:\n\n1. Calendar renders and loads entries\n2. Drag and drop still work\n3. Entry creation/editing dialogs function\n4. Custom styling (if any) still applies\n5. Entry provider (if used) still loads data correctly\n\n## Troubleshooting\n\n### Compilation Error: \"cannot find symbol: method isOverlap()\"\n\n**Cause**: In 6.4, `isOverlap()` is deprecated but still available. This error typically means the addon dependency is not correctly resolved. If you have a subclass of `Entry` that overrides `isOverlap()` with a `boolean` return type, it now conflicts with the `Boolean` return type.\n\n**Fix**:\n```java\n// Replace:\nboolean value = entry.isOverlap();\n\n// With:\nBoolean value = entry.getOverlap();\n```\n\n### Compilation Error: \"incompatible types: Boolean cannot be converted to boolean\"\n\n**Cause**: You're assigning the result of `getOverlap()` to a primitive `boolean`.\n\n**Fix**:\n```java\n// Replace:\nboolean value = entry.getOverlap();\n\n// With:\nBoolean value = entry.getOverlap();\n// Or, to convert to primitive:\nboolean value = entry.getOverlap() != null && entry.getOverlap();\n```\n\n### Calendar Not Rendering\n\n**Cause**: Vaadin 24.10 not properly configured or stale frontend cache.\n\n**Check**:\n```bash\ngrep \"vaadin.version\" pom.xml\n```\n\nEnsure the Vaadin version is 24.10 or later, then clear your browser cache and reload:\n```bash\nmvn clean install\n```\n\n### RRule Entries Not Recurring\n\n**Cause**: RRule entries may require the `@fullcalendar/rrule` plugin, which is included but may need a page reload.\n\n**Fix**: Hard-refresh your browser (Ctrl+Shift+R / Cmd+Shift+R) to clear cached JavaScript.\n\n## Important Notes\n\n- **No automatic migration script**: Breaking changes are minimal, but review code for `isOverlap()` and deprecated method calls.\n- **Backward compatibility**: Apart from the `overlap` field type change, v6.3 code should work with minimal changes.\n- **Binary compatibility**: If you compiled v6.3 with `boolean` overlap, recompilation against v6.4 is required.\n\n## Next Steps\n\n- Review the [Release Notes](release-notes-detail/Release-notes-6.4.md) for new features\n- Check the [demo module](https://github.com/stefanuebe/vaadin-fullcalendar) for usage examples\n- File issues on [GitHub](https://github.com/stefanuebe/vaadin-fullcalendar/issues) if problems arise\n\n---\n\n*Revision: March 2026*\n",
      "category": "docs",
      "tags": [
        "migration-guide-6.3-to-6.4",
        "boolean",
        "entry",
        "migration",
        "upgrade",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "migration-guide-6.4-to-6.5",
      "title": "Migration-guide-6.4-to-6.5",
      "path": "Migration-guide-6.4-to-6.5.md",
      "content": "This guide covers upgrading from v6.4.x to v6.5.0.\n\n**What 6.5 is:** a **backport of the 7.2 feature set** to the v6 line (Vaadin 24 / Java 17 / elemental JSON). If you can move to Vaadin 25 / Java 21, upgrade to 7.2 instead — that's the forward line; 6.5 is for teams that need to stay on V24. 6.5 and 7.2 ship the same feature set; the choice is about platform, not functionality.\n\n**Platform:** FullCalendar JS 6.1.20, Vaadin 24.9.x, Java 17, elemental JSON — same stack as 6.4.\n\n**Source compatibility:** 6.5 is a minor release. Existing source compiles against 6.5 unchanged; all migration steps below are **optional** and deprecated API continues to work throughout 6.x.\n\n**Binary compatibility (one caveat):** `Entry.setEditable(...)`'s JVM descriptor changed from `(Z)V` (primitive) to `(Ljava/lang/Boolean;)V` (boxed) as part of the fix for [#212](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-6.5#per-entry-editable-default-no-longer-overrides-calendar-level-editable-false-212). Existing call sites that pass `true`/`false` continue to compile (Java auto-boxes at the call site). A downstream artifact that was compiled against 6.4 and runs unchanged on 6.5 would hit `NoSuchMethodError` on that single method — the normal \"rebuild your app with the new addon on the classpath\" flow avoids this. No other public method descriptors changed.\n\n**Vocabulary used below:**\n- *Start segment* — FullCalendar renders multi-day entries as one DOM element per day-cell; the \"start segment\" is the one rendered on the entry's first day.\n- *`applyChangesOnEntry()`* — method on `EntryDataEvent` subclasses (drop/resize) that copies the client-side change onto the server-side `Entry`. Skipping this call is the trigger for auto-revert.\n\n## Rolling back to 6.4 behaviour\n\nTwo new default-on behaviours landed in 6.5. The auto-revert change (#225) is the more behaviourally impactful one — see the upgrade-impact call-out under [#225](#new-auto-revert-for-unapplied-entry-changes-225) below. If you hit unexpected issues with either, switch them off in one place to get the 6.4 defaults back:\n\n```java\ncalendar.setAutoProvideEntryIdOnClient(false);       // revert id propagation (#202)\ncalendar.setAutoRevertUnappliedEntryChanges(false);  // revert auto-revert (#225)\n```\n\nAll other 6.5 changes are either opt-in (new API like `Option.INITIAL_VIEW`) or pure bug fixes (#212, #230, #231) — those have no runtime switch because reverting them would re-introduce the bug.\n\n## New: Client-side entry IDs provided automatically (#202)\n\nEnabled by default. Each rendered entry's start segment receives `id=\"entry-<entryId>\"` on the DOM, so server-side components (e.g. `Popover`) can anchor via `document.getElementById`. See [Release notes 6.5](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-6.5#client-side-entry-ids-provided-automatically-202) for details.\n\nNo code changes required to benefit. To opt out:\n\n```java\ncalendar.setAutoProvideEntryIdOnClient(false);\n```\n\n**If you already set `id` in a custom `eventDidMount` callback in 6.4:** your callback now runs AFTER the default id-assignment, so reassigning `info.el.id` inside your callback still wins. No change required. If your callback used to check `if (!info.el.id)` before assigning, that condition will now be false — remove the guard or call `setAutoProvideEntryIdOnClient(false)`.\n\n## New: Auto-revert for unapplied entry changes (#225)\n\nEnabled by default. Entries dragged or resized on the client now revert to their original position if `event.applyChangesOnEntry()` is not called on the server. See [Release notes 6.5](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-6.5#auto-revert-for-unapplied-entry-changes-225) for details.\n\n**Upgrade impact — check your drop/resize listeners.** In 6.4 a listener that did *not* call `applyChangesOnEntry()` left the client showing the new position while the server kept the old `start`/`end` — visually the drop/resize appeared accepted, but server state diverged. In 6.5 that same listener will instead animate the entry back to its original position. If your 6.4 code relied on the client keeping the new position without calling `applyChangesOnEntry()`, pick one of:\n\n- add `event.applyChangesOnEntry();` in the listener so the server-side entry matches what the client shows, or\n- keep the old divergence by calling `setAutoRevertUnappliedEntryChanges(false)` (not recommended — server and client will be out of sync).\n\nNo code changes required if your 6.4 listeners already call `applyChangesOnEntry()` on every accepted drop/resize. To opt out entirely:\n\n```java\ncalendar.setAutoRevertUnappliedEntryChanges(false);\n```\n\n## Deprecated: `FullCalendarBuilder`\n\n`FullCalendarBuilder` is deprecated since 6.5.0. **No removal is scheduled for 6.x** — the class will continue to work throughout the 6.x line and is only slated for removal in a future major version. `FullCalendar` and `FullCalendarScheduler` can be constructed directly and configured through `setOption(Option, value)`; the builder no longer provides value beyond syntactic sugar.\n\n### Migration table\n\n| Builder call | Replacement |\n|---|---|\n| `FullCalendarBuilder.create().build()` | `new FullCalendar()` |\n| `.withScheduler().build()` | `new FullCalendarScheduler()` |\n| `.withScheduler(key).build()` | `new FullCalendarScheduler()` + `setOption(Option.SCHEDULER_LICENSE_KEY, key)` |\n| `.withInitialOptions(obj).build()` | `new FullCalendar(obj)` / `new FullCalendarScheduler(obj)` |\n| `.withEntryLimit(n).build()` | `new FullCalendar()` + `setOption(Option.MAX_ENTRIES_PER_DAY, n)` |\n| `.withEntryProvider(p).build()` | `new FullCalendar()` + `setEntryProvider(p)` |\n| `.withInitialEntries(entries).build()` | `FullCalendar calendar = new FullCalendar();`<br>`((InMemoryEntryProvider<Entry>) calendar.getEntryProvider()).addEntries(entries);` — see caveat below |\n| `.withInitialView(view).build()` | `new FullCalendar()` + `setOption(Option.INITIAL_VIEW, view.getClientSideValue())` |\n| `.withLocale(l).build()` / `.withTimezone(t).build()` / `.withBusinessHours(h).build()` | `new FullCalendar()` + `setLocale(l)` / `setTimezone(t)` / `setBusinessHours(h)` |\n| `.withDirection(d).build()` | `new FullCalendar()` + `setOption(Option.DIRECTION, d.getClientSideValue())` |\n| `.withAutoBrowserTimezone().build()` | `new FullCalendar()` + `addBrowserTimezoneObtainedListener(e -> calendar.setTimezone(e.getTimezone()))` |\n| `.withAutoBrowserLocale().build()` | `new FullCalendar()` + `setLocale(UI.getCurrent().getLocale())` (after UI is available) |\n| `.withCustomCalendarViews(views).build()` | `new FullCalendar()` + `setCustomCalendarViews(views)` |\n| `.withCustomType(Cls.class).build()` | `new Cls()` — the builder previously instantiated a user-provided `FullCalendar` subclass via reflection; direct construction is simpler |\n\n**Caveats:**\n\n- *`withInitialEntries` replacement assumes the default in-memory entry provider is still in place.* A fresh `new FullCalendar()` ships with an `InMemoryEntryProvider`, so the cast is safe. Only call this before switching to a different provider — otherwise the cast will fail at runtime.\n- *`withInitialView` replacement uses the new `Option.INITIAL_VIEW` constant, added in 6.5 after verifying that FullCalendar 6.1.20 applies the `initialView` option correctly on first render (the pre-6.5 builder carried an attach-listener + `changeView()` workaround that is no longer needed). The option takes the FC view key as a String; pass `view.getClientSideValue()` on any `CalendarView` — typically a `CalendarViewImpl` enum constant like `TIME_GRID_WEEK`. Example:*\n  ```java\n  FullCalendar calendar = new FullCalendar();\n  calendar.setOption(Option.INITIAL_VIEW, CalendarViewImpl.TIME_GRID_WEEK.getClientSideValue());\n  ```\n\n### Example\n\n```java\n// Old (6.4)\nFullCalendarScheduler scheduler = (FullCalendarScheduler) FullCalendarBuilder.create()\n    .withScheduler(licenseKey)\n    .withEntryLimit(5)\n    .withLocale(Locale.GERMAN)\n    .build();\n```\n\n```java\n// New (6.5)\nFullCalendarScheduler scheduler = new FullCalendarScheduler();\nscheduler.setOption(Option.SCHEDULER_LICENSE_KEY, licenseKey);\nscheduler.setOption(Option.MAX_ENTRIES_PER_DAY, 5);\nscheduler.setLocale(Locale.GERMAN);\n```\n\nDeprecated methods still work in 6.5.x. Migration is recommended but not urgent.\n\n## Also deprecated in 6.5.0\n\n- **`FullCalendar(int entryLimit)` and `FullCalendarScheduler(int entryLimit)` constructors** — replaced by `new FullCalendar()` + `setOption(Option.MAX_ENTRIES_PER_DAY, n)`.\n- **`Delta.getYears()` and `Delta.getMonths()`** — deprecated (see #191). FullCalendar JS normalises any year/month span into `days` before emitting the delta, so both always return zero for drop/resize events. Use `delta.getDays()` plus the time components. No behaviour change.\n- **`EntryDataEvent.createCopyBasedOnChanges()`** — renamed to `getChangesAsEntry()` for clarity. The old name still works and delegates to the new method; no behaviour change.\n  ```java\n  // 6.4\n  Entry copy = event.createCopyBasedOnChanges();\n  // 6.5\n  Entry copy = event.getChangesAsEntry();\n  ```\n",
      "category": "docs",
      "tags": [
        "migration-guide-6.4-to-6.5",
        "nosuchmethoderror",
        "entrydataevent",
        "entry",
        "popover",
        "fullcalendarbuilder",
        "fullcalendar",
        "fullcalendarscheduler",
        "inmemoryentryprovider",
        "calendarview",
        "calendarviewimpl",
        "migration",
        "upgrade",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "migration-guide-6.x-to-7.x",
      "title": "Migration-guide-6.x-to-7.x",
      "path": "Migration-guide-6.x-to-7.x.md",
      "content": "This guide covers the platform switch from the v6 line (Vaadin 24 / Java 17 / elemental JSON) to the v7 line (Vaadin 25 / Java 21 / Jackson 3). It is purely technical — no addon features are added or removed across the jump if you follow the version mapping below.\n\n**Prerequisite:** you are ready to move your application to Vaadin 25 (Java 21, Jackson 3). The Vaadin platform upgrade itself is covered by [Vaadin's own migration docs](https://vaadin.com/docs/latest/upgrading); this guide covers the addon-facing changes you will need to make on top of that.\n\n## Pick your v7 target\n\nTo avoid mixing a platform migration with a feature-delta migration, jump to the v7 release that ships the same addon feature set as your current v6:\n\n| From (v6) | Target (v7) — feature parity | Notes |\n|---|---|---|\n| 6.5 | **7.2** | same addon feature set on a different platform |\n| 6.4 | **7.1** | same addon feature set on a different platform |\n| 6.3 or older | *go via 6.4 first* | follow [6.3 → 6.4](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-6.3-to-6.4) first to absorb the 6.3→6.4 feature deltas, then continue here |\n\nWhen new 6.x releases ship, this table gains matching entries (6.6 ↔ 7.3, etc.). You can also jump to a different v7.x than your paired target, but that combines a platform migration with a feature-delta migration at once — cleaner to do the feature-delta hop inside v6 first and then use this guide for the platform switch.\n\nOnce you're on the paired v7.x, use the [within-7.x migration guides](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guides) to move further forward.\n\n## JSON framework: elemental.json → Jackson 3\n\nv7 replaces elemental.json with Jackson 3 (`com.fasterxml.jackson`). This only affects you if you use these types directly — for example, in custom converters implementing `JsonItemPropertyConverter`, or when inspecting `EntryDataEvent#getJsonObject()`.\n\n| Old (elemental.json) | New (Jackson 3) |\n|---|---|\n| `JsonObject` | `ObjectNode` |\n| `JsonArray` | `ArrayNode` |\n| `JsonValue` | `JsonNode` |\n| `json.hasKey(key)` | `json.has(key)` / `json.hasNonNull(key)` |\n| `json.put(key, value)` | `json.set(key, value)` (for `JsonNode` children) |\n| `json.keys()` | `json.propertyNames()` |\n| `array.set(array.length(), value)` | `array.add(value)` — elemental appends via `set(length(), ...)`; Jackson's `add()` appends directly. |\n| `JsonUtils.toJsonValue()` | `JsonUtils.toJsonNode()` |\n| `JsonUtils.ofJsonValue()` | `JsonUtils.ofJsonNode()` |\n\n**Note:** `CustomCalendarView.getViewSettings()` returns `ObjectNode` (Jackson) instead of `JsonObject` (elemental). Update any custom view implementations accordingly.\n\n## BusinessHours API\n\n*Introduced in 7.0; documented here for readers coming from v6.* The `BusinessHours` constructors have been replaced with a fluent static factory API:\n\n```java\n// Old (v6)\nnew BusinessHours(LocalTime.of(9, 0), LocalTime.of(17, 0), DayOfWeek.MONDAY, DayOfWeek.FRIDAY);\n\n// New (v7) — fluent builder\nBusinessHours.builder()\n    .start(LocalTime.of(9, 0))\n    .end(LocalTime.of(17, 0))\n    .dayOfWeeks(DayOfWeek.MONDAY, DayOfWeek.FRIDAY)\n    .build();\n\n// Or for a standard Mon–Fri business week:\nBusinessHours.businessWeek().start(LocalTime.of(9, 0)).end(LocalTime.of(17, 0));\n```\n\n## Theme variant rename\n\n*Introduced in 7.0; documented here for readers coming from v6.* `FullCalendarVariant.LUMO` has been renamed to `FullCalendarVariant.VAADIN`. Update any references.\n\n## CSS design tokens\n\nThe addon's built-in CSS uses these Lumo tokens internally. If you have **custom CSS** that references the addon's theme variables directly, switch to Vaadin 25's unified `--vaadin-*` tokens, which work across both the Lumo and Aura themes:\n\n| Old (Lumo) | New (Vaadin unified) |\n|---|---|\n| `--lumo-base-color` | `--vaadin-background-color` |\n| `--lumo-body-text-color` | `--vaadin-text-color` |\n| `--lumo-contrast-10pct` | `--vaadin-border-color-secondary` |\n| `--lumo-contrast-20pct` | `--vaadin-border-color` |\n| `--lumo-space-xs` | `--vaadin-padding-xs` |\n| `--lumo-border-radius-s` | `--vaadin-radius-s` |\n\nThis only applies if your own CSS references those addon theme variables. Stock usage needs no changes.\n\n## Aura theme support\n\nv7 supports the Aura theme (Vaadin 25). The addon's CSS automatically includes Aura fallbacks — no action required.\n",
      "category": "docs",
      "tags": [
        "migration-guide-6.x-to-7.x",
        "jsonitempropertyconverter",
        "jsonobject",
        "objectnode",
        "jsonarray",
        "arraynode",
        "jsonvalue",
        "jsonnode",
        "businesshours",
        "migration",
        "upgrade",
        "entry",
        "event"
      ]
    },
    {
      "id": "migration-guide-7.1-to-7.2",
      "title": "Migration-guide-7.1-to-7.2",
      "path": "Migration-guide-7.1-to-7.2.md",
      "content": "This guide covers upgrading from v7.1.x to v7.2.0.\n\n**Platform:** 7.2 keeps the same platform baseline as 7.1 — FullCalendar JS 6.1.20, Vaadin 25.x, Java 21, Jackson 3.\n\n**Source compatibility:** 7.2 is a minor release. Existing source compiles against 7.2 unchanged; all migration steps below are **optional** and deprecated API continues to work throughout 7.x.\n\n**Binary compatibility (one caveat):** `Entry.setEditable(...)`'s JVM descriptor changed from `(Z)V` (primitive) to `(Ljava/lang/Boolean;)V` (boxed) as part of the fix for [#212](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-7.2#per-entry-editable-default-no-longer-overrides-calendar-level-editable-false-212). Existing call sites that pass `true`/`false` continue to compile (Java auto-boxes at the call site). A downstream artifact that was compiled against 7.1 and runs unchanged on 7.2 would hit `NoSuchMethodError` on that single method — the normal \"rebuild your app with the new addon on the classpath\" flow avoids this. No other public method descriptors changed.\n\n**Vocabulary used below:**\n- *Start segment* — FullCalendar renders multi-day entries as one DOM element per day-cell; the \"start segment\" is the one rendered on the entry's first day.\n- *`applyChangesOnEntry()`* — method on `EntryDataEvent` subclasses (drop/resize) that copies the client-side change onto the server-side `Entry`. Skipping this call is the trigger for auto-revert.\n\n## Rolling back to 7.1 behaviour\n\nTwo new default-on behaviours landed in 7.2. The auto-revert change (#225) is the more behaviourally impactful one — see the upgrade-impact call-out under [#225](#new-auto-revert-for-unapplied-entry-changes-225) below. If you hit unexpected issues with either, switch them off in one place to get the 7.1 defaults back:\n\n```java\ncalendar.setAutoProvideEntryIdOnClient(false);       // revert id propagation (#202)\ncalendar.setAutoRevertUnappliedEntryChanges(false);  // revert auto-revert (#225)\n```\n\nAll other 7.2 changes are either opt-in (new API like `Option.INITIAL_VIEW`) or pure bug fixes (#212, #230, #231) — those have no runtime switch because reverting them would re-introduce the bug.\n\n## New: Client-side entry IDs provided automatically (#202)\n\nEnabled by default. Each rendered entry's start segment receives `id=\"entry-<entryId>\"` on the DOM, so server-side components (e.g. `Popover`) can anchor via `document.getElementById`. See [Release notes 7.2](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-7.2#client-side-entry-ids-provided-automatically-202) for details.\n\nNo code changes required to benefit. To opt out:\n\n```java\ncalendar.setAutoProvideEntryIdOnClient(false);\n```\n\n**If you already set `id` in a custom `eventDidMount` callback in 7.1:** your callback now runs AFTER the default id-assignment, so reassigning `info.el.id` inside your callback still wins. No change required. If your callback used to check `if (!info.el.id)` before assigning, that condition will now be false — remove the guard or call `setAutoProvideEntryIdOnClient(false)`.\n\n## New: Auto-revert for unapplied entry changes (#225)\n\nEnabled by default. Entries dragged or resized on the client now revert to their original position if `event.applyChangesOnEntry()` is not called on the server. See [Release notes 7.2](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-7.2#auto-revert-for-unapplied-entry-changes-225) for details.\n\n**Upgrade impact — check your drop/resize listeners.** In 7.1 a listener that did *not* call `applyChangesOnEntry()` left the client showing the new position while the server kept the old `start`/`end` — visually the drop/resize appeared accepted, but server state diverged. In 7.2 that same listener will instead animate the entry back to its original position. If your 7.1 code relied on the client keeping the new position without calling `applyChangesOnEntry()`, pick one of:\n\n- add `event.applyChangesOnEntry();` in the listener so the server-side entry matches what the client shows, or\n- keep the old divergence by calling `setAutoRevertUnappliedEntryChanges(false)` (not recommended — server and client will be out of sync).\n\nNo code changes required if your 7.1 listeners already call `applyChangesOnEntry()` on every accepted drop/resize. To opt out entirely:\n\n```java\ncalendar.setAutoRevertUnappliedEntryChanges(false);\n```\n\n## Deprecated: `FullCalendarBuilder`\n\n`FullCalendarBuilder` is deprecated since 7.2.0. **No removal is scheduled for 7.x** — the class will continue to work throughout the 7.x line and is only slated for removal in a future major version. `FullCalendar` and `FullCalendarScheduler` can be constructed directly and configured through `setOption(Option, value)`; the builder no longer provides value beyond syntactic sugar.\n\n### Migration table\n\n| Builder call | Replacement |\n|---|---|\n| `FullCalendarBuilder.create().build()` | `new FullCalendar()` |\n| `.withScheduler().build()` | `new FullCalendarScheduler()` |\n| `.withScheduler(key).build()` | `new FullCalendarScheduler()` + `setOption(Option.SCHEDULER_LICENSE_KEY, key)` |\n| `.withInitialOptions(obj).build()` | `new FullCalendar(obj)` / `new FullCalendarScheduler(obj)` |\n| `.withEntryLimit(n).build()` | `new FullCalendar()` + `setOption(Option.MAX_ENTRIES_PER_DAY, n)` |\n| `.withEntryProvider(p).build()` | `new FullCalendar()` + `setEntryProvider(p)` |\n| `.withInitialEntries(entries).build()` | `new FullCalendar()` + `((InMemoryEntryProvider<Entry>) calendar.getEntryProvider()).addEntries(entries)` — see caveat below |\n| `.withInitialView(view).build()` | `new FullCalendar()` + `setOption(Option.INITIAL_VIEW, view.getClientSideValue())` |\n| `.withLocale(l).build()` / `.withTimezone(t).build()` / `.withBusinessHours(h).build()` | `new FullCalendar()` + `setLocale(l)` / `setTimezone(t)` / `setBusinessHours(h)` |\n| `.withDirection(d).build()` | `new FullCalendar()` + `setOption(Option.DIRECTION, d.getClientSideValue())` |\n| `.withAutoBrowserTimezone().build()` | `new FullCalendar()` + `addBrowserTimezoneObtainedListener(e -> calendar.setTimezone(e.getTimezone()))` |\n| `.withAutoBrowserLocale().build()` | `new FullCalendar()` + `setLocale(UI.getCurrent().getLocale())` (after UI is available) |\n| `.withCustomCalendarViews(views).build()` | `new FullCalendar()` + `setCustomCalendarViews(views)` |\n| `.withCustomType(Cls.class).build()` | `new Cls()` — the builder previously instantiated a user-provided `FullCalendar` subclass via reflection; direct construction is simpler |\n\n**Caveats:**\n\n- *`withInitialEntries` replacement assumes the default in-memory entry provider is still in place.* A fresh `new FullCalendar()` ships with an `InMemoryEntryProvider`, so the cast is safe. Only call this before switching to a different provider — otherwise the cast will fail at runtime.\n- *`withInitialView` replacement uses the new `Option.INITIAL_VIEW` constant, added in 7.2 after verifying that FullCalendar 6.1.20 applies the `initialView` option correctly on first render (earlier FC versions needed an attach-listener + `changeView()` workaround, which is why the pre-7.2 builder carried it). The option takes the FC view key as a String; pass `view.getClientSideValue()` on any `CalendarView` — typically a `CalendarViewImpl` enum constant like `TIME_GRID_WEEK`. Example:*\n  ```java\n  FullCalendar calendar = new FullCalendar();\n  calendar.setOption(Option.INITIAL_VIEW, CalendarViewImpl.TIME_GRID_WEEK.getClientSideValue());\n  ```\n\n### Example\n\n```java\n// Old (7.1)\nFullCalendarScheduler scheduler = (FullCalendarScheduler) FullCalendarBuilder.create()\n    .withScheduler(licenseKey)\n    .withEntryLimit(5)\n    .withLocale(Locale.GERMAN)\n    .build();\n```\n\n```java\n// New (7.2)\nFullCalendarScheduler scheduler = new FullCalendarScheduler();\nscheduler.setOption(Option.SCHEDULER_LICENSE_KEY, licenseKey);\nscheduler.setOption(Option.MAX_ENTRIES_PER_DAY, 5);\nscheduler.setLocale(Locale.GERMAN);\n```\n\nDeprecated methods still work in 7.2.x. Migration is recommended but not urgent.\n\n## Also deprecated in 7.2.0\n\n- **`FullCalendar(int entryLimit)` and `FullCalendarScheduler(int entryLimit)` constructors** — replaced by `new FullCalendar()` + `setOption(Option.MAX_ENTRIES_PER_DAY, n)`.\n- **`Delta.getYears()` and `Delta.getMonths()`** — deprecated (see #191). FullCalendar JS normalises any year/month span into `days` before emitting the delta, so both always return zero for drop/resize events. Use `delta.getDays()` plus the time components. No behaviour change.\n- **`EntryDataEvent.createCopyBasedOnChanges()`** — renamed to `getChangesAsEntry()` for clarity. The old name still works and delegates to the new method; no behaviour change.\n  ```java\n  // 7.1\n  Entry copy = event.createCopyBasedOnChanges();\n  // 7.2\n  Entry copy = event.getChangesAsEntry();\n  ```\n",
      "category": "docs",
      "tags": [
        "migration-guide-7.1-to-7.2",
        "nosuchmethoderror",
        "entrydataevent",
        "entry",
        "popover",
        "fullcalendarbuilder",
        "fullcalendar",
        "fullcalendarscheduler",
        "inmemoryentryprovider",
        "calendarview",
        "calendarviewimpl",
        "migration",
        "upgrade",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "migration-guides",
      "title": "Migration-guides",
      "path": "Migration-guides.md",
      "content": "We know that migrations suck. Not only developers fear the appearance of a new major version but also every\nproduct or project manager of an application, that uses 3rd party software, knows, that it can be a stressful and time consuming horror to\nintegrate a new major version.\n\nUnfortunately this applies also for this addon. There will be breaking changes here and there, that requires you to get back\ninto your code and review everything. Nevertheless, we hope, that this migration guide helps you as good as possible\nto get a detailed insight of what has changed and what needs to be done to get you back on track.\n\nIf we missed something or anything is unclear, please ping us on GitHub. We hope, that your upgrade goes through\nas smoothly as possible.\n\n## Upgrading within 7.x\n\n- [7.1 → 7.2](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-7.1-to-7.2) — client-side entry IDs (#202), auto-revert (#225), `FullCalendarBuilder` deprecation (#232), `Entry.setEditable` binary-compat caveat (#212), `Delta.getYears/getMonths` deprecation (#191), `createCopyBasedOnChanges` → `getChangesAsEntry` rename\n\n\n## Upgrading to v7 / Vaadin 25\n\n- [v6.x → v7.x](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-6.x-to-7.x) — Vaadin 24 to 25. Includes a 6 ↔ 7 version mapping table so you can jump to the v7 release with the same feature set you have today.\n\n## Upgrading within 6.x\n\n- [6.4 → 6.5](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-6.4-to-6.5) — backport of the 7.2 feature set (auto-revert, client-side entry IDs, `FullCalendarBuilder` deprecation, `setEditable` binary-compat caveat, Delta / `createCopyBasedOnChanges` deprecations) to Vaadin 24 / Java 17 / elemental JSON\n- [6.3 → 6.4](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-6.3-to-6.4) — Vaadin 14 to 24.10 plus v7 feature backports. If your target is v7, do this hop first and then continue via the [v6.x → v7.x](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-6.x-to-7.x) guide.\n\n## Older upgrades\n\n- [4.1 → 6.0](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-4.1-to-6.0) — Polymer removal, light DOM, TypeScript\n- [4.0 → 4.1](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-4.0-to-4.1) — introduction of `EntryProvider`\n- [3.x → 4.0](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-3.x-to-4.0) — UTC-based times, `JsonItem`, timezone handling\n",
      "category": "docs",
      "tags": [
        "migration-guides",
        "fullcalendarbuilder",
        "entryprovider",
        "jsonitem",
        "migration",
        "upgrade",
        "entry",
        "event"
      ]
    },
    {
      "id": "release-notes-4.0.x",
      "title": "Release notes for 4.0",
      "path": "Release-Notes-4.0.x.md",
      "content": "# Release notes for 4.0\nThis page gives you an overview of the major changes, that came with the release of [FullCalendar for Flow, version 4.0](https://vaadin.com/directory/component/full-calendar-flow).\n\nIf you are going to update from 3.x, please also have a look into the [migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-MigrationGuides#migrating-from-3x--40).\n\nIf you are new to the FullCalendar or want to see, what might have changed in code, please visit our [examples](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples).\n\n# New base type JsonItem for calendar items\nWith this major version we introduced a new based type for calendar items (e.g. `Entry`). JsonItem provides a dynamic property approach, that allows defining properties via keys. Those keys provide details and rules for the automatic conversion of items from and to json.\n\nCurrently the Entry and it's subclasses implement JsonItem. Other implementations will follow in future.\n\nSee the [examples page](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples#use-the-low-level-jsonitem-api-to-modify-a-calendar-item) for some details.\n\n# Date Time communication changed to UTC based \n\nWhile internally entries stored time values as UTC already beforehand, the communication was always based on the calendar's timezone. This led to the issue, that on a timezone change, the entries had to be resent. While this might be no problem for some use cases, other scenarios could lead to a freezing UI, when having many entries and switching the timezone.\n\nTo improve the performance here and unify the transport of times, we decided to introduce this breaking change and let the communication always be UTC based.\n\nThis means also, that custom timezones for Entries are not supported anymore as they have been before. If you used that feature, you may need to catch that missing feature in your edit forms and displayment. We apologize for that inconvenience.\n\nAlso the behavior of all day entries regarding timezones has changed. All day entries are now no longer affected by timezones.\n\nPlease see the [migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-MigrationGuides#migrating-from-3x--40) for more details.\n\n# Changed entry data is now sent at once\nIn 3.x the server instance did not check, if you already sent some data to the client. Instead, it fired a java script call for every entry CRUD call. This means, that for instance calling `addEntry()` 20 times, the server called the respective client side api 20 times and also the calendar hat to rerender 20 times. \n\nStarting with 4.0.x those server side data changes are collected internally and sent at once. This means, you can call the CRUD api as often as you want in a request - there will only be one call on the client side (or to be more concrete maximal 3  one for add, update and remove respectively - this may be also change in future for a more optimal handling).\n\n# Custom properties on the client side\n\nWhen you customize the entry content via setEntryContent or setEntryDidMount, you may now access custom properties via a dedicated getter instead of traversing through multiple properties.\n\nSee the [example page](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples#customize-the-entry-content) for details.\n\n# Recurrence\nThere are minor changes to recurrence, that most likely will need your attention regarding compiler issues. See [this chapter](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-MigrationGuides#recurrence) for details.\n\n- renamed several methods\n- recurrence has some changes regarding enable recurrence and timezones\n\n# Other\nSome methods have become deprecated. Please check the compiler warnings and try to replace them soon.",
      "category": "docs",
      "tags": [
        "release-notes-4.0.x",
        "entry",
        "migration",
        "upgrade",
        "event"
      ]
    },
    {
      "id": "release-notes-4.1.x",
      "title": "Release notes for 4.1",
      "path": "Release-Notes-4.1.x.md",
      "content": "# Release notes for 4.1\nThis page gives you an overview of the major changes, that came with the release of [FullCalendar for Flow, version 4.1](https://vaadin.com/directory/component/full-calendar-flow).\n\nPlease also have a look on our [migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-MigrationGuides#migrating-from-40--41) and our [examples](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples).\n\n## Entry Provider\nWith 4.1 we introduced a new way of providing calendar items. Up to now the official supported way was to register all known entries to the server side, which itself would push it then to the client. This means that both, the server and the client, needed to keep all the data in memory. \n\nWith the newly introduces `EntryProvider` we provide a way of providing entries similar to the common Vaadin `DataProvider`. When using an `EntryProvider`, the client will control via parameters, which entries are to be fetched to the client. The server on the otherside only needs to create and provide the entries, that are requested. \n\n### In memory variants\nOf course, it is up to the server side, how and when the entries are created. Beside the base interface we also introduced the sub interface `InMemoryEntryProvider`, which comes in two pre-implemented variants\n* EagerInMemoryEntryProvider\n* LazyInMemoryEntryProvider\n\nThe eager variant is an exception to the above described behavior of the `EntryProvider`. While it implements the `EntryProvider` interface, it behaves like the old way the FullCalendar transported entries to the client: it pushes them itself. So if you still want to have all entries on the client available at any time (e. g. when your application operats in a scope with a slow network access), you can use this instance. \n\nThe lazy variant is a mixture between the old and the new way. It acts a bit like the common `ListDataProvider`, where all known entries are cached on the server side, but only the necessary ones are fetched from the client. \n\n### Initial EntryProvider on FullCalendar\nWith this update the FullCalendar itself does not cache any entries directly, but uses an `EntryProvider` for all cases. A new FullCalendar is initialized with an instance of the `EagerInMemoryEntryProvider`. This shall prevent any breaking changes for updating applications. Yet we recommend to change to a different `EntryProvider` due to the advantages of fetching only the necessary entries.\n\n### Entry CRUD operations on FullCalendar\nAll entry CRUD operations (e. g. `addEntries()`) are therefore delegated to the calendar's provider, when that provider supports those methods. For that, the provider has to be at least an `InMemoryEntryProvider`. If you want to use the `update` api, it needs to be the `EagerInMemoryEntryProvider`, since for the lazy variant the update api is not necessary any more as updating the client side is handled by the `refresh` api.\n\nBe aware, that any calls to the CRUD operations will lead to an exception, if you don't use the correct data provider. \n\n### Callback Entry Provider\nFor easy integration of using a callback based variant we introduced the `CallbackEntryProvider`. You can simply create an instance by calling `EntryProvider.fromCallbacks()`.\n\n### Custom implemenation\nIf none of the predefined variants fits your needs, you are of course free to implement your own version. In that case we recommend to extend the `AbstractEntryProvider` as a starting point.\n\n## Info on missing offset api for recurrence\nWith 4.0.x the date time api for entries has changed. You might have seen, that the recurring start / end time variants do not provide an offset variant. This is due to an [issue in the native FullCalendar library](https://github.com/fullcalendar/fullcalendar/issues/5273). As soon as the issue has been fixed, we try to add the respective api.\n\n## Deprecation\nSome methods have become deprecated, especially the CRUD operations in the `FullCalendar`. We recommend to replace them with the respective replacements, since they might be removed with the next major release.\n\n\n ",
      "category": "docs",
      "tags": [
        "release-notes-4.1.x",
        "entryprovider",
        "dataprovider",
        "inmemoryentryprovider",
        "listdataprovider",
        "eagerinmemoryentryprovider",
        "callbackentryprovider",
        "abstractentryprovider",
        "fullcalendar",
        "migration",
        "upgrade",
        "entry",
        "event"
      ]
    },
    {
      "id": "release-notes-6.1.x",
      "title": "Release notes for 6.1",
      "path": "Release-Notes-6.1.x.md",
      "content": "# Release notes for 6.1\n\nWith 6.1, the (for now experimental) Lumo theme has been added to the addon. This theme slightly changes\nthe appearance of the calendar to align more with other Vaadin components' Lumo styles.\n\nTo use it, simply apply the respective theme variant to your calendar instance. It also works with custom\nsubclasses of the calendar. Please be aware, that changing Lumo variables or overriding FC styles also affect\nthis theme.\n\n```java\ncalendar.addThemeVariant(FullCalendarVariant.LUMO);\n```\n\nMajor changes:\n* the today marker is now shown as a badge instead of having a background color\n* header font sizes reduced\n* selection colors aligned with Grid selection\n* using the lumo prime color as the default color for events (that have no own color); the default color of background events is not changed at the moment\n* applying several other lumo colors, sizes and spaces to different parts of the calendar\n ",
      "category": "docs",
      "tags": [
        "release-notes-6.1.x"
      ]
    },
    {
      "id": "release-notes-6.2.x",
      "title": "Release notes for 6.2",
      "path": "Release-Notes-6.2.x.md",
      "content": "# Release notes for 6.2\n\nWith 6.2 custom native event handlers for entries have been added. These allow you to setup JavaScript events for\neach entry, e.g. a mouse over event handler. Inside these event handlers you may also access the created entry dom\nelement.\n\nCustom native event handlers are added to the FullCalender object. They will then be applied to each created\nentry object (using the entryDidMount callback).\n\nTo add an event handler, simply call the method `addEntryNativeEventListener` on the calendar. The first parameter\nis the JavaScript event name (e.g. \"mouseover\"), the second parameter is the callback, that shall be used for\nthat event. Please be aware, that we do NOT check or sanitize the given JavaScript. It is up to you to prevent\nmalicious code from being sent to your users.\n\nInside the event callback, you may access the entryDidMount argument object, that contains additional information\nabout the current entry. See the official docs (https://fullcalendar.io/docs/event-render-hooks) \nfor more details about which details it provide.\n\n```java\nFullCalendar calendar = new FullCalendar();\n\n// ... other configurations\n\n// write the js event, the current entry info and the current entry's element to the browser console.\ncalendar.addEntryNativeEventListener(\"mouseover\", \"e => console.warn(e, info.event, info.el)\");\n\nadd(calendar);\n```\n\nPlease be aware, that due to the design of the used library, these event handlers have to be setup before the\ncalendar is initialized on the client side.\n\nYou can combine the event handlers with a custom entryDidMount callback, if you want additional customizations\nof the entries. The FC will take care of combining the event handlers and you EDM callback",
      "category": "docs",
      "tags": [
        "release-notes-6.2.x",
        "entry",
        "event"
      ]
    },
    {
      "id": "release-notes-4.0",
      "title": "New base type JsonItem for calendar items",
      "path": "Release-notes-4.0.md",
      "content": "This page gives you an overview of the major changes, that came with the release of [FullCalendar for Flow, version 4.0](https://vaadin.com/directory/component/full-calendar-flow).\n\nIf you are going to update from 3.x, please also have a look into the [migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-MigrationGuides#migrating-from-3x--40).\n\nIf you are new to the FullCalendar or want to see, what might have changed in code, please visit our [examples](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples).\n\n# New base type JsonItem for calendar items\nWith this major version we introduced a new based type for calendar items (e.g. `Entry`). JsonItem provides a dynamic property approach, that allows defining properties via keys. Those keys provide details and rules for the automatic conversion of items from and to json.\n\nCurrently the Entry and it's subclasses implement JsonItem. Other implementations will follow in future.\n\nSee the [examples page](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples#use-the-low-level-jsonitem-api-to-modify-a-calendar-item) for some details.\n\n# Date Time communication changed to UTC based\n\nWhile internally entries stored time values as UTC already beforehand, the communication was always based on the calendar's timezone. This led to the issue, that on a timezone change, the entries had to be resent. While this might be no problem for some use cases, other scenarios could lead to a freezing UI, when having many entries and switching the timezone.\n\nTo improve the performance here and unify the transport of times, we decided to introduce this breaking change and let the communication always be UTC based.\n\nThis means also, that custom timezones for Entries are not supported anymore as they have been before. If you used that feature, you may need to catch that missing feature in your edit forms and displayment. We apologize for that inconvenience.\n\nAlso the behavior of all day entries regarding timezones has changed. All day entries are now no longer affected by timezones.\n\nPlease see the [migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-MigrationGuides#migrating-from-3x--40) for more details.\n\n# Changed entry data is now sent at once\nIn 3.x the server instance did not check, if you already sent some data to the client. Instead, it fired a java script call for every entry CRUD call. This means, that for instance calling `addEntry()` 20 times, the server called the respective client side api 20 times and also the calendar hat to rerender 20 times.\n\nStarting with 4.0.x those server side data changes are collected internally and sent at once. This means, you can call the CRUD api as often as you want in a request - there will only be one call on the client side (or to be more concrete maximal 3  one for add, update and remove respectively - this may be also change in future for a more optimal handling).\n\n# Custom properties on the client side\n\nWhen you customize the entry content via setEntryContent or setEntryDidMount, you may now access custom properties via a dedicated getter instead of traversing through multiple properties.\n\nSee the [example page](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples#customize-the-entry-content) for details.\n\n# Recurrence\nThere are minor changes to recurrence, that most likely will need your attention regarding compiler issues. See [this chapter](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-MigrationGuides#recurrence) for details.\n\n- renamed several methods\n- recurrence has some changes regarding enable recurrence and timezones\n\n# Other\nSome methods have become deprecated. Please check the compiler warnings and try to replace them soon.",
      "category": "docs",
      "tags": [
        "release-notes-4.0",
        "entry",
        "migration",
        "upgrade",
        "event"
      ]
    },
    {
      "id": "release-notes-4.1",
      "title": "Release-notes-4.1",
      "path": "Release-notes-4.1.md",
      "content": "This page gives you an overview of the major changes, that came with the release of [FullCalendar for Flow, version 4.1](https://vaadin.com/directory/component/full-calendar-flow).\n\nPlease also have a look on our [migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-MigrationGuides#migrating-from-40--41) and our [examples](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Examples).\n\n## Entry Provider\nWith 4.1 we introduced a new way of providing calendar items. Up to now the official supported way was to register all known entries to the server side, which itself would push it then to the client. This means that both, the server and the client, needed to keep all the data in memory.\n\nWith the newly introduces `EntryProvider` we provide a way of providing entries similar to the common Vaadin `DataProvider`. When using an `EntryProvider`, the client will control via parameters, which entries are to be fetched to the client. The server on the otherside only needs to create and provide the entries, that are requested.\n\n### In memory variants\nOf course, it is up to the server side, how and when the entries are created. Beside the base interface we also introduced the sub interface `InMemoryEntryProvider`, which comes in two pre-implemented variants\n* EagerInMemoryEntryProvider\n* LazyInMemoryEntryProvider\n\nThe eager variant is an exception to the above described behavior of the `EntryProvider`. While it implements the `EntryProvider` interface, it behaves like the old way the FullCalendar transported entries to the client: it pushes them itself. So if you still want to have all entries on the client available at any time (e. g. when your application operats in a scope with a slow network access), you can use this instance.\n\nThe lazy variant is a mixture between the old and the new way. It acts a bit like the common `ListDataProvider`, where all known entries are cached on the server side, but only the necessary ones are fetched from the client.\n\n### Initial EntryProvider on FullCalendar\nWith this update the FullCalendar itself does not cache any entries directly, but uses an `EntryProvider` for all cases. A new FullCalendar is initialized with an instance of the `EagerInMemoryEntryProvider`. This shall prevent any breaking changes for updating applications. Yet we recommend to change to a different `EntryProvider` due to the advantages of fetching only the necessary entries.\n\n### Entry CRUD operations on FullCalendar\nAll entry CRUD operations (e. g. `addEntries()`) are therefore delegated to the calendar's provider, when that provider supports those methods. For that, the provider has to be at least an `InMemoryEntryProvider`. If you want to use the `update` api, it needs to be the `EagerInMemoryEntryProvider`, since for the lazy variant the update api is not necessary any more as updating the client side is handled by the `refresh` api.\n\nBe aware, that any calls to the CRUD operations will lead to an exception, if you don't use the correct data provider.\n\n### Callback Entry Provider\nFor easy integration of using a callback based variant we introduced the `CallbackEntryProvider`. You can simply create an instance by calling `EntryProvider.fromCallbacks()`.\n\n### Custom implemenation\nIf none of the predefined variants fits your needs, you are of course free to implement your own version. In that case we recommend to extend the `AbstractEntryProvider` as a starting point.\n\n## Info on missing offset api for recurrence\nWith 4.0.x the date time api for entries has changed. You might have seen, that the recurring start / end time variants do not provide an offset variant. This is due to an [issue in the native FullCalendar library](https://github.com/fullcalendar/fullcalendar/issues/5273). As soon as the issue has been fixed, we try to add the respective api.\n\n## Deprecation\nSome methods have become deprecated, especially the CRUD operations in the `FullCalendar`. We recommend to replace them with the respective replacements, since they might be removed with the next major release.\n\n\n ",
      "category": "docs",
      "tags": [
        "release-notes-4.1",
        "entryprovider",
        "dataprovider",
        "inmemoryentryprovider",
        "listdataprovider",
        "eagerinmemoryentryprovider",
        "callbackentryprovider",
        "abstractentryprovider",
        "fullcalendar",
        "migration",
        "upgrade",
        "entry",
        "event"
      ]
    },
    {
      "id": "release-notes-6.0",
      "title": "Release-notes-6.0",
      "path": "Release-notes-6.0.md",
      "content": "Nothing to see here, check migration page for 6.0.",
      "category": "docs",
      "tags": [
        "release-notes-6.0",
        "migration",
        "upgrade"
      ]
    },
    {
      "id": "release-notes-6.1",
      "title": "Release-notes-6.1",
      "path": "Release-notes-6.1.md",
      "content": "With 6.1, the (for now experimental) Lumo theme has been added to the addon. This theme slightly changes\nthe appearance of the calendar to align more with other Vaadin components' Lumo styles.\n\nTo use it, simply apply the respective theme variant to your calendar instance. It also works with custom\nsubclasses of the calendar. Please be aware, that changing Lumo variables or overriding FC styles also affect\nthis theme.\n\n```java\ncalendar.addThemeVariant(FullCalendarVariant.LUMO);\n```\n\nMajor changes:\n* the today marker is now shown as a badge instead of having a background color\n* header font sizes reduced\n* selection colors aligned with Grid selection\n* using the lumo prime color as the default color for events (that have no own color); the default color of background events is not changed at the moment\n* applying several other lumo colors, sizes and spaces to different parts of the calendar",
      "category": "docs",
      "tags": [
        "release-notes-6.1"
      ]
    },
    {
      "id": "release-notes-6.2",
      "title": "Release-notes-6.2",
      "path": "Release-notes-6.2.md",
      "content": "With 6.2 custom native event handlers for entries have been added. These allow you to setup JavaScript events for\neach entry, e.g. a mouse over event handler. Inside these event handlers you may also access the created entry dom\nelement.\n\nCustom native event handlers are added to the FullCalender object. They will then be applied to each created\nentry object (using the entryDidMount callback).\n\nTo add an event handler, simply call the method `addEntryNativeEventListener` on the calendar. The first parameter\nis the JavaScript event name (e.g. \"mouseover\"), the second parameter is the callback, that shall be used for\nthat event. Please be aware, that we do NOT check or sanitize the given JavaScript. It is up to you to prevent\nmalicious code from being sent to your users.\n\nInside the event callback, you may access the entryDidMount argument object, that contains additional information\nabout the current entry. See the official docs (https://fullcalendar.io/docs/event-render-hooks) \nfor more details about which details it provide.\n\n```java\nFullCalendar calendar = new FullCalendar();\n\n// ... other configurations\n\n// write the js event, the current entry info and the current entry's element to the browser console.\ncalendar.addEntryNativeEventListener(\"mouseover\", \"e => console.warn(e, info.event, info.el)\");\n\nadd(calendar);\n```\n\nPlease be aware, that due to the design of the used library, these event handlers have to be setup before the\ncalendar is initialized on the client side.\n\nYou can combine the event handlers with a custom entryDidMount callback, if you want additional customizations\nof the entries. The FC will take care of combining the event handlers and your EDM callback",
      "category": "docs",
      "tags": [
        "release-notes-6.2",
        "entry",
        "event"
      ]
    },
    {
      "id": "release-notes-6.4",
      "title": "FullCalendar Addon 6.4.0 Release Notes",
      "path": "Release-notes-6.4.md",
      "content": "# FullCalendar Addon 6.4.0 Release Notes\n\nVersion 6.4.0 represents a significant platform modernization and feature expansion of the FullCalendar addon. This release bridges the gap for Vaadin 24 users who cannot yet migrate to Vaadin 25, while bringing a comprehensive set of v7 features to the v6 codebase.\n\n## Platform Upgrade\n\n### Vaadin 14 → Vaadin 24.10\n\nThe addon has been upgraded from Vaadin 14 (LTS) to Vaadin 24.10.x. This is a major platform shift that modernizes the underlying component framework.\n\n- **Java version**: Requires Java 17+ (upgraded from Java 8)\n- **Polymer removal**: Vaadin 14's Polymer 3 has been replaced with plain HTML Element-based web components (already completed in v6.0)\n- **Vaadin Flow**: Updated to Vaadin Flow 24.10.x with all associated ecosystem updates\n\n> **Breaking Change**: This version requires **Vaadin 24.10**. Vaadin 14 LTS is no longer supported.\n\n## Entry Model Enhancements\n\n### New Entry Fields\n\nThe `Entry` class now includes several new properties backported from v7:\n\n| Field | Type | Purpose |\n|-------|------|---------|\n| `url` | String | Hyperlink for the entry; integrated into entry rendering |\n| `interactive` | Boolean | Controls whether the entry is interactive (draggable, resizable) |\n| `overlap` | Boolean | **Breaking change** — now `Boolean` (nullable) instead of `boolean` primitive; use getters carefully |\n| `recurringDuration` | String | For recurring entries, controls the duration of recurrence windows independently of event duration |\n\n### Recurrence Rule Support (RFC 5545 — RRULE)\n\nVersion 6.4 introduces full RFC 5545 recurrence rule support via the new `RRule` class:\n\n```java\nEntry event = new Entry(\"Team Meeting\");\nevent.setStart(LocalDateTime.of(2025, 3, 24, 10, 0));\nevent.setEnd(LocalDateTime.of(2025, 3, 24, 11, 0));\n\n// Weekly meetings, Monday and Friday, until end of April\nRRule rule = RRule.weekly()\n    .byWeekday(DayOfWeek.MONDAY, DayOfWeek.FRIDAY)\n    .until(LocalDate.of(2025, 4, 30));\n\nevent.setRRule(rule);\ncalendar.getEntryProvider().asInMemory().addEntry(event);\n```\n\n**Key Features**:\n- Structured form (recommended): Set frequency and properties like `byWeekday`, `until`, `count`, etc.\n- Raw RRULE string: For importing from external sources (e.g., iCalendar exports): `RRule.ofRaw(\"FREQ=WEEKLY;BYDAY=MO,FR\")`\n- Exclusions: Use `excludeDates()` or `excludeRules()` to define exception dates or patterns\n- Mutually exclusive with legacy recurrence fields (`recurringDaysOfWeek`, `recurringStartDate`, etc.)\n\nThe `@fullcalendar/rrule` npm package is automatically bundled and loaded.\n\n### Nullable Overlap Property\n\nThe `overlap` field's type has changed from `boolean` to `Boolean`:\n\n```java\nentry.setOverlap(true);      // supported\nentry.setOverlap(null);      // now allowed\nBoolean val = entry.getOverlap();  // returns null if not set\n```\n\nRecompilation is required. Be careful when reading the value — `null` is now a distinct state from `false`.\n\n## JsCallback System (Type-Safe Client-Side Callbacks)\n\nVersion 6.4 introduces the `JsCallback` wrapper for client-side event handlers, replacing raw string-based callback injection:\n\n```java\n// New (6.4+): type-safe wrapper\ncalendar.setOption(Option.ENTRY_DID_MOUNT,\n    JsCallback.of(\"function(info) { info.el.title = info.event.title; }\"));\n\n// Clear a callback\ncalendar.setOption(Option.ENTRY_DID_MOUNT, JsCallback.clearCallback());\n```\n\nThis replaces the previous `setEntryDidMountCallback(String)` pattern. The `JsCallback.of()` factory method wraps a JavaScript function string for safe transport to the client, where it is evaluated via `new Function()`.\n\n## FullCalendar JavaScript Library Updates\n\nThe bundled FullCalendar JavaScript library has been upgraded from **6.1.9 to 6.1.20**, bringing:\n- Bug fixes and performance improvements\n- Enhanced compatibility with modern browser APIs\n- Better internationalization support\n\n## Event Classes and DOM Event Integration\n\nEleven new event classes have been added to support additional user interactions:\n\n| Event Class | Purpose |\n|-------------|---------|\n| `EntryDragStartEvent` | Fired when user begins dragging an entry |\n| `EntryDragStopEvent` | Fired when user completes or cancels a drag operation |\n| `EntryResizeStartEvent` | Fired when user begins resizing an entry |\n| `EntryResizeStopEvent` | Fired when user completes or cancels a resize operation |\n| `DropEvent` | Fired when content is dropped from outside the calendar |\n| `EntryReceiveEvent` | Fired when an entry is received from an external source |\n| `ExternalEntryDroppedEvent` | Fired when an external entry is dropped on the calendar |\n| `ExternalEntryResizedEvent` | Fired when an external entry is resized |\n| `ExternalEntryEvent` | Base class for external entry events |\n| `TimeslotsUnselectEvent` | Fired when a selection is cleared |\n| `EntryTimeChangedEvent` | Fired when an entry's time is changed |\n\nThese events integrate native browser DOM events with the FullCalendar backend, allowing precise control over drag, resize, and drop behaviors.\n\n## New Option Enum Constants\n\nA large number of new `Option` enum constants have been added for advanced customization. See the `Option` enum Javadoc for the complete list.\n\n- **Render hooks**: `ENTRY_CONTENT`, `ENTRY_DID_MOUNT`, `DAY_CELL_CONTENT`, `SLOT_LABEL_CONTENT`, etc.\n- **Interaction handlers**: `SELECT_CONSTRAINT`, `SELECT_ALLOW`, `SELECT_OVERLAP`, etc.\n- **Display configuration**: `SLOT_LABEL_FORMAT`, `ENTRY_TIME_FORMAT`, `BUSINESS_HOURS`, etc.\n\nThese options map directly to FullCalendar's JavaScript API and allow fine-grained control over rendering and behavior without requiring custom JavaScript.\n\n## Client-Side Event Sources\n\nThree new event source types enable fetching calendar entries from external systems:\n\n| Source Type | Purpose |\n|-------------|---------|\n| **Google Calendar** | Load events directly from Google Calendar feeds |\n| **iCalendar (ICS)** | Import .ics files and feed URLs |\n| **JSON Feed** | Load custom event feeds from URLs or APIs |\n\nThese are automatically integrated with the `@fullcalendar/google-calendar`, `@fullcalendar/icalendar`, and `@fullcalendar/core` packages.\n\n```java\n// Set a global API key (applies to all Google Calendar sources)\ncalendar.setOption(Option.EXTERNAL_EVENT_SOURCE_GOOGLE_CALENDAR_API_KEY, \"AIzaSy...\");\n\n// Add a Google Calendar event source\ncalendar.addClientSideEventSource(new GoogleCalendarEventSource(\"holidays@group.calendar.google.com\")\n    .withId(\"holidays\")\n    .withColor(\"green\"));\n```\n\n## Scheduler Extensions\n\n### ComponentResourceAreaColumn\n\nThe scheduler component now supports Vaadin components directly in resource area columns:\n\n```java\nFullCalendarScheduler scheduler = new FullCalendarScheduler();\nComponentResourceAreaColumn column = new ComponentResourceAreaColumn(\n    resource -> new Button(\"Edit \" + resource.getTitle(),\n        e -> editResource(resource))\n);\nscheduler.setResourceAreaColumns(List.of(column));\n```\n\n### ResourceAreaColumn Configuration\n\nA new `ResourceAreaColumn` configuration class provides declarative control over scheduler resource area styling and layout.\n\n## Draggable API\n\nNew server-side `Draggable` class for making external Vaadin components draggable onto the calendar,\nreplacing the previous manual JS initialization approach.\n\n- `new Draggable(component)` — wrap any Vaadin component to make it draggable\n- `new Draggable(component, entry)` — include entry data that FC uses to create a calendar entry on drop\n- `withItemSelector(String)` — container mode: only children matching the CSS selector are draggable\n- `withEventDataCallback(JsCallback)` — dynamically create entry data from the dragged element via JS\n- `calendar.addDraggable(draggable)` — register on a calendar; returns `Registration` for cleanup\n- `EntryReceiveEvent.getDraggable()` — access the original Draggable from the entry receive listener\n- `DropEvent.getDraggable()` — access the Draggable from the drop listener\n\nThe `Draggable` lifecycle is fully managed: re-initialization on reattach, cleanup of JS listeners\non deregistration and disconnect.\n\n## Performance Improvements\n\n### Bounded Entry Cache\n\nThe in-memory entry provider now applies an internal size bound to prevent unbounded memory growth. This is handled automatically and requires no configuration change. No new API was added.\n\n### Thread-Safe Refresh Operations\n\nEntry provider refresh operations are now fully thread-safe, allowing background processes to update the calendar without synchronization overhead.\n\n### BeanProperties Converter Caching\n\nConversion overhead for Entry serialization has been reduced via reflection-based caching of property accessors, improving responsiveness during calendar interaction.\n\n## Dependencies\n\n### New NPM Packages (Automatic)\n\nThe following npm packages are now automatically bundled and loaded:\n\n- `@fullcalendar/rrule` — RFC 5545 recurrence rules\n- `@fullcalendar/google-calendar` — Google Calendar integration\n- `@fullcalendar/icalendar` — iCalendar (ICS) support\n- `ical.js` — ICS file parsing\n\nThese are included in the build automatically; **no manual npm installation required**.\n\n## Deprecated Functionality\n\nApproximately 30 convenience methods have been deprecated in favor of the unified `setOption()` API. Examples:\n\n```java\n// Deprecated (still works)\ncalendar.setFirstDay(DayOfWeek.MONDAY);\n\n// Preferred (v6.4+)\ncalendar.setOption(Option.FIRST_DAY, DayOfWeek.MONDAY);\n```\n\nDeprecated methods remain functional but log warnings if invoked. They will be removed in a future major version.\n\nSee the Migration Guide for a complete list of deprecated methods and their replacements.\n\n## What's NOT Included\n\nThe following v7 features are **not** backported to v6.4:\n\n- **Aura Theme variant** — The Aura theme (introduced in Vaadin 25) is not available. The Lumo-based `full-calendar-theme-vaadin.css` is included and works with Vaadin 24.\n- **Jackson JSON** — The addon continues to use `elemental.json` (Vaadin's built-in JSON library) for compatibility\n- **Java 21+ Language Features** — Code remains Java 17-compatible; no records, pattern matching, or sealed classes\n\n## Upgrade Path\n\n| Current Version | Recommended Action |\n|-----------------|-------------------|\n| v6.3.x | Review Migration Guide, update Maven dependency, recompile |\n| v6.2.x or earlier | Review full v6.0 migration guide first, then v6.3→6.4 |\n| v5.x or earlier | Not recommended; consider v7.x instead |\n\n## Support\n\n- Documentation: See Migration Guide for step-by-step instructions\n- Issues: [GitHub Issues](https://github.com/stefanuebe/vaadin-fullcalendar/issues)\n- Demo: Clone the repository and run the demo app with Vaadin 24.10\n\n---\n\n*Release date: March 2026*\n*FullCalendar JS Library: 6.1.20*\n*Vaadin: 24.10.x*\n*Java: 17+*\n",
      "category": "docs",
      "tags": [
        "release-notes-6.4",
        "entry",
        "boolean",
        "rrule",
        "jscallback",
        "entrydragstartevent",
        "entrydragstopevent",
        "entryresizestartevent",
        "entryresizestopevent",
        "dropevent",
        "entryreceiveevent",
        "externalentrydroppedevent",
        "externalentryresizedevent",
        "externalentryevent",
        "timeslotsunselectevent",
        "entrytimechangedevent",
        "option",
        "resourceareacolumn",
        "draggable",
        "migration",
        "upgrade",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "release-notes-6.5",
      "title": "Release-notes-6.5",
      "path": "Release-notes-6.5.md",
      "content": "This page gives you an overview of the major changes that came with the release of\n[FullCalendar for Flow, version 6.5](https://vaadin.com/directory/component/full-calendar-flow).\n\n**Platform:** FullCalendar JS 6.1.20, Vaadin 24.9.x, Java 17, elemental JSON. 6.5 is a source-compatible minor release **backporting the 7.2 feature set** to the v6 line — designed for teams that want the 7.2 features without the Vaadin 25 / Java 21 upgrade. See the [migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-6.4-to-6.5) for the single binary-compat caveat and migration notes, or the [7.2 release notes](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-7.2) for the original v7-line release.\n\n## 6.5 or 7.x?\n\n- **Stay on 6.5** if you need to keep running on Vaadin 24 / Java 17 (e.g. your Vaadin licence, CI infrastructure, or dependent modules aren't ready to jump). 6.5 gives you the complete 7.2 feature set on that stack.\n- **Upgrade to 7.1/7.2** if you can move to Vaadin 25 / Java 21. That's the forward line; 6.x is maintenance-track.\n- 6.5 and 7.2 share the same feature set; the choice is about platform, not functionality.\n\n## Highlights\n\n- **[Client-side entry IDs](#client-side-entry-ids-provided-automatically-202)** — default on, no configuration needed.\n- **[Auto-revert for unapplied entry changes](#auto-revert-for-unapplied-entry-changes-225)** — default on; prevents server/client drift when a drop/resize listener rejects the change.\n- **[`FullCalendarBuilder` deprecated](#deprecated-fullcalendarbuilder-232)** — direct construction + `setOption(...)` is the forward path. No removal scheduled for 6.x.\n- Bug fixes for scheduler extended-prop updates ([#230](#schedulerupdateresource-now-propagates-extended-props-230)), scheduler timeline sizing ([#231](#scheduler-timeline-sizing-in-dense-resource-layouts-231)) and per-entry editable ([#212](#per-entry-editable-default-no-longer-overrides-calendar-level-editable-false-212)).\n\n## Client-Side Entry IDs Provided Automatically (#202)\n\nServer-side components such as `Popover` anchor to target elements via `document.getElementById`. Before 6.5, rendered calendar entries had no DOM `id`, so anchoring required a custom `eventDidMount` callback with JavaScript-side id generation.\n\nStarting with 6.5, `FullCalendar` assigns `id=\"entry-<entryId>\"` to the **start segment** of each rendered entry by default. The feature is controlled by `setAutoProvideEntryIdOnClient(boolean)`, which defaults to `true`.\n\n### Usage\n\n```java\n// Default on — nothing to configure.\nEntry meeting = new Entry(\"m-1\");\nmeeting.setTitle(\"Quarterly review\");\n// ...\n\n// Anchor a Popover to the rendered entry:\nPopover popover = new Popover();\npopover.setFor(\"entry-m-1\");\n```\n\nOpt-out:\n\n```java\ncalendar.setAutoProvideEntryIdOnClient(false);\n```\n\n### ID schema and uniqueness\n\n- **Single-day entry**, any view → `id=\"entry-<entryId>\"` on the single segment.\n- **Multi-day entry** (month/week view) → `id=\"entry-<entryId>\"` on the **start segment only**; continuation segments stay id-free so HTML id uniqueness is preserved.\n- **Scheduler, entry assigned to multiple resources** → to keep ids unique across the resource rows, the id is suffixed with the row's resource id: `id=\"entry-<entryId>-<resourceId>\"`. Entries that live in a single resource row get the plain `entry-<entryId>` schema.\n- **Drag-preview (\"mirror\") elements** during an ongoing drag are not tagged — the id stays on the real element.\n\n### Overriding the default\n\nIf you set your own `eventDidMount` callback via `setOption(Option.ENTRY_DID_MOUNT, JsCallback.of(...))`, the default snippet runs first and your callback runs afterwards, so reassigning `info.el.id` in your callback wins.\n\n```java\ncalendar.setOption(Option.ENTRY_DID_MOUNT, JsCallback.of(\n    \"function(info) { info.el.id = 'my-' + info.event.id; }\"));\n// Result: id='my-<entryId>' (your value, the default was overwritten)\n```\n\n### Notes\n\n- For anchoring to the exact segment a user clicked, prefer the element from the click event rather than `getElementById` — the click element always points at the clicked segment, even for multi-day entries whose id lives only on the start.\n- The feature relies on the `eventDidMount` render hook. If you replace that hook with a brace-less arrow expression (e.g. `\"info => info.el.title = info.event.title\"`), the default snippet is skipped to keep the output syntactically valid. Use a braced function body to keep the default id-assignment alongside your callback.\n\n## Auto-Revert for Unapplied Entry Changes (#225)\n\nWhen a user drags or resizes an entry, FullCalendar JS immediately moves the entry to its new position on the client. The server receives an `EntryDroppedEvent` or `EntryResizedEvent`. Previously, if the developer chose not to call `event.applyChangesOnEntry()` (e.g., after a validation failure), the client would keep showing the entry at the new position while the server still had the old data — an inconsistent state.\n\nStarting with 6.5, the calendar **automatically reverts** the client-side entry to its original position when `applyChangesOnEntry()` is not called. This is controlled by `setAutoRevertUnappliedEntryChanges(boolean)`, which defaults to `true`.\n\n### Usage\n\n```java\n// Auto-revert is enabled by default — no configuration needed.\n// Entries revert automatically when applyChangesOnEntry() is not called.\n\ncalendar.addEntryDroppedListener(event -> {\n    if (isDropAllowed(event)) {\n        event.applyChangesOnEntry();       // entry stays at new position\n        entryProvider.refreshItem(event.getEntry());\n    }\n    // If not called: entry reverts to original position on the client\n});\n```\n\nTo restore the previous behavior (client keeps the new position regardless):\n\n```java\ncalendar.setAutoRevertUnappliedEntryChanges(false);\n```\n\n### How It Works\n\n1. When a drop or resize occurs, the FullCalendar JS `revert()` function is captured on the client side.\n2. On the server, after all event listeners have been executed, a `beforeClientResponse` callback checks whether `applyChangesOnEntry()` was called.\n3. If not called (and auto-revert is enabled), the server sends a `revertEntry` command to the client, which triggers FullCalendar's native revert animation.\n4. If `applyChangesOnEntry()` was called, the pending revert is cleared — the entry stays at the new position.\n\n### Notes\n\n- Auto-revert works for `EntryDroppedEvent`, `EntryResizedEvent`, and `EntryDroppedSchedulerEvent`.\n- `ExternalEntryDroppedEvent` / `ExternalEntryResizedEvent` (from client-side event sources or draggable external DOM) do **not** participate in auto-revert — those flows create new entries on drop, so the server-side handler typically owns the accept/reject decision explicitly.\n- The revert uses FullCalendar's native revert mechanism, which provides a smooth animation back to the original position.\n- If you need to inspect the state from another listener or a downstream component, `EntryDataEvent#isChangesApplied()` returns whether `applyChangesOnEntry()` was called on this event — useful when multiple listeners are chained and a later one needs to know whether the earlier ones already accepted the change.\n\n## Deprecated: `FullCalendarBuilder` (#232)\n\n`FullCalendarBuilder` and all its `with...` methods are now `@Deprecated`. `FullCalendar` and `FullCalendarScheduler` can be constructed directly and configured through `setOption(Option, value)`; the builder no longer provides value beyond syntactic sugar. No removal is scheduled for 6.x — the class is slated for removal in a future major version.\n\n### Example\n\n```java\n// 6.4 — builder\nFullCalendarScheduler scheduler = (FullCalendarScheduler) FullCalendarBuilder.create()\n    .withScheduler(licenseKey)\n    .withEntryLimit(5)\n    .build();\n```\n\n```java\n// 6.5 — direct construction\nFullCalendarScheduler scheduler = new FullCalendarScheduler();\nscheduler.setOption(Option.SCHEDULER_LICENSE_KEY, licenseKey);\nscheduler.setOption(Option.MAX_ENTRIES_PER_DAY, 5);\n```\n\nSee the [6.4 → 6.5 migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-6.4-to-6.5#deprecated-fullcalendarbuilder) for the full mapping table.\n\n**New `Option.INITIAL_VIEW`:** verified that FullCalendar 6.1.20 applies the `initialView` option correctly on first render, so the `withInitialView(view)` replacement is a clean `setOption(Option.INITIAL_VIEW, view.getClientSideValue())` rather than the attach-listener + `changeView()` workaround the builder used to carry. The builder's `build()` method now uses the option directly as well.\n\nAlso deprecated: the single-argument constructors `FullCalendar(int entryLimit)` and `FullCalendarScheduler(int entryLimit)`. Replace with the no-arg constructor plus `setOption(Option.MAX_ENTRIES_PER_DAY, n)`.\n\n## Demo: DemoDialog now supports resource assignment (#164)\n\nThe bundled `DemoDialog` (used by the full demo and entry-provider demos) now shows a \"Resources\" multi-select field when the edited entry is a `ResourceEntry` on a Scheduler-capable calendar. Available resources are read from `Scheduler.getResources()`. When creating an entry via timeslot selection in a resource view, the resource the user clicked on is pre-selected.\n\nDemo-only change — no addon API surface.\n\n## Deprecated: `Delta.getYears()` and `Delta.getMonths()` (#191)\n\nFullCalendar JS normalises year/month portions of a drop/resize delta into `days` before sending it to the server — dragging an entry from e.g. 31 March to 29 February produces `days: -31`, not `months: -1`. The `Delta.years` and `Delta.months` fields therefore stay zero for every FC-originated drag/drop event.\n\nThe two getters are now `@Deprecated` to document this. Handlers that react to drag/drop should read `Delta.getDays()` and the time components; the year/month fields remain only for manually-constructed `Delta` instances.\n\nNo removal scheduled; deprecated methods continue to work throughout 6.x.\n\n## Renamed: `EntryDataEvent.createCopyBasedOnChanges()` → `getChangesAsEntry()`\n\nThe old name was verbose and did not describe what the method actually returns. From 6.5 the method is called `getChangesAsEntry()`. The old name remains as a `@Deprecated` delegate — existing code keeps working.\n\n## Bug Fixes\n\n### `Scheduler.updateResource` now propagates extended props (#230)\n\nPreviously, calling `scheduler.updateResource(resource)` only applied changes to known built-in properties (title, color, eventOverlap, …) on the client side. Any changes to extended props were silently dropped.\n\n```java\nResource room = new Resource(\"room-1\", \"Room 1\", null);\nroom.addExtendedProps(\"department\", \"Engineering\");\nscheduler.addResource(room);\n\n// Later — update the extended prop\nroom.addExtendedProps(\"department\", \"Marketing\");\nscheduler.updateResource(room);\n// Before 6.5: client still shows \"Engineering\"\n// From 6.5:  client reflects \"Marketing\"\n```\n\nResource properties that are not part of FC's built-in resource object (anything except `title`, `eventColor`, `eventBackgroundColor`, `eventBorderColor`, `eventTextColor`, `eventConstraint`, `eventOverlap`, `eventAllow`, `eventClassNames`) now route through FC's `Resource.setExtendedProp(name, value)` on update, matching the initial-creation behavior.\n\n### Scheduler timeline sizing in dense resource layouts (#231)\n\nPreviously, code that registered many resources one at a time — e.g. a `for`-loop calling `scheduler.addResource(...)` per entry — could leave the scrollgrid chunk tables stuck at `style=\"width: 0px; min-width: 930px\"`, rendering at min-width instead of filling the container. Users saw a large empty dead-zone to the right of the timeline.\n\n**Root cause:** every `addResource` / `removeResource` / `updateResource` call on the server fired an immediate `callJsFunction`. N calls → N JS round-trips → N inner FC updates, which pushed FC's internal Preact tree past its double-rAF settling window; `computeScrollerDims()` then wrote `width: 0` and nothing re-measured afterwards.\n\n**Fix:** resource writes on the scheduler now accumulate in a per-request pending state and flush once in a `beforeClientResponse` callback. A request that calls `addResource` 100 times fires exactly one `callJsFunction(\"addResources\", [...100], ...)` at the end of the request. FC sees one inner update and settles correctly.\n\nCollapse rules within a single request:\n- `addResource(R)` followed by `removeResource(R)` → no client op (R was never sent).\n- `removeResource(R)` followed by `addResource(R')` (same id) → remove + re-add, in that order.\n- `updateResource(R)` after `addResource(R)` → collapses into the add (the add payload carries the latest state).\n- `removeAllResources()` → supersedes any earlier piecewise ops in the same request.\n\nNo API change: `addResource`, `addResources(Iterable)`, `removeResource`, `removeResources(Iterable)`, `updateResource`, and `removeAllResources` keep their existing signatures. The difference is purely in _when_ the client is notified — at the end of the current request, not immediately.\n\n### Per-entry `editable` default no longer overrides calendar-level `editable: false` (#212)\n\nCalling `calendar.setOption(Option.EDITABLE, false)` to disable drag'n'drop globally used to have no effect — entries still responded to drag. Reason: each `Entry` carried an implicit `editable: true` default that was serialized to the client, overriding the calendar-level setting.\n\nStarting with 6.5, `Entry.editable` defaults to \"not set\" (internally `null`). An unset value is no longer sent to the client, so the calendar-level option takes effect. Explicit `entry.setEditable(true)` or `setEditable(false)` continue to work as before — they remain per-entry overrides.\n\n```java\n// 6.5 — actually works\ncalendar.setOption(Option.EDITABLE, false);\ncalendar.setEntryProvider(EntryProvider.inMemoryFrom(someEntries));\n// None of the entries are draggable.\n```\n\n**Source-level compatibility:** `entry.isEditable()` still returns `boolean` with the same default (true), and `entry.setEditable(true/false)` still works (auto-boxing). `setEditable(null)` is newly allowed — it clears the explicit override and lets the entry inherit the calendar-level setting again.\n\n**Addon-default change:** FullCalendar JS itself defaults the calendar-level `editable` option to `false`. With the per-entry override gone, that would have flipped the out-of-the-box UX to \"nothing draggable or resizable\". To preserve the pre-6.5 experience (entries are draggable by default unless the dev opts out), the addon now sets `editable: true` as a calendar-level default in every `FullCalendar` constructor. An explicit `setOption(Option.EDITABLE, false)` or a user-supplied `initialOptions` with `editable: false` continues to win.\n\n**Binary compatibility note:** the `setEditable` method descriptor changed from `(Z)V` (primitive boolean) to `(Ljava/lang/Boolean;)V` (boxed). Pre-compiled dependents calling `setEditable(...)` must be recompiled against 6.5 before use. Source recompilation is the normal path when upgrading the addon, so this rarely matters in practice.\n",
      "category": "docs",
      "tags": [
        "release-notes-6.5",
        "fullcalendarbuilder",
        "popover",
        "fullcalendar",
        "entrydroppedevent",
        "entryresizedevent",
        "entrydroppedschedulerevent",
        "externalentrydroppedevent",
        "externalentryresizedevent",
        "fullcalendarscheduler",
        "demodialog",
        "resourceentry",
        "delta",
        "entry",
        "migration",
        "upgrade",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "release-notes-7.0",
      "title": "Release-notes-7.0",
      "path": "Release-notes-7.0.md",
      "content": "This page gives you an overview of the major changes, that came with the release of \n[FullCalendar for Flow, version 7.0](https://vaadin.com/directory/component/full-calendar-flow).\n\nThe main change in version 7.0 is the Vaadin 25 support, which includes the new requirement\nfor at least Java 21 and, if used, Spring Boot 4. \n\nAlso the used FullCalendar version has been increased to 6.1.20.\n\n## Major code changes\nSince element Json is gone and Jackson 3 is the new player on the field, json related things have been\nreworked to use Jackson types instead of elemental Json ones. Some method names have changed to align better with \nthe handled types.\n\n## Theming\nThe FullCalendar theme variant `LUMO` has been renamed to `VAADIN` to cover all themes at once. This should\naffect you only, when you have explicitly removed the theme variant.\n\nThe Vaadin theming now covers Lumo and Aura and applies the respective styles to the calendar. As before,\nthere might be variables or cases, where the styling is not applied correctly or missing - in this case\nplease open a github issue.\n\n## Other\nThe class `BusinessHours` has been reworked. The constructors have been removed and instead\nthere are now static methods to define new instance. The api also has been changed to allow a fluent definition\nstyle of business hours.\n\nDeprecated APIs are subject to change or removal in future versions.",
      "category": "docs",
      "tags": [
        "release-notes-7.0",
        "lumo",
        "vaadin",
        "businesshours"
      ]
    },
    {
      "id": "release-notes-7.1",
      "title": "Release-notes-7.1",
      "path": "Release-notes-7.1.md",
      "content": "This page gives you an overview of the major changes that came with the release of\n[FullCalendar for Flow, version 7.1](https://vaadin.com/directory/component/full-calendar-flow).\n\nVersion 7.1 is driven by the following goals:\n\n1. **Close the feature gap** — bring the Java API up to parity with FullCalendar v6 so that options which\n   previously required raw `setOption` calls now have proper typed support.\n2. **Keep the API lean** — rather than growing a sprawling set of individual setter methods, new functionality\n   is surfaced through the generic `setOption` API, backed by typed enums, automatic value converters, and\n   `JsCallback` for function values. Dedicated one-off setters that duplicate what `setOption` can already\n   express are deprecated.\n3. New event types to allow more fine-grain control over what happens on the client side\n\nNo APIs have been removed in this release. Deprecated methods continue to work and will be removed in a future\nmajor version. See the [migration guide](Migration-guides#migration-notes-70--71) for the one behaviour change\ninvolving `Entry.overlap` and the full list of deprecated methods.\n\n## Entry model enhancements\n\nSeveral new properties have been added to `Entry`:\n\n- `setUrl(String)` — entries with a URL are rendered as `<a>` tags; FC navigates to the URL on click\n- `setInteractive(Boolean)` — per-entry keyboard-focusability override (`null` inherits the global `eventInteractive` setting)\n- `setRecurringDuration(String)` — ISO 8601 duration for multi-day all-day recurring events (e.g. `\"P2D\"`)\n- `setRRule(RRule)` — RFC 5545 recurrence rules via the `RRule` fluent builder, including `RRule.excludeDates(LocalDate...)` to exclude specific dates\n- `setOverlap(Boolean)` — changed from primitive `boolean` to `Boolean`; `null` means \"inherit global overlap setting\"\n\n## Unified callback API: `JsCallback` and `setOption`\n\nJavaScript callbacks and static option values now share a single API path: `setOption(Option, value)`.\n`JsCallback` is a lightweight wrapper that marks a string as a JavaScript function — the client\nevaluates it via `new Function()` before passing it to FullCalendar.\n\nThe `Option` enum now includes all callback-related constants (render hooks, interaction guards,\ndata transforms, etc.). Scheduler-specific callback constants are in `SchedulerOption`:\n\n```java\n// Static value — unchanged\ncalendar.setOption(Option.ENTRY_OVERLAP, false);\n\n// Function — wrap in JsCallback\ncalendar.setOption(Option.ENTRY_OVERLAP,\n    JsCallback.of(\"function(stillEvent, movingEvent) { return stillEvent.display === 'background'; }\"));\n\n// Render hook\ncalendar.setOption(Option.ENTRY_DID_MOUNT,\n    JsCallback.of(\"function(info) { info.el.title = info.event.title; }\"));\n\n// Scheduler resource hook\nscheduler.setOption(SchedulerOption.RESOURCE_LABEL_CLASS_NAMES,\n    JsCallback.of(\"function(arg) { return arg.resource.extendedProps.isSpecial ? ['special'] : []; }\"));\n```\n\n`JsCallback.of(null)` returns `null`, enabling clean \"clear callback\" patterns:\n\n```java\ncalendar.setOption(Option.ENTRY_CONTENT, JsCallback.of(userProvidedFunction));  // safe when null\n```\n\nThe individual callback setter methods from 7.0 (`setEntryClassNamesCallback`, `setEntryDidMountCallback`,\netc.) are deprecated. See the [migration guide](Migration-guides#deprecated-individual-callback-methods-use-setoption--jscallback-instead) for\nthe complete replacement table.\n\n## Draggable API\n\nNew server-side `Draggable` class for making external Vaadin components draggable onto the calendar,\nreplacing the previous manual JS initialization approach.\n\n- `new Draggable(component)` — wrap any Vaadin component to make it draggable\n- `new Draggable(component, entry)` — include entry data that FC uses to create a calendar entry on drop\n- `withItemSelector(String)` — container mode: only children matching the CSS selector are draggable\n- `withEventDataCallback(JsCallback)` — dynamically create entry data from the dragged element via JS\n- `calendar.addDraggable(draggable)` — register on a calendar; returns `Registration` for cleanup\n- `EntryReceiveEvent.getDraggable()` — access the original Draggable from the entry receive listener\n- `DropEvent.getDraggable()` — access the Draggable from the drop listener\n\nThe `Draggable` lifecycle is fully managed: re-initialization on reattach, cleanup of JS listeners\non deregistration and disconnect.\n\n## Interaction events\n\nNew server-side events cover the full drag/resize lifecycle:\n`EntryDragStartEvent`, `EntryDragStopEvent`, `EntryResizeStartEvent`, `EntryResizeStopEvent`.\n\nPlease note, that these should be mainly used for visual feedback. `EntryDroppedEvent` and `EntryResizedEvent` are still\nthe main events for reacting on calendar modification by the user.\n\nExternal entry support has been added via `ExternalEntryDroppedEvent` and `ExternalEntryResizedEvent`, fired when\nentries from a client-side event source are dropped into or resized within the calendar.\n\nAdditional interaction options are available via the `Option` enum:\n- `Option.DROP_ACCEPT` — CSS selector or JS function to filter accepted draggable elements\n- `Option.UNSELECT_CANCEL` — CSS selector for elements that should not cancel an active selection\n\n## Event sources\n\nTyped Java wrappers have been added for three common FC event source types:\n\n- `JsonFeedEventSource` — FC's JSON feed event source\n- `GoogleCalendarEventSource` — Google Calendar integration\n- `ICalendarEventSource` — iCalendar (.ics) feeds\n\nThe `JsonFeedEventSource` builder supports per-source parameter name overrides via `withStartParam(String)`,\n`withEndParam(String)`, and `withTimeZoneParam(String)`. For global overrides, use the corresponding\n`Option.EXTERNAL_EVENT_SOURCE_START_PARAM`, `EXTERNAL_EVENT_SOURCE_END_PARAM`, and\n`EXTERNAL_EVENT_SOURCE_TIME_ZONE_PARAM` option keys via `setOption`.\n\n`EventSourceFailureEvent` is fired server-side when an event source fails to load.\n\n## Scheduler resource features\n\nThe resource area can now be configured with typed column definitions via\n`setResourceAreaColumns(ResourceAreaColumn...)`. Resources can be grouped by a shared field using\n`setOption(SchedulerOption.RESOURCE_GROUP_FIELD, \"fieldName\")`,\nwith customizable render hooks for group headers and lanes via callback options.\nUse `setOption(SchedulerOption.REFETCH_RESOURCES_ON_NAVIGATE, true)` to re-fetch resources on each navigation.\nResource lifecycle events (`resourceAdd`, `resourceChange`, `resourceRemove`, `resourcesSet`) are\navailable as callback options for custom logic on resource data changes.\n\nIn addition to static text columns, the resource area sidebar can display interactive Vaadin components (DatePicker, TextField, ComboBox, etc.) \n— one component instance per resource. This pattern mirrors Vaadin Grid's `ComponentColumn` and is useful for:\n\n- Inline editing of resource metadata (deadlines, priority, owner, notes)\n- One-way binding to entry properties (display entry start/end dates, duration)\n- Two-way binding (component change updates entry; entry change updates component)\n\nComponents are created by a callback that receives the `Resource` and returns a component instance. They are fully interactive \n— users can type, select, open dropdowns, etc. — and survive FullCalendar view changes and re-renders. Type-safe runtime access is provided at any time via `getComponent(resource)`.\n\n\n## Accessibility\n\nA set of new options improves keyboard accessibility and screen reader support:\n\n- `Option.ENTRY_INTERACTIVE` — make all entries keyboard-focusable (WCAG 2.1 AA) via `setOption`\n- `Option.NATIVE_TOOLBAR_BUTTON_HINTS` — accessible labels for toolbar buttons\n- `Option.NATIVE_TOOLBAR_VIEW_HINT` / `Option.NAV_LINK_HINT` / `Option.MORE_LINK_HINT` — labels for view switchers, nav links, and \"+N more\" links\n- `Option.CLOSE_HINT` / `Option.TIME_HINT` / `Option.ENTRY_HINT` — labels for popover close buttons, time displays, and entries\n\n## Other new options and methods\n\nA number of smaller additions round out the release:\n\n- `Option.PROGRESSIVE_EVENT_RENDERING` — render events in batches as they arrive (via `setOption`)\n- `Option.DATE_INCREMENT` / `Option.DATE_ALIGNMENT` — navigation increment and alignment for custom views (via `setOption`)\n- `Entry.setConstraint(BusinessHours)` — constrain drag/resize to specific time slots\n- `Option.CONTENT_SECURITY_POLICY` — CSP nonce for dynamically generated `<style>` tags (via `setOption`)\n- `setViewSpecificOption(viewType, option, value)` — per-view option overrides\n- `Option.FIXED_MIRROR_PARENT` — drag-mirror parent element; accepts `JsCallback.of(\"function() { return document.body; }\")` (via `setOption`)\n- `Option.DRAG_SCROLL_ELS` — CSS selectors for auto-scroll containers during drag (via `setOption`)\n- `Option.MORE_LINK_CLICK` — custom JS function for \"+N more\" link click behavior; accepts a static string value or `JsCallback.of(...)` (via `setOption`)\n- `getCurrentIntervalStart()` / `getCurrentIntervalEnd()` — returns `Optional<LocalDate>` for the current view interval; empty before the first `DatesRenderedEvent` is received\n\n`FullCalendarBuilder` has been refactored to a mutable fluent builder — all `withXxx` methods now return `this`,\nso chained calls no longer need to be re-assigned.\n\nNew enums `Direction` and `WeekNumberCalculation` replace raw string options.\n\n## Option converters\n\nA new converter system allows `setOption` to accept type-rich Java values. Each converter is registered\non the `Option` / `SchedulerOption` constant via the `@JsonConverter` annotation and converts automatically\nwhen a matching type is passed.\n\n**Duration options** — `DurationConverter` converts `Duration` or `LocalTime` to FullCalendar's `\"HH:mm:ss\"` format:\n- `Option.SNAP_DURATION`, `Option.SLOT_DURATION`, `Option.SLOT_LABEL_INTERVAL`\n- `Option.SLOT_MIN_TIME`, `Option.SLOT_MAX_TIME`, `Option.SCROLL_TIME`, `Option.NEXT_DAY_THRESHOLD`\n\n**Business hours** — `BusinessHoursConverter` converts `BusinessHours` or `BusinessHours[]` to FC's business-hours JSON:\n- `Option.BUSINESS_HOURS`, `Option.ENTRY_CONSTRAINT`\n\n**Day of week** — `DayOfWeekConverter` converts `DayOfWeek` to FC's 0-based weekday number (0=Sunday):\n- `Option.FIRST_DAY`\n\n**Day of week arrays** — `DayOfWeekArrayConverter` converts `DayOfWeek[]` or `Collection<DayOfWeek>`:\n- `Option.HIDDEN_DAYS`\n\n**Locale** — `LocaleConverter` converts `java.util.Locale` to FC's locale string:\n- `Option.LOCALE`\n\n**String arrays** — `StringArrayConverter` joins `String[]` or `Collection<String>` with commas:\n- `Option.DRAG_SCROLL_ELS`\n\n**Toolbar** — `ToolbarConverter` converts `Header`, `Footer`, or `Map<String, String>` to FC's toolbar config:\n- `Option.HEADER_TOOLBAR`, `Option.FOOTER_TOOLBAR`\n\nExample:\n```java\ncalendar.setOption(Option.SLOT_DURATION, Duration.ofMinutes(30));\ncalendar.setOption(Option.FIRST_DAY, DayOfWeek.MONDAY);\ncalendar.setOption(Option.LOCALE, Locale.GERMAN);\ncalendar.setOption(Option.BUSINESS_HOURS, BusinessHours.businessWeek().start(LocalTime.of(9, 0)).end(LocalTime.of(17, 0)));\ncalendar.setOption(Option.HIDDEN_DAYS, new DayOfWeek[]{DayOfWeek.SATURDAY, DayOfWeek.SUNDAY});\n```\n\nThe legacy setter methods `setSnapDuration(String)`, `setSlotMinTime(...)`, `setSlotMaxTime(...)`, etc.\nfrom 7.0 are now deprecated. Use `setOption` with the corresponding `Option` enum value instead.\n\n## Deprecated methods\n\nA number of individual setter methods from 7.0 are now deprecated in favour of the generic `setOption` API.\nExamples:\n\n```java\n// Before (deprecated)\ncalendar.setSlotMinTime(LocalTime.of(9, 0));\ncalendar.setEntryDidMountCallback(\"function(info) { ... }\");\nscheduler.setResourceLabelClassNamesCallback(\"function(arg) { ... }\");\n\n// After\ncalendar.setOption(Option.SLOT_MIN_TIME, LocalTime.of(9, 0));\ncalendar.setOption(Option.ENTRY_DID_MOUNT, JsCallback.of(\"function(info) { ... }\"));\nscheduler.setOption(SchedulerOption.RESOURCE_LABEL_CLASS_NAMES, JsCallback.of(\"function(arg) { ... }\"));\n```\n\nSee the [migration guide](Migration-guides#migration-notes-70--71) for the complete replacement table.\n\n## Bug fixes\n\n- `EntryQuery.applyFilter()`: entries without an explicit end date (e.g. all-day single-day entries created with\n  only `setStart(LocalDate)`) were incorrectly excluded from `InMemoryEntryProvider` fetch results. They now\n  appear correctly when the start date falls within the visible date range.\n- When a scheduler has been detached and re-attached, the resources were not sent to the client. This led to an empty scheduler view. ",
      "category": "docs",
      "tags": [
        "release-notes-7.1",
        "jscallback",
        "entry",
        "rrule",
        "boolean",
        "option",
        "scheduleroption",
        "draggable",
        "registration",
        "entrydragstartevent",
        "entrydragstopevent",
        "entryresizestartevent",
        "entryresizestopevent",
        "entrydroppedevent",
        "entryresizedevent",
        "externalentrydroppedevent",
        "externalentryresizedevent",
        "migration",
        "upgrade",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "release-notes-7.2",
      "title": "Release-notes-7.2",
      "path": "Release-notes-7.2.md",
      "content": "This page gives you an overview of the major changes that came with the release of\n[FullCalendar for Flow, version 7.2](https://vaadin.com/directory/component/full-calendar-flow).\n\n**Platform (unchanged from 7.1):** FullCalendar JS 6.1.20, Vaadin 25.x, Java 21, Jackson 3. 7.2 is a source-compatible minor release; see the [migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-7.1-to-7.2) for the single binary-compat caveat and migration notes.\n\n## Highlights\n\n- **[Client-side entry IDs](#client-side-entry-ids-provided-automatically-202)** — default on, no configuration needed.\n- **[Auto-revert for unapplied entry changes](#auto-revert-for-unapplied-entry-changes-225)** — default on; prevents server/client drift when a drop/resize listener rejects the change.\n- **[`FullCalendarBuilder` deprecated](#deprecated-fullcalendarbuilder-232)** — direct construction + `setOption(...)` is the forward path. No removal scheduled for 7.x.\n- Bug fixes for scheduler extended-prop updates ([#230](#schedulerupdateresource-now-propagates-extended-props-230)), scheduler timeline sizing ([#231](#scheduler-timeline-sizing-in-dense-resource-layouts-231)) and per-entry editable ([#212](#per-entry-editable-default-no-longer-overrides-calendar-level-editable-false-212)).\n\n## Client-Side Entry IDs Provided Automatically (#202)\n\nServer-side components such as `Popover` anchor to target elements via `document.getElementById`. Before 7.2, rendered calendar entries had no DOM `id`, so anchoring required a custom `eventDidMount` callback with JavaScript-side id generation.\n\nStarting with 7.2, `FullCalendar` assigns `id=\"entry-<entryId>\"` to the **start segment** of each rendered entry by default. The feature is controlled by `setAutoProvideEntryIdOnClient(boolean)`, which defaults to `true`.\n\n### Usage\n\n```java\n// Default on — nothing to configure.\nEntry meeting = new Entry(\"m-1\");\nmeeting.setTitle(\"Quarterly review\");\n// ...\n\n// Anchor a Popover to the rendered entry:\nPopover popover = new Popover();\npopover.setFor(\"entry-m-1\");\n```\n\nOpt-out:\n\n```java\ncalendar.setAutoProvideEntryIdOnClient(false);\n```\n\n### ID schema and uniqueness\n\n- **Single-day entry**, any view → `id=\"entry-<entryId>\"` on the single segment.\n- **Multi-day entry** (month/week view) → `id=\"entry-<entryId>\"` on the **start segment only**; continuation segments stay id-free so HTML id uniqueness is preserved.\n- **Scheduler, entry assigned to multiple resources** → to keep ids unique across the resource rows, the id is suffixed with the row's resource id: `id=\"entry-<entryId>-<resourceId>\"`. Entries that live in a single resource row get the plain `entry-<entryId>` schema.\n- **Drag-preview (\"mirror\") elements** during an ongoing drag are not tagged — the id stays on the real element.\n\n### Overriding the default\n\nIf you set your own `eventDidMount` callback via `setOption(Option.ENTRY_DID_MOUNT, JsCallback.of(...))`, the default snippet runs first and your callback runs afterwards, so reassigning `info.el.id` in your callback wins.\n\n```java\ncalendar.setOption(Option.ENTRY_DID_MOUNT, JsCallback.of(\n    \"function(info) { info.el.id = 'my-' + info.event.id; }\"));\n// Result: id='my-<entryId>' (your value, the default was overwritten)\n```\n\n### Notes\n\n- For anchoring to the exact segment a user clicked, prefer the element from the click event rather than `getElementById` — the click element always points at the clicked segment, even for multi-day entries whose id lives only on the start.\n- The feature relies on the `eventDidMount` render hook. If you replace that hook with a brace-less arrow expression (e.g. `\"info => info.el.title = info.event.title\"`), the default snippet is skipped to keep the output syntactically valid. Use a braced function body to keep the default id-assignment alongside your callback.\n\n## Auto-Revert for Unapplied Entry Changes (#225)\n\nWhen a user drags or resizes an entry, FullCalendar JS immediately moves the entry to its new position on the client. The server receives an `EntryDroppedEvent` or `EntryResizedEvent`. Previously, if the developer chose not to call `event.applyChangesOnEntry()` (e.g., after a validation failure), the client would keep showing the entry at the new position while the server still had the old data — an inconsistent state.\n\nStarting with 7.2, the calendar **automatically reverts** the client-side entry to its original position when `applyChangesOnEntry()` is not called. This is controlled by `setAutoRevertUnappliedEntryChanges(boolean)`, which defaults to `true`.\n\n### Usage\n\n```java\n// Auto-revert is enabled by default — no configuration needed.\n// Entries revert automatically when applyChangesOnEntry() is not called.\n\ncalendar.addEntryDroppedListener(event -> {\n    if (isDropAllowed(event)) {\n        event.applyChangesOnEntry();       // entry stays at new position\n        entryProvider.refreshItem(event.getEntry());\n    }\n    // If not called: entry reverts to original position on the client\n});\n```\n\nTo restore the previous behavior (client keeps the new position regardless):\n\n```java\ncalendar.setAutoRevertUnappliedEntryChanges(false);\n```\n\n### How It Works\n\n1. When a drop or resize occurs, the FullCalendar JS `revert()` function is captured on the client side.\n2. On the server, after all event listeners have been executed, a `beforeClientResponse` callback checks whether `applyChangesOnEntry()` was called.\n3. If not called (and auto-revert is enabled), the server sends a `revertEntry` command to the client, which triggers FullCalendar's native revert animation.\n4. If `applyChangesOnEntry()` was called, the pending revert is cleared — the entry stays at the new position.\n\n### Notes\n\n- Auto-revert works for `EntryDroppedEvent`, `EntryResizedEvent`, and `EntryDroppedSchedulerEvent`.\n- `ExternalEntryDroppedEvent` / `ExternalEntryResizedEvent` (from client-side event sources or draggable external DOM) do **not** participate in auto-revert — those flows create new entries on drop, so the server-side handler typically owns the accept/reject decision explicitly.\n- The revert uses FullCalendar's native revert mechanism, which provides a smooth animation back to the original position.\n- If you need to inspect the state from another listener or a downstream component, `EntryDataEvent#isChangesApplied()` returns whether `applyChangesOnEntry()` was called on this event — useful when multiple listeners are chained and a later one needs to know whether the earlier ones already accepted the change.\n\n## Deprecated: `FullCalendarBuilder` (#232)\n\n`FullCalendarBuilder` and all its `with...` methods are now `@Deprecated`. `FullCalendar` and `FullCalendarScheduler` can be constructed directly and configured through `setOption(Option, value)`; the builder no longer provides value beyond syntactic sugar. No removal is scheduled for 7.x — the class is slated for removal in a future major version.\n\n### Example\n\n```java\n// 7.1 — builder\nFullCalendarScheduler scheduler = (FullCalendarScheduler) FullCalendarBuilder.create()\n    .withScheduler(licenseKey)\n    .withEntryLimit(5)\n    .build();\n```\n\n```java\n// 7.2 — direct construction\nFullCalendarScheduler scheduler = new FullCalendarScheduler();\nscheduler.setOption(Option.SCHEDULER_LICENSE_KEY, licenseKey);\nscheduler.setOption(Option.MAX_ENTRIES_PER_DAY, 5);\n```\n\nSee the [7.1 → 7.2 migration guide](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-7.1-to-7.2#deprecated-fullcalendarbuilder) for the full mapping table.\n\n**New `Option.INITIAL_VIEW`:** verified that FullCalendar 6.1.20 applies the `initialView` option correctly on first render, so the `withInitialView(view)` replacement is a clean `setOption(Option.INITIAL_VIEW, view.getClientSideValue())` rather than the attach-listener + `changeView()` workaround the builder used to carry. The builder's `build()` method now uses the option directly as well.\n\nAlso deprecated: the single-argument constructors `FullCalendar(int entryLimit)` and `FullCalendarScheduler(int entryLimit)`. Replace with the no-arg constructor plus `setOption(Option.MAX_ENTRIES_PER_DAY, n)`.\n\n## Demo: DemoDialog now supports resource assignment (#164)\n\nThe bundled `DemoDialog` (used by the full demo and entry-provider demos) now shows a \"Resources\" multi-select field when the edited entry is a `ResourceEntry` on a Scheduler-capable calendar. Available resources are read from `Scheduler.getResources()`. When creating an entry via timeslot selection in a resource view, the resource the user clicked on is pre-selected.\n\nDemo-only change — no addon API surface.\n\n## Deprecated: `Delta.getYears()` and `Delta.getMonths()` (#191)\n\nFullCalendar JS normalises year/month portions of a drop/resize delta into `days` before sending it to the server — dragging an entry from e.g. 31 March to 29 February produces `days: -31`, not `months: -1`. The `Delta.years` and `Delta.months` fields therefore stay zero for every FC-originated drag/drop event.\n\nThe two getters are now `@Deprecated(since = \"7.2.0\")` to document this. Handlers that react to drag/drop should read `Delta.getDays()` and the time components; the year/month fields remain only for manually-constructed `Delta` instances.\n\nNo removal scheduled; deprecated methods continue to work throughout 7.x.\n\n## Renamed: `EntryDataEvent.createCopyBasedOnChanges()` → `getChangesAsEntry()`\n\nThe old name was verbose and did not describe what the method actually returns. From 7.2 the method is called `getChangesAsEntry()`. The old name remains as a `@Deprecated(since = \"7.2.0\")` delegate — existing code keeps working.\n\n## Bug Fixes\n\n### `Scheduler.updateResource` now propagates extended props (#230)\n\nPreviously, calling `scheduler.updateResource(resource)` only applied changes to known built-in properties (title, color, eventOverlap, …) on the client side. Any changes to extended props were silently dropped.\n\n```java\nResource room = new Resource(\"room-1\", \"Room 1\", null);\nroom.addExtendedProps(\"department\", \"Engineering\");\nscheduler.addResource(room);\n\n// Later — update the extended prop\nroom.addExtendedProps(\"department\", \"Marketing\");\nscheduler.updateResource(room);\n// Before 7.2: client still shows \"Engineering\"\n// From 7.2:  client reflects \"Marketing\"\n```\n\nResource properties that are not part of FC's built-in resource object (anything except `title`, `eventColor`, `eventBackgroundColor`, `eventBorderColor`, `eventTextColor`, `eventConstraint`, `eventOverlap`, `eventAllow`, `eventClassNames`) now route through FC's `Resource.setExtendedProp(name, value)` on update, matching the initial-creation behavior.\n\n### Scheduler timeline sizing in dense resource layouts (#231)\n\nPreviously, code that registered many resources one at a time — e.g. a `for`-loop calling `scheduler.addResource(...)` per entry — could leave the scrollgrid chunk tables stuck at `style=\"width: 0px; min-width: 930px\"`, rendering at min-width instead of filling the container. Users saw a large empty dead-zone to the right of the timeline.\n\n**Root cause:** every `addResource` / `removeResource` / `updateResource` call on the server fired an immediate `callJsFunction`. N calls → N JS round-trips → N inner FC updates, which pushed FC's internal Preact tree past its double-rAF settling window; `computeScrollerDims()` then wrote `width: 0` and nothing re-measured afterwards.\n\n**Fix:** resource writes on the scheduler now accumulate in a per-request pending state and flush once in a `beforeClientResponse` callback. A request that calls `addResource` 100 times fires exactly one `callJsFunction(\"addResources\", [...100], ...)` at the end of the request. FC sees one inner update and settles correctly.\n\nCollapse rules within a single request:\n- `addResource(R)` followed by `removeResource(R)` → no client op (R was never sent).\n- `removeResource(R)` followed by `addResource(R')` (same id) → remove + re-add, in that order.\n- `updateResource(R)` after `addResource(R)` → collapses into the add (the add payload carries the latest state).\n- `removeAllResources()` → supersedes any earlier piecewise ops in the same request.\n\nNo API change: `addResource`, `addResources(Iterable)`, `removeResource`, `removeResources(Iterable)`, `updateResource`, and `removeAllResources` keep their existing signatures. The difference is purely in _when_ the client is notified — at the end of the current request, not immediately.\n\n### Per-entry `editable` default no longer overrides calendar-level `editable: false` (#212)\n\nCalling `calendar.setOption(Option.EDITABLE, false)` to disable drag'n'drop globally used to have no effect — entries still responded to drag. Reason: each `Entry` carried an implicit `editable: true` default that was serialized to the client, overriding the calendar-level setting.\n\nStarting with 7.2, `Entry.editable` defaults to \"not set\" (internally `null`). An unset value is no longer sent to the client, so the calendar-level option takes effect. Explicit `entry.setEditable(true)` or `setEditable(false)` continue to work as before — they remain per-entry overrides.\n\n```java\n// 7.2 — actually works\ncalendar.setOption(Option.EDITABLE, false);\ncalendar.setEntryProvider(EntryProvider.inMemoryFrom(someEntries));\n// None of the entries are draggable.\n```\n\n**Source-level compatibility:** `entry.isEditable()` still returns `boolean` with the same default (true), and `entry.setEditable(true/false)` still works (auto-boxing). `setEditable(null)` is newly allowed — it clears the explicit override and lets the entry inherit the calendar-level setting again.\n\n**Addon-default change:** FullCalendar JS itself defaults the calendar-level `editable` option to `false`. With the per-entry override gone, that would have flipped the out-of-the-box UX to \"nothing draggable or resizable\". To preserve the pre-7.2 experience (entries are draggable by default unless the dev opts out), the addon now sets `editable: true` as a calendar-level default in every `FullCalendar` constructor. An explicit `setOption(Option.EDITABLE, false)` or a user-supplied `initialOptions` with `editable: false` continues to win.\n\n**Binary compatibility note:** the `setEditable` method descriptor changed from `(Z)V` (primitive boolean) to `(Ljava/lang/Boolean;)V` (boxed). Pre-compiled dependents calling `setEditable(...)` must be recompiled against 7.2 before use. Source recompilation is the normal path when upgrading the addon, so this rarely matters in practice.\n",
      "category": "docs",
      "tags": [
        "release-notes-7.2",
        "fullcalendarbuilder",
        "popover",
        "fullcalendar",
        "entrydroppedevent",
        "entryresizedevent",
        "entrydroppedschedulerevent",
        "externalentrydroppedevent",
        "externalentryresizedevent",
        "fullcalendarscheduler",
        "demodialog",
        "resourceentry",
        "delta",
        "entry",
        "migration",
        "upgrade",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "release-notes",
      "title": "Release-notes",
      "path": "Release-notes.md",
      "content": "## Index\n* [7.2.x](#72x)\n* [7.1.x](#71x)\n* [7.0.x](#70x)\n* [6.5.x](#65x)\n* [6.4.x](#64x)\n* [6.2.x](#62x)\n* [6.1.x](#61x)\n* [6.0.x](#60x)\n* [4.1.x](#41x)\n* [4.0.x](#40x)\n\n## 7.2.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-7.2)\n- added automatic publishing of entry ids as client-side DOM ids (#202)\n- deprecated `Delta.getYears()` / `getMonths()` — FC never produces a non-zero year/month delta (#191)\n- demo: `DemoDialog` now allows selecting resources for `ResourceEntry` (#164)\n- renamed `EntryDataEvent.createCopyBasedOnChanges()` to `getChangesAsEntry()` (old name deprecated, still works)\n- added auto-revert for unapplied entry changes after drop/resize (#225)\n- deprecated `FullCalendarBuilder` in favour of direct constructors + `setOption` (#232)\n- fixed `Scheduler.updateResource` to propagate extended props to the client (#230)\n- fixed scheduler timeline sizing race in dense resource layouts (#231)\n- fixed per-entry `editable` default overriding calendar-level `editable: false` (#212)\n\n## 6.5.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-6.5)\n\nBackport of the 7.2 feature set to the 6.x line (Vaadin 24 / Java 17 / elemental JSON):\n- added automatic publishing of entry ids as client-side DOM ids (#202)\n- added auto-revert for unapplied entry changes after drop/resize (#225)\n- deprecated `FullCalendarBuilder` in favour of direct constructors + `setOption` (#232)\n- deprecated `Delta.getYears()` / `getMonths()` — FC never produces a non-zero year/month delta (#191)\n- renamed `EntryDataEvent.createCopyBasedOnChanges()` to `getChangesAsEntry()` (old name deprecated, still works)\n- demo: `DemoDialog` now allows selecting resources for `ResourceEntry` (#164)\n- fixed `Scheduler.updateResource` to propagate extended props to the client (#230)\n- fixed scheduler timeline sizing race in dense resource layouts (#231)\n- fixed per-entry `editable` default overriding calendar-level `editable: false` (#212)\n\n## 7.1.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-7.1)\n- added entry model enhancements: URL, interactive flag, RRule recurrence, recurring duration\n- added typed `Option` enum constants to close the feature gap with FullCalendar JS v6 (replaces individual setter methods, now unified via `setOption`)\n- added `JsCallback` wrapper and unified callback API: all callback options set via `setOption(Option, JsCallback.of(...))`\n- added option converter system\n- added missing event types\n- added typed event source wrappers for Google Calendar, ICal and Json\n- added accessibility hints and options (WCAG 2.1 AA support)\n- added scheduler resource area columns including support for interactive Vaadin components via `ComponentResourceAreaColumn`, resource grouping, and refetch-on-navigate\n- deprecated a lot of setters in favour of `setOption` with converters\n- deprecated callback setters in favour of `setOption` with `JsCallback`\n- several bugfixes\n\n## 7.0.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-7.0)\n- updated to FullCalendar 6.1.20\n- increased required Vaadin version to 25\n- increased required Java version to 21\n- replaced elemental Json with Jackson 3, renamed some related methods\n- reworked BusinessHours\n- added deprecations to existing API\n- renamed theme variant `LUMO` to `VAADIN` and integrated Aura into theming\n\n## 6.4.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-6.4)\n- platform upgrade: Vaadin 14 → 24.10, Java 8 → 17\n- backported v7 features to Vaadin 24: RRule, JsCallback, event sources, scheduler extensions\n- entry model: url, interactive, nullable overlap, recurringDuration\n- 60+ new Option enum constants (render hooks, interaction callbacks)\n- 11 new event classes (drag/resize start/stop, external drop, etc.)\n- client-side event sources (Google Calendar, iCalendar, JSON feed)\n- ComponentResourceAreaColumn for Vaadin components in scheduler resource area\n- performance: bounded entry cache, thread-safe refresh, BeanProperties converter caching\n- FullCalendar JS 6.1.9 → 6.1.20\n- deprecated ~30 convenience methods in favour of setOption()\n- see [Migration Guide 6.3 → 6.4](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-6.3-to-6.4) for upgrade instructions\n\n## 6.2.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-6.2)\n- added custom native event handlers for entries\n\n## 6.1.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-6.1)\n- added an optional Lumo theme for the addon\n\n## 6.0.x\n- updated to FullCalendar 6.1.6\n- Migrated from Polymer 3 to simple HTML Element based web component (no Lit nor Polymer)\n- Migrated source code from JavaScript to TypeScript (ongoing process, not yet finished)\n- Folder structures changed\n- Tag names prefixed with \"vaadin-\"\n- Content is now part of the light dom, thus styling will be easier\n- Client side eager loading removed, items will now always be fetched\n- Added prefetch mode to allow smoother transition between periods\n- Breaking changes regarding methods and fields (client side and server side). Also usage of private / protected modifiers in TS.\n- Added support for FC's \"multi-month\" views.\n- Added proper API for creating and registering custom views. Also added an internal handling of \"anonymous\" custom views created by initial options.\n- Deprecated code from previous versions has been removed\n- JsonItem has been removed, Entry is a \"normal field\" class again due to issues with proxying frameworks\n- setHeight has been minimalized to be more aligned with Vaadin standards. FC internal height settings / options are not\n  supported anymore. Calendar content will take only as much space as needed.\n- added type `RecurringTime` to allow setting an entry recurrence of more than 24h\n\n\nMinor changes:\n- getResources now may return null. Use getOrCreateResources.\n- CalendarLocale is now an enum. Use getLocale() to obtain the contained locale value.\n- week numbers within days is no longer available, weeknumbers are now always display inside days.\n- RenderingMode and alike namings have been named to DisplayMode / display to match the FC library naming. Also DisplayMode is now a top level class.\n- added resize observer to client side to automatically take care of resizes\n- added our own @NotNull annotation to allow support for Vaadin 23 and 24\n- Entry's method `copy(Class<T>)` has been renamed to `copyAsType(Class<T>)`.\n\nOther things that we may have overseen :)\n\nDue to lack of time, we have no release note details at this time. We tried to provide additional info as part of the migration page.\n\n## 4.1.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-4.1)\n- added EntryProvider, a data provider like callback based class to allow lazy loading entries based on the actual displayed timespan\n\n## 4.0.x\n[Details](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes-4.0)\n- introduced a new type JsonItem for creating item classes with dynamic property handling and automated conversion from and to json\n- integrated json item api into Entry types for dynamic type conversion. Due to that entries will not send all data to the client, when updating existing ones\n- changed date time handling on server side and communication to be always utc\n- entries are not resent to server anymore when changing timezone on server\n- entry data changes are now sent at once the the client\n- client side entries (\"event\") have now a getCustomProperty method inside eventDidMount or eventContent callbacks\n- removed official support of custom timezones for entries\n- renamed several methods\n- recurrence has some changes regarding enable recurrence and timezones\n",
      "category": "docs",
      "tags": [
        "release-notes",
        "demodialog",
        "resourceentry",
        "fullcalendarbuilder",
        "option",
        "jscallback",
        "componentresourceareacolumn",
        "lumo",
        "vaadin",
        "recurringtime",
        "migration",
        "upgrade",
        "scheduler",
        "resource",
        "entry",
        "event"
      ]
    },
    {
      "id": "samples",
      "title": "Samples",
      "path": "Samples.md",
      "content": "This page contains some samples to get you started with the FullCalendar addon. The samples are always based on the\nlatest version of the addon.\n\nSome samples use an in-memory entry provider when modifying the calendar data to keep things simple. You may\nneed to adapt those parts, if you use a different entry provider.\n\nAlso we tried to keep things short. So you may see variables like `calendar`, `entry` or `entryProvider`\nwithout any declaration. In those cases these represent the basic types `FullCalendar`, `Entry` or `EntryProvider`.\n\n> **Note for 7.2.x readers:** several samples below still use the pre-7.2 API\n> (`FullCalendarBuilder.create()`, `event.createCopyBasedOnChanges()`). Both\n> remain functional in 7.2 as `@Deprecated(since = \"7.2.0\")` with no removal\n> scheduled for 7.x. For the equivalents, see\n> [Migration guide 7.1 → 7.2](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guide-7.1-to-7.2).\n\nIf you find an outdated sample, please create an issue for that.\n\n## Creating a basic calendar instance and add an entry\n\nThe FullCalendar is a normal Vaadin component, that can be added to your view as any other component. By default it uses\nan eager loading in memory entry provider, with which you simply can add, update or remove calendar entries.\n\n```java\n// Create a new calendar instance and attach it to our layout\nFullCalendar calendar = FullCalendarBuilder.create().build();\ncalendar.setSizeFull();\ncontainer.add(calendar);\n\n// Create an initial sample entry\nEntry entry = new Entry();\nentry.setTitle(\"Some event\");\nentry.setColor(\"#ff3333\");\n\n// the given times will be interpreted as utc based - useful when the times are fetched from your database\nentry.setStart(LocalDate.now().withDayOfMonth(3).atTime(10, 0));\nentry.setEnd(entry.getStart().plusHours(2));\n\n// FC uses a data provider concept similar to the Vaadin default's one, with some differences\n// By default the FC uses a in-memory data provider, which is sufficient for most basic use cases.\ncalendar.getEntryProvider().asInMemory().addEntry(entry); // use addEntries(e1, e2, ...) to add multiple at once\n```\n\n## Add, update or remove a calendar entry\n\nThis sample shows some basic CRUD functions using the in memory entry provider.\nWhen you use a callback entry provider, the add/remove methods are not available. Instead\nyou need to update your data structure and call the refresh methods. See details\nin the [EntryProvider](#Entry-providers) section.\n\n```java\n// ... create a form and binder to provide editable components to the user\nInMemoryEntryProvider<Entry> entryProvider = calendar.getEntryProvider().asInMemory();\n\nHorizontalLayout buttons = new HorizontalLayout();\nButton buttonSave;\nif (newInstance) {\n    buttonSave = new Button(\"Create\", e -> {\n        if (binder.validate().isOk()) {\n            // add the entry to the calendar instance and inform the client to update itself\n            entryProvider.addEntry(entry);\n            entryProvider.refreshAll();\n        }\n    });\n} else {\n    buttonSave = new Button(\"Save\", e -> {\n        if (binder.validate().isOk()) {\n            // update an existing entry in the client side\n            // this will only send changed data\n            entryProvider.refreshItem(entry);\n        }\n   });\n}\nbuttons.add(buttonSave);\n\nif (!newInstance) {\n    Button buttonRemove = new Button(\"Remove\", e -> {\n        entryProvider.removeEntry(entry);\n        entryProvider.refreshAll();\n    });\n    buttons.add(buttonRemove);\n}\n```\n\n## Calendar event handling\nThis sample shows how to react on calendar events, that are triggered by the user or the calendar lifecycle.\n\n```java\n/*\n * The day click event listener is called when a user clicks in an empty space inside of the\n * calendar. Depending of if the clicked point was a day or time slot the event will provide the\n * time details of the clicked point. With this info you can show a dialog to create a new entry.\n */\ncalendar.addTimeslotsSelectedListener((event) -> {\n// react on the selected timeslot, for instance create a new instance and let the user edit it\n    Entry entry = new Entry();\n   \n    entry.setStart(event.getStart()); // also event times are always utc based\n    entry.setEnd(event.getEnd());\n    entry.setAllDay(event.isAllDay());\n\n    entry.setColor(\"dodgerblue\");\n\n    // ... show an editor or do something else with the entry\n});\n\n/*\n * The entry click event listener is called when the user clicks on an existing entry.\n * The event provides the clicked event which might be then opened in a dialog.\n */\ncalendar.addEntryClickedListener((event) -> {\n    // react on the clicked entry, for instance let the user edit it\n    Entry entry = event.getEntry();\n\n    // ... show an editor or do something else with the entry\n});\n```\n\n## Entry providers\n\nEntry providers allow you to minimize the memory footprint by activating lazy loading for calendar entries.\nThe `InMemoryEntryProvider` keeps all entries server-side and streams only the visible period to the client;\nthe `CallbackEntryProvider` delegates every fetch to your own backend query.\n\n### In memory entry provider\n\nThe `InMemoryEntryProvider` caches all registered entries on the server side, but provides only a subset of them to\nthe client (i. e. the entries of the current shown period). This way you can use the CRUD API on the server side\nwithout the need of implementing it yourself. On the other hand the client will be kept free of unnecessary information.\n\n```java\n// load items from backend\nList<Entry> entryList = backend.streamEntries().collect(Collectors.toList());\n\n// init provider from a collection — does NOT use the collection as a live backend (changes must be pushed via addEntries/removeEntry)\nInMemoryEntryProvider<Entry> entryProvider = EntryProvider.inMemoryFrom(entryList);\n\n// set entry provider\ncalendar.setEntryProvider(entryProvider);\n\n// CRUD operations\n// to add\nEntry entry = new Entry();          // ... plus some init\nentryProvider.addEntry(entry);      // use addEntries(e1, e2, ...) to add multiple at once\nentryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch\n\n// after some change\nentryProvider.refreshItem(entry);   // call refresh to inform the client about the data change and trigger a refetch\n\n// to remove\nentryProvider.removeEntry(entry);\nentryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch\n```\n\n### Using callbacks\n\nThe callback entry provider is a base implementation of the `EntryProvider` interface. It does not care about how the\nbackend creates or stores the entry data, but only fetches the entries to show from it by passing a query. The backend\nis responsible for providing the entries and handle any changes to the data (e. g. due to calendar entry events).\n\n```java\n// the callback provider uses the given callback to fetch entries when necessary\nCallbackEntryProvider<Entry> entryProvider = EntryProvider.fromCallbacks(\n        query -> backend.streamEntries(query),\n        entryId -> backend.getEntry(entryId).orElse(null)\n);\n\n// set entry provider\ncalendar.setEntryProvider(entryProvider);\n\n// CRUD operations\n// to add\nEntry entry = new Entry();          // ... plus some init\nbackend.addEntry(entry);            // register in your backend\nentryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch\n\n// after some change\nbackend.updateEntry(entry);         // inform your backend\nentryProvider.refreshItem(entry);   // call refresh to inform the client about the data change and trigger a refetch\n\n// to remove\nbackend.removeEntry(entry);         // remove from your backend\nentryProvider.refreshAll();   // call refresh to inform the client about the data change and trigger a refetch\n```\n\n### Custom implementation\n\nFeel free to create your own custom implementation, for instance to provide advanced internal caching on the server\nside. We recommend to extend the `AbstractEntryProvider` to start with.\n\nThe simplest variant is similar to the callback variant, but with its own class:\n\n```java\nprivate static class BackendEntryProvider extends AbstractEntryProvider<Entry> {\n    private final EntryService service;\n\n    public BackendEntryProvider(EntryService service) {\n        this.service = service;\n    }\n\n    @Override\n    public Stream<Entry> fetch(@NonNull EntryQuery query) {\n        return service.streamEntries(query);\n    }\n\n    @Override\n    public Optional<Entry> fetchById(@NonNull String id) {\n        return service.getEntry(id);\n    }\n}\n```\n\n### Prefetch mode \nNormally an entry provider would only fetch data for the current period. Switching to an adjacent one could\nlead to flickering, since the calendar will most likely resize itself (because the now shown entries have a different\nsize, are on different days, the month is shorter or longer, etc).\n\nTo prevent that flickering, the calendar provides a feature called \"prefetch mode\". This by default activated feature \nensures, that the calendar will additionally fetch the previous and next period together with the current one. \nWhen switching to an adjacent period, the calendar will not simply be empty, but show the prefetched entries to prevent\nvisual glitches. In the same time, the client will fetch the latest state for the current period and update it\nagain, so that the shown data is up-to-date. \n\nBe aware, that this feature leads to an increased amount of data transported between server and client, but in the same \ntime leads to a better user experience as the above mentioned flickering will be prevented.\n\nThe prefetch mode determines adjacent periods based on the active view's *range unit* — the natural navigation step of the view (e.g., `timeGridWeek` has a \"week\" unit, `dayGridMonth` has a \"month\" unit). The supported units are `\"day\"`, `\"month\"`, and `\"year\"`. If the range unit cannot be determined, a warning is logged to the Java console (SLF4J at WARN level) and prefetch behaves as if disabled. Custom or unsupported views also fall back silently to the non-prefetch behavior.\n\nWe recommend keeping this feature enabled, unless you experience issues due to slow bandwidth or other network issues.\n\n```java\ncalendar.setPrefetchEnabled(false); // disables the prefetch feature\n```\n\n## Setting the calendar's dimensions\n\nYou may set the dimensions as with every other Vaadin component. The FC library also brings in some additional\nsettings for content height or an aspect ratio, that can be taken into account. These can be set via `setOption`,\ne.g. `calendar.setOption(Option.CONTENT_HEIGHT, \"500px\")` or `calendar.setOption(Option.ASPECT_RATIO, 1.5)`.\nSee the [FullCalendar sizing docs](https://fullcalendar.io/docs/sizing) for all available options.\n\n## Using timezones\nYou can set a timezone to the calendar, so that your UTC-based entries are automatically shown with the respective\ntimezone's offset at the client. \n\nPlease note, that this only affects the FullCalendar. Vaadin date pickers, that are for instance there to edit\ncalendar entries in a form have to be configured respectively. \n\n```java\n// FC allows to show entries in a specifc timezone. Setting a timezone only affects the client side\n// and might be interesting, when editing those entries in some kind of edit form\n\nTimezone tzBerlinGermany = new Timezone(ZoneId.of(\"Europe/Berlin\"));\ncalendar.setTimezone(tzBerlinGermany); // will rerender the client side and show all times 1-2 hours \"later\".\n\n// We can also reset the timezone to default.\ncalendar.setTimezone(Timezone.UTC);\n\n// We can also read the browsers timezone, after the component has been attached to the client side.\n// There are other ways to obtain the browser's timezone, so you are not obliged to use the listener.\ncalendar.addBrowserTimezoneObtainedListener(event -> calendar.setTimezone(event.getTimezone()));\n\n// If you want to let the calendar obtain the browser time zone automatically, you may simply use the builder.\n// In that case as soon as the client connected, it will set it's timezone in the server side instance.\nFullCalendarBuilder.create().withAutoBrowserTimezone().build();\n\n// Entries use internally utc to define times. The LocalDateTime and Instant methods setStart/End have the same effect.\nentry.setStart(Instant.now()); // UTC\nentry.setEnd(LocalDateTime.now()); // treated as UTC — LocalDateTime carries no timezone info in this API\n\n// Entry provides some additional convenience methods to handle the current calendar's timezone's offset, e.g. to allow easy\n// integration into edit forms.\ncalendar.setTimezone(tzBerlinGermany); // times are now 1-2 hours \"ahead\" (depending on daylight saving)\nentry.setStart(LocalDate.of(2000, 1, 1).atStartOfDay());\n\nLocalDateTime utcStart = entry.getStart(); // will be 2000-01-01, 00:00\nLocalDateTime offsetStart = entry.getStartWithOffset(); // will be 2000-01-01, 01:00\n\n// ... modify the offset start, for instance in a date picker\n// e.g. modifiedOffsetStart = offsetStart.plusHours(5);\nLocalDateTime modifiedOffsetStart = offsetStart.plusHours(5);\n\nentry.setStartWithOffset(modifiedOffsetStart); // automatically takes care of conversion back to utc\nutcStart = entry.getStart(); // will be 2000-01-01, 04:00\noffsetStart = entry.getStartWithOffset(); // will be 2000-01-01, 05:00\n```\n\n## Passing custom initial options in Java\n\nYou can fully customize the client side options in Java by passing a json object when creating the FullCalendar.\nPlease be aware, that some options are always set, regardless of the values you set. Please check the\nApiDocs of the `withInitialOptions` method (or respective constructors) for details\n\nThe following example shows the default initial options as they are set internally by the web component.\n\n```java\nimport org.vaadin.stefan.fullcalendar.JsonFactory;\n\n// ...\n\nObjectNode initialOptions = JsonFactory.createObject();\ninitialOptions.put(\"height\", \"100%\");\ninitialOptions.put(\"timeZone\", \"UTC\");\ninitialOptions.put(\"headerToolbar\", false);\ninitialOptions.put(\"weekNumbers\", true);\ninitialOptions.put(\"dayMaxEvents\", false); // pass an int value to limit the entries per day\ninitialOptions.put(\"navLinks\", true); \ninitialOptions.put(\"selectable\", true);\n\ncalendar = FullCalendarBuilder.create().withInitialOptions(initialOptions).build();\n```\n\n## Style the calendar\n\n### Vaadin Theming\nThe calendar provides a built-in Vaadin theme variant, that applies some styling from the current Vaadin theme, like\nsizes, colors, etc. It is active by default. \n\nPlease note, that there might be parts, that have been forgotten or not looking as expected. \nAlso any additional custom stylings may override the Vaadin stylings. If you find anything, that looks suspicious,\nplease create an issue. \n\nTo remove the Vaadin theme, simply remove the theme variant, as you would do with other Vaadin components. Please note,\nthat the overall styling still may affect your calendar component in some ways.\n\n```java\ncalendar.removeThemeVariants(FullCalendarVariant.VAADIN);\n```\n\n### Global / custom styles\n\nThe FullCalendar client element is part of the light dom and thus can be styles via plain css. For any details\non styling the FullCalendar please refer to the FC docs (regarding css properties, classes, etc.).\n\nThe styles can be defined as you are used to using the Vaadin theme mechanism.\n\nSample styles.css, that utilizes custom css properties from Lumo.\n\n```css\n/* change the border color of the fc in a global way*/\n.fc {\n    --fc-border-color: #ddd;\n}\n\n/* change the border color of the fc for dark themes*/\n[theme~=\"dark\"] .fc {\n    --fc-border-color: #333;\n}\n\n/* change the appearance of the week and day number to a more button like style when hovering */\n.fc a:is(.fc-daygrid-week-number, .fc-daygrid-day-number) {\n    background: transparent;\n    font-size: 12px;\n    transition: background 200ms ;\n    border-radius: 3px;\n}\n\n.fc a:is(.fc-daygrid-week-number, .fc-daygrid-day-number):hover {\n    background: var(--lumo-primary-color-10pct);\n    text-decoration: none;\n}\n\n.fc a.fc-daygrid-day-number {\n    padding-left: 6px;\n    padding-right: 6px;\n}\n```\n\n## Show the current shown time interval (e. g. month) with Vaadin components\n\nYou can use the \"dates rendered event\" to show details about the current shown period in separate elements instead\nof the built-in FullCalendar header.\n\n```java\nprivate void init() {\n    // The element that should show the current interval.\n    HasText intervalLabel = new Span();\n\n    // combo box to select a view for the calendar, like \"monthly\", \"weekly\", ...\n    ComboBox<CalendarView> viewBox = new ComboBox<>(\"\", CalendarViewImpl.values());\n    viewBox.addValueChangeListener(e -> {\n        CalendarView value = e.getValue();\n        calendar.changeView(value == null ? CalendarViewImpl.DAY_GRID_MONTH : value);\n    });\n    viewBox.setValue(CalendarViewImpl.DAY_GRID_MONTH);\n\n    /*\n     * The view rendered listener is called when the view has been rendererd on client side\n     * and FC is aware of the current shown interval. Might be accessible more directly in\n     * future.\n     */\n    calendar.addDatesRenderedListener(event -> {\n        LocalDate intervalStart = event.getIntervalStart();\n        CalendarView cView = viewBox.getValue();\n\n        String formattedInterval = ... // format the intervalStart based on cView. See the demos for examples.\n\n        intervalLabel.setText(formattedInterval);\n    });\n}\n```\n\n## Creating a background entry\nA background entry is an entry, that is rendered behind all other entries. It is not clickable and\nhas no tooltip. It is useful for marking a time range, e. g. for marking a vacation.\n\n```java\nEntry entry = new Entry();\n// ... setup entry details\n        \nentry.setDisplayMode(DisplayMode.BACKGROUND);\ncalendar.getEntryProvider().asInMemory().addEntry(entry);\n```\n\n## Adding business hours\nYou can define business hours for each day of the week to provide visual feedback to the user, when someone is available\nor not. If you don't define any business hours, the calendar will assume, that the business hours are from 0:00 to 24:00 for each day.\n\nNon-business hours are grayed out in the calendar.\n\n```java\n// Single instance for \"normal\" business week (mo-fr)\ncalendar.setOption(Option.BUSINESS_HOURS, BusinessHours.businessWeek().start(LocalTime.of(9, 0)).end(LocalTime.of(17, 0)));\n\n// Multiple instances\ncalendar.setOption(Option.BUSINESS_HOURS, new BusinessHours[]{\n    BusinessHours.businessWeek().start(9).end(17),\n    BusinessHours.of(DayOfWeek.SATURDAY).start(10).end(14)\n});\n\n// Single instance for \"each day from 9am to midnight\"\ncalendar.setOption(Option.BUSINESS_HOURS, BusinessHours.allDays().start(9));\n```\n\n## Using the Scheduler\nThe scheduler is a commercial plugin of the FullCalendar library, that provides some additional features like\nresource related calendar entries and additional views.  \n\n### Activating the Scheduler\n\n```java\nFullCalendar calendar = FullCalendarBuilder.create().withScheduler().build();\n// scheduler options\ncalendar.setOption(SchedulerOption.LICENSE_KEY, \"YourFullCalendarSchedulerKey\");\n```\n\n### Adding a resource to a calendar and link it with entries\n```java\nScheduler scheduler = (Scheduler) calendar;\n\n// null as first argument means: let FullCalendar auto-generate an ID\nResource resource = new Resource(null, \"Room A\", color);\nscheduler.addResource(resource);\n\n// When we want to link an entry with a resource, we need to use ResourceEntry\n// (a subclass of Entry)\nResourceEntry entry = new ResourceEntry();\nentry.setTitle(title);\nentry.setStart(start.atStartOfDay());\nentry.setEnd(start.plusDays(days).atStartOfDay());\nentry.setAllDay(true);\nentry.setColor(color);\nentry.setDescription(\"Some description...\");\nentry.addResources(resource);\ncalendar.getEntryProvider().asInMemory().addEntry(entry);\n```\n\n### Handling change of an entry's assigned resource by drag and drop\n```java\ncalendar.addEntryDroppedListener(event -> {\n    event.applyChangesOnEntry();\n\n    Entry entry = event.getEntry();\n\n    if(entry instanceof ResourceEntry) {\n        Set<Resource> resources = ((ResourceEntry) entry).getResources();\n        if(!resources.isEmpty()) {\n            // do something with the resource info\n        }\n    }\n});\n```\n\n### Switching to a timeline view\n```java\ncalendar.changeView(SchedulerView.TIMELINE_DAY);\n```\n\n### Activate vertical resource view\n```java\ncalendar.setGroupEntriesBy(GroupEntriesBy.RESOURCE_DATE);\n```\n\n### Creating a resource based background entry\n```java\nResourceEntry entry = new ResourceEntry();\n// ... setup entry details, including addResource()\n\nentry.setDisplayMode(DisplayMode.BACKGROUND);\ncalendar.getEntryProvider().asInMemory().addEntry(entry);\n```\n\n### Creating hierarchical resources\n```java\n// Create a parent resource. When adding the sub resources first before adding the parent to the calendar,\n// the sub resources are registered automatically on client side and server side.\n\nScheduler scheduler = (Scheduler) calendar;\n\nResource parent = new Resource();\nparent.addChildren(new Resource(), new Resource(), new Resource());\n\nscheduler.addResource(parent); // will add the resource and also its children to server and client\n\n// add new resources to already registered parents\nResource child = new Resource();\nparent.addChild(child);\nscheduler.addResource(child); // this will update the client side\n\n// or remove them from already registered ones\nscheduler.removeResource(child);\nparent.removeChild(child);\n```\n\n### Making a resource entry draggable between resources\n```java\n// activate globally — allows all entries to be dragged between resources\ncalendar.setOption(SchedulerOption.ENTRY_RESOURCES_EDITABLE, true);\n```\n\n### Using component resource area columns\n\nResource area columns can display interactive Vaadin components (such as DatePicker, TextField, ComboBox, etc.) — one component per resource. This is useful for inline editing or displaying resource-related metadata. Components are created by a callback and support type-safe runtime access.\n\n#### Basic component column\n\n```java\nFullCalendarScheduler scheduler = (FullCalendarScheduler) FullCalendarBuilder.create()\n    .withScheduler(Scheduler.GPL_V3_LICENSE_KEY)\n    .build();\n\n// Create a DatePicker column that receives a Resource and returns a component\nComponentResourceAreaColumn<DatePicker> deadlineCol = new ComponentResourceAreaColumn<>(\n    \"deadline\",  // unique field key\n    \"Deadline\",  // column header\n    resource -> {\n        DatePicker picker = new DatePicker();\n        picker.setWidth(\"130px\");\n        picker.addValueChangeListener(e -> {\n            if (e.isFromClient()) {\n                // Handle user interaction — e.g., update entry or resource data\n                System.out.println(\"Deadline for \" + resource.getTitle() + \" → \" + e.getValue());\n            }\n        });\n        return picker;\n    }\n);\n\n// Combine with regular text columns\nscheduler.setResourceAreaColumns(\n    new ResourceAreaColumn(\"title\", \"Name\").withWidth(\"200px\"),\n    deadlineCol.withWidth(\"160px\")\n);\n```\n\n#### Accessing and updating components\n\n```java\n// Type-safe access to a component at any time\ndeadlineCol.getComponent(resource).ifPresent(picker ->\n    picker.setValue(LocalDate.now())\n);\n\n// Iterate all resource-component mappings (unmodifiable, keyed by resource ID)\ndeadlineCol.getComponents().forEach((resourceId, picker) -> {\n    // Read or update — picker is already typed as DatePicker\n});\n\n// Force re-creation of all components (state is lost)\ndeadlineCol.refreshAll();\n\n// Re-create a single resource's component\ndeadlineCol.refresh(resource);\n```\n\n#### Syncing with entry drag/resize\n\nComponents and entries can be kept in sync — for example, a DatePicker showing entry start/end dates that updates when the entry is dragged or resized:\n\n```java\nComponentResourceAreaColumn<DatePicker> startCol = new ComponentResourceAreaColumn<>(\n    \"start\", \"Start\",\n    resource -> new DatePicker()\n);\n\nscheduler.addEntryResizedListener(event -> {\n    event.applyChangesOnEntry();\n\n    // Update component(s) with new entry time\n    if (event.getEntry() instanceof ResourceEntry re) {\n        for (Resource resource : re.getResources()) {\n            startCol.getComponent(resource).ifPresent(picker ->\n                picker.setValue(event.getEntry().getStart().toLocalDate())\n            );\n        }\n    }\n});\n```\n\n## Using tippy.js for description tooltips\nBy default the calendar does not provide tooltips for entries. However, you can easily integrate any type of\ntooltip mechanism or library, for instance by simply applying an html title or using a matured tooltip library\nlike tippy.js.\n\nThis sample shows how to easy integrate tippy.js into a custom subclass of FullCalendar to show an entry's description\nas a tooltip when hovering the entry inside the FC. Please customize the example as needed.\n\n1. Create a new TypeScript file inside the frontend folder of your project. It needs to extend either FullCalendar or\n   FullCalendarScheduler. This example utilizes FullCalendarScheduler. If you want to use the normal FC, simply remove\n   all the -Scheduler parts. You may also use plain JavaScript instead of TypeScript — in that case remove the type\n   annotations and rename the file to `.js`.\n\n   > **Note:** The `@JsModule` annotation in the Java class references `full-calendar-with-tooltip.js` (without the\n   > `s` at the end, and `.js` extension). Vaadin's frontend build (Vite) compiles the `.ts` file to `.js` automatically,\n   > so the annotation must point to the compiled output name.\n\nfull-calendar-with-tooltip.ts\n\n```typescript\nimport {FullCalendarScheduler} from 'Frontend/generated/jar-resources/vaadin-full-calendar/full-calendar-scheduler';\nimport tippy from 'tippy.js';\n\n\nexport class FullCalendarWithTooltip extends FullCalendarScheduler {\n    private _tooltipInitialized: boolean = false;\n\n    initCalendar() {\n        super.initCalendar();\n\n        // Prevent duplicate event handler registration on re-initialization\n        if (this._tooltipInitialized) {\n            return;\n        }\n        this._tooltipInitialized = true;\n\n        this.calendar!.setOption(\"eventDidMount\", e => {\n            this.initTooltip(e);\n        });\n    }\n\n    initTooltip(e: any) {\n        if (e.event.title && !e.isMirror) {\n            e.el.addEventListener(\"mouseenter\", () => {\n                let tooltip = e.event.getCustomProperty(\"description\", e.event.title);\n\n                e.el._tippy = tippy(e.el, {\n                    theme: 'light',\n                    content: tooltip,\n                    trigger: 'manual'\n                });\n\n                e.el._tippy.show();\n            })\n\n            e.el.addEventListener(\"mouseleave\", () => {\n                if (e.el._tippy) {\n                    e.el._tippy.destroy();\n                }\n            })\n        }\n    }\n}\n\ncustomElements.define(\"full-calendar-with-tooltip\", FullCalendarWithTooltip);\n\n```\n\n2. Now create a simple JavaClass, that utilizes your js file. This Java class also imports the needed CSS files.\n\n```java\n@Tag(\"full-calendar-with-tooltip\")\n@JsModule(\"./full-calendar-with-tooltip.js\")\n@CssImport(\"tippy.js/dist/tippy.css\")\n@CssImport(\"tippy.js/themes/light.css\")\npublic class FullCalendarWithTooltip extends FullCalendarScheduler {\n\n    public FullCalendarWithTooltip() {\n    }\n}\n```\n\nAs shown in the subclass sample, you may also use the FullCalendarBuilder to create your custom class.\n\n## Customize entry rendering (render hooks)\n\nFC allows you to hook into the rendering of entries using `setOption` with a `JsCallback` value\nand an `Option` constant (see [FullCalendar render hook docs](https://fullcalendar.io/docs/event-render-hooks)\nfor callback arguments). The function string is evaluated in the browser — no server round-trip occurs.\n\n> **Note for `FullCalendarBuilder` users:** `withEntryContent(String)` on the builder is deprecated.\n> Use `setOption(Option.ENTRY_CONTENT, JsCallback.of(...))` after building instead.\n\n**`Option.ENTRY_DID_MOUNT`** — called after an entry element is added to the DOM. Use it for setup, e.g.\nsetting element attributes:\n\n```java\ncalendar.setOption(Option.ENTRY_DID_MOUNT, JsCallback.of(\"\"\"\n        function(info) {\n            info.el.id = \"entry-\" + info.event.id;\n        }\n        \"\"\"));\n```\n\n**`Option.ENTRY_CONTENT`** — customize the HTML content rendered inside the entry element. See\n[content injection](https://fullcalendar.io/docs/content-injection) for the return value format:\n\n```java\ncalendar.setOption(Option.ENTRY_CONTENT,\n        JsCallback.of(\"function(info) { return { html: '<b>' + info.event.title + '</b>' }; }\"));\n```\n\nInside entry callbacks you may access the entry's default properties or custom ones set via\n`entry.setCustomProperty(String, Object)`. The `getCustomProperty(key)` and\n`getCustomProperty(key, defaultValue)` methods are injected automatically onto the event object:\n\n```java\n// set the custom property beforehand\nentry.setCustomProperty(Entry.EntryCustomProperties.DESCRIPTION, \"some description\");\n\n// access it inside the callback\ncalendar.setOption(Option.ENTRY_CONTENT, JsCallback.of(\n        \"function(info) {\" +\n        \"   let desc = info.event.getCustomProperty('\" + Entry.EntryCustomProperties.DESCRIPTION + \"', '');\" +\n        \"   return { html: '<b>' + info.event.title + '</b><br>' + desc };\" +\n        \"}\"));\n```\n\nCallbacks can be set before or after the calendar is attached.\n\nAlso make sure that your callback function does not contain any harmful code or allow cross-site scripting.\n\n## Use native javascript events for entries\nSometimes the available events are not enough. For that purpose, we added native event listeners for calendar entries. \nThese allow you to setup JavaScript events for each entry, e.g. a mouse over event handler. Inside these event handlers \nyou may also access the created entry dom element.\n\nCustom native event handlers are added to the FullCalender object. They will then be applied to each created\nentry object (using the entryDidMount callback).\n\nTo add an event handler, simply call the method `addEntryNativeEventListener` on the calendar. The first parameter\nis the JavaScript event name (e.g. \"mouseover\"), the second parameter is the callback, that shall be used for\nthat event. Please be aware, that we do NOT check or sanitize the given JavaScript. It is up to you to prevent\nmalicious code from being sent to your users.\n\nInside the event callback, you may access the entryDidMount argument object, that contains additional information\nabout the current entry. See the official docs (https://fullcalendar.io/docs/event-render-hooks)\nfor more details about which details it provide.\n\n```java\nFullCalendar calendar = new FullCalendar();\n\n// ... other configurations\n\n// write the js event, the current entry info and the current entry's element to the browser console.\ncalendar.addEntryNativeEventListener(\"mouseover\", \"e => console.warn(e, info.event, info.el)\");\n\nadd(calendar);\n```\n\nThis sample will change the element style, when the mouse moves over it and changes back, when leaving the element.\n\n```java\ncalendar.addEntryNativeEventListener(\"mouseover\", \"e => info.el.style.opacity = '0.5'\");\ncalendar.addEntryNativeEventListener(\"mouseout\", \"e => info.el.style.opacity = ''\");\n```\n\nYou can also access the client side dom to utilize other elements, like the parents. With this you may for instance\ncall a server side method.\n\nThe following sample shows, how a client callable method in the current view, containing the FullCalendar object, can\nbe called, when right clicking the entry. With this info you can for instance open a custom popup as a context menu.\n\n```java\n@Route(...)\npublic class MyCalendarView extends VerticalLayout {\n    public MyCalendarView() {\n\n        FullCalendar calendar = new FullCalendar();\n        // adds a contextmenu / right client event listener, that calls our openContextMenu.\n        // \"this\" is the fc object, \"this.el\" is the Flow element and \"this.el.parentElement\" is our current view.\n        // This hierarchy access may change, when you nest the FC into other containers.\n\n        calendar.addEntryNativeEventListener(\"contextmenu\",\n                \"e => this.el.parentElement.$server.openContextMenu(info.event, e.clientX, e.clientY)\");\n\n        add(calendar);\n    }\n\n    @ClientCallable\n    public void openContextMenu(JsonObject e, int pointerX, int pointerY) {\n        System.out.println(e);\n        System.out.println(pointerX);\n        System.out.println(pointerY);\n    }\n} \n```\n\nYou can combine the event handlers with a custom entryDidMount callback, if you want additional customizations\nof the entries. The FC will take care of combining the event handlers and your EDM callback\n```java\ncalendar.setOption(Option.ENTRY_DID_MOUNT, JsCallback.of(\"\"\"\n       function(info) {\n           console.warn(\"my custom callback\");\n       }\"\"\"));\n\ncalendar.addEntryNativeEventListener(\"mouseover\", \"e => info.el.style.opacity = '0.5'\");\ncalendar.addEntryNativeEventListener(\"mouseout\", \"e => info.el.style.opacity = ''\");\n```\n\nThe following sample shows how to utilize the entryDidMount callback, the native event handlers and the\n[Popup addon](https://vaadin.com/directory/component/popup) to show a context menu. In this sample, the context\nmenu is based on a ListBox.\n\n```java\n@Route(...)\npublic class MyCalendarView extends VerticalLayout {\n\n    private Popup popup;\n\n    public MyCalendarView() {\n\n        FullCalendar calendar = new FullCalendar();\n        // adds a contextmenu / right client event listener, that calls our openContextMenu.\n        // \"this\" is the fc object, \"this.el\" is the Flow element and \"this.el.parentElement\" is our current view.\n        // This hierarchy access may change, when you nest the FC into other containers.\n\n        calendar.addEntryNativeEventListener(\"contextmenu\",\n                \"e => {\" +\n                        \"   e.preventDefault(); \" +\n                        \"   this.el.parentElement.$server.openContextMenu(info.event.id);\" +\n                        \"}\");\n\n        // by default, the entry element has no id attribute. Therefore we have to add it ourselves, using the\n        // entry id, that is by default an auto generated UUID\n        calendar.setOption(Option.ENTRY_DID_MOUNT, JsCallback.of(\"\"\"\n                function(info) {\n                    info.el.id = \"entry-\" + info.event.id;\n                }\"\"\"));\n\n    }\n\n    @ClientCallable\n    public void openContextMenu (String id){\n        initPopup(); // init the popup\n\n        popup.removeAll(); // remove old content\n\n\n        // setup the context menu\n        // (side note: the list box shows a checkmark, when selecting an item, therefore you may want to use a different \n        // component for a real application or hide the checkmark with CSS)\n        ListBox<String> listBox = new ListBox<>();\n        listBox.setItems(\"Option A\", \"Option B\", \"Option C\");\n        listBox.addValueChangeListener(event -> {\n            Notification.show(\"Selected \" + event.getValue());\n            popup.hide();\n        });\n\n        popup.add(listBox);\n        popup.setFor(\"entry-\" + id);\n\n        popup.show();\n    }\n\n    private void initPopup () {\n        if (popup == null) {\n            popup = new Popup();\n            popup.setFocusTrap(true);\n            add(popup);\n        }\n    }\n} \n```\n\n## Creating a subclass of FullCalendar for custom mods\nThe FullCalendar itself is just a simple Vaadin component on the server and client side, that can be extended\nand customized beyond the default behavior - be aware, that anything you do here is on your own risk and that\nsupport for this use case is limited. \n\nThe client side has the following methods, that you can override / extend to customize the behavior. There are\nothers, but they should normally not be overridden - except for you know what you do ;) \n\n* connectedCallback() - called when the component is attached to the dom\n* initCalendar() - called when the calendar is initialized - only called once\n* createInitOptions(initialOptions) - called when the calendar is initialized. You can modify the initial options here.\n* createEventHandlers() - called when the calendar is initialized. You can modify the event handlers here.\n\nBe aware, that during `connectedCallback()` and before calling `initCalendar()` no internal calendar\nobject is available. Calling `this.calendar` will automatically infer `initCalendar()` and thus can lead\nto unwanted side effects. Therefore, if you want to set options, add entries or do other things with the\ncalendar object, do it after `super.initCalendar()` has been called.\n\nIf you want to modifiy options, that are passed into the calendar object, you can extend the method\n`createInitOptions(initialOptions)` and return a modified options object.\n\nIf you want to modify or extend the event handlers, you can override the method `createEventHandlers()`-\n\nWe recommend to use the `override` modifier on overridden methods to make sure, that the method is\nalways up-to-date.\n\n1. Create a custom web component\n   Create a custom component, that extends FullCalendar or FullCalendarScheduler.\n\n\n```typescript\nimport {FullCalendar} from 'Frontend/generated/jar-resources/vaadin-full-calendar/full-calendar';\n\nexport class MyFullCalendar extends FullCalendar {\n    connectedCallback() {\n        super.connectedCallback();\n\n        // do something with this.calendar\n        // ...\n    }\n\n    initCalendar() {\n        super.initCalendar();\n\n        // do something with this.calendar\n        // ...\n    }\n\n    createInitOptions(initialOptions) {\n        let options = super.createInitOptions(initialOptions);\n        // modify the initial options\n        // attention: this.calendar is not available here!\n        // ...\n\n        return options;\n    }\n\n    createEventHandlers() {\n        // modify the event handlers\n        // attention: this.calendar is not available here!\n        // ...\n\n        return super.createEventHandlers();\n    }\n}\n\ncustomElements.define(\"my-full-calendar\", MyFullCalendar);\n```\n\n2. Create a subclass of FullCalendar\n\n```java\nimport com.vaadin.flow.component.Tag;\nimport com.vaadin.flow.component.dependency.JsModule;\nimport org.vaadin.stefan.fullcalendar.FullCalendar;\n\n@Tag(\"my-full-calendar\")\n@JsModule(\"./my-full-calendar.js\")\npublic class MyFullCalendar extends FullCalendar {\n\n    public MyFullCalendar() {\n    }\n}\n```\n\n3. Use this class in your code\n\n```java\ncalendar = new MyFullCalendar();\n```\n\nYou can even use the FullCalendarBuilder to create your custom class. Be aware, that your\ncustom class needs to provide all constructors, that the extended FullCalendar has.\n\n```java\ncalendar = FullCalendarBuilder.create().withCustomType(MyFullCalendar.class).build();\n```   \n\n## Entry data utilities\n\n### Handling data changes in events\n\nWhen an event occurs, you may want to check or apply the event's changes against the related calendar item.\n\nYou may either do this manually or use the provided utility functions, that are part of the `EntryDataEvent` class\n(and subclasses).\n\nIt might come in handy, that you get changes from an event in form of an `Entry` object instead of the different\nchanged values of the event itself.\n\nTo do so, you can simply call `createCopyBasedOnChanges()`, that the `EntryDataEvent` provides.\nThis will create complete copy of the entry but with the changes of the event applied. This copy will not be added to\nthe calendar and is simply intended for data checks.\n\nTo apply any incoming changes to the related `Entry`, the event class provides the method `applyChangesOnEntry()`.\nThis will override the entry with the event data, but not automatically update the client side. This is up to you\nto do with an `refreshItem()` or `refreshAll()` call. Also any backend updates (except for the in memory provider)\nneeds to be handled by your logic.\n\n```java\n// directly apply the changes\ncalendar.addEntryDroppedListener(event -> {\n    event.applyChangesOnEntry(); // includes now the allDay attribute if sent by client\n});\n\n// create a copy to do some business logic checks\ncalendar.addEntryDroppedListener(event -> {\n    Entry copy = event.createCopyBasedOnChanges();\n\n    if(copy.getStartAsLocalDate().isBefore(someRequiredMinimalDate) /* do some background checks on the changed data */) {\n        event.applyChangesOnEntry();\n        event.getSource().getEntryProvider().refreshItem(event.getEntry()); // refresh the entry to update the UI\n    }\n});\n```\n\n### Create a temporary copy\n\nThe `Entry` class provides a copy API, that allows you to create a copy of an entry or from a given entry. With this you\ncan easily create temporary instances for an edit dialog without needing to write a lot of \"get-set\" calls. This is\nuseful, when your binders work with the `setBean` api\n\nPlease be aware, that this api is considered \"experimental\" and might not work in every special use case or with every\ncustom property key.\n\n```java\nEntry tmpEntry = entry.copy(); // create a temporary copy\n// you may also call copyAsType to allow the copy to be of a different type\n\nBinder<Entry> binder = new Binder<>();\n\n// ... init binder\n\nbinder.setBean(tmpEntry); // you can of course also use the read/writeBean api\n\n// modify the bound fields\n\nif (binder.validate().isOk()) {\n    entry.copyFrom(tmpEntry); // this will overwrite the entry with the values of the tmpEntry\n    // ... update the backend as needed, e.g. by calling refreshItem on the entry provider\n}\n```\n\nAlternatively you can use the copy API in a JPA fashion, where new instances are created on changes.\n\n```java\nEntry tmpEntry = entry.copy(); // create a temporary copy\n\n// ... modify the temporary copy\n\n// return a new copy at the end without changing the initial entry\nreturn tmpEntry.copy();\n```\n\n## RRule — RFC 5545 recurrence rules\n\nUse `RRule` for recurrence patterns that the built-in `recurringDaysOfWeek` / `recurringStartTime` approach cannot express.\nThe `@fullcalendar/rrule` plugin is bundled automatically; no extra dependency is needed.\n\n```java\n// Weekly on Monday, Wednesday, Friday — all of 2025.\n// dtstart uses LocalDate, so occurrences are all-day.\nEntry standup = new Entry();\nstandup.setTitle(\"Weekly Standup\");\nstandup.setRRule(RRule.weekly()\n    .byWeekday(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)\n    .dtstart(LocalDate.of(2025, 1, 1))\n    .until(LocalDate.of(2025, 12, 31)));\n\n// Last Friday of each month\n// byWeekday(\"-1fr\") uses RFC 5545 notation: sign + ordinal + 2-letter day code.\n// \"-1fr\" = last Friday; \"1mo\" = first Monday; \"-2tu\" = second-to-last Tuesday.\n// Positive numbers count from the start of the period; negative from the end.\nEntry review = new Entry();\nreview.setTitle(\"Monthly Review\");\nreview.setRRule(RRule.monthly().byWeekday(\"-1fr\"));\n\n// Every two weeks on Tuesday (bi-weekly)\nEntry planning = new Entry();\nplanning.setTitle(\"Bi-weekly Planning\");\nplanning.setRRule(RRule.weekly().byWeekday(DayOfWeek.TUESDAY).interval(2)\n    .dtstart(LocalDate.of(2025, 1, 7))\n    .excludeDates(LocalDate.of(2025, 7, 22), LocalDate.of(2025, 12, 30)));\n\n// Raw RFC 5545 string for unsupported patterns.\n// Note: raw strings use uppercase RFC 5545 syntax (e.g. BYDAY=1MO), not\n// the fluent API's lowercase notation (e.g. byWeekday(\"1mo\")).\nEntry custom = new Entry();\ncustom.setRRule(RRule.ofRaw(\"FREQ=MONTHLY;BYDAY=1MO,3MO;COUNT=12\"));\n\ncalendar.getEntryProvider().asInMemory().addEntries(standup, review, planning, custom);\n```\n\n## Entry URL and keyboard accessibility\n\nEntries with a URL are rendered as `<a>` tags and navigate the browser on click.\nEntries marked `interactive` are keyboard-focusable (Tab navigation + Enter/Space activation).\n\n```java\n// URL entry — FC navigates to the URL when clicked\nEntry link = new Entry();\nlink.setTitle(\"Visit Documentation\");\nlink.setStart(LocalDate.now());\nlink.setAllDay(true);\nlink.setUrl(\"https://vaadin.com/docs\");\n\n// Keyboard-accessible entry (no URL, no drag — just focusable)\nEntry keyboardEntry = new Entry();\nkeyboardEntry.setTitle(\"Press Enter to open wizard\");\nkeyboardEntry.setStart(LocalDate.now().plusDays(1));\nkeyboardEntry.setAllDay(true);\nkeyboardEntry.setInteractive(true); // per-entry override\n\n// Or make ALL entries keyboard-accessible globally:\ncalendar.setOption(FullCalendar.Option.ENTRY_INTERACTIVE, true);\n// Then per-entry override is still possible (e.g., to opt out):\nkeyboardEntry.setInteractive(false);\n\ncalendar.addEntryClickedListener(e -> {\n    // Fired for both mouse clicks and keyboard activations (Enter/Space)\n    System.out.println(\"Clicked: \" + e.getEntry().getTitle());\n});\n```\n\n## Entry overlap control\n\nControl whether entries may visually overlap. The `overlap` field is nullable: `null` means\n\"inherit the global `eventOverlap` setting\".\n\n```java\n// This entry cannot be overlapped by other entries\nEntry blocked = new Entry();\nblocked.setTitle(\"Blocked Time\");\nblocked.setStart(LocalDateTime.of(2025, 3, 5, 9, 0));\nblocked.setEnd(LocalDateTime.of(2025, 3, 5, 11, 0));\nblocked.setOverlap(false);\n\n// Explicitly allow overlap (overrides a global eventOverlap=false if set)\nEntry flexible = new Entry();\nflexible.setTitle(\"Flexible Slot\");\nflexible.setOverlap(true);\n\n// null means \"use whatever the calendar-level eventOverlap says\" (the default)\nEntry normal = new Entry();\nnormal.setOverlap(null);  // same as not calling setOverlap at all\n```\n\n## View-specific options\n\nApply an option only when a specific view type is active. Options set here override the global value\nfor that view; other views are unaffected.\n\n```java\n// Limit stacked events to 3 only in month view (not in week or day views)\ncalendar.setViewSpecificOption(\"dayGridMonth\", FullCalendar.Option.DAY_MAX_EVENT_ROWS, 3);\n\n// Custom slot duration for all time-grid variants\ncalendar.setViewSpecificOption(\"timeGrid\", FullCalendar.Option.SLOT_DURATION, \"00:30:00\");\n\n// Multiple options at once for the same view.\n// Keys here are raw FullCalendar option names (camelCase strings), not Java Option enum values.\ncalendar.setViewSpecificOptions(\"listWeek\", Map.of(\n    \"noEventsText\", \"No events scheduled this week\"\n));\n\n// Use CalendarView enum instead of a raw string\ncalendar.setViewSpecificOption(CalendarViewImpl.DAY_GRID_MONTH,\n    FullCalendar.Option.NOW_INDICATOR, true);\n```\n\n## Force calendar to recalculate its size\n\nIf a calendar is rendered inside a hidden container (e.g., a `Dialog`), it may have zero dimensions\non first render. A `ResizeObserver` on the client side handles most cases automatically, but in some\nedge cases you may need to trigger a resize manually:\n\n```java\nDialog dialog = new Dialog();\nFullCalendar calendar = FullCalendarBuilder.create().build();\ndialog.add(calendar);\n\ndialog.addOpenedChangeListener(event -> {\n    if (event.isOpened()) {\n        // Force recalculation now that the dialog is visible\n        calendar.getElement().callJsFunction(\"updateSize\");\n    }\n});\n```\n\n## Accessibility hints for toolbar buttons\n\nSet `aria-label` values on the prev/next/today toolbar buttons for screen-reader users.\n\n```java\ncalendar.setOption(FullCalendar.Option.NATIVE_TOOLBAR_BUTTON_HINTS, Map.of(\n    \"today\", \"Jump to today\",\n    \"prev\",  \"Go to previous period\",\n    \"next\",  \"Go to next period\"\n));\n\n// Accessible label for the \"+N more\" overflow link (e.g., \"+ 3 more\")\n// $0 is replaced with the hidden-event count at runtime\ncalendar.setOption(Option.MORE_LINK_HINT, \"$0 more events — click to expand\");\n\n// Accessible label for day-number navigation links\ncalendar.setOption(Option.NAV_LINK_HINT, \"Go to $0\");  // $0 = full date text\n```\n\n## Client-side event sources\n\nClient-side event sources let the **browser** fetch events directly from an external URL — bypassing the Vaadin server.\nThis is useful when events come from third-party services (Google Calendar, iCal feeds, REST APIs).\n\nClient-side sources coexist with the server-side `EntryProvider`. Entries from both appear on the same calendar.\n\n### JSON feed\n\n```java\n// The browser will GET this URL whenever the visible date range changes.\nJsonFeedEventSource jsonFeed = new JsonFeedEventSource(\"https://example.com/api/events\");\njsonFeed.withId(\"company-events\");\njsonFeed.withColor(\"#3788d8\");\njsonFeed.withExtraParams(Map.of(\"department\", \"engineering\"));  // appended as query params\n\ncalendar.addClientSideEventSource(jsonFeed);\n```\n\n### Google Calendar\n\n```java\n// Set the API key globally (applies to all Google sources on this calendar)\ncalendar.setOption(FullCalendar.Option.EXTERNAL_EVENT_SOURCE_GOOGLE_CALENDAR_API_KEY, \"YOUR_GOOGLE_API_KEY\");\n\nGoogleCalendarEventSource holidays = new GoogleCalendarEventSource(\"en.german#holiday@group.v.calendar.google.com\");\nholidays.withId(\"holidays\");\nholidays.withColor(\"#4caf50\");\n\ncalendar.addClientSideEventSource(holidays);\n```\n\n### iCalendar (ICS)\n\n```java\nICalendarEventSource ical = new ICalendarEventSource(\"https://example.com/calendar.ics\");\nical.withId(\"team-calendar\");\nical.withColor(\"#ff9800\");\n\ncalendar.addClientSideEventSource(ical);\n```\n\n### Error handling and per-source refresh\n\n```java\n// React to fetch failures on the server side\ncalendar.addEventSourceFailureListener(event -> {\n    Notification.show(\"Failed to load source '\" + event.getSourceId() + \"': \" + event.getMessage(),\n            3000, Notification.Position.BOTTOM_START);\n});\n\n// Refresh only a specific source (e.g. after the user changed a filter)\ncalendar.refetchClientSideEventSource(\"company-events\");\n\n// Or refresh all sources at once\ncalendar.refetchEvents();\n```\n\n### Per-source options\n\n```java\n// Event sources support the same display options as entries\nJsonFeedEventSource feed = new JsonFeedEventSource(\"https://example.com/api/events\");\nfeed.withId(\"external\");\nfeed.withEditable(false);          // entries from this source are read-only\nfeed.withColor(\"#888\");\nfeed.withDisplay(\"background\");    // render as background events\nfeed.withDefaultAllDay(true);\n\n// Transform incoming event data before FC processes it\nfeed.withEventDataTransform(JsCallback.of(\"\"\"\n    function(eventData) {\n        eventData.title = '[EXT] ' + eventData.title;\n        return eventData;\n    }\"\"\"));\n\ncalendar.addClientSideEventSource(feed);\n```\n\n## External drag and drop\n\nMake external Vaadin components draggable onto the calendar using the `Draggable` API.\n\n### Simple draggable with entry data\n\n```java\n// 1. Enable external drops on the calendar\ncalendar.setOption(Option.DROPPABLE, true);\n\n// 2. Create a Vaadin component and an Entry with the data for the drop\nDiv meetingItem = new Div(\"New Meeting\");\nmeetingItem.getStyle().set(\"cursor\", \"grab\");\n\nEntry meetingData = new Entry();\nmeetingData.setTitle(\"New Meeting\");\nmeetingData.setColor(\"#4CAF50\");\n\n// 3. Register the draggable on the calendar\ncalendar.addDraggable(new Draggable(meetingItem, meetingData));\n\n// 4. Listen for entry creation — fires when FC creates an entry from the drop\n//    The entry is transient — add it to your provider to persist it\ncalendar.addEntryReceiveListener(event -> {\n    Entry created = event.getEntry();\n    calendar.getEntryProvider().asInMemory().addEntry(created);\n    calendar.getEntryProvider().asInMemory().refreshAll();\n\n    // Access the original Draggable if needed\n    event.getDraggable().ifPresent(d -> {\n        System.out.println(\"Dropped component: \" + d.getComponent());\n    });\n});\n```\n\nThe `DropEvent` (via `addDropListener`) fires for all external drops, including elements without\nentry data. Use it when you need to react to any drop regardless of whether an entry was created.\n\n### Container draggable with itemSelector\n\nMake children of a container draggable using a CSS selector. A `JsCallback` dynamically\ncreates entry data from the dragged child element.\n\n```java\n// A container with multiple draggable children\nDiv taskList = new Div();\ntaskList.add(createTask(\"Write report\"), createTask(\"Fix bug #42\"), createTask(\"Review PR\"));\n\n// Only children matching \".task-item\" are draggable.\n// The JS callback reads the element's text to create the entry title.\ncalendar.addDraggable(new Draggable(taskList)\n        .withItemSelector(\".task-item\")\n        .withEventDataCallback(JsCallback.of(\n                \"function(el) { return { title: el.innerText, duration: '01:00' }; }\")));\n\n// Helper\nprivate Div createTask(String name) {\n    Div item = new Div(name);\n    item.addClassName(\"task-item\");\n    item.getStyle().set(\"cursor\", \"grab\");\n    return item;\n}\n```\n\n### Multi-calendar: entry leave listener\n\nWhen entries can be dragged between calendars, listen on the source calendar for entries leaving:\n\n```java\ncalendar.addEntryLeaveListener(event -> {\n    Entry leaving = event.getEntry();\n    calendar.getEntryProvider().asInMemory().removeEntry(leaving);\n    calendar.getEntryProvider().asInMemory().refreshAll();\n});\n```\n\n## Drag and resize lifecycle events\n\nThese events fire at the **start** and **end** of a drag or resize gesture — before the final\n`EntryDroppedEvent` / `EntryResizedEvent`. Use them for visual feedback (e.g. disabling a delete button\nduring drag).\n\n**Important:** Do NOT call `applyChangesOnEntry()` on these events — they report the *original* position,\nnot the final one. Use `EntryDroppedEvent` / `EntryResizedEvent` for applying changes.\n\n```java\nButton deleteButton = new Button(\"Delete\");\n\n// Disable the delete button while the user is dragging an entry\ncalendar.addEntryDragStartListener(event -> {\n    deleteButton.setEnabled(false);\n});\ncalendar.addEntryDragStopListener(event -> {\n    deleteButton.setEnabled(true);\n});\n\n// Same pattern for resize\ncalendar.addEntryResizeStartListener(event -> {\n    deleteButton.setEnabled(false);\n});\ncalendar.addEntryResizeStopListener(event -> {\n    deleteButton.setEnabled(true);\n});\n\n// Apply changes only in the final event\ncalendar.addEntryDroppedListener(event -> {\n    event.applyChangesOnEntry();\n    calendar.getEntryProvider().asInMemory().refreshItem(event.getEntry());\n});\n```\n\n## Resource area columns (Scheduler)\n\nDefine multiple columns in the resource area of timeline views. Each column can display a different\nresource property.\n\n```java\nScheduler scheduler = (Scheduler) calendar;\n\n// Define columns — the field name must match a key in Resource.extendedProps or a standard property\nResourceAreaColumn nameCol = new ResourceAreaColumn(\"title\", \"Name\");\nnameCol.withWidth(\"150px\");\n\nResourceAreaColumn roleCol = new ResourceAreaColumn(\"role\", \"Role\");\nroleCol.withWidth(\"100px\");\n\nResourceAreaColumn deptCol = new ResourceAreaColumn(\"department\", \"Dept\");\ndeptCol.withWidth(\"80px\");\ndeptCol.withGroup(true);  // group resources by this column's values\n\nscheduler.setResourceAreaColumns(List.of(nameCol, roleCol, deptCol));\n\n// IMPORTANT: grouping requires both withGroup(true) on the column AND setOption(SchedulerOption.RESOURCE_GROUP_FIELD, ...)\nscheduler.setOption(SchedulerOption.RESOURCE_GROUP_FIELD, \"department\");\n\n// Create resources with matching extendedProps\nResource dev1 = new Resource(\"1\", \"Alice\", null);\ndev1.addExtendedProps(\"role\", \"Developer\");\ndev1.addExtendedProps(\"department\", \"Engineering\");\n\nResource dev2 = new Resource(\"2\", \"Bob\", null);\ndev2.addExtendedProps(\"role\", \"Designer\");\ndev2.addExtendedProps(\"department\", \"Design\");\n\nscheduler.addResources(dev1, dev2);\n```\n\n### Column render hooks\n\n```java\n// Customize how cells in a column are rendered — pass JsCallback for function values\nResourceAreaColumn statusCol = new ResourceAreaColumn(\"status\", \"Status\");\nstatusCol.withCellContent(JsCallback.of(\"\"\"\n    function(arg) {\n        var val = arg.resource.extendedProps.status || 'unknown';\n        return { html: '<span class=\"status-' + val + '\">' + val + '</span>' };\n    }\"\"\"));\nstatusCol.withCellClassNames(JsCallback.of(\"\"\"\n    function(arg) {\n        return arg.resource.extendedProps.status === 'active' ? ['active-cell'] : [];\n    }\"\"\"));\n\n// Static content is also supported — pass a plain String instead\nstatusCol.withCellContent(\"n/a\");  // displayed as-is in every cell\n```\n\n## Entry constraints with BusinessHours\n\nRestrict where a specific entry can be dragged or resized — independently of the calendar's\nglobal business hours display.\n\n```java\n// This entry can only be placed during custom hours (Mon–Fri, 9–17)\nEntry meeting = new Entry();\nmeeting.setTitle(\"Client Meeting\");\nmeeting.setStart(LocalDateTime.of(2025, 3, 10, 10, 0));\nmeeting.setEnd(LocalDateTime.of(2025, 3, 10, 11, 0));\nmeeting.setConstraint(BusinessHours.businessWeek().start(9).end(17));\n\n// This entry defers to the calendar's defined business hours\nEntry standup = new Entry();\nstandup.setTitle(\"Standup\");\nstandup.setConstraintToBusinessHours();\n\n// This entry can only overlap with entries in the same group\nEntry teamEvent = new Entry();\nteamEvent.setGroupId(\"team-a\");\nteamEvent.setConstraint(\"team-a\");  // only droppable where other \"team-a\" entries are\n```\n\n## Global event overlap control\n\nControl whether events may overlap when dragged or resized. Per-entry `setOverlap()` overrides\nthe global setting.\n\n```java\n// Prevent all entries from overlapping each other\ncalendar.setOption(FullCalendar.Option.ENTRY_OVERLAP, false);\n\n// Individual entries can still opt in\nEntry flexible = new Entry();\nflexible.setTitle(\"Flexible\");\nflexible.setOverlap(true);  // overrides the global false\n\n// For more complex logic, use a JS callback\ncalendar.setOption(FullCalendar.Option.ENTRY_OVERLAP, JsCallback.of(\"\"\"\n    function(stillEvent, movingEvent) {\n        // Allow overlap only with background events\n        return stillEvent.display === 'background';\n    }\"\"\"));\n```\n\n## Render hook callbacks\n\nFullCalendar provides render hooks for almost every visual element: day cells, day headers, slot labels,\nslot lanes, week numbers, now indicator, more-link, no-events, all-day, and view. All follow the same\npattern: `classNames` / `content` / `didMount` / `willUnmount`.\n\nUse `setOption(Option, JsCallback.of(...))` with the appropriate `Option` constant to set these callbacks.\nThis is the recommended approach for all render hook callbacks.\n\n### Highlight weekends in the day grid\n\n```java\ncalendar.setOption(Option.DAY_CELL_CLASS_NAMES, JsCallback.of(\"\"\"\n    function(arg) {\n        var dow = arg.date.getUTCDay();\n        return (dow === 0 || dow === 6) ? ['weekend-cell'] : [];\n    }\"\"\"));\n```\n\nThen in your CSS:\n```css\n.weekend-cell {\n    background-color: rgba(255, 200, 200, 0.15);\n}\n```\n\n### Custom slot labels in the time grid\n\n```java\ncalendar.setOption(Option.SLOT_LABEL_CONTENT, JsCallback.of(\"\"\"\n    function(arg) {\n        var h = arg.date.getUTCHours();\n        if (h < 9 || h >= 17) return { html: '<span style=\"color:#999\">' + arg.text + '</span>' };\n        return arg.text;\n    }\"\"\"));\n```\n\n### Custom day header with extra info\n\n```java\ncalendar.setOption(Option.DAY_HEADER_CONTENT, JsCallback.of(\"\"\"\n    function(arg) {\n        var d = arg.date;\n        var dayName = d.toLocaleDateString('en', { weekday: 'short' });\n        var dayNum = d.getDate();\n        return { html: '<div>' + dayName + '<br><b>' + dayNum + '</b></div>' };\n    }\"\"\"));\n```\n\n### Other render hooks\n\nThe same pattern applies to all other hooks. A few examples:\n\n```java\n// Week numbers — e.g. prefix with \"CW \"\ncalendar.setOption(Option.WEEK_NUMBER_CONTENT, JsCallback.of(\n    \"function(arg) { return { html: 'CW ' + arg.num }; }\"));\n\n// Now indicator — custom styling\ncalendar.setOption(Option.NOW_INDICATOR_CLASS_NAMES, JsCallback.of(\n    \"function() { return ['my-now-line']; }\"));\n\n// More-link — custom text\ncalendar.setOption(Option.MORE_LINK_CONTENT, JsCallback.of(\n    \"function(arg) { return { html: arg.num + ' more...' }; }\"));\n\n// No-events message in list view\ncalendar.setOption(Option.NO_ENTRIES_CONTENT, JsCallback.of(\n    \"function() { return { html: '<em>Nothing scheduled</em>' }; }\"));\n```\n\n## Resource-level display overrides (Scheduler)\n\nResources can define default display properties for all entries assigned to them. The cascade is:\n**Calendar defaults → Resource overrides → Entry overrides** (most specific wins).\n\n```java\n// Room A: all its entries are green by default\nResource roomA = new Resource(\"room-a\", \"Room A\", null);\nroomA.setEntryBackgroundColor(\"#4caf50\");\nroomA.setEntryBorderColor(\"#388e3c\");\n\n// Room B: entries cannot overlap each other on this resource\nResource roomB = new Resource(\"room-b\", \"Room B\", null);\nroomB.setEntryOverlap(false);\nroomB.setEntryBackgroundColor(\"#2196f3\");\n\n// Room C: restrict entries to business hours on this resource\nResource roomC = new Resource(\"room-c\", \"Room C\", null);\nroomC.setEntryConstraint(\"businessHours\");\n\n// Add CSS classes to all entries on this resource\nroomA.setEntryClassNames(Set.of(\"room-a-entry\", \"highlight\"));\n\nScheduler scheduler = (Scheduler) calendar;\nscheduler.addResources(roomA, roomB, roomC);\n```\n\n## JsCallback usage\n\n`JsCallback` wraps a JavaScript function string so that FullCalendar evaluates it in the browser.\nPass a `JsCallback` value to `setOption` with any `Option` constant that accepts a function.\nThis works for render hooks, interaction guards, and any other FC option that expects a JS function.\n\n### Render hook example — custom entry content with an icon\n\n```java\n// Use a render hook to prepend an icon based on a custom property\nentry.setCustomProperty(\"category\", \"meeting\");\n\ncalendar.setOption(Option.ENTRY_CONTENT, JsCallback.of(\"\"\"\n    function(info) {\n        var cat = info.event.getCustomProperty('category', '');\n        var icon = cat === 'meeting' ? '\\u{1F4C5} ' : '';\n        return { html: icon + '<b>' + info.event.title + '</b>' };\n    }\"\"\"));\n```\n\n### Interaction guard example — conditional overlap via callback\n\n```java\n// Use a JsCallback to allow overlap only with background entries\ncalendar.setOption(Option.ENTRY_OVERLAP, JsCallback.of(\"\"\"\n    function(stillEvent, movingEvent) {\n        return stillEvent.display === 'background';\n    }\"\"\"));\n```\n\n### Clearing a callback\n\nUse `JsCallback.clearCallback()` to explicitly clear a previously set callback:\n\n```java\n// Clear the entry-content callback\ncalendar.setOption(Option.ENTRY_CONTENT, JsCallback.clearCallback());\n```\n\nAlternatively, passing `null` directly or `JsCallback.of(null)` has the same effect — useful when\nyou have a nullable string variable:\n\n```java\nString userFn = ...; // may be null\ncalendar.setOption(Option.ENTRY_CONTENT, JsCallback.of(userFn));  // clears if userFn is null\n```\n\n## fixedMirrorParent — controlling the drag-mirror container\n\nThe `fixedMirrorParent` option controls where the drag-mirror element is appended during drag operations.\nSet it via `Option.FIXED_MIRROR_PARENT` with a `JsCallback` that returns a DOM element.\n\n### Simple case — document.body\n\n```java\n// The drag mirror will be appended to document.body\ncalendar.setOption(Option.FIXED_MIRROR_PARENT,\n    JsCallback.of(\"function() { return document.body; }\"));\n```\n\n### Dynamic lookup — function evaluated on each drag start\n\n```java\ncalendar.setOption(Option.FIXED_MIRROR_PARENT, JsCallback.of(\"\"\"\n    function() {\n        return document.querySelector('.my-drag-container');\n    }\"\"\"));\n```\n\nTo clear the option, pass `null`:\n\n```java\ncalendar.setOption(Option.FIXED_MIRROR_PARENT, null);\n```\n\n## moreLinkClick callback\n\nWhen the number of visible entries exceeds the row limit, FullCalendar shows a \"+N more\" link.\nYou can control what happens when the user clicks it.\n\n### Static value — use Option or the convenience method\n\n```java\n// Show a popover with the hidden entries (default behaviour)\ncalendar.setMoreLinkClickAction(MoreLinkClickAction.POPUP);\n\n// Or navigate to the day view\ncalendar.setOption(FullCalendar.Option.MORE_LINK_CLICK, \"day\");\n```\n\n### Function callback — use JsCallback\n\nUse `Option.MORE_LINK_CLICK` with a `JsCallback` when you need custom logic, for instance logging or\nconditionally choosing the action.\n\n```java\ncalendar.setOption(Option.MORE_LINK_CLICK, JsCallback.of(\"\"\"\n    function(info) {\n        console.log('More link clicked on ' + info.date);\n        return 'day';\n    }\"\"\"));\n```\n\n## Restricting navigation with valid range\n\nLimit which dates the user can navigate to. Dates outside the range are greyed out and the\nprev/next buttons are automatically disabled when the edge is reached.\n\n```java\n// Only allow navigation within the current year\ncalendar.setValidRange(\n    LocalDate.of(2025, 1, 1),\n    LocalDate.of(2025, 12, 31)\n);\n\n// Or set only one boundary\ncalendar.setValidRangeStart(LocalDate.now());  // no past navigation\ncalendar.setValidRangeEnd(null);               // no future limit\n```\n",
      "category": "docs",
      "tags": [
        "samples",
        "fullcalendar",
        "entry",
        "entryprovider",
        "inmemoryentryprovider",
        "callbackentryprovider",
        "abstractentryprovider",
        "jscallback",
        "option",
        "fullcalendarbuilder",
        "entrydataevent",
        "rrule",
        "dialog",
        "resizeobserver",
        "scheduler",
        "resource",
        "event"
      ]
    },
    {
      "id": "scheduler-license",
      "title": "Scheduler-license",
      "path": "Scheduler-license.md",
      "content": "The FullCalendar Scheduler library has a different license model then the basic FullCalendar.\n\nFor more details please visit https://fullcalendar.io/license and https://fullcalendar.io/docs/plugin-index\n\n**This addon does not provide any commercial license for the Scheduler. The license model of MIT does only affect the additional files of this addon, not the used original files.**\n\n## Activating the Scheduler - [Example](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FullCalendar-Scheduler-Examples#activating-the-scheduler)\n\nBy default the scheduler is not active, when you use a FullCalendar instance. To have an instance with scheduler activated, use the `.withScheduler(...)` method of the `FullCalendarBuilder`.\n\nThis method will throw an exception, if the scheduler extension is not on the class path.\n\nTo link a resource with entries, use the Entry subclass `ResourceEntry`.",
      "category": "docs",
      "tags": [
        "scheduler-license",
        "fullcalendarbuilder",
        "resourceentry",
        "scheduler",
        "resource",
        "entry",
        "event"
      ]
    },
    {
      "id": "_sidebar",
      "title": "_Sidebar",
      "path": "_Sidebar.md",
      "content": "## [FullCalendar](https://github.com/stefanuebe/vaadin-fullcalendar/wiki)\n### [Getting Started](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Getting-Started)\n### [Features](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Features)\n### [Samples](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Samples)\n### [Release Notes](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Release-notes)\n### [Migration Guides](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Migration-guides)\n### [FAQ](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/FAQ)\n### [Known Issues](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Known-issues)\n### [Scheduler License Info](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/Scheduler-license)\n### [MCP-Server](https://github.com/stefanuebe/vaadin-fullcalendar/wiki/MCP-Server)",
      "category": "docs",
      "tags": [
        "_sidebar",
        "scheduler",
        "resource"
      ]
    },
    {
      "id": "signals-patterns-reference",
      "title": "Vaadin Signals — Idiomatic Patterns Reference",
      "path": "signals-patterns-reference.md",
      "content": "# Vaadin Signals — Idiomatic Patterns Reference\n\n> Compiled from the official `vaadin/signals-cases` repository (all 20+ use cases) and the Vaadin 25.2 documentation. Use this document when reviewing signal code for correctness, performance, and idiomatic style.\n\n---\n\n## Table of Contents\n\n1. [Taxonomy: Which Signal Type to Use](#1-taxonomy-which-signal-type-to-use)\n2. [get() vs peek() — The Most Misused Decision](#2-get-vs-peek)\n3. [Effect Scoping and Lifecycle](#3-effect-scoping-and-lifecycle)\n4. [Split Effects — One Concern Per Effect](#4-split-effects)\n5. [Binding Methods — Prefer Over Manual Effects](#5-binding-methods)\n6. [Computed Signals and map()](#6-computed-signals-and-map)\n7. [Two-Way Mapping: updater() and modifier()](#7-two-way-mapping)\n8. [bindChildren() for Dynamic Lists](#8-bindchildren-for-dynamic-lists)\n9. [peek() to Avoid Circular Dependencies](#9-peek-to-avoid-circular-dependencies)\n10. [Service-to-Signal Pattern](#10-service-to-signal-pattern)\n11. [Event Bridge Pattern](#11-event-bridge-pattern)\n12. [Computed Signal Chains](#12-computed-signal-chains)\n13. [Session-Scoped Signals](#13-session-scoped-signals)\n14. [Async Operations and Signals](#14-async-operations-and-signals)\n15. [Debounce with Manual Scheduling](#15-debounce-with-manual-scheduling)\n16. [Binder + Signal Integration](#16-binder--signal-integration)\n17. [Element.bindAttribute() for Non-Component DOM](#17-elementbindattribute)\n18. [Signal.not() and Boolean Derivations](#18-signalnot-and-boolean-derivations)\n19. [Custom Equality Checkers](#19-custom-equality-checkers)\n20. [Memory and Lifecycle: Standalone vs Component Effects](#20-memory-and-lifecycle)\n21. [Anti-Patterns Index](#21-anti-patterns-index)\n\n---\n\n## 1. Taxonomy: Which Signal Type to Use\n\n| Scenario | Signal Type |\n|---|---|\n| Single-user local UI state (toggle, form field, local filter) | `ValueSignal<T>` |\n| Dynamic list of items, single-user | `ListSignal<T>` |\n| Cross-user shared state (real-time collaboration, dashboards) | `SharedValueSignal<T>` / `SharedListSignal<T>` |\n| Derived/computed value from one source | `signal.map(fn)` |\n| Derived value from multiple sources | `Signal.computed(() -> ...)` |\n| Read-only exposure of a writable signal | `signal.asReadonly()` |\n| Negating a boolean signal | `Signal.not(signal)` |\n\n**Rule**: `ValueSignal` / `ListSignal` cannot participate in transactions. If you need transactional atomicity (all-or-nothing updates), use shared signals.\n\n**Rule**: Declare signals as `final` class fields, grouped at the top of the class. This makes the reactive state explicit.\n\n```java\n// Good — state is visible at a glance\npublic class MyView extends VerticalLayout {\n    private final ValueSignal<String> querySignal = new ValueSignal<>(\"\");\n    private final ValueSignal<Boolean> loadingSignal = new ValueSignal<>(false);\n    private final Signal<Boolean> canSearch = querySignal.map(s -> !s.isBlank());\n\n    public MyView() { ... }\n}\n```\n\n---\n\n## 2. get() vs peek()\n\nThis is the most important distinction and the source of most bugs.\n\n| Method | Registers dependency? | Where to use |\n|---|---|---|\n| `get()` | YES | Inside `Signal.effect()`, `Signal.computed()`, `bindText()` lambdas, any reactive context |\n| `peek()` | NO | Click listeners, `onAttach()`, initialization code, service callbacks, debounce handlers, anywhere outside a reactive context |\n\n**Hard rule**: `get()` outside a reactive context throws `IllegalStateException`. `peek()` inside a reactive context silently breaks reactivity.\n\n```java\n// CORRECT: get() in reactive context\nSignal.effect(this, () -> {\n    String value = nameSignal.get();   // dependency registered\n    label.setText(value);\n});\n\n// CORRECT: peek() in event listener (outside reactive context)\nbutton.addClickListener(e -> {\n    String current = nameSignal.peek();  // no dependency, just a read\n    doSomethingWith(current);\n});\n\n// CORRECT: peek() in service callback (background thread, not reactive context)\nprivate void onDataUpdate(DashboardData data) {\n    currentUsersSignal.set(data.currentUsers());\n    // peek() used to read current window size when computing a new value\n    if (timelineCategoriesSignal.peek().size() >= TIMELINE_POINTS) {\n        timelineCategoriesSignal.remove(timelineCategoriesSignal.peek().getFirst());\n    }\n    timelineCategoriesSignal.insertLast(data.timestamp());\n}\n```\n\n**Use `peek()` for addToCart-style logic** where you scan the list for an existing item without wanting to subscribe to every item change:\n\n```java\n// UC06: Adding to cart — peek() to search without creating subscriptions\nprivate void addToCart(Product product, ListSignal<CartItem> cartItemsSignal) {\n    cartItemsSignal.peek().stream()\n        .filter(signal -> signal.peek().product().id().equals(product.id()))\n        .findFirst()\n        .ifPresentOrElse(\n            existing -> existing.set(existing.peek().withQuantity(existing.peek().quantity() + 1)),\n            () -> cartItemsSignal.insertLast(new CartItem(product, 1)));\n}\n```\n\n---\n\n## 3. Effect Scoping and Lifecycle\n\n### Component-bound effects (most common)\n\n```java\nSignal.effect(component, () -> { ... });\n```\n\n- Active while `component` is attached to the DOM.\n- Automatically paused when component is detached; resumed on re-attach.\n- No manual cleanup needed.\n\n### Unbound/standalone effects\n\n```java\nRegistration cleanup = Signal.unboundEffect(() -> { ... });\n// Must call cleanup.remove() when done — memory leak risk otherwise\n```\n\nUse only when the effect is not tied to any UI component lifetime (e.g., service-level background tracking). Always store the `Registration` and remove it explicitly.\n\n### EffectContext — initial run vs background change detection\n\n```java\nSignal.effect(this, ctx -> {\n    String value = priceSignal.get();\n    span.setText(\"$\" + value);\n\n    if (!ctx.isInitialRun() && ctx.isBackgroundChange()) {\n        span.getElement().executeJs(\"this.classList.add('highlight')\");\n    }\n});\n```\n\n`ctx.isInitialRun()` — true on first execution.\n`ctx.isBackgroundChange()` — true when triggered by a different user session or background thread.\n\n### Manual effect removal\n\n```java\nRegistration effectRegistration = Signal.effect(chart, () -> { ... });\n// Later:\neffectRegistration.remove();\n```\n\nUseful when you need to detach an effect before the component is detached.\n\n---\n\n## 4. Split Effects\n\n**Rule**: Each effect has exactly one responsibility. Never bundle multiple independent concerns into one large effect.\n\n**Why it matters**: When a signal changes, only the effects that depend on it re-run. A fat effect re-runs on any of its many dependencies, doing unnecessary work.\n\n```java\n// WRONG: One effect doing multiple things — ALL re-runs when ANY dependency changes\nSignal.effect(container, () -> {\n    nameLabel.setText(userSignal.get().name());\n    ageLabel.setText(String.valueOf(userSignal.get().age()));\n    statusIndicator.setVisible(userSignal.get().isActive());\n    // ... more updates\n});\n\n// CORRECT: Separate bindings per concern — each updates only when its dependency changes\nnameLabel.bindText(userSignal.map(User::name));\nageLabel.bindText(userSignal.map(u -> String.valueOf(u.age())));\nstatusIndicator.bindVisible(userSignal.map(User::isActive));\n```\n\n**Real-world split from UC14 (dashboard with charts):**\n\n```java\n// Each series gets its own effect — only that series rerenders when its signal changes\nbindChartData(chart, berlinSeries, berlinTimelineSignal);\nbindChartData(chart, londonSeries, londonTimelineSignal);\nbindChartData(chart, newYorkSeries, newYorkTimelineSignal);\n\n// Separate effect for x-axis categories\nSignal.effect(chart, () -> xAxis.setCategories(\n    timelineCategoriesSignal.get().stream().map(Signal::get).toArray(String[]::new)));\n\n// Separate \"coordination\" effect that only triggers chart.drawChart()\nSignal.effect(chart, () -> {\n    berlinTimelineSignal.get();    // register dependency\n    londonTimelineSignal.get();    // register dependency\n    newYorkTimelineSignal.get();   // register dependency\n    chart.drawChart();\n});\n```\n\nThis approach: data effects update series independently; a single coordination effect fires `drawChart()` only after all series have had a chance to update.\n\n---\n\n## 5. Binding Methods\n\n**Rule**: Use binding methods for standard component properties. Use `Signal.effect()` only for custom logic that binding methods cannot express.\n\n### Available binding methods on components\n\n| Method | Target |\n|---|---|\n| `bindText(signal)` | Text content (also: `new Span(signal)`, `new Paragraph(signal)`) |\n| `bindVisible(signal)` | Visibility |\n| `bindEnabled(signal)` | Enabled/disabled state |\n| `bindValue(readSignal, writeFn)` | Two-way form field binding |\n| `bindReadOnly(signal)` | Read-only state |\n| `bindRequiredIndicatorVisible(signal)` | Required indicator |\n| `bindClassName(name, booleanSignal)` | CSS class toggle |\n| `bindClassNames(listSignal)` | Full CSS class list |\n| `bindThemeName(name, booleanSignal)` | Theme variant toggle |\n| `bindThemeVariant(variant, booleanSignal)` | Button/component theme variant |\n| `bindHelperText(signal)` | Helper text |\n| `bindPlaceholder(signal)` | Placeholder text |\n| `bindWidth(signal)` / `bindHeight(signal)` | Size |\n| `getStyle().bind(property, signal)` | Inline CSS property |\n| `getThemeList().bind(name, booleanSignal)` | Theme class toggle |\n| `getElement().getClassList().bind(...)` | Element-level class |\n\n### Multi-signal lambdas in binding methods\n\nWhen a binding depends on multiple signals, pass a lambda instead of a signal directly:\n\n```java\n// Depends on multiple signals — use lambda\nsection.bindVisible(() -> needsVisaSignal.get() && visaTypeSignal.get() == VisaType.H1B);\n\nbutton.bindEnabled(() -> binder.validationStatusSignal().get().isOk()\n    && submissionStateSignal.get() != SubmissionState.SUBMITTING);\n```\n\nThe framework tracks which signals the lambda reads during execution and creates the appropriate dependencies dynamically.\n\n---\n\n## 6. Computed Signals and map()\n\n### map() — single-source derived values\n\n```java\nValueSignal<Integer> age = new ValueSignal<>(0);\nSignal<String> category = age.map(a -> a < 18 ? \"Child\" : (a < 65 ? \"Adult\" : \"Senior\"));\nSignal<Boolean> adult = age.map(a -> a >= 18);\n```\n\n- Read-only.\n- Lazy: only recalculates when the source changes.\n- Cached: multiple reads return the cached value between changes.\n\n### Signal.computed() — multi-source derived values\n\n```java\nSignal<Double> total = Signal.computed(() -> {\n    double subtotal = price.get() * quantity.get();\n    return subtotal * (1 + taxRate.get());\n});\n```\n\n- Use when combining two or more source signals.\n- Dependencies tracked dynamically — if a branch is not taken, signals in that branch are not dependencies.\n\n### Lambda vs Signal.computed() in bindText()\n\n```java\n// Lambda: recalculates on every read AND on every dependency change\nspan.bindText(() -> firstName.get() + \" \" + lastName.get());\n\n// Signal.computed(): caches the result, only recalculates on dependency change\nspan.bindText(Signal.computed(() -> firstName.get() + \" \" + lastName.get()));\n```\n\nFor cheap string concat: lambda is fine. For expensive computations that might be read multiple times: use `Signal.computed()` explicitly.\n\n### Computed signal chains (UC06 shopping cart)\n\nComputed signals can depend on other computed signals. The framework traces the full dependency graph automatically:\n\n```java\nSignal<BigDecimal> subtotalSignal = Signal.computed(() ->\n    cartItemsSignal.get().stream().map(ValueSignal::get)\n        .map(item -> item.product().price().multiply(BigDecimal.valueOf(item.quantity())))\n        .reduce(BigDecimal.ZERO, BigDecimal::add));\n\nSignal<BigDecimal> discountSignal = Signal.computed(() -> {\n    DiscountCode discount = validateDiscountCode(discountCodeSignal.get());\n    if (discount != null) {\n        return subtotalSignal.get().multiply(discount.percentage())    // depends on subtotalSignal\n            .divide(new BigDecimal(\"100\"), 2, RoundingMode.HALF_UP);\n    }\n    return BigDecimal.ZERO;\n});\n\nSignal<BigDecimal> taxSignal = Signal.computed(() ->\n    subtotalSignal.get().subtract(discountSignal.get())               // depends on both\n        .multiply(new BigDecimal(\"0.08\")).setScale(2, RoundingMode.HALF_UP));\n\nSignal<BigDecimal> totalSignal = Signal.computed(() ->\n    subtotalSignal.get().subtract(discountSignal.get())\n        .add(shippingSignal.get()).add(taxSignal.get())\n        .setScale(2, RoundingMode.HALF_UP));\n```\n\nWhen `quantity` changes in a cart item: `subtotal` → `discount` → `tax` → `total` all recalculate automatically. No manual wiring.\n\n### Dynamic dependency tracking (conditional dependencies)\n\nDependencies are tracked based on what was actually read in the last execution:\n\n```java\nSignal.effect(component, () -> {\n    if (showDetails.get()) {\n        component.setText(details.get());   // showDetails + details are dependencies\n    } else {\n        component.setText(summary.get());   // only showDetails + summary are dependencies\n    }\n});\n```\n\nWhen `showDetails` is false, changes to `details` do NOT trigger re-execution. This is a performance optimization built into the tracking system.\n\n---\n\n## 7. Two-Way Mapping\n\nFor binding a form field directly to a property of a complex record or bean.\n\n### With immutable records — map() + updater()\n\n```java\nrecord Todo(String text, boolean done) {\n    Todo withDone(boolean done) { return new Todo(this.text, done); }\n}\n\nValueSignal<Todo> todoSignal = new ValueSignal<>(new Todo(\"Write docs\", false));\n\nCheckbox checkbox = new Checkbox();\ncheckbox.bindValue(\n    todoSignal.map(Todo::done),             // read: Todo -> Boolean\n    todoSignal.updater(Todo::withDone)      // write: (Todo, Boolean) -> Todo\n);\n```\n\n`updater(merger)` receives the current parent value and the new child value, returns a new parent. The signal framework calls `set()` with the returned value automatically.\n\n### With mutable beans — map() + modifier()\n\n```java\nTextField nameField = new TextField(\"Name\");\nnameField.bindValue(\n    userSignal.map(User::getName),\n    userSignal.modifier(User::setName)      // mutates in place, signal handles change notification\n);\n```\n\nPrefer records over beans. Use `modifier()` only when working with existing mutable bean classes.\n\n### Nested mapping (UC22)\n\nWhen the property lives inside a nested object:\n\n```java\nSignal<Address> addressSignal = personSignal.map(Person::address);\n\ncityField.bindValue(\n    addressSignal.map(Address::city),\n    personSignal.updater((person, city) ->\n        person.withAddress(person.address().withCity(city)))\n);\n```\n\nThe updater always operates on the top-level signal (`personSignal`). The read side uses the intermediate `addressSignal` for clarity.\n\n### When NOT to use map()+updater()\n\nUse Vaadin `Binder` instead when you need:\n- Field-level validation messages\n- Cross-field validation\n- `isValid()` checks\n- `validationStatusSignal()` for reactive valid/invalid state\n\nUse `map()+updater()` for simple field-to-record binding without validation.\n\n---\n\n## 8. bindChildren() for Dynamic Lists\n\n**Rule**: Use `bindChildren()` for dynamic component lists, never manually add/remove children in a loop.\n\n```java\nListSignal<CartItem> cartItemsSignal = new ListSignal<>();\n\nVerticalLayout list = new VerticalLayout();\nlist.bindChildren(cartItemsSignal, itemSignal -> createCartItemRow(itemSignal));\n```\n\n**What `bindChildren()` guarantees:**\n- Factory function runs once per item (not on every list change)\n- Add: new component created, appended\n- Remove: component detached\n- Reorder: components moved in DOM, not recreated\n- Value update: existing component's bindings update, not recreated\n\n**Performance implication**: If you use `setItems()` on a Grid or similar data component (which re-renders the entire list), that is NOT `bindChildren()`. For containers where you want individual components per item, `bindChildren()` is the correct API.\n\n**When to use `Signal.effect()` with `setItems()` instead:**\n\n```java\n// For Grid, ComboBox, VirtualList, etc. that manage their own rendering:\nSignal.effect(grid, () -> grid.setItems(\n    itemsSignal.get().stream().map(ValueSignal::get).toList()));\n```\n\n`bindChildren()` = custom component per item in a layout container.\n`Signal.effect()` + `setItems()` = data component (Grid, VirtualList) that renders its own rows.\n\n**UC15 trick — peek() inside bindChildren() factory when items are immutable:**\n\n```java\n// Items in this list are never updated after creation — peek() is correct\nresultsContainer.bindChildren(searchResultsSignal,\n    productSignal -> createProductCard(productSignal.peek()));\n```\n\nIf items are never mutated after insertion, `peek()` in the factory saves subscription overhead. Only use this when you know items are immutable.\n\n---\n\n## 9. peek() to Avoid Circular Dependencies\n\nThe canonical example: a \"change tracker\" that stores both `previous` and `current` value.\n\n```java\nrecord Change(double previous, double current) {}\n\nValueSignal<Change> changeSignal = new ValueSignal<>(\n    new Change(signal.peek().doubleValue(), signal.peek().doubleValue()));\n\n// Effect that tracks previous value — MUST use peek() on changeSignal\nSignal.unboundEffect(() -> {\n    double current = signal.get();                     // creates dependency on 'signal'\n    double previous = changeSignal.peek().current();   // NO dependency on changeSignal\n    changeSignal.set(new Change(previous, current));\n});\n```\n\nIf `changeSignal.get()` were used instead of `peek()`, the effect would depend on `changeSignal`. Since the effect also writes to `changeSignal`, it would create an infinite re-run loop. `peek()` breaks the cycle by reading the value without registering the dependency.\n\n**Pattern**: When an effect needs to read a signal that it also writes to, use `peek()` for the read.\n\n---\n\n## 10. Service-to-Signal Pattern\n\n**Rule**: Backend services must not know about signals or UI components. Callbacks are the boundary. Callbacks only update signals — they never manipulate UI directly.\n\n```java\n// CORRECT architecture (UC14, real-time dashboard)\n\n// Service: works with plain data, calls callbacks\npublic class SchedulerService {\n    public void scheduleDashboardDataUpdate(Consumer<DashboardData> callback) { ... }\n}\n\n// View: registers callback, callback ONLY updates signals\npublic class DashboardView extends VerticalLayout {\n    private final ValueSignal<Number> usersSignal = new ValueSignal<>(0);\n\n    public DashboardView(SchedulerService service) {\n        service.scheduleDashboardDataUpdate(this::onDataUpdate);\n        // ... build UI bound to signals\n    }\n\n    // Callback: signals ONLY — no UI calls\n    private void onDataUpdate(DashboardData data) {\n        usersSignal.set(data.currentUsers());       // OK\n        // label.setText(...) — FORBIDDEN here\n    }\n}\n```\n\n**No UI.access() needed**: Local signals (`ValueSignal`, `ListSignal`) are thread-safe and handle UI synchronization internally. You can call `.set()` from any thread. Push (`@Push`) must still be enabled for real-time delivery to the browser.\n\n---\n\n## 11. Event Bridge Pattern\n\n**Rule**: Wrap any event-based API into a signal using `event → signal.set()`. The framework provides no magic here — it's always a manual adapter.\n\n```java\n// Bridge 1: Upload callbacks → ValueSignal\nUpload upload = new Upload(UploadHandler.inMemory(...)\n    .whenStart(ctx -> uploadStateSignal.set(new UploadState.InProgress(...)))\n    .onProgress((ctx, transferred, total) -> uploadStateSignal.set(...))\n    .whenComplete((ctx, success) -> { if (!success) uploadStateSignal.set(new UploadState.Failed(...)); }));\n\n// Bridge 2: Keyboard shortcuts → ValueSignal\nShortcuts.addShortcutListener(this, () -> lastShortcutSignal.set(\"Ctrl+K\"), Key.KEY_K, KeyModifier.CONTROL);\n\n// Bridge 3: Browser matchMedia → ValueSignal (requires @ClientCallable)\ngetElement().executeJs(\"\"\"\n    const mq = window.matchMedia('(prefers-color-scheme: dark)');\n    mq.addEventListener('change', (e) => this.$server.onDarkModeChange(mq.matches));\n\"\"\");\n\n@ClientCallable\npublic void onDarkModeChange(boolean dark) {\n    darkModeSignal.set(dark);\n}\n```\n\nOnce bridged, the events participate in all normal signal patterns (computed, effects, bindings).\n\n**Always clean up browser-side listeners on detach:**\n\n```java\naddDetachListener(detach -> {\n    detach.getUI().getPage().executeJs(\"if (window[$0]) { window[$0](); delete window[$0]; }\", key);\n});\n```\n\n---\n\n## 12. Computed Signal Chains\n\nComplex derivation should be broken into named steps, not one large lambda:\n\n```java\n// UC14: Derived UI state from a single enum signal — each step is clear\nSignal<Boolean> isLoadingSignal = stateSignal.map(state ->\n    state == LoadingState.LOADING || state == LoadingState.GENERATING);\n\n// Each metric card gets its own computed signal\nSignal<String> revenueSignal = reportDataSignal.map(report ->\n    report.isEmpty() ? \"\" : String.format(\"$%,d\", report.getTotalRevenue()));\n\nSignal<String> ordersSignal = reportDataSignal.map(report ->\n    report.isEmpty() ? \"\" : String.format(\"%,d\", report.getTotalOrders()));\n```\n\n**Benefit**: Each signal has a clear name and single purpose. When debugging reactivity, you trace the chain by name rather than reading a sprawling lambda.\n\n**UC10: Composing unrelated signals into one computed summary:**\n\n```java\nSignal<String> summarySignal = Signal.computed(() -> {\n    String uploadPart = switch (uploadStateSignal.get()) { ... };\n    String shortcutPart = \"Shortcut: \" + lastShortcutSignal.get();\n    String darkPart = darkModeSignal.get() ? \"Theme: dark\" : \"Theme: light\";\n    return uploadPart + \"  |  \" + shortcutPart + \"  |  \" + darkPart;\n});\n```\n\nThis is idiomatic: bridged event signals from multiple unrelated sources composed into one reactive display signal.\n\n---\n\n## 13. Session-Scoped Signals\n\nFor user preferences that must survive navigation between views, inject the signal carrier as a `@SessionScope` Spring bean:\n\n```java\n@Component\n@SessionScope\npublic class UserPreferences {\n    public static final String DEFAULT_COLOR = \"var(--lumo-base-color)\";\n    private final ValueSignal<String> backgroundColorSignal = new ValueSignal<>(DEFAULT_COLOR);\n\n    public ValueSignal<String> backgroundColorSignal() {\n        return backgroundColorSignal;\n    }\n}\n\n// In a view or layout:\npublic class MainLayout extends AppLayout {\n    public MainLayout(UserPreferences preferences) {\n        Signal<String> colorSignal = preferences.backgroundColorSignal();\n        getContent().getStyle().bind(\"background-color\", colorSignal);\n    }\n}\n\n// In a settings view:\npublic class UseCase20View extends VerticalLayout {\n    public UseCase20View(UserPreferences preferences) {\n        ValueSignal<String> colorSignal = preferences.backgroundColorSignal();\n        colorPicker.bindValue(colorSignal, colorSignal::set);\n    }\n}\n```\n\n**Key**: The signal lives in the bean (not the view). Views receive and bind to the same signal instance. When any view updates it, all bound views update automatically — including across navigation.\n\n---\n\n## 14. Async Operations and Signals\n\n**Rule**: Signals are thread-safe. Set signal values directly from `CompletableFuture` callbacks — no `UI.access()` needed.\n\n```java\nprivate final ValueSignal<LoadingState> stateSignal = new ValueSignal<>(LoadingState.IDLE);\nprivate final ValueSignal<ReportData> reportDataSignal = new ValueSignal<>(ReportData.empty());\n\nprivate void loadReport() {\n    stateSignal.set(LoadingState.LOADING);\n\n    // Read non-reactive state before async — peek() because we are not in reactive context\n    boolean shouldFail = shouldFailSignal.peek();\n\n    analyticsService.fetchReportData(shouldFail)\n        .thenCompose(rawData -> {\n            stateSignal.set(LoadingState.GENERATING);    // direct, no UI.access()\n            return analyticsService.generateReportFromData(rawData, shouldFail);\n        })\n        .thenAccept(report -> {\n            reportDataSignal.set(report);                // direct, no UI.access()\n            stateSignal.set(LoadingState.SUCCESS);\n        })\n        .exceptionally(error -> {\n            stateSignal.set(LoadingState.ERROR);\n            return null;\n        });\n}\n```\n\n**UI visibility switches reactively** from the signal, not from the async callbacks:\n\n```java\nidleContent.bindVisible(() -> stateSignal.get() == LoadingState.IDLE);\nloadingContent.bindVisible(isLoadingSignal);\nsuccessContent.bindVisible(() -> stateSignal.get() == LoadingState.SUCCESS);\nerrorContent.bindVisible(() -> stateSignal.get() == LoadingState.ERROR);\n```\n\n**Per-item async loading (UC19):**\n\nUse a `ListSignal<DataItem>` where each item has its own `ValueSignal<LoadingState>`. Individual items update independently without causing the whole list to re-render.\n\n---\n\n## 15. Debounce with Manual Scheduling\n\nSignals have no built-in debounce. Use a `ScheduledExecutorService` manually:\n\n```java\nprivate final ValueSignal<String> instantQuerySignal = new ValueSignal<>(\"\");\nprivate final ValueSignal<String> debouncedQuerySignal = new ValueSignal<>(\"\");\nprivate final ScheduledExecutorService debounceExecutor = Executors.newSingleThreadScheduledExecutor();\nprivate volatile ScheduledFuture<?> pendingDebounce = null;\n\n// EAGER mode sends on every keystroke\nsearchField.setValueChangeMode(ValueChangeMode.EAGER);\nsearchField.bindValue(instantQuerySignal, value -> {\n    instantQuerySignal.set(value);\n    scheduleDebouncedSearch(value);\n});\n\nprivate void scheduleDebouncedSearch(String query) {\n    ScheduledFuture<?> pending = pendingDebounce;\n    if (pending != null) pending.cancel(false);\n\n    pendingDebounce = debounceExecutor.schedule(() -> {\n        debouncedQuerySignal.set(query);     // thread-safe\n        performSearch(query);\n    }, 1000, TimeUnit.MILLISECONDS);\n}\n\n@Override\nprotected void onDetach(DetachEvent e) {\n    super.onDetach(e);\n    if (pendingDebounce != null) pendingDebounce.cancel(false);\n    debounceExecutor.shutdownNow();\n}\n```\n\n`instantQuerySignal` and `debouncedQuerySignal` serve different UI roles: instant shows \"what you typed\", debounced shows \"what was searched\". Displaying both is a good UX pattern for revealing debounce behavior to users.\n\n---\n\n## 16. Binder + Signal Integration\n\nVaadin `Binder` exposes two signal integration points:\n\n### validationStatusSignal()\n\n```java\nBinder<AccountData> binder = new Binder<>(AccountData.class);\n// ... add field bindings with validators ...\n\n// Use Binder's validation signal to drive submit button state\nsubmitButton.bindEnabled(() ->\n    binder.validationStatusSignal().get().isOk()\n    && submissionStateSignal.get() != SubmissionState.SUBMITTING);\n```\n\n`validationStatusSignal()` returns a reactive `Signal<BinderValidationStatus<T>>` that updates on every validation event. `.isOk()` is true when all bound fields pass validation.\n\n### Binding.valueSignal() — cross-field validation\n\nWhen a field validator needs the value of another field (e.g., confirm password), read the other binding's `valueSignal()` inside the validator:\n\n```java\nvar passwordBinding = binder.forField(passwordField)\n    .withValidator(value -> value != null && value.length() >= 8, \"Password too short\")\n    .bind(AccountData::getPassword, AccountData::setPassword);\n\nbinder.forField(confirmField)\n    .withValidator(\n        value -> value != null && value.equals(passwordBinding.valueSignal().get()),\n        \"Passwords do not match\")\n    .bind(AccountData::getConfirmPassword, AccountData::setConfirmPassword);\n```\n\n`passwordBinding.valueSignal().get()` reads the current field signal value at validation time — reactive cross-field validation without manual listeners.\n\n### Binder + ValueSignal for submission state\n\nA common pattern in UC01:\n\n```java\nValueSignal<SubmissionState> submissionStateSignal = new ValueSignal<>(SubmissionState.IDLE);\n\n// Button text reacts to submission state\nsubmitButton.bindText(submissionStateSignal.map(state -> switch (state) {\n    case IDLE -> \"Create Account\";\n    case SUBMITTING -> \"Creating...\";\n    case SUCCESS -> \"Success!\";\n    case ERROR -> \"Retry\";\n}));\n\n// Theme variant reacts to success state\nsubmitButton.bindThemeVariant(ButtonVariant.LUMO_SUCCESS,\n    submissionStateSignal.map(SubmissionState.SUCCESS::equals));\nsubmitButton.bindThemeVariant(ButtonVariant.LUMO_PRIMARY,\n    Signal.not(submissionStateSignal.map(SubmissionState.SUCCESS::equals)));\n```\n\n---\n\n## 17. Element.bindAttribute()\n\nFor non-component DOM elements (e.g., raw SVG elements), use `Element.bindAttribute()`:\n\n```java\nElement rect = new Element(\"rect\");\n\n// Single-signal binding\nrect.bindAttribute(\"fill\", rectFillSignal);\nrect.bindAttribute(\"opacity\", rectOpacitySignal.map(String::valueOf));\n\n// Multi-signal lambda\nrect.bindAttribute(\"stroke-width\", () -> {\n    int base = rectStrokeWidthSignal.get();\n    boolean selected = selectedShapeSignal.get() == 0;\n    return String.valueOf(selected ? base + 2 : base);\n});\n\n// Signal.computed() for expensive transform calculations\nrect.bindAttribute(\"transform\", Signal.computed(() -> {\n    int centerX = rectXSignal.get() + rectWidthSignal.get() / 2;\n    int centerY = rectYSignal.get() + rectHeightSignal.get() / 2;\n    return String.format(\"rotate(%d %d %d)\", rectRotationSignal.get(), centerX, centerY);\n}));\n```\n\nSame rules apply: single signal → direct; multi-signal → lambda or `Signal.computed()`.\n\nSimilarly for inline styles at the element level:\n\n```java\ndot.getStyle().bind(\"background-color\",\n    () -> activeSignal.get() ? \"var(--lumo-contrast-80pct)\" : \"var(--lumo-contrast-30pct)\");\n```\n\n---\n\n## 18. Signal.not() and Boolean Derivations\n\n`Signal.not()` creates a computed signal that negates a boolean signal. Preferred over `.map(v -> !v)` for clarity:\n\n```java\nValueSignal<Boolean> loading = new ValueSignal<>(true);\nSignal<Boolean> notLoading = Signal.not(loading);\n\nbutton.bindEnabled(notLoading);\n```\n\nFor conditional theme variants, the complement pattern from UC01:\n\n```java\nSignal<Boolean> isSuccess = stateSignal.map(SubmissionState.SUCCESS::equals);\nbutton.bindThemeVariant(ButtonVariant.LUMO_SUCCESS, isSuccess);\nbutton.bindThemeVariant(ButtonVariant.LUMO_PRIMARY, Signal.not(isSuccess));\n```\n\n---\n\n## 19. Custom Equality Checkers\n\nBy default, signal equality uses `Objects.equals()`. Override to suppress updates when values are semantically equal:\n\n```java\n// Skip updates for case-insensitive string equality\nValueSignal<String> name = new ValueSignal<>(\"John\",\n    (a, b) -> a != null && a.equalsIgnoreCase(b));\n\nname.set(\"john\");  // No update triggered\nname.set(\"Jane\");  // Update triggered\n```\n\nFor `ListSignal`, the equality checker applies to all entry `ValueSignal` instances in the list:\n\n```java\nListSignal<String> items = new ListSignal<>(\n    (a, b) -> a != null && a.equalsIgnoreCase(b));\n```\n\nUse this when your value type has meaningful equality that differs from `Objects.equals()`, to avoid unnecessary re-renders.\n\n---\n\n## 20. Memory and Lifecycle\n\n### Signals as class fields (not constructor-local variables)\n\n```java\n// CORRECT: signals as fields — reachable, lifecycle managed by component\npublic class MyView extends VerticalLayout {\n    private final ValueSignal<String> stateSignal = new ValueSignal<>(\"idle\");\n}\n\n// WRONG: signal in constructor scope — effect keeps a closure reference,\n// but the signal itself may be GC'd if nothing else holds a reference\npublic MyView() {\n    ValueSignal<String> localSignal = new ValueSignal<>(\"idle\");\n    Signal.effect(this, () -> label.setText(localSignal.get()));\n    // localSignal not stored anywhere — risky\n}\n```\n\n### ListSignal entries are themselves signals\n\n```java\nListSignal<String> items = new ListSignal<>();\nValueSignal<String> entry = items.insertLast(\"value\");\n\n// entry is a live ValueSignal — keep a reference if you need to update it later\nentry.set(\"updated\");   // updates the item in the list reactively\n\n// Or retrieve it later via peek()\nitems.peek().get(0).set(\"updated\");\n```\n\n### Signal.runWithoutTransaction() — last resort\n\nEffects run inside a read-only transaction. Modifying a signal from inside an effect normally throws. If you absolutely must:\n\n```java\nSignal.effect(component, () -> {\n    String value = sourceSignal.get();\n    // WARNING: infinite loop risk — only use when you are certain\n    Signal.runWithoutTransaction(() -> otherSignal.set(value));\n});\n```\n\n**Prefer `Signal.computed()` instead** for derived values that depend on another signal.\n\n### Signal.untracked() — read without subscribing\n\nFor reading signal values inside an effect for logging or analytics without creating a dependency:\n\n```java\nSignal.effect(component, () -> {\n    String primary = primarySignal.get();   // tracked dependency\n    Signal.untracked(() -> {\n        String analytics = analyticsSignal.get();   // NOT a dependency\n        log(analytics);\n    });\n});\n```\n\n---\n\n## 21. Anti-Patterns Index\n\n| Anti-Pattern | Correct Pattern |\n|---|---|\n| `get()` in click listener / `onAttach()` / service callback | Use `peek()` outside reactive contexts |\n| `signal.get()` inside an effect when you also write to that signal | Use `signal.peek()` for the read |\n| One large `Signal.effect()` doing many unrelated things | Split into separate `bindXxx()` calls or separate effects |\n| `Signal.effect()` for simple property binding | Use `bindText()`, `bindVisible()`, `bindEnabled()`, etc. |\n| Storing state in regular fields alongside signals | All mutable UI state in signals |\n| `Signal.unboundEffect()` without storing the `Registration` | Always store and call `remove()` |\n| `cartItemsSignal.get().stream().filter(...)...` inside an effect (subscribes to every item) | Use `peek()` in scan-and-write operations |\n| `new ValueSignal<>()` as a local constructor variable when used in effects | Store as a class field |\n| Calling `UI.access()` when updating a local signal from a background thread | Not needed — local signals are thread-safe |\n| Using `Signal.computed()` for derived values but mutating the source inside an effect | Source mutations go through `signal.set()` / `signal.update()` outside the computed |\n| `bindValue(signal)` only (read-only) when you need two-way binding | `bindValue(readSignal, writeFn)` for two-way |\n| Manually scanning `ListSignal.get()` to update items in an effect | Use `bindChildren()` for component lists |\n| Not cleaning up `ScheduledExecutorService` on `onDetach()` | Always `shutdownNow()` + cancel pending futures on detach |\n| Modifying a mutable object retrieved from a signal directly | Use `modify(Consumer)` or `update(UnaryOperator)` |\n\n---\n\n*Source: `vaadin/signals-cases` all 20+ use cases + Vaadin 25.2 official documentation (effects-computed.md, local-signals.md, building-ui.md, shared-signals.md, usage-examples/*).*\n",
      "category": "docs",
      "tags": [
        "signals-patterns-reference",
        "valuesignal",
        "listsignal",
        "illegalstateexception",
        "registration",
        "binder",
        "completablefuture",
        "scheduledexecutorservice",
        "scheduler",
        "resource",
        "entry",
        "event"
      ]
    }
  ],
  "classes": [
    {
      "name": "BeanProperties",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.BeanProperties",
      "description": "@author Stefan Uebe",
      "type": "class",
      "methods": [
        {
          "name": "read",
          "description": "Reads the field of the given type (and its superclasses). Any field, that has a valid bean-styled\ngetter (\"get\" or \"is\", alternative a method named like the field) will be included in the set.<br>\nSetters are optional. If no setter is available, invoking the setter will lead to an\nUnsupportedOperationException.",
          "returnType": "<T> Set<BeanProperties<T>>",
          "parameters": [
            {
              "type": "Class<T>",
              "name": "type"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "getSetter",
          "description": "",
          "returnType": "Optional<Setter<T, Object>>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getName",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "isJsonIgnored",
          "description": "Returns whether this field should be ignored for JSON serialization.",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "isJsonUpdateAllowed",
          "description": "Returns whether this field can be updated from JSON.",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getJsonName",
          "description": "Returns the JSON property name for this field.",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getConverter",
          "description": "Returns the cached converter instance for this field, if any.",
          "returnType": "<V, E> JsonItemPropertyConverter<V, E>",
          "parameters": [],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "BrowserTimezoneObtainedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.BrowserTimezoneObtainedEvent",
      "description": "This event gets fired when the client side reported the browser's timezone to the server. Since this is\ndone after the element has been attached to the client, it will be fired after all UI attach events.",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new event using the given source and indicator whether the\nevent originated from the client side or the server side.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "Timezone",
              "name": "timezone"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "BusinessHours",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.BusinessHours",
      "description": "Definition of business hours for a calendar instance.\n<p>\n    Use one of the static methods to define the days of week. You can define the range per day using the #start\n    and #end methods or leave them, to let the business hours range from the start of the day to its end.\n</p>",
      "type": "class",
      "methods": [
        {
          "name": "getEnd",
          "description": "Returns the end time. If none has been set, the returned time will be LocalTime#MAX.",
          "returnType": "LocalTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStart",
          "description": "Returns the start time. If none has been set, the returned time will be LocalTime#MIN.",
          "returnType": "LocalTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getDayOfWeeks",
          "description": "Returns the days of week for business. Empty if there are no business days.",
          "returnType": "Set<DayOfWeek>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toJson",
          "description": "Converts the given object into a json object.",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "convertToClientSideDow",
          "description": "Converts the given day of the week to the correct client side number (handles sundays differently).",
          "returnType": "int",
          "parameters": [
            {
              "type": "DayOfWeek",
              "name": "dayOfWeek"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        }
      ],
      "fields": [
        {
          "name": "ALL_DAYS",
          "type": "Set<DayOfWeek>",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        },
        {
          "name": "DEFAULT_BUSINESS_WEEK",
          "type": "Set<DayOfWeek>",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        }
      ],
      "constructors": [],
      "annotations": [
        "ToString",
        "EqualsAndHashCode"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "CalendarLocale",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.CalendarLocale",
      "description": "A list of all supported locales.",
      "type": "enum",
      "methods": [
        {
          "name": "valueOf",
          "description": "Returns a matching instead for the given locale or empty, if no match has been found.",
          "returnType": "Optional<CalendarLocale>",
          "parameters": [
            {
              "type": "Locale",
              "name": "locale"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "getAvailableLocales",
          "description": "Get all available locales as an array of Locale.",
          "returnType": "Locale[]",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "getDefaultLocale",
          "description": "Returns the default locale. This is by default the system language. If the system language is not supported\nby the calender, english will be used instead.\n<p>\nThis value is used as a fallback in different places, if no locale could be\ndetermined from the browser (or that should not be used).",
          "returnType": "Locale",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "setDefault",
          "description": "Sets the default locale. This is by default the system language. If the system language is not supported\nby the calender, english will be used instead.\n<p>\nThis value is used as a fallback in different places, if no locale could be\ndetermined from the browser (or that should not be used).",
          "returnType": "void",
          "parameters": [
            {
              "type": "CalendarLocale",
              "name": "locale"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "CalendarView",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.CalendarView",
      "description": "Defines a possible view for the calendar.",
      "type": "interface",
      "extends": "ClientSideValue",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "CalendarViewImpl",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.CalendarViewImpl",
      "description": "Basic enumeration of possible calendar views.",
      "type": "enum",
      "implements": [
        "CalendarView"
      ],
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [
        "RequiredArgsConstructor",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ClientSideEventSource",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ClientSideEventSource",
      "description": "Abstract base class for all client-managed event sources. Client-managed sources (JSON feed, Google Calendar, iCal)\nfetch events directly in the browser — they do NOT go through the server-side org.vaadin.stefan.fullcalendar.dataprovider.EntryProvider.\n<br><br>\nEntries fetched by these sources are NOT accessible as Java Entry objects on the server side.\nIf editable drag/drop is enabled (opt-in via #withEditable(boolean)), dropped or resized entries\nfrom these sources fire ExternalEntryDroppedEve",
      "type": "class",
      "extends": "ClientSideEventSource<S>>",
      "methods": [
        {
          "name": "withId",
          "description": "Sets the developer-assigned id for this source.\nUse a meaningful id if you plan to handle ExternalEntryDroppedEvent / ExternalEntryResizedEvent\nfor entries from this source.",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withColor",
          "description": "Sets the color (background + border shorthand) for all entries from this source.",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "color"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withBackgroundColor",
          "description": "Sets the background color for all entries from this source.",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "backgroundColor"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withBorderColor",
          "description": "Sets the border color for all entries from this source.",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "borderColor"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withTextColor",
          "description": "Sets the text color for all entries from this source.",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "textColor"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withClassNames",
          "description": "Sets CSS class names applied to all entries from this source.",
          "returnType": "S",
          "parameters": [
            {
              "type": "List<String>",
              "name": "classNames"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withEditable",
          "description": "Sets whether entries from this source can be dragged and resized. Defaults to `false` (read-only).\nSet to `true` to opt in to drag/drop, then handle persistence in\nFullCalendar#addExternalEntryDroppedListener / FullCalendar#addExternalEntryResizedListener.",
          "returnType": "S",
          "parameters": [
            {
              "type": "boolean",
              "name": "editable"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withStartEditable",
          "description": "Sets whether the start time of entries can be dragged.",
          "returnType": "S",
          "parameters": [
            {
              "type": "boolean",
              "name": "startEditable"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withDurationEditable",
          "description": "Sets whether the duration of entries can be resized.",
          "returnType": "S",
          "parameters": [
            {
              "type": "boolean",
              "name": "durationEditable"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withConstraint",
          "description": "Sets the constraint for drag/drop of entries from this source.\n                  restricts when entries can be dropped",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "constraint"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withOverlap",
          "description": "Sets whether entries from this source can overlap with other entries.",
          "returnType": "S",
          "parameters": [
            {
              "type": "boolean",
              "name": "overlap"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withDisplay",
          "description": "Sets the display mode for entries from this source.\n               `\"background\"`, `\"inverse-background\"`, `\"none\"`",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "display"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withResourceEditable",
          "description": "Sets whether entries from this source can be moved between resources (Scheduler only).",
          "returnType": "S",
          "parameters": [
            {
              "type": "boolean",
              "name": "resourceEditable"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withDefaultAllDay",
          "description": "Sets whether entries from this source default to all-day.",
          "returnType": "S",
          "parameters": [
            {
              "type": "boolean",
              "name": "defaultAllDay"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withAllow",
          "description": "Sets a per-source `eventAllow` JS callback that controls where entries can be dropped.",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "jsFunction"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withAllow",
          "description": "Sets a per-source `eventAllow` JS callback that controls where entries can be dropped.",
          "returnType": "S",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withSuccess",
          "description": "Sets a per-source `success` JS callback called when the source successfully fetches events.",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "jsFunction"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withSuccess",
          "description": "Sets a per-source `success` JS callback.",
          "returnType": "S",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withFailure",
          "description": "Sets a per-source `failure` JS callback called when the source fails to fetch events.",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "jsFunction"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withFailure",
          "description": "Sets a per-source `failure` JS callback.",
          "returnType": "S",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withEventDataTransform",
          "description": "Sets a per-source `eventDataTransform` JS callback that transforms each raw event record.",
          "returnType": "S",
          "parameters": [
            {
              "type": "String",
              "name": "jsFunction"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withEventDataTransform",
          "description": "Sets a per-source `eventDataTransform` JS callback.",
          "returnType": "S",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toJson",
          "description": "Serializes this event source to a JSON object suitable for passing to FullCalendar's `eventSources` config.",
          "returnType": "abstract ObjectNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ClientSideValue",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ClientSideValue",
      "description": "Marks a class as a client side setting, which returns client side representation for an instance of this class.\nAn enumeration for instance would return a client side parseable version of the server side enum instance,\ne.g. RenderingMode.INVERSE_BACKGROUND.getClientSideName() // returns \"inverse-background\"",
      "type": "interface",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "CustomCalendarView",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.CustomCalendarView",
      "description": "Interface for custom calendar views. This is used to create custom views for the calendar.\n@author Stefan Uebe",
      "type": "interface",
      "extends": "CalendarView",
      "methods": [
        {
          "name": "getClientSideValue",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getViewSettings",
          "description": "",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DateEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.DateEvent",
      "description": "An abstract class for date events, that are not directly entry related. They are always whole day events.",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the date as iso string (e.g. \"2018-10-23\").",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "String",
              "name": "dateString"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DateTimeEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.DateTimeEvent",
      "description": "An abstract class for date events, that are not directly entry related.",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [
        {
          "name": "getDateTimeAsInstant",
          "description": "The utc based date time related to this event. For day slots the time will be at start of the day.",
          "returnType": "Instant",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getDateTimeWithOffset",
          "description": "The date time related to this event including the calendar timezone's offset.\nFor day slots the time will be at start of the day and ignore the timezone.",
          "returnType": "LocalDateTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getDate",
          "description": "Returns only the date part of the contained local date time. This method is intended to be used on\nall day entry related events.",
          "returnType": "LocalDate",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the date (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "String",
              "name": "dateString"
            },
            {
              "type": "boolean",
              "name": "allDay"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DatesRenderedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.DatesRenderedEvent",
      "description": "Occurs when a new set of dates has been rendered.. Provides information about the shown timespan.\n<br><br>\nThe values are always daybased, regardless of the current view.\n<br><br>\nCalled after registered ViewSkeletonRenderedEvent listeners.",
      "type": "class",
      "extends": "ViewRenderEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new event using the given source and indicator whether the\nevent originated from the client side or the server side.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DayNumberClickedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.DayNumberClickedEvent",
      "description": "Occurs when number links are active and a user clicked on a day's number.",
      "type": "class",
      "extends": "DateEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the date (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "Delta",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.Delta",
      "description": "Represents a delta between two times. A delta can contain negative values if the first date is later than the second one.\n<p>\n<b>Note on `years` and `months` (see issue #191):</b> FullCalendar JS emits drop/resize\ndeltas as `{years, months, days, milliseconds`}, but in practice the client always\nnormalises the year/month portion into `days`. Dragging an entry across several months\nproduces, for example, `days: 31` rather than `months: 1`. The `years` and\n`months` fields on this class therefore r",
      "type": "class",
      "methods": [
        {
          "name": "getYears",
          "description": "Returns the years component of this delta.\n\n@deprecated since 7.2.0 — FullCalendar never produces a non-zero `years` component for\n            drop/resize events. Retained for backward compatibility with manually-constructed\n            `Delta` instances. See class-level Javadoc for details.",
          "returnType": "int",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getMonths",
          "description": "Returns the months component of this delta.\n\n@deprecated since 7.2.0 — FullCalendar never produces a non-zero `months` component for\n            drop/resize events. Retained for backward compatibility with manually-constructed\n            `Delta` instances. See class-level Javadoc for details.",
          "returnType": "int",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "applyOn",
          "description": "Applies this delta instance on the given local date time by adding all day and time related delta values.",
          "returnType": "LocalDateTime",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "dateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "subtractFrom",
          "description": "Inverse of #applyOn(LocalDateTime): returns the given date-time with all components of\nthis delta subtracted. Useful for reconstructing the \"before\" value from a received delta +\n\"after\" value (e.g. in external drop/resize events, where only the new position is known on\nthe server side).",
          "returnType": "LocalDateTime",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "dateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "subtractFrom",
          "description": "Inverse of #applyOn(LocalDate): returns the given date with all day-related components\nof this delta subtracted. Time components are ignored.",
          "returnType": "LocalDate",
          "parameters": [
            {
              "type": "LocalDate",
              "name": "date"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "subtractFrom",
          "description": "Inverse of #applyOn(Instant): returns the given instant with all components of this\ndelta subtracted.",
          "returnType": "Instant",
          "parameters": [
            {
              "type": "Instant",
              "name": "instant"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "applyOn",
          "description": "Applies this delta instance on the given local date by adding all day related delta values. Time values are ignored.",
          "returnType": "LocalDate",
          "parameters": [
            {
              "type": "LocalDate",
              "name": "date"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "applyOn",
          "description": "Applies this delta instance on the given instant by adding all day and time related delta values.",
          "returnType": "Instant",
          "parameters": [
            {
              "type": "Instant",
              "name": "instant"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new instance.",
          "parameters": [
            {
              "type": "int",
              "name": "years"
            },
            {
              "type": "int",
              "name": "months"
            },
            {
              "type": "int",
              "name": "days"
            },
            {
              "type": "int",
              "name": "hours"
            },
            {
              "type": "int",
              "name": "minutes"
            },
            {
              "type": "int",
              "name": "seconds"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "EqualsAndHashCode",
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "Direction",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.Direction",
      "description": "Text direction for the calendar. Corresponds to the FullCalendar `direction` option.",
      "type": "enum",
      "implements": [
        "ClientSideValue"
      ],
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DisplayMode",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.DisplayMode",
      "description": "Constants for rendering of an entry.",
      "type": "enum",
      "implements": [
        "ClientSideValue"
      ],
      "methods": [
        {
          "name": "getClientSideValue",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "Draggable",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.Draggable",
      "description": "Wraps a Vaadin Component to make it (or its children) draggable onto a FullCalendar.\n<p>\n<b>Simple mode</b> (no itemSelector): The component itself is draggable. Optionally carries\nstatic Entry data that will be used to create a calendar entry on drop.\n<p>\n<b>Container mode</b> (with itemSelector): The component acts as a container. Only children\nmatching the CSS selector are draggable. Use #withEventDataCallback(JsCallback) to\ndynamically create entry data based on the dragged child element.\n<p",
      "type": "class",
      "methods": [
        {
          "name": "getEntryData",
          "description": "Returns the static entry data associated with this draggable, if any.",
          "returnType": "Optional<Entry>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a Draggable wrapping the given component without entry data.",
          "parameters": [
            {
              "type": "Component",
              "name": "component"
            }
          ],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a Draggable wrapping the given component with optional static entry data.",
          "parameters": [
            {
              "type": "Component",
              "name": "component"
            },
            {
              "type": "Entry",
              "name": "entryData"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DropEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.DropEvent",
      "description": "Fires when any external HTML element is dropped onto the calendar (requires `droppable` to be `true`).\nThis fires for <em>all</em> external drops, including non-event elements.\n<br><br>\nThe created entry can be obtained via #getCreatedEntry().\n<br><br>\nIf the dropped element was registered via FullCalendar#addDraggable(Draggable),\nuse #getDraggable() for typed access.\n<br><br>\nFor drops of external elements that carry event data (`data-event` attribute) and are successfully\nadded to the calendar",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [
        {
          "name": "getDraggable",
          "description": "Returns the Draggable instance if the dropped element was registered via\nFullCalendar#addDraggable(Draggable) on this calendar.",
          "returnType": "Optional<Draggable>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCreatedEntry",
          "description": "Returns the entry, that has been created by the client side as a result of the drop operation. The content\nof this entry may differ from the draggable entry data, depending on restrictions or limitations of the calendar.\n<p>\n    Please note, that this entry will NOT be automatically added to your entry provider in any case.\n</p>",
          "returnType": "Entry",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "ToString",
        "Getter",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "Entry",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.Entry",
      "description": "",
      "type": "class",
      "methods": [
        {
          "name": "getRRule",
          "description": "Returns the RRule-based recurrence definition, or `null` if not set.",
          "returnType": "RRule",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setRRule",
          "description": "Sets the RRule-based recurrence definition. If the RRule has excluded dates\n(set via RRule#excludeDates(LocalDate...)), they are automatically transferred\nto the entry's `exdate` property and serialized separately as required by\nFullCalendar's RRule plugin.\n<p>\nPass `null` to remove the recurrence rule and any associated excluded dates.",
          "returnType": "void",
          "parameters": [
            {
              "type": "RRule",
              "name": "rrule"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCalendar",
          "description": "Returns the calendar instance of this entry. Is empty when not yet added to a calendar.",
          "returnType": "Optional<FullCalendar>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setCalendar",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "calendar"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toJson",
          "description": "Converts the given instance to a json object representing its inner state. This json is intended to be\ntransported to and interpreted by the client and thus should not be modified manually, except for concrete\nreasons.",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "updateFromJson",
          "description": "Updates this instance with the given json object. Only fields, that are updateable will be overwritten.\nThrows an exception, when the given json object has not the same id as this instance.",
          "returnType": "void",
          "parameters": [
            {
              "type": "ObjectNode",
              "name": "jsonObject"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "updateFromJson",
          "description": "Updates this instance with the given json object. Only fields, that are updateable will be overwritten.\nBased on the boolean parameter, the id will be either ignored (false) or has to be the same as this instance's one\n(true), otherwise an exception will be thrown",
          "returnType": "void",
          "parameters": [
            {
              "type": "ObjectNode",
              "name": "jsonObject"
            },
            {
              "type": "boolean",
              "name": "requiresMatchingId"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "updateAllFromJson",
          "description": "Updates this instance with the given json object. ALL fields will be overwritten, regardless whether they are allowed to\nbe updated or not. Ignored properties still will be not overwritten as they are intended to be invisible for the json parser.\nBased on the boolean parameter, the id will be either ignored (false) or has to be the same as this instance's one\n(true), otherwise an exception will be thrown",
          "returnType": "void",
          "parameters": [
            {
              "type": "ObjectNode",
              "name": "jsonObject"
            },
            {
              "type": "boolean",
              "name": "requiresMatchingId"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "copy",
          "description": "Creates a copy of this instance. Collection, Map and Array values are copied (but their values are taken\nas they are, so no deep copy).",
          "returnType": "<T extends Entry> T",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "copyAsType",
          "description": "Creates a copy of this instance. Collection, Map and Array values are copied (but their values are taken\nas they are, so no deep copy).\n<p></p>\nPlease make sure, that both types are compatible in their properties. Any property, that exists in the source\nbut not the target type might lead to an exception. Also the target type must have a public constructor, taking\nthe id as the parameter.",
          "returnType": "<T extends Entry> T",
          "parameters": [
            {
              "type": "Class<T>",
              "name": "targetType"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "copyFrom",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "Entry",
              "name": "source"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "copyFrom",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "Entry",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "ignoreId"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "copy",
          "description": "Copies all values from source to target (except for the id). When the boolean is set to false,\nboth objects have to be of the <b>same</b> type. Otherwise it is up to the developer to guarantee,\nthat the target can take all properties of the source.<br>\nProperties without a setter are ignored.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Entry",
              "name": "source"
            },
            {
              "type": "Entry",
              "name": "target"
            },
            {
              "type": "boolean",
              "name": "ignoreTypeDifference"
            }
          ],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "toJsonWithIdOnly",
          "description": "Converts this instance to a json object, that only contains the id. This still represents\nthis item but without any data.",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStartAsInstant",
          "description": "Returns the entry's start as an Instant. The contained time is the same as when calling\n#getStart().",
          "returnType": "Instant",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStartAsLocalDate",
          "description": "Returns the entry's start date.",
          "returnType": "LocalDate",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStartWithTimezone",
          "description": "Returns the start time as a zoned date time using this entry's start time zone. By default this is\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>\nCalling ZonedDateTime#toLocalDateTime() returns the time including the offset as LocalDateTime.",
          "returnType": "ZonedDateTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStartWithOffset",
          "description": "Returns the start time as a local date time after applying the timezone's offset to\nthe utc based start date (#getStart()). By default the timezone is\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>\nTo get a OffsetDateTime please use #getStartWithTimezone() and call\nZonedDateTime#toOffsetDateTime()",
          "returnType": "LocalDateTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStartWithOffset",
          "description": "Returns the start time as a local date time after applying the timezone's offset to\nthe utc based start date (#getStart()).\n<p></p>\nThis method is intended to be used for new entries that have not yet been added to the\ncalendar and thus have no reference to its timezone.\n<p></p>\nTo get a OffsetDateTime please use #getStartWithTimezone() and call\nZonedDateTime#toOffsetDateTime()",
          "returnType": "LocalDateTime",
          "parameters": [
            {
              "type": "Timezone",
              "name": "timezone"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setStart",
          "description": "Sets the entry's start. The given date time will be interpreted as the UTC start time of this entry.",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "start"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setStart",
          "description": "Sets the entry's start. The given instant will be interpreted as the UTC start time of this entry.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Instant",
              "name": "start"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setStart",
          "description": "Sets the given local date as start using the start of the day as time (utc based).",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalDate",
              "name": "start"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setStartWithTimezone",
          "description": "Sets the entry's start based on the zoned date time instance. The given date time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting start time will be ...T00:00.\n<p></p>",
          "returnType": "void",
          "parameters": [
            {
              "type": "ZonedDateTime",
              "name": "startWithTimezone"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setStartWithOffset",
          "description": "Sets the entry's start. The given date time will be interpreted as having the offset of the\nstart time zone applied. The time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting start time will be ...T00:00.\n<p></p>\nThis method is intended to be used in cases where the start time is edited in relation to\nthe current time zone (like a calendar entry editor).\n<p></p>",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "startWithTimezone"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setStartWithOffset",
          "description": "Sets the entry's start. The given date time will be interpreted as having the offset of the\ngiven time zone applied. The time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting start time will be ...T00:00.\n<p></p>\nThis method is intended to be used in cases where entry is not yet added to the calendar and thus\ncannot use its timezone to interpret the offset.\n<p></p>",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "startWithTimezone"
            },
            {
              "type": "Timezone",
              "name": "timezone"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "clearStart",
          "description": "Clears the current start time. Convenience method to prevent unnecessary casting when using\nsetStart(null).",
          "returnType": "void",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEndAsInstant",
          "description": "Returns the entry's end as an Instant. The contained time is the same as when calling\n#getEnd().",
          "returnType": "Instant",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEndAsLocalDate",
          "description": "Returns the entry's end date.",
          "returnType": "LocalDate",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEndWithTimezone",
          "description": "Returns the end time as a zoned date time using this entry's end time zone. By default this is\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>\nCalling ZonedDateTime#toLocalDateTime() returns the time including the offset as LocalDateTime.",
          "returnType": "ZonedDateTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEndWithOffset",
          "description": "Returns the end time as a local date time after applying the timezone's offset to\nthe utc based end date (#getEnd()). By default the timezone is\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>\nTo get a OffsetDateTime please use #getEndWithTimezone() and call\nZonedDateTime#toOffsetDateTime()",
          "returnType": "LocalDateTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEndWithOffset",
          "description": "Returns the end time as a local date time after applying the timezone's offset to\nthe utc based end date (#getEnd()).\n<p></p>\nThis method is intended to be used for new entries that have not yet been added to the\ncalendar and thus have no reference to its timezone.\n<p></p>\nTo get a OffsetDateTime please use #getEndWithTimezone() and call\nZonedDateTime#toOffsetDateTime()",
          "returnType": "LocalDateTime",
          "parameters": [
            {
              "type": "Timezone",
              "name": "timezone"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEnd",
          "description": "Sets the entry's end. The given date time will be interpreted as the UTC end time of this entry.",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "end"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEnd",
          "description": "Sets the entry's end. The given instant will be interpreted as the UTC end time of this entry.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Instant",
              "name": "end"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEnd",
          "description": "Sets the given local date as end using the end of the day as time (utc based).",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalDate",
              "name": "end"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEndWithTimezone",
          "description": "Sets the entry's end based on the zoned date time instance. The given date time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting end time will be ...T00:00.\n<p></p>",
          "returnType": "void",
          "parameters": [
            {
              "type": "ZonedDateTime",
              "name": "endWithTimezone"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEndWithOffset",
          "description": "Sets the entry's end. The given date time will be interpreted as having the offset of the\nend time zone applied. The time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting end time will be ...T00:00.\n<p></p>\nThis method is intended to be used in cases where the end time is edited in relation to\nthe current time zone (like a calendar entry editor).\n<p></p>",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "endWithTimezone"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEndWithOffset",
          "description": "Sets the entry's end. The given date time will be interpreted as having the offset of the\ngiven time zone applied. The time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting end time will be ...T00:00.\n<p></p>\nThis method is intended to be used in cases where entry is not yet added to the calendar and thus\ncannot use its timezone to interpret the offset.\n<p></p>",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "endWithTimezone"
            },
            {
              "type": "Timezone",
              "name": "timezone"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "clearEnd",
          "description": "Clears the current end time. Convenience method to prevent unnecessary casting when using\nsetEnd(null).",
          "returnType": "void",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "moveStartEnd",
          "description": "Moves the entry by the given delta. Negative deltas will result in moving the entry to the past.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Delta",
              "name": "delta"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "moveStart",
          "description": "Moves the entry's start by the given delta without modifying the end.\nNegative deltas will result in moving the start to the past.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Delta",
              "name": "delta"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "moveEnd",
          "description": "Moves the entry's end by the given delta without modifying the start.\nNegative deltas will result in moving the end to the past.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Delta",
              "name": "delta"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStartTimezone",
          "description": "Returns the timezone which is used on the client side. It is used to convert the internal utc timestamp\nto the client side timezone. By default UTC.",
          "returnType": "Timezone",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEndTimezone",
          "description": "Returns the timezone which is used on the client side. It is used to convert the internal utc timestamp\nto the client side timezone. By default UTC.",
          "returnType": "Timezone",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getOrCreateClassNames",
          "description": "Returns the set of class names or creates a new, empty one, if none exists yet. The returned set is\nthe same as used internally, therefore any changes to it will be reflected to the client side on the\nnext refresh.",
          "returnType": "Set<String>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "assignClassName",
          "description": "Assign an additional className to this entry. Already assigned classNames will be kept.\n\n@deprecated use #addClassNames(String...)",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "className"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "assignClassNames",
          "description": "Assign additional classNames to this entry. Already assigned classNames will be kept.\n\n@deprecated use #addClassNames(String...)",
          "returnType": "void",
          "parameters": [
            {
              "type": "String...",
              "name": "classNames"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "assignClassNames",
          "description": "Assign additional classNames to this entry. Already assigned classNames will be kept.\n\n@deprecated use #addClassNames(Collection)",
          "returnType": "void",
          "parameters": [
            {
              "type": "Collection<String>",
              "name": "classNames"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addClassNames",
          "description": "Adds css class names to this entry. Duplicates will automatically be filtered out.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String...",
              "name": "classNames"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addClassNames",
          "description": "Adds css class names to this entry. Duplicates will automatically be filtered out.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Collection<String>",
              "name": "classNames"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "unassignClassName",
          "description": "Unassigns the given className from this entry.\n\n@deprecated use #removeClassNames(String...)",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "className"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [
        {
          "name": "DESCRIPTION",
          "type": "String",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        }
      ],
      "constructors": [
        {
          "description": "Creates a new editable instance with a generated id.",
          "parameters": [],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new entry with the given id. Null will lead to a generated id.\n<br><br>\nPlease be aware, that the ID needs to be unique in the calendar instance. Otherwise it can lead to\nunpredictable results.",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "FieldNameConstants",
        "EqualsAndHashCode",
        "lombok",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryChangedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryChangedEvent",
      "description": "An event that occurs when an entry has been changed on the client side.\n<br><br>\nYou can apply the changes to the referred entry by calling the method #applyChangesOnEntry().",
      "type": "class",
      "extends": "EntryDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the changed data object.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "ObjectNode",
              "name": "jsonObject"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryClickedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryClickedEvent",
      "description": "Occurs when an entry has been clicked on the client side.\n<br><br>\nClient side event: eventClick",
      "type": "class",
      "extends": "EntryDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the id of the clicked entry.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryDataEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryDataEvent",
      "description": "Extended entry event type, that provides also additional client side entry data, that can be interpreted on the\nserver side.",
      "type": "class",
      "extends": "EntryEvent",
      "methods": [
        {
          "name": "applyChangesOnEntry",
          "description": "Applies the contained changes on the referring entry and returns this instance.",
          "returnType": "Entry",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getChangesAsEntry",
          "description": "Returns a new Entry instance with the changes from this event applied on top of the\noriginal entry. The original entry stored in #getEntry() is not modified.\n<p>\nThis is the standard way to inspect \"the entry as it would look after applying the change\"\nwithout touching server-side state — useful for validation before calling\n#applyChangesOnEntry() or for rendering a dialog preview.",
          "returnType": "<R extends Entry> R",
          "parameters": [],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "createCopyBasedOnChanges",
          "description": "@deprecated since 7.2.0, use #getChangesAsEntry() — the new name is shorter and\n            clearer about what the method returns.",
          "returnType": "<R extends Entry> R",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the changed data object.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "ObjectNode",
              "name": "jsonObject"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryDragStartEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryDragStartEvent",
      "description": "Fires when the user begins dragging an entry. Complements EntryDroppedEvent, which only fires when\nthe drag actually changed the entry's position. This event fires regardless of whether the drag results\nin a position change or not.\n<br><br>\nUse this event to show UI feedback while a drag is in progress (e.g. disabling a \"Delete\" button).\nUse EntryDragStopEvent to re-enable such feedback when dragging ends.\n<br><br>\nNote: #getEntry() returns the server-side entry at its <em>original</em> position",
      "type": "class",
      "extends": "EntryDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryDragStopEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryDragStopEvent",
      "description": "Fires when the user stops dragging an entry, regardless of whether the position changed.\nComplements EntryDroppedEvent, which only fires when the drag actually moved the entry to a new position.\n<br><br>\nUse this event to clean up UI feedback that was shown in response to EntryDragStartEvent\n(e.g. re-enabling a \"Delete\" button after any drag, regardless of outcome).\n<br><br>\nNote: #getEntry() returns the server-side entry at its <em>original</em> position.\nDo not call #applyChangesOnEntry() on t",
      "type": "class",
      "extends": "EntryDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryDroppedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryDroppedEvent",
      "description": "Occurs when an entry time has changed by drag and drop.\n<br><br>\nYou can apply the changes to the referred entry by calling the method #applyChangesOnEntry().\n<br><br>\nClient side name: eventDrop",
      "type": "class",
      "extends": "EntryTimeChangedEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the changed data object for the entry plus the json object for the delta information.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryEvent",
      "description": "Simple event that occurred for a specific calendar item.",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the entry id.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "String",
              "name": "entryId"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryLeaveEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryLeaveEvent",
      "description": "Fires when a calendar entry is dragged from this calendar to another calendar instance.\nThis is the counterpart to EntryReceiveEvent on the receiving calendar.\n<br><br>\nThis event requires that multiple FullCalendar instances have been configured for inter-calendar drag:\ncall FullCalendar#setEditable(boolean) setEditable(true) on the source calendar and\nFullCalendar#setDroppable(boolean) setDroppable(true) on the target calendar.\n<br><br>\nClient side name: eventLeave",
      "type": "class",
      "extends": "EntryDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryMouseEnterEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryMouseEnterEvent",
      "description": "Occurs when the user mouses over an entry\n<br><br>\nClient side event: eventMouseEnter",
      "type": "class",
      "extends": "EntryDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryMouseLeaveEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryMouseLeaveEvent",
      "description": "Occurs when the user mouses out of an entry\n<br><br>\nClient side event: eventMouseLeave",
      "type": "class",
      "extends": "EntryDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryReceiveEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryReceiveEvent",
      "description": "Fires when an external element carrying event data (`data-event` attribute) has been dropped\nonto the calendar and FullCalendar has created a new entry from it.\n<br><br>\nThe #getEntry() method returns a freshly constructed Entry populated from the data\npassed by the client. This entry is <em>not</em> added to the calendar's entry provider automatically;\nthe application must do this explicitly if it wants to persist the received entry\n(e.g. via org.vaadin.stefan.fullcalendar.dataprovider.InMemory",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [
        {
          "name": "getDraggable",
          "description": "Returns the Draggable instance if the dropped element was registered via\nFullCalendar#addDraggable(Draggable) on this calendar.",
          "returnType": "Optional<Draggable>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "ToString",
        "Getter",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryResizeStartEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryResizeStartEvent",
      "description": "Fires when the user begins resizing an entry. Complements EntryResizedEvent, which only fires when\nthe resize actually changed the entry's duration.\n<br><br>\nUse this event to show UI feedback while a resize is in progress. Use EntryResizeStopEvent to\nclean up such feedback when resizing ends.\n<br><br>\nNote: #getEntry() returns the server-side entry at its <em>original</em> duration.\nDo not call #applyChangesOnEntry() on this event — resize start does not represent\na committed duration change. U",
      "type": "class",
      "extends": "EntryDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryResizeStopEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryResizeStopEvent",
      "description": "Fires when the user stops resizing an entry, regardless of whether the duration changed.\nComplements EntryResizedEvent, which only fires when the resize actually changed the entry's duration.\n<br><br>\nUse this event to clean up UI feedback that was shown in response to EntryResizeStartEvent\n(e.g. re-enabling controls after any resize, regardless of outcome).\n<br><br>\nNote: #getEntry() returns the server-side entry at its <em>original</em> duration.\nDo not call #applyChangesOnEntry() on this even",
      "type": "class",
      "extends": "EntryDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryResizedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryResizedEvent",
      "description": "Occurs when an entry time has changed by resizing.\n<br><br>\nYou can apply the changes to the referred entry by calling the method #applyChangesOnEntry().\n<br><br>\nClient side name: eventResize",
      "type": "class",
      "extends": "EntryTimeChangedEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the changed data object for the entry plus the json object for the delta information.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryTimeChangedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryTimeChangedEvent",
      "description": "This specialized version of the entry changed event gives additional information about the changed time as\na delta instance.\n<br><br>\nYou can apply the changes to the referred entry by calling the method #applyChangesOnEntry().",
      "type": "class",
      "extends": "EntryChangedEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the changed data object for the entry plus the json object for the delta information.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "ObjectNode",
              "name": "jsonEntry"
            },
            {
              "type": "ObjectNode",
              "name": "jsonDelta"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EventSourceFailureEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EventSourceFailureEvent",
      "description": "Fires when a client-managed event source (JSON feed, Google Calendar, iCal) fails to load.\n<br><br>\nUse this to react on the server side (e.g. show an error `Notification`, log the failure, etc.).\nThe #getSourceId() identifies which configured source failed — this is the id set on the\nClientSideEventSource when it was added.\n<br><br>\nClient side name: eventSourceFailure",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [
        "ToString",
        "Getter",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ExternalEntryDroppedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ExternalEntryDroppedEvent",
      "description": "Fires when an entry from a <em>client-managed</em> event source (JSON feed, Google Calendar, iCal) is dragged\nto a new time slot. This event fires instead of EntryDroppedEvent when the dropped entry's id is not\nfound in the server-side entry cache (i.e. it came from a ClientSideEventSource, not from the\nserver-side org.vaadin.stefan.fullcalendar.dataprovider.EntryProvider).\n<br><br>\nThe #getEntry() method returns a <em>transient</em> data carrier constructed from the dropped entry's\nJS data. Thi",
      "type": "class",
      "extends": "ExternalEntryEvent",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [
        "ToString",
        "Getter",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ExternalEntryEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ExternalEntryEvent",
      "description": "Base class for events fired when an entry from a <em>client-managed</em> event source\n(JSON feed, Google Calendar, iCal) is interacted with (dropped or resized).\n<br><br>\nThe #getEntry() method returns a <em>transient</em> data carrier constructed from the entry's\nJS data. This entry is NOT part of any org.vaadin.stefan.fullcalendar.dataprovider.EntryProvider.\nUse Entry#getId() to locate and update the corresponding record in the external system.",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ExternalEntryResizedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ExternalEntryResizedEvent",
      "description": "Fires when an entry from a <em>client-managed</em> event source (JSON feed, Google Calendar, iCal) is resized.\nThis event fires instead of EntryResizedEvent when the resized entry's id is not in the server-side\nentry cache (i.e. it came from a ClientSideEventSource).\n<br><br>\nThe #getEntry() method returns a <em>transient</em> data carrier. NOT owned by any EntryProvider.\nUse #getOldEnd() to get the end time before the resize.\n<br><br>\nResize on client-managed source entries is opt-in. Set `with",
      "type": "class",
      "extends": "ExternalEntryEvent",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [
        "ToString",
        "Getter",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "FullCalendar",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.FullCalendar",
      "description": "",
      "type": "class",
      "extends": "Component",
      "implements": [
        "HasStyle",
        "HasSize",
        "HasTheme"
      ],
      "methods": [
        {
          "name": "allowDatesRenderEventOnOptionChange",
          "description": "Sets a property to allow or disallow (re-)rendering of dates, when an option changes. When allowed,\neach option will fire a dates rendering event, which can lead to multiple rendering events, even if only\none is needed.",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "allow"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "next",
          "description": "Moves to the next interval (e. g. next month if current view is monthly based).",
          "returnType": "void",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "previous",
          "description": "Moves to the previous interval (e. g. previous month if current view is monthly based).",
          "returnType": "void",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "today",
          "description": "Moves to the current interval (e. g. current month if current view is monthly based).",
          "returnType": "void",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryProvider",
          "description": "Sets the entry provider for this instance. The previous entry provider will be removed and the\nclient side will be updated.\n<p></p>\nBy default a new full calendar is initialized with an InMemoryEntryProvider.",
          "returnType": "void",
          "parameters": [
            {
              "type": "EntryProvider<? extends Entry>",
              "name": "entryProvider"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryProvider",
          "description": "Returns the entry provider of this calendar. Never null.",
          "returnType": "<R extends Entry, T extends EntryProvider<R>> T",
          "parameters": [],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "isInMemoryEntryProvider",
          "description": "Indicates, if the entry provider is a in memory provider.",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCachedEntryFromFetch",
          "description": "Returns an entry with the given id from the last fetched set of entries. Returns an empty instance,\nwhen there was no fetch yet or the id is unknown.\n<p></p>\nUses InMemoryEntryProvider#getEntryById(String) when the eager in memory provider is used.\n<p></p>\nThis method is an internal method, intended to be used by entry based events only. Do not use it for\nany other purpose as the implementation or scope may change in future.",
          "returnType": "Optional<Entry>",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "changeView",
          "description": "Change the view of the calendar (e. g. from monthly to weekly)",
          "returnType": "void",
          "parameters": [
            {
              "type": "CalendarView",
              "name": "view"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCurrentViewName",
          "description": "The name of the current view.",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCurrentView",
          "description": "The current view of this isntance. Empty, if the current view could not be matched with one of the predefined\nviews (e.g. in case of a custom view).",
          "returnType": "Optional<CalendarView>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "gotoDate",
          "description": "Switch to the interval containing the given date (e. g. to month \"October\" if the \"15th October ...\" is passed).",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalDate",
              "name": "date"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCurrentIntervalStart",
          "description": "Returns the start of the currently displayed date interval (e.g., the first day of the\ndisplayed month in month view). Updated after each render via `DatesRenderedEvent`.\n<p>\nNote: The value lags by one server round-trip — it reflects the state after the last\n`datesSet` event was processed. Calling this immediately after a navigation method\n(e.g., #next()) before the client fires the next `datesSet` event will\nreturn the previous value.",
          "returnType": "Optional<LocalDate>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCurrentIntervalEnd",
          "description": "Returns the end of the currently displayed date interval (exclusive). Updated after each\nrender via `DatesRenderedEvent`.\n<p>\nNote: The value lags by one server round-trip (see #getCurrentIntervalStart()).",
          "returnType": "Optional<LocalDate>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "scrollToTime",
          "description": "Programatically scroll the current view to the given time in the format `hh:mm:ss.sss`, `hh:mm:sss` or `hh:mm`. For example, '05:00' signifies 5 hours.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "duration"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "scrollToTime",
          "description": "Programatically scroll the current view to the given time in the format `hh:mm:ss.sss`, `hh:mm:sss` or `hh:mm`. For example, '05:00' signifies 5 hours.",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalTime",
              "name": "duration"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setOption",
          "description": "Sets a option for this instance. Passing a null value removes the option.\n<br><br>\nPlease be aware that this method does not check the passed value. Use the typed\nOption constants for type safety (e.g. `setOption(Option.LOCALE, myLocale)`).",
          "returnType": "void",
          "parameters": [
            {
              "type": "Option",
              "name": "option"
            },
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setOption",
          "description": "Sets an option for this instance. Passing a null value removes the option. The third parameter\nmight be used to explicitly store a \"more complex\" variant of the option's value to be returned\nby #getOption(Option). It is always stored when not equal to the value except for null.\nIf it is equal to the value or null it will not be stored (old version will be removed from internal cache).\n<br><br>\nExample:\n<pre>\n// sends a client parseable version to client and stores original in server side\ncalenda",
          "returnType": "void",
          "parameters": [
            {
              "type": "Option",
              "name": "option"
            },
            {
              "type": "Object",
              "name": "value"
            },
            {
              "type": "Object",
              "name": "valueForServerSide"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setOption",
          "description": "Sets an option for this instance. Passing a null value removes the option.\n<br><br>\nPlease be aware that this method does not check the passed value. Use the typed\nOption constants for type safety (e.g. `setOption(Option.LOCALE, myLocale)`).\n<br><br>\nFor a full overview of possible options have a look at the FullCalendar documentation\n(<a href='https://fullcalendar.io/docs'>https://fullcalendar.io/docs</a>).",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "option"
            },
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setOption",
          "description": "Sets an option for this instance. Passing a null value removes the option. The third parameter\nmight be used to explicitly store a \"more complex\" variant of the option's value to be returned\nby #getOption(Option). It is always stored when not equal to the value except for null.\nIf it is equal to the value or null it will not be stored (old version will be removed from internal cache).\n<br><br>\nOptionally, one or more JsonItemPropertyConverter converters can be passed to automatically\nconvert the",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "option"
            },
            {
              "type": "Object",
              "name": "value"
            },
            {
              "type": "Object",
              "name": "valueForServerSide"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setFirstDay",
          "description": "Sets the first day of a week to be shown by the calendar. Per default sunday.\n<br><br>\n<b>Note:</b> FC works internally with 0 for sunday. This method converts SUNDAY to\nthis number before passing it to the client.\n\n@deprecated Use #setOption(Option, Object) with Option#FIRST_DAY instead.\n            Accepts a DayOfWeek directly via the option converter.",
          "returnType": "void",
          "parameters": [
            {
              "type": "DayOfWeek",
              "name": "firstDay"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setHeight",
          "description": "Sets the calendar's height to a fixed amount of pixels.\n\n@deprecated Use #setHeight(String) or #setHeight(float, Unit) instead",
          "returnType": "void",
          "parameters": [
            {
              "type": "int",
              "name": "heightInPixels"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setHeightByParent",
          "description": "Sets the calendar's height to be calculated from parents height. Please be aware, that a block parent with\nrelative height (e. g. 100%) might not work properly. In this case use flex layout or set a fixed height for\nthe parent or the calendar.\n@deprecated Use #setHeight(String) or #setHeight(float, Unit) instead",
          "returnType": "void",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setHeightAuto",
          "description": "Sets the calendar's height to be calculated automatically. In current implementation this means by the calendars\nwidth-height-ratio.\n@deprecated Use #setHeight(String) or #setHeight(float, Unit) instead",
          "returnType": "void",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setHeight",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "height"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setTimeslotsSelectable",
          "description": "Set if timeslots might be selected by the user. Please see also documentation of #addTimeslotsSelectedListener(ComponentEventListener).\n\n@deprecated Use #setOption(Option, Object) with Option#SELECTABLE instead.",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "selectable"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setWeekNumbersVisible",
          "description": "Should the calendar show week numbers (when available for the current view)?\n\n@deprecated Use #setOption(Option, Object) with Option#WEEK_NUMBERS instead.",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "weekNumbersVisible"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setWeekNumbersWithinDays",
          "description": "Determines the styling for week numbers in Month and DayGrid views.\n\n@deprecated this functionality is no longer supported, thus you can remove the call",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "weekNumbersWithinDays"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getLocale",
          "description": "Returns the current set locale.\n\n@deprecated Use #getOption(Option) with Option#LOCALE instead.\n            Accepts a Locale directly.",
          "returnType": "Locale",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setLocale",
          "description": "Sets the locale to be used. If invoked for the first time it will load additional language scripts.\n\n@deprecated Use #setOption(Option, Object) with Option#LOCALE instead.\n            Accepts a Locale directly.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Locale",
              "name": "locale"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setNowIndicatorShown",
          "description": "If true is passed then the calendar will show a indicator for the current time, depending on the view.\n\n@deprecated Use #setOption(Option, Object) with Option#NOW_INDICATOR instead.",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "shown"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setNumberClickable",
          "description": "When true is passed the day / week numbers (or texts) will become clickable by the user and fire an event\nfor the clicked day / week.\n\n@deprecated Use #setOption(Option, Object) with Option#NAV_LINKS instead.",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "clickable"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryClassNamesCallback",
          "description": "The given string will be interpreted as JS function on the client side\nand attached to the calendar as the eventClassNames callback. It must be a valid JavaScript function.\n<br><br>\nA ClassName Input for adding classNames to the outermost event element. If supplied as a callback function, it is called every time the associated event data changes.\n<br><br>\n<b>Note: </b> Please be aware, that there is <b>NO</b> content parsing, escaping, quoting or\nother security mechanism applied on this string, ",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryDidMountCallback",
          "description": "The given string will be interpreted as JS function on the client side\nand attached to the calendar as the eventDidMount callback. It must be a valid JavaScript function.\n<br><br>\nCalled right after the element has been added to the DOM. If the event data changes, this is <b>NOT</b> called again.\n<br><br>\n<b>Note: </b> Please be aware, that there is <b>NO</b> content parsing, escaping, quoting or\nother security mechanism applied on this string, so check it yourself before passing it to the clien",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addEntryNativeEventListener",
          "description": "Adds a native, client side / java script event listener, that will be added for all entries, when they\nare mounted. The first parameter is the java script event name (for instance \"click\" or \"mouseover\"), the\nsecond parameter is the javascript callback (e.g. \"e => console.warn(e)\" or \"e => alert('Hello')\").\n<br><br>\nThis method does NOT check, if you pass valid event names or callbacks. It will also NOT sanitize the given\ncontent, but pass it to the client as it is. <b>Be careful to not provide ",
          "returnType": "Registration",
          "parameters": [
            {
              "type": "String",
              "name": "eventName"
            },
            {
              "type": "String",
              "name": "eventCallback"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryWillUnmountCallback",
          "description": "The given string will be interpreted as JS function on the client side\nand attached to the calendar as the eventWillUnmount callback. It must be a valid JavaScript function.\n<br><br>\nCalled right before the element will be removed from the DOM.\n<br><br>\n<b>Note: </b> Please be aware, that there is <b>NO</b> content parsing, escaping, quoting or\nother security mechanism applied on this string, so check it yourself before passing it to the client.\n<br><br>\n\n@deprecated Use #setOption(Option, Objec",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryContentCallback",
          "description": "The given string will be interpreted as JS function on the client side\nand attached to the calendar as the \"eventContent\" callback. It must be a valid JavaScript function.\n<br><br>\nCalled when an entry is being rendered, allowing you to return custom HTML content or a DOM node to replace the default entry content.\n<b>Note: </b> Please be aware, that there is <b>NO</b> content parsing, escaping, quoting or\nother security mechanism applied on this string, so check it yourself before passing it to ",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setBusinessHours",
          "description": "Sets the business hours for this calendar instance. You may pass multiple instances for different configurations.\nPlease be aware, that instances with crossing days or times are handled by the client side and may lead\nto unexpected results.\n\n@deprecated Use #setOption(Option, Object) with Option#BUSINESS_HOURS instead.\n            Accepts BusinessHours, `BusinessHours[]`, or `boolean`. Pass `null` to remove.",
          "returnType": "void",
          "parameters": [
            {
              "type": "BusinessHours...",
              "name": "hours"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeBusinessHours",
          "description": "Removes the business hours for this calendar instance.\n\n@deprecated Use #setOption(Option, Object) with Option#BUSINESS_HOURS instead.\n            Accepts BusinessHours, `BusinessHours[]`, or `boolean`. Pass `null` to remove.",
          "returnType": "void",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setSnapDuration",
          "description": "Sets the snap duration for this calendar instance (the time interval entries snap to when dragging).\nThe default is `\"00:30:00\"`.\n\n@deprecated Use #setOption(Option, Object) with Option#SNAP_DURATION instead.\n            Accepts a `String` (e.g. `\"00:15:00\"`) or a java.time.Duration.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "duration"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setSlotMinTime",
          "description": "Sets the min time for this calendar instance. This is the first time slot that will be displayed for each day.\nThe default is `\"00:00:00\"`.\n\n@deprecated Use #setOption(Option, Object) with Option#SLOT_MIN_TIME instead.\n            Accepts a java.time.LocalTime, a java.time.Duration, or a duration string.",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalTime",
              "name": "slotMinTime"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getFixedWeekCount",
          "description": "Returns the fixedWeekCount. By default true.\n\n@deprecated Use #getOption(Option) with Option#FIXED_WEEK_COUNT instead.",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setFixedWeekCount",
          "description": "Determines the number of weeks displayed in a month view.\nIf true, the calendar will always be 6 weeks tall.\nIf false, the calendar will have either 4, 5, or 6 weeks, depending on the month.\n\n@deprecated Use #setOption(Option, Object) with Option#FIXED_WEEK_COUNT instead.",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "fixedWeekCount"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setSlotMaxTime",
          "description": "Sets the max time for this calendar instance. This is the last time slot that will be displayed for each day.\nThe default is `\"24:00:00\"`.\n\n@deprecated Use #setOption(Option, Object) with Option#SLOT_MAX_TIME instead.\n            Accepts a java.time.LocalTime, a java.time.Duration, or a duration string.",
          "returnType": "void",
          "parameters": [
            {
              "type": "LocalTime",
              "name": "slotMaxTime"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getTimezone",
          "description": "Returns the current timezone of this calendar. Entries will be displayed related to this timezone.\nDoes not affect the server side times of entries, only their client side displayment.",
          "returnType": "Timezone",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setTimezone",
          "description": "Sets the timezone the calendar shall show. Does not affect the entries directly but only their client side displayment.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Timezone",
              "name": "timezone"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryDurationEditable",
          "description": "Returns the editable flag. By default true.\n\n@deprecated Use #getOption(Option) with Option#ENTRY_DURATION_EDITABLE instead.",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryDurationEditable",
          "description": "Allow entries’ durations to be editable through resizing.\n<p>\nThis option can be overridden with org.vaadin.stefan.fullcalendar.Entry#setDurationEditable(Boolean)\n\n@deprecated Use #setOption(Option, Object) with Option#ENTRY_DURATION_EDITABLE instead.",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "editable"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryResizableFromStart",
          "description": "Returns the editable flag. By default false.\n\n@deprecated Use #getOption(Option) with Option#ENTRY_RESIZABLE_FROM_START instead.",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryResizableFromStart",
          "description": "Whether the user can resize an event from its starting edge.\n\n@deprecated Use #setOption(Option, Object) with Option#ENTRY_RESIZABLE_FROM_START instead.",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "editable"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [
        {
          "name": "FC_CLIENT_VERSION",
          "type": "String",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        },
        {
          "name": "DEFAULT_TIMED_EVENT_DURATION",
          "type": "int",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        },
        {
          "name": "DEFAULT_DAY_EVENT_DURATION",
          "type": "int",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        }
      ],
      "constructors": [
        {
          "description": "Creates a new instance without any settings beside the default locale (CalendarLocale#getDefaultLocale()).\n<p></p>\nUses InMemoryEntryProvider by default.",
          "parameters": [],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new instance.\n<br><br>\nExpects the default limit of entries shown per day. This does not affect basic or\nlist views. This value has to be set here and cannot be modified afterwards due to\ntechnical reasons of FC. If set afterwards the entry limit would overwrite settings\nand would show the limit also for basic views where it makes no sense (might change in future).\nPassing a negative number disabled the entry limit (same as passing no number at all).\n<br><br>\nSets the locale to Calenda",
          "parameters": [
            {
              "type": "int",
              "name": "entryLimit"
            }
          ],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new instance with custom initial options. This allows a full override of the default\ninitial options, that the calendar would normally receive. Theoretically you can set all options,\nas long as they are not based on a client side variable (as for instance \"plugins\" or \"locales\").\nComplex objects are possible, too, for instance for view-specific settings.\nPlease refer to the official FC documentation regarding potential options.\n<br><br>\nClient side event handlers, that are technically ",
          "parameters": [
            {
              "type": "ObjectNode",
              "name": "initialOptions"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "Tag",
        "CssImport",
        "JsModule",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "FullCalendarBuilder",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.FullCalendarBuilder",
      "description": "This class can be used to create FullCalendar instances via a fluent builder api.\n\n@deprecated since 7.2.0 — FullCalendar and FullCalendarScheduler can be constructed\ndirectly and configured through FullCalendar#setOption(FullCalendar.Option, Object). The\nbuilder no longer provides value beyond syntactic sugar. <b>No removal is scheduled for 7.x</b> —\nexisting code keeps working throughout the 7.x line; the class is only slated for removal in a\nfuture major version.\n<p>\nMigration:\n<table>\n  <cap",
      "type": "class",
      "methods": [
        {
          "name": "build",
          "description": "Builds the FullCalendar with the settings of this instance. Depending on some settings the returned\ninstance might be a subclass of FullCalendar.",
          "returnType": "<T extends FullCalendar> T",
          "parameters": [],
          "annotations": [
            "SuppressWarnings",
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "Deprecated"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "FullCalendarVariant",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.FullCalendarVariant",
      "description": "Themevariants for the FullCalendar. Use FullCalendar#addThemeVariants(FullCalendarVariant...) to\napply them.",
      "type": "enum",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "GoogleCalendarEventSource",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.GoogleCalendarEventSource",
      "description": "A client-managed event source that fetches events from a public Google Calendar.\n<br><br>\nRequires the `@fullcalendar/google-calendar` npm package and a Google Calendar API key.\nSet a global key via `calendar.setOption(Option.EXTERNAL_EVENT_SOURCE_GOOGLE_CALENDAR_API_KEY, key)`,\nor set a per-source key via #withApiKey(String).\n<br><br>\n<strong>Note:</strong> Only public Google Calendars are supported. Private calendars require OAuth and cannot\nuse this source. FullCalendar fetches but never writ",
      "type": "class",
      "extends": "ClientSideEventSource<GoogleCalendarEventSource>",
      "methods": [
        {
          "name": "toJson",
          "description": "",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new Google Calendar event source for the given calendar ID.",
          "parameters": [
            {
              "type": "String",
              "name": "googleCalendarId"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ICalendarEventSource",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ICalendarEventSource",
      "description": "A client-managed event source that fetches events from a public iCalendar (`.ics`) feed URL.\n<br><br>\nRequires the `@fullcalendar/icalendar` and `ical.js` npm packages. The URL must be accessible\nfrom the browser (CORS headers are required for cross-origin feeds).\n<br><br>\niCalendar is a read-only format — drag/drop should remain disabled (the default).\n<br><br>\nExample:\n<pre>\ncalendar.addClientSideEventSource(new ICalendarEventSource(\"https://example.com/holidays.ics\")\n    .withId(\"holiday-ics\"",
      "type": "class",
      "extends": "ClientSideEventSource<ICalendarEventSource>",
      "methods": [
        {
          "name": "toJson",
          "description": "",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new iCalendar event source for the given URL.",
          "parameters": [
            {
              "type": "String",
              "name": "url"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "JsCallback",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.JsCallback",
      "description": "Wraps a JavaScript function string for safe transport from Java to the client.\nWhen the client encounters a JsCallback value in option JSON, it evaluates the\nstring via `new Function(\"return \" + jsFunction)()` to produce a real\nJS function object before passing it to FullCalendar.\n\n<p><b>Custom property injection:</b> For well-known entry callback keys\n(`eventDidMount`, `eventContent`, `eventClassNames`,\n`eventWillUnmount`, `eventOverlap`, `eventAllow`, `selectOverlap`),\nthe client automatically",
      "type": "class",
      "implements": [
        "Serializable"
      ],
      "methods": [
        {
          "name": "getJsFunction",
          "description": "Returns the JavaScript function string.",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toMarkerJson",
          "description": "Produces the JSON marker object that the client recognises as a JsCallback.\nThe marker has the form `{\"__jsCallback\": \"function...\"`}.",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toString",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "equals",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "o"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "hashCode",
          "description": "",
          "returnType": "int",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "JsonFactory",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.JsonFactory",
      "description": "Factory to create new objects. Wraps the current json framework.",
      "type": "class",
      "methods": [
        {
          "name": "factory",
          "description": "Returns the factory instance, that is used to create json nodes.",
          "returnType": "JsonNodeFactory",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "createArray",
          "description": "Creates an empty array node.",
          "returnType": "ArrayNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "createObject",
          "description": "Creates an empty object node.",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "create",
          "description": "Creates a number node with the given double.",
          "returnType": "NumericNode",
          "parameters": [
            {
              "type": "double",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "create",
          "description": "Creates a number node with the given integer.",
          "returnType": "NumericNode",
          "parameters": [
            {
              "type": "int",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "create",
          "description": "Creates a number node with the given long.",
          "returnType": "NumericNode",
          "parameters": [
            {
              "type": "long",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "create",
          "description": "Creates a string node with the given text.",
          "returnType": "StringNode",
          "parameters": [
            {
              "type": "String",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "create",
          "description": "Creates a boolean node with the value.",
          "returnType": "BooleanNode",
          "parameters": [
            {
              "type": "boolean",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "createNull",
          "description": "Creates a node, that represents a null value.",
          "returnType": "NullNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "JsonFeedEventSource",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.JsonFeedEventSource",
      "description": "A client-managed event source that fetches events from a URL returning a JSON array of FullCalendar event objects.\n<br><br>\nThe browser fetches events directly from the given URL — the server only configures the source, it does not\nown or observe the individual entries.\n<br><br>\nThe request includes `start` and `end` query parameters (names overridable per-source via\n#withStartParam(String) / #withEndParam(String), or globally via\n`setOption(Option.EXTERNAL_EVENT_SOURCE_START_PARAM, ...)` / `set",
      "type": "class",
      "extends": "ClientSideEventSource<JsonFeedEventSource>",
      "methods": [
        {
          "name": "toJson",
          "description": "",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new JSON feed event source for the given URL.",
          "parameters": [
            {
              "type": "String",
              "name": "url"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "JsonPropertyConverter",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.JsonPropertyConverter",
      "description": "Converts a server side value to a json value and (optionally) vice versa.",
      "type": "interface",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "JsonUtils",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.JsonUtils",
      "description": "JsonUtils used for internally handling conversion of objects sent to or received from the client side.",
      "type": "class",
      "methods": [
        {
          "name": "toJsonNode",
          "description": "Converts the given object to a json value. Can be null.",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "toJsonNode",
          "description": "Converts the given object to a json value. Can be null. The given custom converter is applied, when\nthere is no default conversion found for the given value. Can be null to convert it to a simple string.",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Object",
              "name": "value"
            },
            {
              "type": "SerializableFunction<Object, JsonNode>",
              "name": "customConverter"
            }
          ],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "isCollectable",
          "description": "Returns true, if this value would be converted to a json array (or iterable like) for the client, like\nany Java iterable, stream, array, map or iterator.",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "formatClientSideTimeString",
          "description": "",
          "returnType": "String",
          "parameters": [
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "formatClientSideDateString",
          "description": "",
          "returnType": "String",
          "parameters": [
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "formatClientSideDateTimeString",
          "description": "",
          "returnType": "String",
          "parameters": [
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "parseClientSideDate",
          "description": "Parses a date string sent from the client side.",
          "returnType": "LocalDate",
          "parameters": [
            {
              "type": "String",
              "name": "dateString"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "parseClientSideDateTime",
          "description": "Parses a date string sent from the client side. Will be converted to a UTC.",
          "returnType": "LocalDateTime",
          "parameters": [
            {
              "type": "String",
              "name": "dateTimeString"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "parseClientSideTime",
          "description": "Parses a time string sent from the client side. Will be converted to a UTC.",
          "returnType": "LocalTime",
          "parameters": [
            {
              "type": "String",
              "name": "timeString"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "ofJsonNode",
          "description": "Shortcut method for #ofJsonNode(JsonNode, SerializableFunction, Collection, Class). Reads a json value object and\ntries to parse it to a Java object.\n<p></p>\nMost basic types are automatically converted. Since Json objects represent a more complex structure, the\ngiven callback can be used to convert them to their Java representation. This method converts them automatically\ninto a Map, using #convertObjectToMap(tools.jackson.databind.node.ObjectNode, Class).\n<p></p>\nJson arrays are automatically ",
          "returnType": "<T> T",
          "parameters": [
            {
              "type": "JsonNode",
              "name": "jsonValue"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "ofJsonNode",
          "description": "Shortcut method for #ofJsonNode(JsonNode, SerializableFunction, Collection, Class). Reads a json value object and\ntries to parse it to a Java object.\n<p></p>\nMost basic types are automatically converted. Since Json objects represent a more complex structure, the\ngiven callback can be used to convert them to their Java representation. This method converts them automatically\ninto a Map, using #convertObjectToMap(tools.jackson.databind.node.ObjectNode, Class).\n<p></p>\nJson arrays are converted to t",
          "returnType": "<T> T",
          "parameters": [
            {
              "type": "JsonNode",
              "name": "jsonValue"
            },
            {
              "type": "Class<? extends Collection>",
              "name": "convertArrayToType"
            }
          ],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "convertObjectToMap",
          "description": "Simple method, that converts a json object to a map. Calls #ofJsonNode(JsonNode, Class) for each\nread value.",
          "returnType": "Map<String, Object>",
          "parameters": [
            {
              "type": "ObjectNode",
              "name": "object"
            },
            {
              "type": "Class<? extends Collection>",
              "name": "convertArrayToType"
            }
          ],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": true
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "MoreLinkClickedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.MoreLinkClickedEvent",
      "description": "This event is fired when a user clicks the \"+x more\" link in the calendar (which occurs when the max\nentries per day are exceeded).",
      "type": "class",
      "extends": "MultipleEntriesDataEvent",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [
        "ToString",
        "Getter",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "MultipleEntriesDataEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.MultipleEntriesDataEvent",
      "description": "Extended multple entries event type, that provides also additional client side entry data, that can be\ninterpreted on the server side.",
      "type": "class",
      "extends": "MultipleEntriesEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the changed data object.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "ArrayNode",
              "name": "jsonObjects"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "MultipleEntriesEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.MultipleEntriesEvent",
      "description": "Simple event that occurred for multiple calendar items.",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [
        {
          "name": "getEntries",
          "description": "Returns the entries for which this event occurred. Never null nor empty.",
          "returnType": "Collection<Entry>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the entry id.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "Collection<String>",
              "name": "entryIds"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "RRule",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.RRule",
      "description": "Represents a recurrence rule (RRULE) for a calendar entry, compatible with the `@fullcalendar/rrule`\nplugin. Used to define rich recurrence patterns beyond the simple built-in recurrence fields\n(`recurringDaysOfWeek`, `recurringStartDate`, etc.).\n<p>\nTwo modes of use:\n<ol>\n  <li><b>Structured form</b> (recommended): Set #freq and optional fields like\n      #byweekday, #until, #count, etc. Serializes to a JSON object.</li>\n  <li><b>Raw RRULE string</b>: Set a raw iCalendar RRULE string via #ofRaw",
      "type": "class",
      "methods": [
        {
          "name": "getClientSideValue",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toJson",
          "description": "Serializes this RRule to a JsonNode for sending to the FC client.\n<ul>\n  <li>If a raw RRULE string was set (via #ofRaw(String)), returns a StringNode.</li>\n  <li>Otherwise, returns an ObjectNode with the structured properties.</li>\n</ul>",
          "returnType": "JsonNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toRRuleString",
          "description": "Converts this RRule to an iCalendar RRULE string that FC's rrule plugin can parse directly.\nIf this was created via #ofRaw(String), the raw string is returned as-is.",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "RecurringTime",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.RecurringTime",
      "description": "A simple time class, that allows times above 24 hours, since the FC allows recurring times to \"bleed\" into the\nnext day. Basically a simple variant of Duration with a specific purpose.",
      "type": "class",
      "methods": [
        {
          "name": "toLocalTime",
          "description": "Converts this recurring time to a local time. Be careful, as LocalTime does not support times of 24h or\nabove and thus such an instance will lead to an exception.",
          "returnType": "LocalTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toDuration",
          "description": "Converts this instance to a Duration instance.",
          "returnType": "Duration",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toFormattedString",
          "description": "Returns this instance as a formatted string. The pattern is always \"HH:mm\".",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "isValidLocalTime",
          "description": "",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "equals",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "LocalTime",
              "name": "localTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "isAfter",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "RecurringTime",
              "name": "recurringTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "isBefore",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "RecurringTime",
              "name": "recurringTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "isAfter",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "LocalTime",
              "name": "recurringTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "isBefore",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "LocalTime",
              "name": "recurringTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "equals",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "o"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "hashCode",
          "description": "",
          "returnType": "int",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "TimeslotClickedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.TimeslotClickedEvent",
      "description": "This event occurs when an empty timeslot in the calendar has clicked. Empty means the empty space itself, not that there\nis not yet another entry located at this timeslot.\n<br><br>\nClient side event: dateClick.",
      "type": "class",
      "extends": "DateTimeEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the clicked date (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "TimeslotsSelectedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.TimeslotsSelectedEvent",
      "description": "Occurs when the user selects one or multiple timeslots on the calendar. The selected timeslots may contain\nentries.\n<br><br>\nClient side event: select",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [
        {
          "name": "getStartAsInstant",
          "description": "Returns the entry's start as an Instant. The contained time is the same as when calling\n#getStart().",
          "returnType": "Instant",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEndAsInstant",
          "description": "Returns the entry's end as an Instant. The contained time is the same as when calling\n#getEnd().",
          "returnType": "Instant",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStartWithOffset",
          "description": "Returns the start time as a local date time after applying the timezone's offset to\nthe utc based start date (#getStart()). By default the timezone is\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>",
          "returnType": "LocalDateTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEndWithOffset",
          "description": "Returns the end time as a local date time after applying the timezone's offset to\nthe utc based end date (#getEnd()). By default the timezone is\nthe calendar's timezone or, if no calendar is set yet, UTC.",
          "returnType": "LocalDateTime",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStartDate",
          "description": "Returns the start of the event as local date.",
          "returnType": "LocalDate",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEndDate",
          "description": "Returns the end of the event as local date.",
          "returnType": "LocalDate",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the selected dates (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "TimeslotsUnselectEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.TimeslotsUnselectEvent",
      "description": "Fires when the current timeslot selection is cleared. This complements TimeslotsSelectedEvent.\n<br><br>\nUnselect can be triggered by:\n<ul>\n  <li>The user clicking elsewhere on the calendar (when `unselectAuto` is `true`, which is the default)</li>\n  <li>The user pressing Escape</li>\n  <li>A new selection being made (which replaces the old one)</li>\n  <li>Code calling FullCalendar#clearSelection() programmatically</li>\n</ul>\n<br>\nClient side name: unselect",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "Timezone",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.Timezone",
      "description": "Represents a timezone, that is usable by the calendar. The timezone is identified by a zone id and a client side\nrepresentation. The client side representation may differ from the zone id.",
      "type": "class",
      "implements": [
        "ClientSideValue"
      ],
      "methods": [
        {
          "name": "getAvailableZones",
          "description": "Returns all available timezones. This arrayy bases on all constants of this class plus all available zone ids\nreturned by ZoneId#getAvailableZoneIds().",
          "returnType": "Timezone[]",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "getClientSideValue",
          "description": "Returns the client side value of this instance.",
          "returnType": "String",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "applyTimezone",
          "description": "Creates a zoned date time based on this timezone interpreting the given local date time as UTC time.\nPassing ...T00:00 to a GMT+1 instance will result in local date time ...T01:00+01:00\n<p></p>\nFor the UTC instance this method will not modify anything. Passing null will return null.",
          "returnType": "ZonedDateTime",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "localDateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeTimezone",
          "description": "Creates a UTC zoned date time by interpreting the given local date time as a timestamp of this time zone.\nPassing ...T01:00 to a GMT+1 instance will result in local date time ...T00:00Z\n<p></p>\nFor the UTC instance this method will not modify anything.. Passing null will return null.",
          "returnType": "ZonedDateTime",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "localDateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "applyTimezoneOffset",
          "description": "Creates a local date time based by apply the zone offset of this timezone onto the given local date time.\nAny offset modifies like daylight saving will be based on the given local date time.\nPassing ...T00:00 to a GMT+1 instance will result in local date time ...T01:00\n<p></p>\nFor the UTC instance this method will not modify anything, but return a new local date time instance.\nPassing null will return null.",
          "returnType": "LocalDateTime",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "localDateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeTimezoneOffset",
          "description": "Creates a local date time based by removing the zone offset of this timezone from the given local date time.\nAny offset modifies like daylight saving will be based on the given local date time.\nPassing ...T01:00 to a GMT+1 instance will result in local date time ...T00:00\n<p></p>\nFor the UTC instance this method will not modify anything, but return a new local date time instance.\nPassing null will return null.",
          "returnType": "LocalDateTime",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "localDateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "asZonedDateTime",
          "description": "Converts the given local date time to a zoned date time without changing the time itself other then.\nPassing null will return null.\n#applyTimezone(LocalDateTime) or #removeTimezone(LocalDateTime).",
          "returnType": "ZonedDateTime",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "localDateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "convertToInstant",
          "description": "Applies the rules of this timezone on the given local date and creates an instant at the start\nof the given day. Please check the additional documentation on\njava.time.zone.ZoneRules#getOffset(LocalDateTime)",
          "returnType": "Instant",
          "parameters": [
            {
              "type": "LocalDate",
              "name": "date"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "convertToInstant",
          "description": "Applies the rules of this timezone on the given local date time and creates an instant. Please check\nthe additional documentation on java.time.zone.ZoneRules#getOffset(LocalDateTime)",
          "returnType": "Instant",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "dateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "convertToLocalDateTime",
          "description": "Applies the rules of this timezone on the given instant and creates a local date time.",
          "returnType": "LocalDateTime",
          "parameters": [
            {
              "type": "Instant",
              "name": "instant"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "convertToLocalDate",
          "description": "Applies the rules of this timezone on the given instant and creates a local date.",
          "returnType": "LocalDate",
          "parameters": [
            {
              "type": "Instant",
              "name": "instant"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toString",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "equals",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "o"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "hashCode",
          "description": "",
          "returnType": "int",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [
        {
          "name": "ZONE_ID_UTC",
          "type": "ZoneId",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        },
        {
          "name": "UTC",
          "type": "Timezone",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        }
      ],
      "constructors": [
        {
          "description": "Creates a new instance based on the given zone id. The zone id is also used as client side representation.",
          "parameters": [
            {
              "type": "ZoneId",
              "name": "zoneId"
            }
          ],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new instance based on the given zone id and client side value.",
          "parameters": [
            {
              "type": "ZoneId",
              "name": "zoneId"
            },
            {
              "type": "String",
              "name": "clientSideValue"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ViewRenderEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ViewRenderEvent",
      "description": "Basic event for view render events. Provides information about the shown timespan.\n<br><br>\nThe values are always daybased, regardless of the current view.",
      "type": "class",
      "extends": "ComponentEvent<FullCalendar>",
      "methods": [
        {
          "name": "getName",
          "description": "Same as #getViewName()\n@deprecated use #getViewName() instead",
          "returnType": "String",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCalendarView",
          "description": "The calendar view of this event. Empty, if the view name could not be matched with one of the predefined\nviews (e.g. in case of a custom view).",
          "returnType": "Optional<CalendarView>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new event using the given source and indicator whether the\nevent originated from the client side or the server side.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            },
            {
              "type": "ObjectNode",
              "name": "eventData"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ViewSkeletonRenderedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ViewSkeletonRenderedEvent",
      "description": "Occurs after a view's non-date-related DOM structure has been rendered. Provides information about the shown timespan.\n<br><br>\nThe values are always daybased, regardless of the current view.\n<br><br>\nCalled before registered DatesRenderedEvent listeners.",
      "type": "class",
      "extends": "ViewRenderEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new event using the given source and indicator whether the\nevent originated from the client side or the server side.",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "Getter",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "WeekNumberCalculation",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.WeekNumberCalculation",
      "description": "Determines how week numbers are calculated. Corresponds to the FullCalendar `weekNumberCalculation` option.",
      "type": "enum",
      "implements": [
        "ClientSideValue"
      ],
      "methods": [
        {
          "name": "getClientSideValue",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "WeekNumberClickedEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.WeekNumberClickedEvent",
      "description": "Occurs when number links are active and a user clicked on a week's number.",
      "type": "class",
      "extends": "DateEvent",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the date (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "BusinessHoursConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.BusinessHoursConverter",
      "description": "Converts BusinessHours or BusinessHours`[]` to their JSON representation\nfor the FullCalendar client side.",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<Object",
        "Object>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Object",
              "name": "serverValue"
            },
            {
              "type": "Object",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ClientSideValueConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.ClientSideValueConverter",
      "description": "Converts any ClientSideValue to its client-side string representation.",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<ClientSideValue",
        "Object>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "ClientSideValue",
              "name": "serverValue"
            },
            {
              "type": "Object",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DayOfWeekArrayConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.DayOfWeekArrayConverter",
      "description": "Converts DayOfWeek`[]` or Collection`<DayOfWeek>` to a JSON array\nof FullCalendar day-of-week integers (Sunday=0, Monday=1, ..., Saturday=6).",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<Object",
        "Object>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Object",
              "name": "serverValue"
            },
            {
              "type": "Object",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DayOfWeekConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.DayOfWeekConverter",
      "description": "Converts a single DayOfWeek to a FullCalendar day-of-week integer\n(Sunday=0, Monday=1, ..., Saturday=6).",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<DayOfWeek",
        "Object>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "DayOfWeek",
              "name": "serverValue"
            },
            {
              "type": "Object",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DayOfWeekItemConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.DayOfWeekItemConverter",
      "description": "@author Stefan Uebe",
      "type": "class",
      "extends": "Entry>",
      "implements": [
        "JsonItemPropertyConverter<Set<DayOfWeek>",
        "T>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Set<DayOfWeek>",
              "name": "serverValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toServerModel",
          "description": "",
          "returnType": "Set<DayOfWeek>",
          "parameters": [
            {
              "type": "JsonNode",
              "name": "clientValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DisplayModeConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.DisplayModeConverter",
      "description": "Converts DisplayMode to/from its FullCalendar client-side string representation.\nExtends ClientSideValueConverter for the toClientModel direction.",
      "type": "class",
      "extends": "ClientSideValueConverter",
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toServerModel",
          "description": "",
          "returnType": "DisplayMode",
          "parameters": [
            {
              "type": "JsonNode",
              "name": "clientValue"
            },
            {
              "type": "Object",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "DurationConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.DurationConverter",
      "description": "Converts a Duration or LocalTime to a FullCalendar duration string in `\"HH:mm:ss\"` format\n(e.g. `\"00:30:00\"`, `\"06:00:00\"`).\n<p>\nFullCalendar options like `slotDuration`, `snapDuration`, `slotLabelInterval`,\n`scrollTime`, `slotMinTime`, `slotMaxTime`, and `nextDayThreshold`\naccept this format.",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<Object",
        "Object>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Object",
              "name": "serverValue"
            },
            {
              "type": "Object",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ExdateConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.ExdateConverter",
      "description": "Converts the `exdate` field of an Entry to the JSON array format expected by\nFullCalendar's RRule plugin (`exdate: [\"2025-03-10\", \"2025-03-17\"]`).",
      "type": "class",
      "extends": "Entry>",
      "implements": [
        "JsonItemPropertyConverter<Collection<LocalDate>",
        "T>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Collection<LocalDate>",
              "name": "serverValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ExruleConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.ExruleConverter",
      "description": "Converts the `exrule` field of an Entry to the JSON format expected by\nFullCalendar's RRule plugin. A single RRule is serialized as an object; multiple RRules\nare serialized as an array.",
      "type": "class",
      "extends": "Entry>",
      "implements": [
        "JsonItemPropertyConverter<Collection<RRule>",
        "T>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Collection<RRule>",
              "name": "serverValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "JsonItemPropertyConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.JsonItemPropertyConverter",
      "description": "Converts a server side value to a json value and (optionally) vice versa. Also provides info\nabout the current parsed json item, if available.",
      "type": "interface",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "LocalDateConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.LocalDateConverter",
      "description": "@author Stefan Uebe",
      "type": "class",
      "extends": "Entry>",
      "implements": [
        "JsonItemPropertyConverter<LocalDate",
        "T>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "LocalDate",
              "name": "serverValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toServerModel",
          "description": "",
          "returnType": "LocalDate",
          "parameters": [
            {
              "type": "JsonNode",
              "name": "clientValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "RequiredArgsConstructor",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "LocalDateTimeConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.LocalDateTimeConverter",
      "description": "@author Stefan Uebe",
      "type": "class",
      "extends": "Entry>",
      "implements": [
        "JsonItemPropertyConverter<LocalDateTime",
        "T>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "serverValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toServerModel",
          "description": "",
          "returnType": "LocalDateTime",
          "parameters": [
            {
              "type": "JsonNode",
              "name": "clientValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "RequiredArgsConstructor",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "LocalTimeConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.LocalTimeConverter",
      "description": "@author Stefan Uebe",
      "type": "class",
      "extends": "Entry>",
      "implements": [
        "JsonItemPropertyConverter<LocalTime",
        "T>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "LocalTime",
              "name": "serverValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toServerModel",
          "description": "",
          "returnType": "LocalTime",
          "parameters": [
            {
              "type": "JsonNode",
              "name": "clientValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "RequiredArgsConstructor",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "LocaleConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.LocaleConverter",
      "description": "Converts a Locale to a lowercase language tag string for the FullCalendar client side.",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<Locale",
        "Object>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Locale",
              "name": "serverValue"
            },
            {
              "type": "Object",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "RRuleConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.RRuleConverter",
      "description": "Converts an RRule instance to its JSON representation for the FC client.\nSupports both structured (JSON object) and raw RRULE string forms.",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<RRule",
        "Entry>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "RRule",
              "name": "serverValue"
            },
            {
              "type": "Entry",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "RecurringTimeConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.RecurringTimeConverter",
      "description": "@author Stefan Uebe",
      "type": "class",
      "extends": "Entry>",
      "implements": [
        "JsonItemPropertyConverter<RecurringTime",
        "T>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "RecurringTime",
              "name": "serverValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toServerModel",
          "description": "",
          "returnType": "RecurringTime",
          "parameters": [
            {
              "type": "JsonNode",
              "name": "clientValue"
            },
            {
              "type": "T",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "StringArrayConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.StringArrayConverter",
      "description": "Converts `String[]` or `Collection<String>` to a single comma-joined\nJSON string value. Used for FullCalendar options that accept comma-separated\nCSS selectors (e.g. `dragScrollEls`).",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<Object",
        "Object>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Object",
              "name": "serverValue"
            },
            {
              "type": "Object",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ToolbarConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converters",
      "fullName": "org.vaadin.stefan.fullcalendar.converters.ToolbarConverter",
      "description": "Converts a AbstractHeaderFooter (Header or Footer) to its JSON representation\nfor the FullCalendar client side.",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<AbstractHeaderFooter",
        "Object>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "AbstractHeaderFooter",
              "name": "serverValue"
            },
            {
              "type": "Object",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "AbstractEntryProvider",
      "packageName": "org.vaadin.stefan.fullcalendar.dataprovider",
      "fullName": "org.vaadin.stefan.fullcalendar.dataprovider.AbstractEntryProvider",
      "description": "Abstract base implementation of the EntryProvider interface.\n@author Stefan Uebe",
      "type": "class",
      "extends": "Entry>",
      "implements": [
        "EntryProvider<T>"
      ],
      "methods": [
        {
          "name": "refreshAll",
          "description": "",
          "returnType": "void",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "refreshItem",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "T",
              "name": "item"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addEntriesChangeListener",
          "description": "",
          "returnType": "Registration",
          "parameters": [
            {
              "type": "EntriesChangeListener<T>",
              "name": "listener"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addEntryRefreshListener",
          "description": "",
          "returnType": "Registration",
          "parameters": [
            {
              "type": "EntryRefreshListener<T>",
              "name": "listener"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setCalendar",
          "description": "Sets the calendar. Throws an exception, when there is already a calendar set and it is not the\nsame instance as the given one.",
          "returnType": "void",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "calendar"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "CallbackEntryProvider",
      "packageName": "org.vaadin.stefan.fullcalendar.dataprovider",
      "fullName": "org.vaadin.stefan.fullcalendar.dataprovider.CallbackEntryProvider",
      "description": "An EntryProvider using a predefined callback to fetch items when necessary.\n\n@author Stefan Uebe",
      "type": "class",
      "extends": "Entry> extends AbstractEntryProvider<T>",
      "methods": [
        {
          "name": "fetch",
          "description": "",
          "returnType": "Stream<T>",
          "parameters": [
            {
              "type": "EntryQuery",
              "name": "query"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "fetchById",
          "description": "",
          "returnType": "Optional<T>",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "An EntryProvider using a predefined callback to fetch items when necessary.\n\n@author Stefan Uebe",
          "parameters": [
            {
              "type": "SerializableFunction<EntryQuery, Stream<T>>",
              "name": "fetchItems"
            },
            {
              "type": "SerializableFunction<String, T>",
              "name": "fetchSingleItem"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntriesChangeEvent",
      "packageName": "org.vaadin.stefan.fullcalendar.dataprovider",
      "fullName": "org.vaadin.stefan.fullcalendar.dataprovider.EntriesChangeEvent",
      "description": "This event is fired, when then items represents by an EntryProvider are about to change\nand a reaction (e.g. fetch) is necessary.\n@author Stefan Uebe",
      "type": "class",
      "extends": "Entry> extends EventObject",
      "methods": [
        {
          "name": "getSource",
          "description": "",
          "returnType": "EntryProvider<T>",
          "parameters": [],
          "annotations": [
            "SuppressWarnings",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Constructs a prototypical Event.",
          "parameters": [
            {
              "type": "EntryProvider<T>",
              "name": "source"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryProvider",
      "packageName": "org.vaadin.stefan.fullcalendar.dataprovider",
      "fullName": "org.vaadin.stefan.fullcalendar.dataprovider.EntryProvider",
      "description": "An EntryProvider provides an API to fetch a list of entries based on filter parameters. It orientates\nin its functionality on the Vaadin com.vaadin.flow.data.provider.DataProvider, but is based\non time spans instead of row counts.\n@author Stefan Uebe",
      "type": "interface",
      "extends": "Entry>",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryQuery",
      "packageName": "org.vaadin.stefan.fullcalendar.dataprovider",
      "fullName": "org.vaadin.stefan.fullcalendar.dataprovider.EntryQuery",
      "description": "A class to provide filter parameters for an EntryProvider fetch query.\n@author Stefan Uebe",
      "type": "class",
      "methods": [
        {
          "name": "applyFilter",
          "description": "Convenience implementation to filter a stream based on this query.\n<p></p>\nSimply applies the filter to the given stream and returns a stream containing only entries matching it.\nEntries, that are \"crossing\" the time range border will be included in the stream.\n<p></p>\nReturns the same stream, when this filter is empty.",
          "returnType": "<T extends Entry> Stream<T>",
          "parameters": [
            {
              "type": "Stream<T>",
              "name": "stream"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "A class to provide filter parameters for an EntryProvider fetch query.\n@author Stefan Uebe",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "start"
            },
            {
              "type": "LocalDateTime",
              "name": "end"
            }
          ],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "",
          "parameters": [
            {
              "type": "Instant",
              "name": "start"
            },
            {
              "type": "Instant",
              "name": "end"
            }
          ],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "",
          "parameters": [
            {
              "type": "Instant",
              "name": "start"
            },
            {
              "type": "Instant",
              "name": "end"
            },
            {
              "type": "AllDay",
              "name": "allDay"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "Builder",
        "RequiredArgsConstructor",
        "AllArgsConstructor",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "EntryRefreshEvent",
      "packageName": "org.vaadin.stefan.fullcalendar.dataprovider",
      "fullName": "org.vaadin.stefan.fullcalendar.dataprovider.EntryRefreshEvent",
      "description": "This event is fired, when a single item shall be refreshed.\n@author Stefan Uebe",
      "type": "class",
      "extends": "Entry> extends EventObject",
      "methods": [
        {
          "name": "getSource",
          "description": "",
          "returnType": "EntryProvider<T>",
          "parameters": [],
          "annotations": [
            "SuppressWarnings",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Constructs a prototypical Event.",
          "parameters": [
            {
              "type": "EntryProvider<T>",
              "name": "source"
            },
            {
              "type": "T",
              "name": "itemToRefresh"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "InMemoryEntryProvider",
      "packageName": "org.vaadin.stefan.fullcalendar.dataprovider",
      "fullName": "org.vaadin.stefan.fullcalendar.dataprovider.InMemoryEntryProvider",
      "description": "Basic implementation of an in memory entry provider utilizing a hashmap.\n\n@author Stefan Uebe",
      "type": "class",
      "extends": "Entry> extends AbstractEntryProvider<T>",
      "implements": [
        "EntryProvider<T>"
      ],
      "methods": [
        {
          "name": "from",
          "description": "Creates a lazy loading instance. The given entries are used as initial items. Leave empty, if there\nare no initial entries.",
          "returnType": "<T extends Entry> InMemoryEntryProvider<T>",
          "parameters": [
            {
              "type": "T...",
              "name": "entries"
            }
          ],
          "annotations": [
            "SafeVarargs"
          ],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "from",
          "description": "Creates a lazy loading instance. The given entries are used as initial items, but the given iterable\nis not used as the backing collection or similar. It will never be modified by this provider.",
          "returnType": "<T extends Entry> InMemoryEntryProvider<T>",
          "parameters": [
            {
              "type": "Iterable<T>",
              "name": "entries"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "setCalendar",
          "description": "Connects this instance with the calendar. Not intended to be called manually, the FC will take care of this.\nNOOP when called for the same calendar instance multiple times.",
          "returnType": "void",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "calendar"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "fetch",
          "description": "",
          "returnType": "Stream<T>",
          "parameters": [
            {
              "type": "EntryQuery",
              "name": "query"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "fetchById",
          "description": "",
          "returnType": "Optional<T>",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addEntries",
          "description": "Adds a list of entries to the calendar. Noop for already registered entries.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Iterable<T>",
              "name": "iterableEntries"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeEntries",
          "description": "Removes the given entries. Noop for not registered entries.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Iterable<T>",
              "name": "iterableEntries"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "updateEntries",
          "description": "Updates the given entries on the client side. Ignores non-registered entries.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Iterable<T>",
              "name": "iterableEntries"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "onEntryUpdate",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "T",
              "name": "entry"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryById",
          "description": "Returns a single entry identified by the given id or an empty optional.",
          "returnType": "Optional<T>",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntries",
          "description": "Returns all entries of this instance.",
          "returnType": "List<T>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntries",
          "description": "Returns all entries, that lay inside or cross the given timespan.",
          "returnType": "List<T>",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "filterStart"
            },
            {
              "type": "LocalDateTime",
              "name": "filterEnd"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntries",
          "description": "Returns all entries, that lay inside or cross the given timespan.",
          "returnType": "List<T>",
          "parameters": [
            {
              "type": "Instant",
              "name": "filterStart"
            },
            {
              "type": "Instant",
              "name": "filterEnd"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntries",
          "description": "Returns all entries registered in this instance which timespan crosses the given date as a new list.",
          "returnType": "List<T>",
          "parameters": [
            {
              "type": "Instant",
              "name": "dateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntries",
          "description": "Returns all entries registered in this instance which timespan crosses the given date as a new list.",
          "returnType": "List<T>",
          "parameters": [
            {
              "type": "LocalDate",
              "name": "date"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntries",
          "description": "Returns all entries registered in this instance which timespan crosses the given date as a new list.",
          "returnType": "List<T>",
          "parameters": [
            {
              "type": "LocalDateTime",
              "name": "dateTime"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addEntry",
          "description": "Adds an entry to this calendar. Noop if the entry id is already registered.",
          "returnType": "void",
          "parameters": [
            {
              "type": "T",
              "name": "entry"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addEntries",
          "description": "Adds an array of entries to the calendar. Noop for the entry id is already registered.",
          "returnType": "void",
          "parameters": [
            {
              "type": "T...",
              "name": "arrayOfEntries"
            }
          ],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeEntry",
          "description": "Removes the given entry. Noop if the id is not registered.",
          "returnType": "void",
          "parameters": [
            {
              "type": "T",
              "name": "entry"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeEntries",
          "description": "Removes the given entries. Noop for not registered entries.",
          "returnType": "void",
          "parameters": [
            {
              "type": "T...",
              "name": "arrayOfEntries"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeAllEntries",
          "description": "Remove all entries.",
          "returnType": "void",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Maps the entry ids to their respective entry instance. Any change to this map reflects directly\nto this instance.",
          "parameters": [],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "",
          "parameters": [
            {
              "type": "Iterable<T>",
              "name": "entries"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "AbstractHeaderFooter",
      "packageName": "org.vaadin.stefan.fullcalendar.model",
      "fullName": "org.vaadin.stefan.fullcalendar.model.AbstractHeaderFooter",
      "description": "Abstract base class for FC header and footer",
      "type": "class",
      "methods": [
        {
          "name": "getParts",
          "description": "Returns all parts. Never null",
          "returnType": "Set<HeaderFooterPart>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getStart",
          "description": "Convenience method to get the left part of this instance. Creates a new instance on the first call.",
          "returnType": "HeaderFooterPart",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCenter",
          "description": "Convenience method to get the center part of this instance. Creates a new instance on the first call.",
          "returnType": "HeaderFooterPart",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEnd",
          "description": "Convenience method to get the right part of this instance. Creates a new instance on the first call.",
          "returnType": "HeaderFooterPart",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toJson",
          "description": "Converts the given object into a json object.",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addPart",
          "description": "Registers the given part. Overrides any previous set definitions.",
          "returnType": "void",
          "parameters": [
            {
              "type": "HeaderFooterPart",
              "name": "part"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "ToString",
        "EqualsAndHashCode"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "Footer",
      "packageName": "org.vaadin.stefan.fullcalendar.model",
      "fullName": "org.vaadin.stefan.fullcalendar.model.Footer",
      "description": "Definition of footer for a calendar instance.",
      "type": "class",
      "extends": "AbstractHeaderFooter",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new instance.",
          "parameters": [],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new instance with the given parts.",
          "parameters": [
            {
              "type": "Collection<HeaderFooterPart>",
              "name": "parts"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "Header",
      "packageName": "org.vaadin.stefan.fullcalendar.model",
      "fullName": "org.vaadin.stefan.fullcalendar.model.Header",
      "description": "Definition of header for a calendar instance.",
      "type": "class",
      "extends": "AbstractHeaderFooter",
      "methods": [],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new instance.",
          "parameters": [],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new instance with the given parts.",
          "parameters": [
            {
              "type": "Collection<HeaderFooterPart>",
              "name": "parts"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "HeaderFooterItem",
      "packageName": "org.vaadin.stefan.fullcalendar.model",
      "fullName": "org.vaadin.stefan.fullcalendar.model.HeaderFooterItem",
      "description": "A predefined enum of available items for the header / footer parts.",
      "type": "enum",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "HeaderFooterPart",
      "packageName": "org.vaadin.stefan.fullcalendar.model",
      "fullName": "org.vaadin.stefan.fullcalendar.model.HeaderFooterPart",
      "description": "Definition of a part of the header and footer.",
      "type": "class",
      "methods": [
        {
          "name": "addItem",
          "description": "Item to add to this part.",
          "returnType": "void",
          "parameters": [
            {
              "type": "HeaderFooterItem",
              "name": "item"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeItem",
          "description": "Removes the given item from this part. Noop if the item has not been added.",
          "returnType": "void",
          "parameters": [
            {
              "type": "HeaderFooterItem",
              "name": "item"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeItems",
          "description": "Removes all items",
          "returnType": "void",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getPosition",
          "description": "Returns the position of this instance.",
          "returnType": "HeaderFooterPartPosition",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getItems",
          "description": "Returns all added items.",
          "returnType": "Set<HeaderFooterItem>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new instance for the given position.",
          "parameters": [
            {
              "type": "HeaderFooterPartPosition",
              "name": "position"
            }
          ],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new instance for the given position with the given items to show.",
          "parameters": [
            {
              "type": "HeaderFooterPartPosition",
              "name": "position"
            },
            {
              "type": "Collection<HeaderFooterItem>",
              "name": "items"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "EqualsAndHashCode"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "HeaderFooterPartPosition",
      "packageName": "org.vaadin.stefan.fullcalendar.model",
      "fullName": "org.vaadin.stefan.fullcalendar.model.HeaderFooterPartPosition",
      "description": "Definition of header and footer positions.",
      "type": "enum",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [
        "Getter"
      ],
      "isPublic": true,
      "source": "addon"
    },
    {
      "name": "ComponentResourceAreaColumn",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ComponentResourceAreaColumn",
      "description": "A resource area column that renders a Vaadin Component per resource, analogous to\nVaadin Grid's `ComponentColumn`. The component is created by a callback that receives\nthe Resource and returns a component instance.\n<p>\nComponents are managed via a \"DOM teleportation\" pattern: they live in the Vaadin component\ntree (hidden container) but their DOM elements are physically moved into FullCalendar cells\nvia `cellDidMount` / `cellWillUnmount` lifecycle hooks.\n<p>\nThe `cellContent`, `cellDidMount`, an",
      "type": "class",
      "extends": "Component> extends ResourceAreaColumn",
      "methods": [
        {
          "name": "isBound",
          "description": "Returns whether this column is currently bound to a calendar.",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getComponent",
          "description": "Returns the component for the given resource, or empty if none exists.",
          "returnType": "Optional<T>",
          "parameters": [
            {
              "type": "Resource",
              "name": "resource"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getComponents",
          "description": "Returns an unmodifiable view of all resource-component mappings, keyed by resource ID.",
          "returnType": "Map<String, T>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "refresh",
          "description": "Destroys and re-creates the component for a single resource. The old component state is lost.\n<p>\nNo-op if the resource is not registered or if the calendar is not attached.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource",
              "name": "resource"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "refreshAll",
          "description": "Destroys and re-creates all components. Component state is lost for all resources.\nContinues on partial callback failures; throws IllegalStateException after\ncompleting iteration if any callback failed.\n<p>\nNo-op if the calendar is not attached.",
          "returnType": "void",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withWidth",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "String",
              "name": "width"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withGroup",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "boolean",
              "name": "group"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withHeaderClassNames",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "String",
              "name": "classNames"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withHeaderClassNames",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withHeaderDidMount",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "String",
              "name": "jsFunction"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withHeaderDidMount",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withHeaderWillUnmount",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "String",
              "name": "jsFunction"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withHeaderWillUnmount",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withCellClassNames",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "String",
              "name": "classNames"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withCellClassNames",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withCellContent",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "String",
              "name": "staticContent"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withCellContent",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withCellDidMount",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "String",
              "name": "jsFunction"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withCellDidMount",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withCellWillUnmount",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "String",
              "name": "jsFunction"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "withCellWillUnmount",
          "description": "",
          "returnType": "ComponentResourceAreaColumn<T>",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toJson",
          "description": "",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "EntryDroppedSchedulerEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.EntryDroppedSchedulerEvent",
      "description": "",
      "type": "class",
      "extends": "EntryTimeChangedEvent",
      "methods": [
        {
          "name": "applyChangesOnEntry",
          "description": "Applies the changes on the entry including updating a resource change.",
          "returnType": "Entry",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "updateResourcesFromEventResourceDelta",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "ResourceEntry",
              "name": "entry"
            },
            {
              "type": "ObjectNode",
              "name": "object"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": true
        },
        {
          "name": "getOldResource",
          "description": "If there has been a change in the resource assignments, this method returns the previous assigned resource.",
          "returnType": "Optional<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getNewResource",
          "description": "If there has been a change in the resource assignments, this method returns the newly assigned resource.",
          "returnType": "Optional<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "FullCalendarScheduler",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.FullCalendarScheduler",
      "description": "",
      "type": "class",
      "extends": "FullCalendar",
      "implements": [
        "Scheduler"
      ],
      "methods": [
        {
          "name": "setSchedulerLicenseKey",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "schedulerLicenseKey"
            }
          ],
          "annotations": [
            "Deprecated",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceAreaHeaderContent",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "resourceAreaHeaderContent"
            }
          ],
          "annotations": [
            "Deprecated",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceAreaWidth",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "resourceAreaWidth"
            }
          ],
          "annotations": [
            "Deprecated",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setSlotMinWidth",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "slotMinWidth"
            }
          ],
          "annotations": [
            "Deprecated",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourcesInitiallyExpanded",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "resourcesInitiallyExpanded"
            }
          ],
          "annotations": [
            "Deprecated",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setFilterResourcesWithEvents",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "filterResourcesWithEvents"
            }
          ],
          "annotations": [
            "Deprecated",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceOrder",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "resourceOrder"
            }
          ],
          "annotations": [
            "Deprecated",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryResourceEditable",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "boolean",
              "name": "eventResourceEditable"
            }
          ],
          "annotations": [
            "Deprecated",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addResources",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "Iterable<Resource>",
              "name": "iterableResource"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addResources",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "Iterable<Resource>",
              "name": "iterableResource"
            },
            {
              "type": "boolean",
              "name": "scrollToLast"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeResources",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "Iterable<Resource>",
              "name": "iterableResources"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getResourceById",
          "description": "",
          "returnType": "Optional<Resource>",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getResources",
          "description": "",
          "returnType": "Set<Resource>",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeAllResources",
          "description": "",
          "returnType": "void",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceLabelClassNamesCallback",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Override",
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceLabelContentCallback",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Override",
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceLabelDidMountCallback",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Override",
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceLablelWillUnmountCallback",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Override",
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceLaneClassNamesCallback",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Override",
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceLaneContentCallback",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Override",
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceLaneDidMountCallback",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Override",
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceLaneWillUnmountCallback",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "s"
            }
          ],
          "annotations": [
            "Override",
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setResourceAreaColumns",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "List<ResourceAreaColumn>",
              "name": "columns"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "updateResource",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource",
              "name": "resource"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setGroupEntriesBy",
          "description": "",
          "returnType": "void",
          "parameters": [
            {
              "type": "GroupEntriesBy",
              "name": "groupEntriesBy"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addTimeslotsSelectedListener",
          "description": "",
          "returnType": "Registration",
          "parameters": [
            {
              "type": "ComponentEventListener<? extends TimeslotsSelectedEvent>",
              "name": "listener"
            }
          ],
          "annotations": [
            "SuppressWarnings",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addTimeslotsSelectedSchedulerListener",
          "description": "",
          "returnType": "Registration",
          "parameters": [
            {
              "type": "ComponentEventListener<? extends TimeslotsSelectedSchedulerEvent>",
              "name": "listener"
            }
          ],
          "annotations": [
            "SuppressWarnings",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addTimeslotClickedListener",
          "description": "",
          "returnType": "Registration",
          "parameters": [
            {
              "type": "ComponentEventListener<? extends TimeslotClickedEvent>",
              "name": "listener"
            }
          ],
          "annotations": [
            "SuppressWarnings",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addTimeslotClickedSchedulerListener",
          "description": "",
          "returnType": "Registration",
          "parameters": [
            {
              "type": "ComponentEventListener<? extends TimeslotClickedSchedulerEvent>",
              "name": "listener"
            }
          ],
          "annotations": [
            "SuppressWarnings",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addEntryDroppedSchedulerListener",
          "description": "",
          "returnType": "Registration",
          "parameters": [
            {
              "type": "ComponentEventListener<? extends EntryDroppedSchedulerEvent>",
              "name": "listener"
            }
          ],
          "annotations": [
            "SuppressWarnings",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setOption",
          "description": "Sets a option for this instance. Passing a null value removes the option.\n<br><br>\nPlease be aware that this method does not check the passed value. Use the typed\nSchedulerOption constants for type safety.",
          "returnType": "void",
          "parameters": [
            {
              "type": "SchedulerOption",
              "name": "option"
            },
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setOption",
          "description": "Sets a option for this instance. Passing a null value removes the option. The third parameter\nmight be used to explicitly store a \"more complex\" variant of the option's value to be returned\nby #getOption(SchedulerOption). It is always stored when not equal to the value except for null.\nIf it is equal to the value or null it will not be stored (old version will be removed from internal cache).\n<pre>\nPlease be aware that this method does not check the passed value. Use the typed\nSchedulerOption co",
          "returnType": "void",
          "parameters": [
            {
              "type": "SchedulerOption",
              "name": "option"
            },
            {
              "type": "Object",
              "name": "value"
            },
            {
              "type": "Object",
              "name": "valueForServerSide"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getOption",
          "description": "Returns an optional option value or empty, that has been set for that key via one of the setOptions methods.\nIf a server side version of the value has been set\nvia #setOption(SchedulerOption, Serializable, Object), that will be returned instead.\n<br><br>\nIf there is a explicit getter method, it is recommended to use these instead (e.g. #getLocale()).",
          "returnType": "<T> Optional<T>",
          "parameters": [
            {
              "type": "SchedulerOption",
              "name": "option"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getOption",
          "description": "Returns an optional option value or empty, that has been set for that key via one of the setOptions methods.\nIf the second parameter is false and a server side version of the\nvalue has been set via #setOption(SchedulerOption, Serializable, Object), that will be returned instead.\n<br><br>\nIf there is a explicit getter method, it is recommended to use these instead (e.g. #getLocale()).",
          "returnType": "<T> Optional<T>",
          "parameters": [
            {
              "type": "SchedulerOption",
              "name": "option"
            },
            {
              "type": "boolean",
              "name": "forceClientSideValue"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "lookupViewName",
          "description": "",
          "returnType": "<T extends CalendarView> Optional<T>",
          "parameters": [
            {
              "type": "String",
              "name": "clientSideValue"
            }
          ],
          "annotations": [
            "SuppressWarnings",
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getConverters",
          "description": "Returns the converters registered for this option via JsonConverter annotations, in order.",
          "returnType": "List<JsonItemPropertyConverter<?, ?>>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "convertValue",
          "description": "If this option has one or more JsonConverter annotations and the given value is\nsupported by one of them, returns the converted JsonNode. Otherwise returns empty.",
          "returnType": "Optional<JsonNode>",
          "parameters": [
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [
            "SuppressWarnings"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [
        {
          "name": "FC_SCHEDULER_CLIENT_VERSION",
          "type": "String",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        }
      ],
      "constructors": [
        {
          "description": "Creates a new instance without any settings beside the default locale (CalendarLocale#getDefaultLocale()).",
          "parameters": [],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new instance.\n<br><br>\nExpects the default limit of entries shown per day. This does not affect basic or\nlist views. This value has to be set here and cannot be modified afterwards due to\ntechnical reasons of FC. If set afterwards the entry limit would overwrite settings\nand would show the limit also for basic views where it makes no sense (might change in future).\nPassing a negative number or 0 disabled the entry limit (same as passing no number at all).\n<br><br>\nSets the locale to Ca",
          "parameters": [
            {
              "type": "int",
              "name": "entryLimit"
            }
          ],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new instance with custom initial options. This allows a full override of the default\ninitial options, that the calendar would normally receive. Theoretically you can set all options,\nas long as they are not based on a client side variable (as for instance \"plugins\" or \"locales\").\nComplex objects are possible, too, for instance for view-specific settings.\n Please refer to the official FC documentation regarding potential options.\n<br><br>\nClient side event handlers, that are technically",
          "parameters": [
            {
              "type": "ObjectNode",
              "name": "initialOptions"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "Tag",
        "CssImport",
        "JsModule",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage",
        "NpmPackage"
      ],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "GroupEntriesBy",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.GroupEntriesBy",
      "description": "Enumeration of possible ways of how resource entries should be grouped.",
      "type": "enum",
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "Resource",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.Resource",
      "description": "Represents a resource. ResourceEntries contain these resources (a resource itself does not know anything about\nthe assigned entries). A resource can have sub resources / child resources.\n<p>\nResources can carry per-resource entry style overrides (#setEntryBackgroundColor(String),\n#setEntryBorderColor(String), #setEntryTextColor(String), and\n#setEntryClassNames(java.util.Set)) that apply to all entries associated with the resource.",
      "type": "class",
      "methods": [
        {
          "name": "getChildren",
          "description": "Returns the resource's children as unmodifiable set. Empty, when not children are set.",
          "returnType": "Set<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addChild",
          "description": "Adds the given resource as children to this instance. If the given resource has been added to\nother resources before, it will be removed from there. Also the parent is replaced.\n<br><br>\nDoes not update the resource instances on the client side when this instance has been added to the calendar\nbefore. In that case you need to add the child resources manually via Scheduler#addResource(Resource).",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource",
              "name": "child"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addChildren",
          "description": "Adds the given resources as children to this instance. If the given resources have been added to\nother resources before, they will be removed from there. Also the parent is replaced.\n<br><br>\nDoes not update the resource instances on the client side when this instance has been added to the calendar\nbefore. In that case you need to add the child resources manually via Scheduler#addResources(Iterable).",
          "returnType": "void",
          "parameters": [
            {
              "type": "Collection<Resource>",
              "name": "children"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addChildren",
          "description": "Adds the given resources as children to this instance. If the given resources have been added to\nother resources before, they will be removed from there. Also the parent is replaced.\n<br><br>\nDoes not update the resource instances on the client side when this instance has been added to the calendar\nbefore. In that case you need to add the child resources manually via Scheduler#addResources(Resource...).",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource...",
              "name": "children"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeChild",
          "description": "Removes the given resource from this instance. Does not update the resource instance on the client side.\nFor that you need to call Scheduler#removeResource(Resource) manually for the given instance.\n<br><br>\nUnsets the parent, if it matches this instance.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource",
              "name": "child"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeChildren",
          "description": "Removes the given resources from this instance. Does not update the resource instance on the client side.\nFor that you need to call Scheduler#removeResources(Resource...) manually for the given instance.\n<br><br>\nUnsets the parent, if it matches this instance.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource...",
              "name": "children"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeChildren",
          "description": "Removes the given resources from this instance. Does not update the resource instance on the client side.\nFor that you need to call Scheduler#removeResources(Resource...) manually for the given instance.\n<br><br>\nUnsets the parent, if it matches this instance.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Collection<Resource>",
              "name": "children"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addExtendedProps",
          "description": "Adds or updates a custom extended property on this resource. If this resource has been\nadded to a scheduler, the change is propagated to the client immediately.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "key"
            },
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeExtendedProps",
          "description": "Removes a custom extended property from this resource by key. If this resource has been\nadded to a scheduler, the change is propagated to the client immediately.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "key"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeExtendedProps",
          "description": "Removes a custom extended property from this resource only if it matches both key and value.\nIf this resource has been added to a scheduler, the change is propagated to the client immediately.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "key"
            },
            {
              "type": "Object",
              "name": "value"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setTitle",
          "description": "Sets the display title of this resource. If this resource has been added to a scheduler,\nthe change is propagated to the client immediately.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "title"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setColor",
          "description": "Sets the entry color shorthand for this resource (sets both background and border color of\nevents associated with this resource). If this resource has been added to a scheduler,\nthe change is propagated to the client immediately.\n<p>\nTo control background and border colors independently, use\n#setEntryBackgroundColor(String) and #setEntryBorderColor(String).",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "color"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryBackgroundColor",
          "description": "Sets the background color for entries associated with this resource.\nOverrides the #setColor(String) eventColor shorthand for background color.\n<p>\nUnlike #setTitle(String) and #setColor(String), this change is NOT\nautomatically propagated to the client. Call Scheduler#updateResource(Resource)\non the scheduler after modifying entry style properties.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "color"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryBackgroundColor",
          "description": "Returns the entry background color override for this resource, or `null` if not set.",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryBorderColor",
          "description": "Sets the border color for entries associated with this resource.\nOverrides the #setColor(String) eventColor shorthand for border color.\n<p>\nUnlike #setTitle(String) and #setColor(String), this change is NOT\nautomatically propagated to the client. Call Scheduler#updateResource(Resource)\non the scheduler after modifying entry style properties.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "color"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryBorderColor",
          "description": "Returns the entry border color override for this resource, or `null` if not set.",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryTextColor",
          "description": "Sets the text color for entries associated with this resource.\n<p>\nUnlike #setTitle(String) and #setColor(String), this change is NOT\nautomatically propagated to the client. Call Scheduler#updateResource(Resource)\non the scheduler after modifying entry style properties.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "color"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryTextColor",
          "description": "Returns the entry text color override for this resource, or `null` if not set.",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryConstraint",
          "description": "Sets a constraint for entries associated with this resource. Accepts a business hours\nobject ID, a named entry groupId, or a special constraint object string.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "constraint"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryConstraint",
          "description": "Returns the entry constraint for this resource, or `null` if not set.",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryOverlap",
          "description": "Sets whether entries associated with this resource can overlap other entries.\nUse `null` to inherit the calendar-level default.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Boolean",
              "name": "overlap"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryOverlap",
          "description": "Returns the entry overlap setting for this resource, or `null` if not set (inherits calendar default).",
          "returnType": "Boolean",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryClassNames",
          "description": "Sets CSS class names to be applied to entries associated with this resource.\n<p>\nUnlike #setTitle(String) and #setColor(String), this change is NOT\nautomatically propagated to the client. Call Scheduler#updateResource(Resource)\non the scheduler after modifying entry style properties.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Set<String>",
              "name": "classNames"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryClassNames",
          "description": "Returns an unmodifiable view of the entry class names for this resource,\nor `null` if not set.",
          "returnType": "Set<String>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryAllow",
          "description": "Sets a per-resource `eventAllow` JS callback that controls where entries associated with\nthis resource can be dropped. Receives `(dropInfo, draggedEvent)` and returns a boolean.",
          "returnType": "void",
          "parameters": [
            {
              "type": "String",
              "name": "jsFunction"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "setEntryAllow",
          "description": "Sets a per-resource `eventAllow` JS callback.",
          "returnType": "void",
          "parameters": [
            {
              "type": "JsCallback",
              "name": "callback"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntryAllow",
          "description": "Returns the per-resource `eventAllow` JS callback, or `null` if not set.",
          "returnType": "JsCallback",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEvents",
          "description": "Returns all entries currently associated with this resource.\n\n@deprecated Use #getEntries() instead — same behavior, correct naming\n            (\"entries\" instead of \"events\" per addon naming convention). This method\n            will be removed in a future version.",
          "returnType": "Set<ResourceEntry>",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getEntries",
          "description": "Returns all entries currently associated with this resource. Works with any\norg.vaadin.stefan.fullcalendar.dataprovider.EntryProvider type (in-memory,\ncallback, or signal-based).\n<p>\nNote: For callback-based providers this fetches all entries without a time range filter,\nwhich may be expensive. Consider using the entry provider's `fetch()` method\nwith appropriate filters if performance is a concern.",
          "returnType": "Set<ResourceEntry>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getParent",
          "description": "Returns the parent resource (or empty if top level).",
          "returnType": "Optional<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getBusinessHours",
          "description": "Returns the first item from businessHoursArray or null if array is empty",
          "returnType": "BusinessHours",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toString",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. ID will be generated.",
          "parameters": [],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "New instance. Awaits id and title. If no id is provided, one will be generated.",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            },
            {
              "type": "String",
              "name": "title"
            },
            {
              "type": "String",
              "name": "color"
            }
          ],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "New instance. Awaits id and title. If no id is provided, one will be generated.\n<br><br>\nAdds the given resources as children using #addChildren(Collection) if a value != null is passed.",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            },
            {
              "type": "String",
              "name": "title"
            },
            {
              "type": "String",
              "name": "color"
            },
            {
              "type": "Collection<Resource>",
              "name": "children"
            },
            {
              "type": "BusinessHours...",
              "name": "businessHours"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "EqualsAndHashCode",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "ResourceAreaColumn",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ResourceAreaColumn",
      "description": "Represents a column definition for the resource area sidebar in timeline and vertical resource views.\nWhen Scheduler#setResourceAreaColumns(java.util.List) resourceAreaColumns is configured,\nthe resource area becomes a multi-column data grid with a header row.\n<p>\nEach column maps to a resource property name (from the resource's built-in fields or\nResource#addExtendedProps(String, Object) extendedProps).\n<p>\nUse the fluent `withXxx()` methods to configure optional properties:\n<pre>`ResourceAreaC",
      "type": "class",
      "methods": [
        {
          "name": "getField",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getHeaderContent",
          "description": "Returns the header content (String or JsCallback), or `null` if not set.",
          "returnType": "Object",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "isGroup",
          "description": "",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getWidth",
          "description": "",
          "returnType": "String",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getHeaderClassNames",
          "description": "Returns the header class names (String or JsCallback), or `null` if not set.",
          "returnType": "Object",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getHeaderDidMount",
          "description": "",
          "returnType": "JsCallback",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getHeaderWillUnmount",
          "description": "",
          "returnType": "JsCallback",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCellContent",
          "description": "Returns the cell content (String or JsCallback), or `null` if not set.",
          "returnType": "Object",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCellClassNames",
          "description": "Returns the cell class names (String or JsCallback), or `null` if not set.",
          "returnType": "Object",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCellDidMount",
          "description": "",
          "returnType": "JsCallback",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getCellWillUnmount",
          "description": "",
          "returnType": "JsCallback",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toJson",
          "description": "Serializes this column definition to a JSON object for the FullCalendar\n`resourceAreaColumns` option.",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new column definition for the given resource field name.\nThe field name must match a property in the resource's JSON representation\n(e.g., `\"title\"`, `\"eventColor\"`, or any key added via\nResource#addExtendedProps(String, Object)).",
          "parameters": [
            {
              "type": "String",
              "name": "field"
            }
          ],
          "annotations": [],
          "isPublic": true
        },
        {
          "description": "Creates a new column definition with a field name and header text.\n<p>\n`headerContent` sets static text/HTML for the column header.",
          "parameters": [
            {
              "type": "String",
              "name": "field"
            },
            {
              "type": "String",
              "name": "headerContent"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "ResourceEntry",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.ResourceEntry",
      "description": "Represents an entry that can be connected with a resource. Needed for timeline views.",
      "type": "class",
      "extends": "Entry",
      "methods": [
        {
          "name": "setCalendar",
          "description": "Sets the calendar for this instance. The given calendar must be implementing Scheduler.",
          "returnType": "void",
          "parameters": [
            {
              "type": "FullCalendar",
              "name": "calendar"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getResource",
          "description": "Returns an assigned resource. Is empty if no resource has been assigned yet. This method is mainly intended\nto be used for entries where it is sure, that it only has one resource. For entries with multiple\nresources it might be, that on the next call, the resource change (currently this class uses\na LinkedHashSet, but that might change in future).",
          "returnType": "Optional<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getResourcesOrEmpty",
          "description": "Returns an unmodifiable set of resources or an empty one, if no resources have been defined yet.",
          "returnType": "Set<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getOrCreateResources",
          "description": "Returns the entry's assigned resources. Any changes to this set are reflected to the\nbackend and will be applied to the client on the next entry's update.\n<p></p>\nIn earlier versions this set might have been unmodifiable. This is not the case anymore.",
          "returnType": "Set<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getResources",
          "description": "Returns this instance's resources. Can be null.",
          "returnType": "Set<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "getResourcesSize",
          "description": "Returns the amount of assigned resources.",
          "returnType": "int",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "hasResources",
          "description": "Returns, if the entry has any resources assigned.",
          "returnType": "boolean",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "assignResources",
          "description": "Assigns additional resources to this entry. Already assigned resources will be kept.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource...",
              "name": "resources"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "assignResource",
          "description": "Assign an additional resource to this entry. Already assigned resources will be kept.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource",
              "name": "resource"
            }
          ],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addResources",
          "description": "Assigns additional resources to this entry. Already assigned resources will be kept.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource...",
              "name": "resources"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "addResources",
          "description": "Assign additional resources to this entry. Already assigned resources will be kept.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Collection<Resource>",
              "name": "resources"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeResources",
          "description": "Unassigns the given resources from this entry.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Resource...",
              "name": "resources"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeResources",
          "description": "Unassigns the given resources from this entry.",
          "returnType": "void",
          "parameters": [
            {
              "type": "Collection<Resource>",
              "name": "resources"
            }
          ],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "unassignAllResources",
          "description": "Unassigns all resources from this entry.",
          "returnType": "void",
          "parameters": [],
          "annotations": [
            "Deprecated"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "removeAllResources",
          "description": "Unassigns all resources from this entry.",
          "returnType": "void",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toJson",
          "description": "",
          "returnType": "ObjectNode",
          "parameters": [],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "Creates a new entry with the given id. Null will lead to a generated id.\n<br><br>\nPlease be aware, that the ID needs to be unique in the calendar instance. Otherwise it can lead to\nunpredictable results.",
          "parameters": [
            {
              "type": "String",
              "name": "id"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "NoArgsConstructor",
        "Setter",
        "Getter"
      ],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "Scheduler",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.Scheduler",
      "description": "Represents functionality for the FullCalendarScheduler.",
      "type": "interface",
      "methods": [],
      "fields": [
        {
          "name": "DEVELOPER_LICENSE_KEY",
          "type": "String",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        },
        {
          "name": "NON_COMMERCIAL_CREATIVE_COMMONS_LICENSE_KEY",
          "type": "String",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        },
        {
          "name": "GPL_V3_LICENSE_KEY",
          "type": "String",
          "description": "",
          "annotations": [],
          "isPublic": true,
          "isStatic": true,
          "isFinal": true
        }
      ],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "SchedulerView",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.SchedulerView",
      "description": "Enumeration of possible scheduler views.",
      "type": "enum",
      "implements": [
        "CalendarView"
      ],
      "methods": [],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "TimeslotClickedSchedulerEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.TimeslotClickedSchedulerEvent",
      "description": "This type extends the normal timeslot clicked event by providing the selected resource (if there's one).\n<br><br>\nClient side event: dateClick",
      "type": "class",
      "extends": "TimeslotClickedEvent",
      "methods": [
        {
          "name": "getResource",
          "description": "If the select event has occured in the scheduler, the selected resource will be returned.",
          "returnType": "Optional<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the clicked date (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").",
          "parameters": [
            {
              "type": "FullCalendarScheduler",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "TimeslotsSelectedSchedulerEvent",
      "packageName": "org.vaadin.stefan.fullcalendar",
      "fullName": "org.vaadin.stefan.fullcalendar.TimeslotsSelectedSchedulerEvent",
      "description": "This type extends the normal timeslot selected event by providing the selected resource (if there's one).\n<br><br>\nClient side event: select",
      "type": "class",
      "extends": "TimeslotsSelectedEvent",
      "methods": [
        {
          "name": "getResource",
          "description": "If the select event has occured in the scheduler, the selected resource will be returned.",
          "returnType": "Optional<Resource>",
          "parameters": [],
          "annotations": [],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [
        {
          "description": "New instance. Awaits the selected dates (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").",
          "parameters": [
            {
              "type": "FullCalendarScheduler",
              "name": "source"
            },
            {
              "type": "boolean",
              "name": "fromClient"
            }
          ],
          "annotations": [],
          "isPublic": true
        }
      ],
      "annotations": [
        "ToString",
        "DomEvent"
      ],
      "isPublic": true,
      "source": "addon-scheduler"
    },
    {
      "name": "ResourceConverter",
      "packageName": "org.vaadin.stefan.fullcalendar.converter",
      "fullName": "org.vaadin.stefan.fullcalendar.converter.ResourceConverter",
      "description": "@author Stefan Uebe",
      "type": "class",
      "implements": [
        "JsonItemPropertyConverter<Set<Resource>",
        "ResourceEntry>"
      ],
      "methods": [
        {
          "name": "supports",
          "description": "",
          "returnType": "boolean",
          "parameters": [
            {
              "type": "Object",
              "name": "type"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toClientModel",
          "description": "",
          "returnType": "JsonNode",
          "parameters": [
            {
              "type": "Set<Resource>",
              "name": "serverValue"
            },
            {
              "type": "ResourceEntry",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        },
        {
          "name": "toServerModel",
          "description": "",
          "returnType": "Set<Resource>",
          "parameters": [
            {
              "type": "JsonNode",
              "name": "clientValue"
            },
            {
              "type": "ResourceEntry",
              "name": "currentInstance"
            }
          ],
          "annotations": [
            "Override"
          ],
          "isPublic": true,
          "isStatic": false
        }
      ],
      "fields": [],
      "constructors": [],
      "annotations": [],
      "isPublic": true,
      "source": "addon-scheduler"
    }
  ],
  "examples": [
    {
      "id": "samples-0",
      "title": "Example 1",
      "description": "",
      "code": "// Create a new calendar instance and attach it to our layout\nFullCalendar calendar = FullCalendarBuilder.create().build();\ncalendar.setSizeFull();\ncontainer.add(calendar);\n\n// Create an initial sample entry\nEntry entry = new Entry();\nentry.setTitle(\"Some event\");\nentry.setColor(\"#ff3333\");\n\n// the given times will be interpreted as utc based - useful when the times are fetched from your database\nentry.setStart(LocalDate.now().withDayOfMonth(3).atTime(10, 0));\nentry.setEnd(entry.getStart().plusHours(2));\n\n// FC uses a data provider concept similar to the Vaadin default's one, with some differences\n// By default the FC uses a in-memory data provider, which is sufficient for most basic use cases.\ncalendar.getEntryProvider().asInMemory().addEntry(entry); // use addEntries(e1, e2, ...) to add multiple at once",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "event",
        "builder",
        "create"
      ]
    },
    {
      "id": "samples-1",
      "title": "Example 2",
      "description": "entry.setColor(\"#ff3333\"); // the given times will be interpreted as utc based - useful when the times are fetched from your database entry.setStart(LocalDate.now().withDayOfMonth(3).atTime(10, 0)); entry.setEnd(entry.getStart().plusHours(2)); // FC uses a data provider concept similar to the Vaadin",
      "code": "// ... create a form and binder to provide editable components to the user\nInMemoryEntryProvider<Entry> entryProvider = calendar.getEntryProvider().asInMemory();\n\nHorizontalLayout buttons = new HorizontalLayout();\nButton buttonSave;\nif (newInstance) {\n    buttonSave = new Button(\"Create\", e -> {\n        if (binder.validate().isOk()) {\n            // add the entry to the calendar instance and inform the client to update itself\n            entryProvider.addEntry(entry);\n            entryProvider.refreshAll();\n        }\n    });\n} else {\n    buttonSave = new Button(\"Save\", e -> {\n        if (binder.validate().isOk()) {\n            // update an existing entry in the client side\n            // this will only send changed data\n            entryProvider.refreshItem(entry);\n        }\n   });\n}\nbuttons.add(buttonSave);\n\nif (!newInstance) {\n    Button buttonRemove = new Button(\"Remove\", e -> {\n        entryProvider.removeEntry(entry);\n        entryProvider.refreshAll();\n    });\n    buttons.add(buttonRemove);\n}",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "create",
        "update"
      ]
    },
    {
      "id": "samples-2",
      "title": "Example 3",
      "description": "buttons.add(buttonSave); if (!newInstance) {     Button buttonRemove = new Button(\"Remove\", e -> {         entryProvider.removeEntry(entry);         entryProvider.refreshAll();     });     buttons.add(buttonRemove); } ```",
      "code": "/*\n * The day click event listener is called when a user clicks in an empty space inside of the\n * calendar. Depending of if the clicked point was a day or time slot the event will provide the\n * time details of the clicked point. With this info you can show a dialog to create a new entry.\n */\ncalendar.addTimeslotsSelectedListener((event) -> {\n// react on the selected timeslot, for instance create a new instance and let the user edit it\n    Entry entry = new Entry();\n   \n    entry.setStart(event.getStart()); // also event times are always utc based\n    entry.setEnd(event.getEnd());\n    entry.setAllDay(event.isAllDay());\n\n    entry.setColor(\"dodgerblue\");\n\n    // ... show an editor or do something else with the entry\n});\n\n/*\n * The entry click event listener is called when the user clicks on an existing entry.\n * The event provides the clicked event which might be then opened in a dialog.\n */\ncalendar.addEntryClickedListener((event) -> {\n    // react on the clicked entry, for instance let the user edit it\n    Entry entry = event.getEntry();\n\n    // ... show an editor or do something else with the entry\n});",
      "language": "java",
      "category": "events",
      "tags": [
        "entry",
        "event",
        "listener",
        "click",
        "create"
      ]
    },
    {
      "id": "samples-3",
      "title": "Calendar event handling",
      "description": "* The entry click event listener is called when the user clicks on an existing entry.  * The event provides the clicked event which might be then opened in a dialog.  */ calendar.addEntryClickedListener((event) -> {     // react on the clicked entry, for instance let the user edit it     Entry entry",
      "code": "// load items from backend\nList<Entry> entryList = backend.streamEntries().collect(Collectors.toList());\n\n// init provider from a collection — does NOT use the collection as a live backend (changes must be pushed via addEntries/removeEntry)\nInMemoryEntryProvider<Entry> entryProvider = EntryProvider.inMemoryFrom(entryList);\n\n// set entry provider\ncalendar.setEntryProvider(entryProvider);\n\n// CRUD operations\n// to add\nEntry entry = new Entry();          // ... plus some init\nentryProvider.addEntry(entry);      // use addEntries(e1, e2, ...) to add multiple at once\nentryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch\n\n// after some change\nentryProvider.refreshItem(entry);   // call refresh to inform the client about the data change and trigger a refetch\n\n// to remove\nentryProvider.removeEntry(entry);\nentryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "event",
        "crud"
      ]
    },
    {
      "id": "samples-4",
      "title": "In memory entry provider",
      "description": "entryProvider.addEntry(entry);      // use addEntries(e1, e2, ...) to add multiple at once entryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch // after some change entryProvider.refreshItem(entry);   // call refresh to inform the clien",
      "code": "// the callback provider uses the given callback to fetch entries when necessary\nCallbackEntryProvider<Entry> entryProvider = EntryProvider.fromCallbacks(\n        query -> backend.streamEntries(query),\n        entryId -> backend.getEntry(entryId).orElse(null)\n);\n\n// set entry provider\ncalendar.setEntryProvider(entryProvider);\n\n// CRUD operations\n// to add\nEntry entry = new Entry();          // ... plus some init\nbackend.addEntry(entry);            // register in your backend\nentryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch\n\n// after some change\nbackend.updateEntry(entry);         // inform your backend\nentryProvider.refreshItem(entry);   // call refresh to inform the client about the data change and trigger a refetch\n\n// to remove\nbackend.removeEntry(entry);         // remove from your backend\nentryProvider.refreshAll();   // call refresh to inform the client about the data change and trigger a refetch",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "callback",
        "crud",
        "update"
      ]
    },
    {
      "id": "samples-5",
      "title": "Using callbacks",
      "description": "entryProvider.refreshAll();         // call refresh to inform the client about the data change and trigger a refetch // after some change backend.updateEntry(entry);         // inform your backend entryProvider.refreshItem(entry);   // call refresh to inform the client about the data change and trig",
      "code": "private static class BackendEntryProvider extends AbstractEntryProvider<Entry> {\n    private final EntryService service;\n\n    public BackendEntryProvider(EntryService service) {\n        this.service = service;\n    }\n\n    @Override\n    public Stream<Entry> fetch(@NonNull EntryQuery query) {\n        return service.streamEntries(query);\n    }\n\n    @Override\n    public Optional<Entry> fetchById(@NonNull String id) {\n        return service.getEntry(id);\n    }\n}",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "callback"
      ]
    },
    {
      "id": "samples-6",
      "title": "Custom implementation",
      "description": "public Stream<Entry> fetch(@NonNull EntryQuery query) {         return service.streamEntries(query);     }     @Override     public Optional<Entry> fetchById(@NonNull String id) {         return service.getEntry(id);     } } ```",
      "code": "calendar.setPrefetchEnabled(false); // disables the prefetch feature",
      "language": "java",
      "category": "general",
      "tags": []
    },
    {
      "id": "samples-7",
      "title": "Prefetch mode",
      "description": "Be aware, that this feature leads to an increased amount of data transported between server and client, but in the same  time leads to a better user experience as the above mentioned flickering will be prevented. The prefetch mode determines adjacent periods based on the active view's *range unit* —",
      "code": "// FC allows to show entries in a specifc timezone. Setting a timezone only affects the client side\n// and might be interesting, when editing those entries in some kind of edit form\n\nTimezone tzBerlinGermany = new Timezone(ZoneId.of(\"Europe/Berlin\"));\ncalendar.setTimezone(tzBerlinGermany); // will rerender the client side and show all times 1-2 hours \"later\".\n\n// We can also reset the timezone to default.\ncalendar.setTimezone(Timezone.UTC);\n\n// We can also read the browsers timezone, after the component has been attached to the client side.\n// There are other ways to obtain the browser's timezone, so you are not obliged to use the listener.\ncalendar.addBrowserTimezoneObtainedListener(event -> calendar.setTimezone(event.getTimezone()));\n\n// If you want to let the calendar obtain the browser time zone automatically, you may simply use the builder.\n// In that case as soon as the client connected, it will set it's timezone in the server side instance.\nFullCalendarBuilder.create().withAutoBrowserTimezone().build();\n\n// Entries use internally utc to define times. The LocalDateTime and Instant methods setStart/End have the same effect.\nentry.setStart(Instant.now()); // UTC\nentry.setEnd(LocalDateTime.now()); // treated as UTC — LocalDateTime carries no timezone info in this API\n\n// Entry provides some additional convenience methods to handle the current calendar's timezone's offset, e.g. to allow easy\n// integration into edit forms.\ncalendar.setTimezone(tzBerlinGermany); // times are now 1-2 hours \"ahead\" (depending on daylight saving)\nentry.setStart(LocalDate.of(2000, 1, 1).atStartOfDay());\n\nLocalDateTime utcStart = entry.getStart(); // will be 2000-01-01, 00:00\nLocalDateTime offsetStart = entry.getStartWithOffset(); // will be 2000-01-01, 01:00\n\n// ... modify the offset start, for instance in a date picker\n// e.g. modifiedOffsetStart = offsetStart.plusHours(5);\nLocalDateTime modifiedOffsetStart = offsetStart.plusHours(5);\n\nentry.setStartWithOffset(modifiedOffsetStart); // automatically takes care of conversion back to utc\nutcStart = entry.getStart(); // will be 2000-01-01, 04:00\noffsetStart = entry.getStartWithOffset(); // will be 2000-01-01, 05:00",
      "language": "java",
      "category": "events",
      "tags": [
        "entry",
        "timezone",
        "event",
        "listener",
        "builder",
        "create"
      ]
    },
    {
      "id": "samples-8",
      "title": "Using timezones",
      "description": "LocalDateTime offsetStart = entry.getStartWithOffset(); // will be 2000-01-01, 01:00 // ... modify the offset start, for instance in a date picker // e.g. modifiedOffsetStart = offsetStart.plusHours(5); LocalDateTime modifiedOffsetStart = offsetStart.plusHours(5); entry.setStartWithOffset(modifiedOf",
      "code": "import org.vaadin.stefan.fullcalendar.JsonFactory;\n\n// ...\n\nObjectNode initialOptions = JsonFactory.createObject();\ninitialOptions.put(\"height\", \"100%\");\ninitialOptions.put(\"timeZone\", \"UTC\");\ninitialOptions.put(\"headerToolbar\", false);\ninitialOptions.put(\"weekNumbers\", true);\ninitialOptions.put(\"dayMaxEvents\", false); // pass an int value to limit the entries per day\ninitialOptions.put(\"navLinks\", true); \ninitialOptions.put(\"selectable\", true);\n\ncalendar = FullCalendarBuilder.create().withInitialOptions(initialOptions).build();",
      "language": "java",
      "category": "timezone",
      "tags": [
        "timezone",
        "event",
        "builder",
        "create"
      ]
    },
    {
      "id": "samples-9",
      "title": "Passing custom initial options in Java",
      "description": "initialOptions.put(\"height\", \"100%\"); initialOptions.put(\"timeZone\", \"UTC\"); initialOptions.put(\"headerToolbar\", false); initialOptions.put(\"weekNumbers\", true); initialOptions.put(\"dayMaxEvents\", false); // pass an int value to limit the entries per day initialOptions.put(\"navLinks\", true);  initia",
      "code": "calendar.removeThemeVariants(FullCalendarVariant.VAADIN);",
      "language": "java",
      "category": "general",
      "tags": [
        "theme"
      ]
    },
    {
      "id": "samples-10",
      "title": "Vaadin Theming",
      "description": "Please note, that there might be parts, that have been forgotten or not looking as expected.  Also any additional custom stylings may override the Vaadin stylings. If you find anything, that looks suspicious, please create an issue.  To remove the Vaadin theme, simply remove the theme variant, as yo",
      "code": "## Show the current shown time interval (e. g. month) with Vaadin components\n\nYou can use the \"dates rendered event\" to show details about the current shown period in separate elements instead\nof the built-in FullCalendar header.",
      "language": "java",
      "category": "general",
      "tags": [
        "event"
      ]
    },
    {
      "id": "samples-11",
      "title": "Show the current shown time interval (e. g. month) with Vaadin components",
      "description": "padding-right: 6px; } ``` You can use the \"dates rendered event\" to show details about the current shown period in separate elements instead of the built-in FullCalendar header. ```",
      "code": "## Creating a background entry\nA background entry is an entry, that is rendered behind all other entries. It is not clickable and\nhas no tooltip. It is useful for marking a time range, e. g. for marking a vacation.",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "click"
      ]
    },
    {
      "id": "samples-12",
      "title": "Creating a background entry",
      "description": "intervalLabel.setText(formattedInterval);     }); } ``` A background entry is an entry, that is rendered behind all other entries. It is not clickable and has no tooltip. It is useful for marking a time range, e. g. for marking a vacation. ```",
      "code": "## Adding business hours\nYou can define business hours for each day of the week to provide visual feedback to the user, when someone is available\nor not. If you don't define any business hours, the calendar will assume, that the business hours are from 0:00 to 24:00 for each day.\n\nNon-business hours are grayed out in the calendar.",
      "language": "java",
      "category": "general",
      "tags": [
        "entry"
      ]
    },
    {
      "id": "samples-13",
      "title": "Adding business hours",
      "description": "calendar.getEntryProvider().asInMemory().addEntry(entry); ``` You can define business hours for each day of the week to provide visual feedback to the user, when someone is available or not. If you don't define any business hours, the calendar will assume, that the business hours are from 0:00 to 24",
      "code": "## Using the Scheduler\nThe scheduler is a commercial plugin of the FullCalendar library, that provides some additional features like\nresource related calendar entries and additional views.  \n\n### Activating the Scheduler",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "resource",
        "scheduler",
        "view"
      ]
    },
    {
      "id": "samples-14",
      "title": "Activating the Scheduler",
      "description": "calendar.setOption(Option.BUSINESS_HOURS, BusinessHours.allDays().start(9)); ``` The scheduler is a commercial plugin of the FullCalendar library, that provides some additional features like resource related calendar entries and additional views.   ```",
      "code": "### Adding a resource to a calendar and link it with entries",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "resource",
        "scheduler"
      ]
    },
    {
      "id": "samples-15",
      "title": "Adding a resource to a calendar and link it with entries",
      "description": "```java FullCalendar calendar = FullCalendarBuilder.create().withScheduler().build(); // scheduler options calendar.setOption(SchedulerOption.LICENSE_KEY, \"YourFullCalendarSchedulerKey\"); ``` ```",
      "code": "### Handling change of an entry's assigned resource by drag and drop",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "entry",
        "resource",
        "drop"
      ]
    },
    {
      "id": "samples-16",
      "title": "Handling change of an entry's assigned resource by drag and drop",
      "description": "entry.setEnd(start.plusDays(days).atStartOfDay()); entry.setAllDay(true); entry.setColor(color); entry.setDescription(\"Some description...\"); entry.addResources(resource); calendar.getEntryProvider().asInMemory().addEntry(entry); ``` ```",
      "code": "### Switching to a timeline view",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "entry",
        "resource",
        "drop",
        "view"
      ]
    },
    {
      "id": "samples-17",
      "title": "Switching to a timeline view",
      "description": "Set<Resource> resources = ((ResourceEntry) entry).getResources();         if(!resources.isEmpty()) {             // do something with the resource info         }     } }); ``` ```",
      "code": "### Activate vertical resource view",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "resource",
        "view"
      ]
    },
    {
      "id": "samples-18",
      "title": "Activate vertical resource view",
      "description": "}); ``` ```java calendar.changeView(SchedulerView.TIMELINE_DAY); ``` ```",
      "code": "### Creating a resource based background entry",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "entry",
        "resource",
        "view"
      ]
    },
    {
      "id": "samples-19",
      "title": "Creating a resource based background entry",
      "description": "calendar.changeView(SchedulerView.TIMELINE_DAY); ``` ```java calendar.setGroupEntriesBy(GroupEntriesBy.RESOURCE_DATE); ``` ```",
      "code": "### Creating hierarchical resources",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "entry",
        "resource"
      ]
    },
    {
      "id": "samples-20",
      "title": "Creating hierarchical resources",
      "description": "```java ResourceEntry entry = new ResourceEntry(); // ... setup entry details, including addResource() entry.setDisplayMode(DisplayMode.BACKGROUND); calendar.getEntryProvider().asInMemory().addEntry(entry); ``` ```",
      "code": "### Making a resource entry draggable between resources",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "entry",
        "resource"
      ]
    },
    {
      "id": "samples-21",
      "title": "Making a resource entry draggable between resources",
      "description": "parent.addChild(child); scheduler.addResource(child); // this will update the client side // or remove them from already registered ones scheduler.removeResource(child); parent.removeChild(child); ``` ```",
      "code": "### Using component resource area columns\n\nResource area columns can display interactive Vaadin components (such as DatePicker, TextField, ComboBox, etc.) — one component per resource. This is useful for inline editing or displaying resource-related metadata. Components are created by a callback and support type-safe runtime access.\n\n#### Basic component column",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "entry",
        "callback",
        "resource",
        "create"
      ]
    },
    {
      "id": "samples-22",
      "title": "Basic component column",
      "description": "calendar.setOption(SchedulerOption.ENTRY_RESOURCES_EDITABLE, true); ``` Resource area columns can display interactive Vaadin components (such as DatePicker, TextField, ComboBox, etc.) — one component per resource. This is useful for inline editing or displaying resource-related metadata. Components ",
      "code": "#### Accessing and updating components",
      "language": "java",
      "category": "general",
      "tags": []
    },
    {
      "id": "samples-23",
      "title": "Accessing and updating components",
      "description": "// Combine with regular text columns scheduler.setResourceAreaColumns(     new ResourceAreaColumn(\"title\", \"Name\").withWidth(\"200px\"),     deadlineCol.withWidth(\"160px\") ); ``` ```",
      "code": "#### Syncing with entry drag/resize\n\nComponents and entries can be kept in sync — for example, a DatePicker showing entry start/end dates that updates when the entry is dragged or resized:",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "resize",
        "update"
      ]
    },
    {
      "id": "samples-24",
      "title": "Syncing with entry drag/resize",
      "description": "// Re-create a single resource's component deadlineCol.refresh(resource); ``` Components and entries can be kept in sync — for example, a DatePicker showing entry start/end dates that updates when the entry is dragged or resized: ```",
      "code": "## Using tippy.js for description tooltips\nBy default the calendar does not provide tooltips for entries. However, you can easily integrate any type of\ntooltip mechanism or library, for instance by simply applying an html title or using a matured tooltip library\nlike tippy.js.\n\nThis sample shows how to easy integrate tippy.js into a custom subclass of FullCalendar to show an entry's description\nas a tooltip when hovering the entry inside the FC. Please customize the example as needed.\n\n1. Create a new TypeScript file inside the frontend folder of your project. It needs to extend either FullCalendar or\n   FullCalendarScheduler. This example utilizes FullCalendarScheduler. If you want to use the normal FC, simply remove\n   all the -Scheduler parts. You may also use plain JavaScript instead of TypeScript — in that case remove the type\n   annotations and rename the file to `.js`.\n\n   > **Note:** The `@JsModule` annotation in the Java class references `full-calendar-with-tooltip.js` (without the\n   > `s` at the end, and `.js` extension). Vaadin's frontend build (Vite) compiles the `.ts` file to `.js` automatically,\n   > so the annotation must point to the compiled output name.\n\nfull-calendar-with-tooltip.ts",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "scheduler",
        "resize",
        "create"
      ]
    },
    {
      "id": "samples-25",
      "title": "Using tippy.js for description tooltips",
      "description": "all the -Scheduler parts. You may also use plain JavaScript instead of TypeScript — in that case remove the type    annotations and rename the file to `.js`.    > **Note:** The `@JsModule` annotation in the Java class references `full-calendar-with-tooltip.js` (without the    > `s` at the end, and `",
      "code": "2. Now create a simple JavaClass, that utilizes your js file. This Java class also imports the needed CSS files.",
      "language": "java",
      "category": "general",
      "tags": [
        "create"
      ]
    },
    {
      "id": "samples-26",
      "title": "Using tippy.js for description tooltips",
      "description": "} } customElements.define(\"full-calendar-with-tooltip\", FullCalendarWithTooltip); ``` 2. Now create a simple JavaClass, that utilizes your js file. This Java class also imports the needed CSS files. ```",
      "code": "As shown in the subclass sample, you may also use the FullCalendarBuilder to create your custom class.\n\n## Customize entry rendering (render hooks)\n\nFC allows you to hook into the rendering of entries using `setOption` with a `JsCallback` value\nand an `Option` constant (see [FullCalendar render hook docs](https://fullcalendar.io/docs/event-render-hooks)\nfor callback arguments). The function string is evaluated in the browser — no server round-trip occurs.\n\n> **Note for `FullCalendarBuilder` users:** `withEntryContent(String)` on the builder is deprecated.\n> Use `setOption(Option.ENTRY_CONTENT, JsCallback.of(...))` after building instead.\n\n**`Option.ENTRY_DID_MOUNT`** — called after an entry element is added to the DOM. Use it for setup, e.g.\nsetting element attributes:",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "callback",
        "event",
        "builder",
        "create"
      ]
    },
    {
      "id": "samples-27",
      "title": "Customize entry rendering (render hooks)",
      "description": "and an `Option` constant (see [FullCalendar render hook docs](https://fullcalendar.io/docs/event-render-hooks) for callback arguments). The function string is evaluated in the browser — no server round-trip occurs. > **Note for `FullCalendarBuilder` users:** `withEntryContent(String)` on the builder",
      "code": "**`Option.ENTRY_CONTENT`** — customize the HTML content rendered inside the entry element. See\n[content injection](https://fullcalendar.io/docs/content-injection) for the return value format:",
      "language": "java",
      "category": "general",
      "tags": [
        "entry"
      ]
    },
    {
      "id": "samples-28",
      "title": "Customize entry rendering (render hooks)",
      "description": "function(info) {             info.el.id = \"entry-\" + info.event.id;         }         \"\"\")); ``` **`Option.ENTRY_CONTENT`** — customize the HTML content rendered inside the entry element. See [content injection](https://fullcalendar.io/docs/content-injection) for the return value format: ```",
      "code": "Inside entry callbacks you may access the entry's default properties or custom ones set via\n`entry.setCustomProperty(String, Object)`. The `getCustomProperty(key)` and\n`getCustomProperty(key, defaultValue)` methods are injected automatically onto the event object:",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "callback",
        "event"
      ]
    },
    {
      "id": "samples-29",
      "title": "Customize entry rendering (render hooks)",
      "description": "```java calendar.setOption(Option.ENTRY_CONTENT,         JsCallback.of(\"function(info) { return { html: '<b>' + info.event.title + '</b>' }; }\")); ``` Inside entry callbacks you may access the entry's default properties or custom ones set via `entry.setCustomProperty(String, Object)`. The `getCustom",
      "code": "Callbacks can be set before or after the calendar is attached.\n\nAlso make sure that your callback function does not contain any harmful code or allow cross-site scripting.\n\n## Use native javascript events for entries\nSometimes the available events are not enough. For that purpose, we added native event listeners for calendar entries. \nThese allow you to setup JavaScript events for each entry, e.g. a mouse over event handler. Inside these event handlers \nyou may also access the created entry dom element.\n\nCustom native event handlers are added to the FullCalender object. They will then be applied to each created\nentry object (using the entryDidMount callback).\n\nTo add an event handler, simply call the method `addEntryNativeEventListener` on the calendar. The first parameter\nis the JavaScript event name (e.g. \"mouseover\"), the second parameter is the callback, that shall be used for\nthat event. Please be aware, that we do NOT check or sanitize the given JavaScript. It is up to you to prevent\nmalicious code from being sent to your users.\n\nInside the event callback, you may access the entryDidMount argument object, that contains additional information\nabout the current entry. See the official docs (https://fullcalendar.io/docs/event-render-hooks)\nfor more details about which details it provide.",
      "language": "java",
      "category": "events",
      "tags": [
        "entry",
        "callback",
        "event",
        "listener",
        "create"
      ]
    },
    {
      "id": "samples-30",
      "title": "Use native javascript events for entries",
      "description": "To add an event handler, simply call the method `addEntryNativeEventListener` on the calendar. The first parameter is the JavaScript event name (e.g. \"mouseover\"), the second parameter is the callback, that shall be used for that event. Please be aware, that we do NOT check or sanitize the given Jav",
      "code": "This sample will change the element style, when the mouse moves over it and changes back, when leaving the element.",
      "language": "java",
      "category": "events",
      "tags": [
        "event",
        "style"
      ]
    },
    {
      "id": "samples-31",
      "title": "Use native javascript events for entries",
      "description": "// write the js event, the current entry info and the current entry's element to the browser console. calendar.addEntryNativeEventListener(\"mouseover\", \"e => console.warn(e, info.event, info.el)\"); add(calendar); ``` This sample will change the element style, when the mouse moves over it and changes",
      "code": "You can also access the client side dom to utilize other elements, like the parents. With this you may for instance\ncall a server side method.\n\nThe following sample shows, how a client callable method in the current view, containing the FullCalendar object, can\nbe called, when right clicking the entry. With this info you can for instance open a custom popup as a context menu.",
      "language": "java",
      "category": "events",
      "tags": [
        "entry",
        "event",
        "click",
        "view"
      ]
    },
    {
      "id": "samples-32",
      "title": "Use native javascript events for entries",
      "description": "calendar.addEntryNativeEventListener(\"mouseout\", \"e => info.el.style.opacity = ''\"); ``` You can also access the client side dom to utilize other elements, like the parents. With this you may for instance call a server side method. The following sample shows, how a client callable method in the curr",
      "code": "You can combine the event handlers with a custom entryDidMount callback, if you want additional customizations\nof the entries. The FC will take care of combining the event handlers and your EDM callback",
      "language": "java",
      "category": "events",
      "tags": [
        "entry",
        "callback",
        "event"
      ]
    },
    {
      "id": "samples-33",
      "title": "Use native javascript events for entries",
      "description": "System.out.println(e);         System.out.println(pointerX);         System.out.println(pointerY);     } }  ``` You can combine the event handlers with a custom entryDidMount callback, if you want additional customizations of the entries. The FC will take care of combining the event handlers and you",
      "code": "The following sample shows how to utilize the entryDidMount callback, the native event handlers and the\n[Popup addon](https://vaadin.com/directory/component/popup) to show a context menu. In this sample, the context\nmenu is based on a ListBox.",
      "language": "java",
      "category": "events",
      "tags": [
        "entry",
        "callback",
        "event"
      ]
    },
    {
      "id": "samples-34",
      "title": "Use native javascript events for entries",
      "description": "calendar.addEntryNativeEventListener(\"mouseover\", \"e => info.el.style.opacity = '0.5'\"); calendar.addEntryNativeEventListener(\"mouseout\", \"e => info.el.style.opacity = ''\"); ``` The following sample shows how to utilize the entryDidMount callback, the native event handlers and the [Popup addon](http",
      "code": "## Creating a subclass of FullCalendar for custom mods\nThe FullCalendar itself is just a simple Vaadin component on the server and client side, that can be extended\nand customized beyond the default behavior - be aware, that anything you do here is on your own risk and that\nsupport for this use case is limited. \n\nThe client side has the following methods, that you can override / extend to customize the behavior. There are\nothers, but they should normally not be overridden - except for you know what you do ;) \n\n* connectedCallback() - called when the component is attached to the dom\n* initCalendar() - called when the calendar is initialized - only called once\n* createInitOptions(initialOptions) - called when the calendar is initialized. You can modify the initial options here.\n* createEventHandlers() - called when the calendar is initialized. You can modify the event handlers here.\n\nBe aware, that during `connectedCallback()` and before calling `initCalendar()` no internal calendar\nobject is available. Calling `this.calendar` will automatically infer `initCalendar()` and thus can lead\nto unwanted side effects. Therefore, if you want to set options, add entries or do other things with the\ncalendar object, do it after `super.initCalendar()` has been called.\n\nIf you want to modifiy options, that are passed into the calendar object, you can extend the method\n`createInitOptions(initialOptions)` and return a modified options object.\n\nIf you want to modify or extend the event handlers, you can override the method `createEventHandlers()`-\n\nWe recommend to use the `override` modifier on overridden methods to make sure, that the method is\nalways up-to-date.\n\n1. Create a custom web component\n   Create a custom component, that extends FullCalendar or FullCalendarScheduler.",
      "language": "java",
      "category": "events",
      "tags": [
        "callback",
        "scheduler",
        "event",
        "create"
      ]
    },
    {
      "id": "samples-35",
      "title": "Creating a subclass of FullCalendar for custom mods",
      "description": "If you want to modify or extend the event handlers, you can override the method `createEventHandlers()`- We recommend to use the `override` modifier on overridden methods to make sure, that the method is always up-to-date. 1. Create a custom web component    Create a custom component, that extends F",
      "code": "2. Create a subclass of FullCalendar",
      "language": "java",
      "category": "general",
      "tags": [
        "create"
      ]
    },
    {
      "id": "samples-36",
      "title": "Creating a subclass of FullCalendar for custom mods",
      "description": "return super.createEventHandlers();     } } customElements.define(\"my-full-calendar\", MyFullCalendar); ``` 2. Create a subclass of FullCalendar ```",
      "code": "3. Use this class in your code",
      "language": "java",
      "category": "general",
      "tags": []
    },
    {
      "id": "samples-37",
      "title": "Creating a subclass of FullCalendar for custom mods",
      "description": "public class MyFullCalendar extends FullCalendar {     public MyFullCalendar() {     } } ``` 3. Use this class in your code ```",
      "code": "You can even use the FullCalendarBuilder to create your custom class. Be aware, that your\ncustom class needs to provide all constructors, that the extended FullCalendar has.",
      "language": "java",
      "category": "general",
      "tags": [
        "builder",
        "create"
      ]
    },
    {
      "id": "samples-38",
      "title": "Creating a subclass of FullCalendar for custom mods",
      "description": "3. Use this class in your code ```java calendar = new MyFullCalendar(); ``` You can even use the FullCalendarBuilder to create your custom class. Be aware, that your custom class needs to provide all constructors, that the extended FullCalendar has. ```",
      "code": "// directly apply the changes\ncalendar.addEntryDroppedListener(event -> {\n    event.applyChangesOnEntry(); // includes now the allDay attribute if sent by client\n});\n\n// create a copy to do some business logic checks\ncalendar.addEntryDroppedListener(event -> {\n    Entry copy = event.createCopyBasedOnChanges();\n\n    if(copy.getStartAsLocalDate().isBefore(someRequiredMinimalDate) /* do some background checks on the changed data */) {\n        event.applyChangesOnEntry();\n        event.getSource().getEntryProvider().refreshItem(event.getEntry()); // refresh the entry to update the UI\n    }\n});",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "event",
        "listener",
        "drop",
        "create",
        "update"
      ]
    },
    {
      "id": "samples-39",
      "title": "Handling data changes in events",
      "description": "// create a copy to do some business logic checks calendar.addEntryDroppedListener(event -> {     Entry copy = event.createCopyBasedOnChanges();     if(copy.getStartAsLocalDate().isBefore(someRequiredMinimalDate) /* do some background checks on the changed data */) {         event.applyChangesOnEntr",
      "code": "Entry tmpEntry = entry.copy(); // create a temporary copy\n// you may also call copyAsType to allow the copy to be of a different type\n\nBinder<Entry> binder = new Binder<>();\n\n// ... init binder\n\nbinder.setBean(tmpEntry); // you can of course also use the read/writeBean api\n\n// modify the bound fields\n\nif (binder.validate().isOk()) {\n    entry.copyFrom(tmpEntry); // this will overwrite the entry with the values of the tmpEntry\n    // ... update the backend as needed, e.g. by calling refreshItem on the entry provider\n}",
      "language": "java",
      "category": "events",
      "tags": [
        "entry",
        "provider",
        "event",
        "create",
        "update"
      ]
    },
    {
      "id": "samples-40",
      "title": "Create a temporary copy",
      "description": "binder.setBean(tmpEntry); // you can of course also use the read/writeBean api // modify the bound fields if (binder.validate().isOk()) {     entry.copyFrom(tmpEntry); // this will overwrite the entry with the values of the tmpEntry     // ... update the backend as needed, e.g. by calling refreshIte",
      "code": "Entry tmpEntry = entry.copy(); // create a temporary copy\n\n// ... modify the temporary copy\n\n// return a new copy at the end without changing the initial entry\nreturn tmpEntry.copy();",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "create"
      ]
    },
    {
      "id": "samples-41",
      "title": "Create a temporary copy",
      "description": "Alternatively you can use the copy API in a JPA fashion, where new instances are created on changes. ```java Entry tmpEntry = entry.copy(); // create a temporary copy // ... modify the temporary copy // return a new copy at the end without changing the initial entry return tmpEntry.copy(); ```",
      "code": "// Weekly on Monday, Wednesday, Friday — all of 2025.\n// dtstart uses LocalDate, so occurrences are all-day.\nEntry standup = new Entry();\nstandup.setTitle(\"Weekly Standup\");\nstandup.setRRule(RRule.weekly()\n    .byWeekday(DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY)\n    .dtstart(LocalDate.of(2025, 1, 1))\n    .until(LocalDate.of(2025, 12, 31)));\n\n// Last Friday of each month\n// byWeekday(\"-1fr\") uses RFC 5545 notation: sign + ordinal + 2-letter day code.\n// \"-1fr\" = last Friday; \"1mo\" = first Monday; \"-2tu\" = second-to-last Tuesday.\n// Positive numbers count from the start of the period; negative from the end.\nEntry review = new Entry();\nreview.setTitle(\"Monthly Review\");\nreview.setRRule(RRule.monthly().byWeekday(\"-1fr\"));\n\n// Every two weeks on Tuesday (bi-weekly)\nEntry planning = new Entry();\nplanning.setTitle(\"Bi-weekly Planning\");\nplanning.setRRule(RRule.weekly().byWeekday(DayOfWeek.TUESDAY).interval(2)\n    .dtstart(LocalDate.of(2025, 1, 7))\n    .excludeDates(LocalDate.of(2025, 7, 22), LocalDate.of(2025, 12, 30)));\n\n// Raw RFC 5545 string for unsupported patterns.\n// Note: raw strings use uppercase RFC 5545 syntax (e.g. BYDAY=1MO), not\n// the fluent API's lowercase notation (e.g. byWeekday(\"1mo\")).\nEntry custom = new Entry();\ncustom.setRRule(RRule.ofRaw(\"FREQ=MONTHLY;BYDAY=1MO,3MO;COUNT=12\"));\n\ncalendar.getEntryProvider().asInMemory().addEntries(standup, review, planning, custom);",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "view",
        "create"
      ]
    },
    {
      "id": "samples-42",
      "title": "RRule — RFC 5545 recurrence rules",
      "description": ".excludeDates(LocalDate.of(2025, 7, 22), LocalDate.of(2025, 12, 30))); // Raw RFC 5545 string for unsupported patterns. // Note: raw strings use uppercase RFC 5545 syntax (e.g. BYDAY=1MO), not // the fluent API's lowercase notation (e.g. byWeekday(\"1mo\")). Entry custom = new Entry(); custom.setRRule",
      "code": "// URL entry — FC navigates to the URL when clicked\nEntry link = new Entry();\nlink.setTitle(\"Visit Documentation\");\nlink.setStart(LocalDate.now());\nlink.setAllDay(true);\nlink.setUrl(\"https://vaadin.com/docs\");\n\n// Keyboard-accessible entry (no URL, no drag — just focusable)\nEntry keyboardEntry = new Entry();\nkeyboardEntry.setTitle(\"Press Enter to open wizard\");\nkeyboardEntry.setStart(LocalDate.now().plusDays(1));\nkeyboardEntry.setAllDay(true);\nkeyboardEntry.setInteractive(true); // per-entry override\n\n// Or make ALL entries keyboard-accessible globally:\ncalendar.setOption(FullCalendar.Option.ENTRY_INTERACTIVE, true);\n// Then per-entry override is still possible (e.g., to opt out):\nkeyboardEntry.setInteractive(false);\n\ncalendar.addEntryClickedListener(e -> {\n    // Fired for both mouse clicks and keyboard activations (Enter/Space)\n    System.out.println(\"Clicked: \" + e.getEntry().getTitle());\n});",
      "language": "java",
      "category": "events",
      "tags": [
        "entry",
        "listener",
        "click"
      ]
    },
    {
      "id": "samples-43",
      "title": "Entry URL and keyboard accessibility",
      "description": "// Or make ALL entries keyboard-accessible globally: calendar.setOption(FullCalendar.Option.ENTRY_INTERACTIVE, true); // Then per-entry override is still possible (e.g., to opt out): keyboardEntry.setInteractive(false); calendar.addEntryClickedListener(e -> {     // Fired for both mouse clicks and k",
      "code": "// This entry cannot be overlapped by other entries\nEntry blocked = new Entry();\nblocked.setTitle(\"Blocked Time\");\nblocked.setStart(LocalDateTime.of(2025, 3, 5, 9, 0));\nblocked.setEnd(LocalDateTime.of(2025, 3, 5, 11, 0));\nblocked.setOverlap(false);\n\n// Explicitly allow overlap (overrides a global eventOverlap=false if set)\nEntry flexible = new Entry();\nflexible.setTitle(\"Flexible Slot\");\nflexible.setOverlap(true);\n\n// null means \"use whatever the calendar-level eventOverlap says\" (the default)\nEntry normal = new Entry();\nnormal.setOverlap(null);  // same as not calling setOverlap at all",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "event"
      ]
    },
    {
      "id": "samples-44",
      "title": "Entry overlap control",
      "description": "// Explicitly allow overlap (overrides a global eventOverlap=false if set) Entry flexible = new Entry(); flexible.setTitle(\"Flexible Slot\"); flexible.setOverlap(true); // null means \"use whatever the calendar-level eventOverlap says\" (the default) Entry normal = new Entry(); normal.setOverlap(null);",
      "code": "// Limit stacked events to 3 only in month view (not in week or day views)\ncalendar.setViewSpecificOption(\"dayGridMonth\", FullCalendar.Option.DAY_MAX_EVENT_ROWS, 3);\n\n// Custom slot duration for all time-grid variants\ncalendar.setViewSpecificOption(\"timeGrid\", FullCalendar.Option.SLOT_DURATION, \"00:30:00\");\n\n// Multiple options at once for the same view.\n// Keys here are raw FullCalendar option names (camelCase strings), not Java Option enum values.\ncalendar.setViewSpecificOptions(\"listWeek\", Map.of(\n    \"noEventsText\", \"No events scheduled this week\"\n));\n\n// Use CalendarView enum instead of a raw string\ncalendar.setViewSpecificOption(CalendarViewImpl.DAY_GRID_MONTH,\n    FullCalendar.Option.NOW_INDICATOR, true);",
      "language": "java",
      "category": "views",
      "tags": [
        "entry",
        "event",
        "view"
      ]
    },
    {
      "id": "samples-45",
      "title": "View-specific options",
      "description": "// Multiple options at once for the same view. // Keys here are raw FullCalendar option names (camelCase strings), not Java Option enum values. calendar.setViewSpecificOptions(\"listWeek\", Map.of(     \"noEventsText\", \"No events scheduled this week\" )); // Use CalendarView enum instead of a raw string",
      "code": "Dialog dialog = new Dialog();\nFullCalendar calendar = FullCalendarBuilder.create().build();\ndialog.add(calendar);\n\ndialog.addOpenedChangeListener(event -> {\n    if (event.isOpened()) {\n        // Force recalculation now that the dialog is visible\n        calendar.getElement().callJsFunction(\"updateSize\");\n    }\n});",
      "language": "java",
      "category": "events",
      "tags": [
        "event",
        "listener",
        "view",
        "builder",
        "create",
        "update"
      ]
    },
    {
      "id": "samples-46",
      "title": "Force calendar to recalculate its size",
      "description": "FullCalendar calendar = FullCalendarBuilder.create().build(); dialog.add(calendar); dialog.addOpenedChangeListener(event -> {     if (event.isOpened()) {         // Force recalculation now that the dialog is visible         calendar.getElement().callJsFunction(\"updateSize\");     } }); ```",
      "code": "calendar.setOption(FullCalendar.Option.NATIVE_TOOLBAR_BUTTON_HINTS, Map.of(\n    \"today\", \"Jump to today\",\n    \"prev\",  \"Go to previous period\",\n    \"next\",  \"Go to next period\"\n));\n\n// Accessible label for the \"+N more\" overflow link (e.g., \"+ 3 more\")\n// $0 is replaced with the hidden-event count at runtime\ncalendar.setOption(Option.MORE_LINK_HINT, \"$0 more events — click to expand\");\n\n// Accessible label for day-number navigation links\ncalendar.setOption(Option.NAV_LINK_HINT, \"Go to $0\");  // $0 = full date text",
      "language": "java",
      "category": "general",
      "tags": [
        "event",
        "click"
      ]
    },
    {
      "id": "samples-47",
      "title": "Accessibility hints for toolbar buttons",
      "description": "\"next\",  \"Go to next period\" )); // Accessible label for the \"+N more\" overflow link (e.g., \"+ 3 more\") // $0 is replaced with the hidden-event count at runtime calendar.setOption(Option.MORE_LINK_HINT, \"$0 more events — click to expand\"); // Accessible label for day-number navigation links calendar",
      "code": "// The browser will GET this URL whenever the visible date range changes.\nJsonFeedEventSource jsonFeed = new JsonFeedEventSource(\"https://example.com/api/events\");\njsonFeed.withId(\"company-events\");\njsonFeed.withColor(\"#3788d8\");\njsonFeed.withExtraParams(Map.of(\"department\", \"engineering\"));  // appended as query params\n\ncalendar.addClientSideEventSource(jsonFeed);",
      "language": "java",
      "category": "general",
      "tags": [
        "event"
      ]
    },
    {
      "id": "samples-48",
      "title": "Example 49",
      "description": "```java // The browser will GET this URL whenever the visible date range changes. JsonFeedEventSource jsonFeed = new JsonFeedEventSource(\"https://example.com/api/events\"); jsonFeed.withId(\"company-events\"); jsonFeed.withColor(\"#3788d8\"); jsonFeed.withExtraParams(Map.of(\"department\", \"engineering\"));",
      "code": "// Set the API key globally (applies to all Google sources on this calendar)\ncalendar.setOption(FullCalendar.Option.EXTERNAL_EVENT_SOURCE_GOOGLE_CALENDAR_API_KEY, \"YOUR_GOOGLE_API_KEY\");\n\nGoogleCalendarEventSource holidays = new GoogleCalendarEventSource(\"en.german#holiday@group.v.calendar.google.com\");\nholidays.withId(\"holidays\");\nholidays.withColor(\"#4caf50\");\n\ncalendar.addClientSideEventSource(holidays);",
      "language": "java",
      "category": "general",
      "tags": [
        "event"
      ]
    },
    {
      "id": "samples-49",
      "title": "Example 50",
      "description": "```java // Set the API key globally (applies to all Google sources on this calendar) calendar.setOption(FullCalendar.Option.EXTERNAL_EVENT_SOURCE_GOOGLE_CALENDAR_API_KEY, \"YOUR_GOOGLE_API_KEY\"); GoogleCalendarEventSource holidays = new GoogleCalendarEventSource(\"en.german#holiday@group.v.calendar.go",
      "code": "ICalendarEventSource ical = new ICalendarEventSource(\"https://example.com/calendar.ics\");\nical.withId(\"team-calendar\");\nical.withColor(\"#ff9800\");\n\ncalendar.addClientSideEventSource(ical);",
      "language": "java",
      "category": "general",
      "tags": [
        "event"
      ]
    },
    {
      "id": "samples-50",
      "title": "Example 51",
      "description": "```java ICalendarEventSource ical = new ICalendarEventSource(\"https://example.com/calendar.ics\"); ical.withId(\"team-calendar\"); ical.withColor(\"#ff9800\"); calendar.addClientSideEventSource(ical); ```",
      "code": "// React to fetch failures on the server side\ncalendar.addEventSourceFailureListener(event -> {\n    Notification.show(\"Failed to load source '\" + event.getSourceId() + \"': \" + event.getMessage(),\n            3000, Notification.Position.BOTTOM_START);\n});\n\n// Refresh only a specific source (e.g. after the user changed a filter)\ncalendar.refetchClientSideEventSource(\"company-events\");\n\n// Or refresh all sources at once\ncalendar.refetchEvents();",
      "language": "java",
      "category": "events",
      "tags": [
        "event",
        "listener"
      ]
    },
    {
      "id": "samples-51",
      "title": "Error handling and per-source refresh",
      "description": "Notification.show(\"Failed to load source '\" + event.getSourceId() + \"': \" + event.getMessage(),             3000, Notification.Position.BOTTOM_START); }); // Refresh only a specific source (e.g. after the user changed a filter) calendar.refetchClientSideEventSource(\"company-events\"); // Or refresh a",
      "code": "// Event sources support the same display options as entries\nJsonFeedEventSource feed = new JsonFeedEventSource(\"https://example.com/api/events\");\nfeed.withId(\"external\");\nfeed.withEditable(false);          // entries from this source are read-only\nfeed.withColor(\"#888\");\nfeed.withDisplay(\"background\");    // render as background events\nfeed.withDefaultAllDay(true);\n\n// Transform incoming event data before FC processes it\nfeed.withEventDataTransform(JsCallback.of(\"\"\"\n    function(eventData) {\n        eventData.title = '[EXT] ' + eventData.title;\n        return eventData;\n    }\"\"\"));\n\ncalendar.addClientSideEventSource(feed);",
      "language": "java",
      "category": "general",
      "tags": [
        "callback",
        "event"
      ]
    },
    {
      "id": "samples-52",
      "title": "Example 53",
      "description": "// Transform incoming event data before FC processes it feed.withEventDataTransform(JsCallback.of(\"\"\"     function(eventData) {         eventData.title = '[EXT] ' + eventData.title;         return eventData;     }\"\"\")); calendar.addClientSideEventSource(feed); ```",
      "code": "// 1. Enable external drops on the calendar\ncalendar.setOption(Option.DROPPABLE, true);\n\n// 2. Create a Vaadin component and an Entry with the data for the drop\nDiv meetingItem = new Div(\"New Meeting\");\nmeetingItem.getStyle().set(\"cursor\", \"grab\");\n\nEntry meetingData = new Entry();\nmeetingData.setTitle(\"New Meeting\");\nmeetingData.setColor(\"#4CAF50\");\n\n// 3. Register the draggable on the calendar\ncalendar.addDraggable(new Draggable(meetingItem, meetingData));\n\n// 4. Listen for entry creation — fires when FC creates an entry from the drop\n//    The entry is transient — add it to your provider to persist it\ncalendar.addEntryReceiveListener(event -> {\n    Entry created = event.getEntry();\n    calendar.getEntryProvider().asInMemory().addEntry(created);\n    calendar.getEntryProvider().asInMemory().refreshAll();\n\n    // Access the original Draggable if needed\n    event.getDraggable().ifPresent(d -> {\n        System.out.println(\"Dropped component: \" + d.getComponent());\n    });\n});",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "event",
        "listener",
        "drop",
        "style",
        "create"
      ]
    },
    {
      "id": "samples-53",
      "title": "Example 54",
      "description": "Entry created = event.getEntry();     calendar.getEntryProvider().asInMemory().addEntry(created);     calendar.getEntryProvider().asInMemory().refreshAll();     // Access the original Draggable if needed     event.getDraggable().ifPresent(d -> {         System.out.println(\"Dropped component: \" + d.g",
      "code": "// A container with multiple draggable children\nDiv taskList = new Div();\ntaskList.add(createTask(\"Write report\"), createTask(\"Fix bug #42\"), createTask(\"Review PR\"));\n\n// Only children matching \".task-item\" are draggable.\n// The JS callback reads the element's text to create the entry title.\ncalendar.addDraggable(new Draggable(taskList)\n        .withItemSelector(\".task-item\")\n        .withEventDataCallback(JsCallback.of(\n                \"function(el) { return { title: el.innerText, duration: '01:00' }; }\")));\n\n// Helper\nprivate Div createTask(String name) {\n    Div item = new Div(name);\n    item.addClassName(\"task-item\");\n    item.getStyle().set(\"cursor\", \"grab\");\n    return item;\n}",
      "language": "java",
      "category": "styling",
      "tags": [
        "entry",
        "callback",
        "event",
        "style",
        "view",
        "create"
      ]
    },
    {
      "id": "samples-54",
      "title": "Example 55",
      "description": "\"function(el) { return { title: el.innerText, duration: '01:00' }; }\"))); // Helper private Div createTask(String name) {     Div item = new Div(name);     item.addClassName(\"task-item\");     item.getStyle().set(\"cursor\", \"grab\");     return item; } ```",
      "code": "calendar.addEntryLeaveListener(event -> {\n    Entry leaving = event.getEntry();\n    calendar.getEntryProvider().asInMemory().removeEntry(leaving);\n    calendar.getEntryProvider().asInMemory().refreshAll();\n});",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "event",
        "listener"
      ]
    },
    {
      "id": "samples-55",
      "title": "Multi-calendar: entry leave listener",
      "description": "When entries can be dragged between calendars, listen on the source calendar for entries leaving: ```java calendar.addEntryLeaveListener(event -> {     Entry leaving = event.getEntry();     calendar.getEntryProvider().asInMemory().removeEntry(leaving);     calendar.getEntryProvider().asInMemory().re",
      "code": "Button deleteButton = new Button(\"Delete\");\n\n// Disable the delete button while the user is dragging an entry\ncalendar.addEntryDragStartListener(event -> {\n    deleteButton.setEnabled(false);\n});\ncalendar.addEntryDragStopListener(event -> {\n    deleteButton.setEnabled(true);\n});\n\n// Same pattern for resize\ncalendar.addEntryResizeStartListener(event -> {\n    deleteButton.setEnabled(false);\n});\ncalendar.addEntryResizeStopListener(event -> {\n    deleteButton.setEnabled(true);\n});\n\n// Apply changes only in the final event\ncalendar.addEntryDroppedListener(event -> {\n    event.applyChangesOnEntry();\n    calendar.getEntryProvider().asInMemory().refreshItem(event.getEntry());\n});",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "event",
        "listener",
        "drop",
        "resize",
        "delete"
      ]
    },
    {
      "id": "samples-56",
      "title": "Drag and resize lifecycle events",
      "description": "calendar.addEntryResizeStopListener(event -> {     deleteButton.setEnabled(true); }); // Apply changes only in the final event calendar.addEntryDroppedListener(event -> {     event.applyChangesOnEntry();     calendar.getEntryProvider().asInMemory().refreshItem(event.getEntry()); }); ```",
      "code": "Scheduler scheduler = (Scheduler) calendar;\n\n// Define columns — the field name must match a key in Resource.extendedProps or a standard property\nResourceAreaColumn nameCol = new ResourceAreaColumn(\"title\", \"Name\");\nnameCol.withWidth(\"150px\");\n\nResourceAreaColumn roleCol = new ResourceAreaColumn(\"role\", \"Role\");\nroleCol.withWidth(\"100px\");\n\nResourceAreaColumn deptCol = new ResourceAreaColumn(\"department\", \"Dept\");\ndeptCol.withWidth(\"80px\");\ndeptCol.withGroup(true);  // group resources by this column's values\n\nscheduler.setResourceAreaColumns(List.of(nameCol, roleCol, deptCol));\n\n// IMPORTANT: grouping requires both withGroup(true) on the column AND setOption(SchedulerOption.RESOURCE_GROUP_FIELD, ...)\nscheduler.setOption(SchedulerOption.RESOURCE_GROUP_FIELD, \"department\");\n\n// Create resources with matching extendedProps\nResource dev1 = new Resource(\"1\", \"Alice\", null);\ndev1.addExtendedProps(\"role\", \"Developer\");\ndev1.addExtendedProps(\"department\", \"Engineering\");\n\nResource dev2 = new Resource(\"2\", \"Bob\", null);\ndev2.addExtendedProps(\"role\", \"Designer\");\ndev2.addExtendedProps(\"department\", \"Design\");\n\nscheduler.addResources(dev1, dev2);",
      "language": "java",
      "category": "events",
      "tags": [
        "resource",
        "scheduler",
        "event",
        "resize",
        "create"
      ]
    },
    {
      "id": "samples-57",
      "title": "Resource area columns (Scheduler)",
      "description": "Resource dev1 = new Resource(\"1\", \"Alice\", null); dev1.addExtendedProps(\"role\", \"Developer\"); dev1.addExtendedProps(\"department\", \"Engineering\"); Resource dev2 = new Resource(\"2\", \"Bob\", null); dev2.addExtendedProps(\"role\", \"Designer\"); dev2.addExtendedProps(\"department\", \"Design\"); scheduler.addRes",
      "code": "// Customize how cells in a column are rendered — pass JsCallback for function values\nResourceAreaColumn statusCol = new ResourceAreaColumn(\"status\", \"Status\");\nstatusCol.withCellContent(JsCallback.of(\"\"\"\n    function(arg) {\n        var val = arg.resource.extendedProps.status || 'unknown';\n        return { html: '<span class=\"status-' + val + '\">' + val + '</span>' };\n    }\"\"\"));\nstatusCol.withCellClassNames(JsCallback.of(\"\"\"\n    function(arg) {\n        return arg.resource.extendedProps.status === 'active' ? ['active-cell'] : [];\n    }\"\"\"));\n\n// Static content is also supported — pass a plain String instead\nstatusCol.withCellContent(\"n/a\");  // displayed as-is in every cell",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "callback",
        "resource",
        "scheduler"
      ]
    },
    {
      "id": "samples-58",
      "title": "Column render hooks",
      "description": "return { html: '<span class=\"status-' + val + '\">' + val + '</span>' };     }\"\"\")); statusCol.withCellClassNames(JsCallback.of(\"\"\"     function(arg) {         return arg.resource.extendedProps.status === 'active' ? ['active-cell'] : [];     }\"\"\")); // Static content is also supported — pass a plain ",
      "code": "// This entry can only be placed during custom hours (Mon–Fri, 9–17)\nEntry meeting = new Entry();\nmeeting.setTitle(\"Client Meeting\");\nmeeting.setStart(LocalDateTime.of(2025, 3, 10, 10, 0));\nmeeting.setEnd(LocalDateTime.of(2025, 3, 10, 11, 0));\nmeeting.setConstraint(BusinessHours.businessWeek().start(9).end(17));\n\n// This entry defers to the calendar's defined business hours\nEntry standup = new Entry();\nstandup.setTitle(\"Standup\");\nstandup.setConstraintToBusinessHours();\n\n// This entry can only overlap with entries in the same group\nEntry teamEvent = new Entry();\nteamEvent.setGroupId(\"team-a\");\nteamEvent.setConstraint(\"team-a\");  // only droppable where other \"team-a\" entries are",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "event",
        "drop"
      ]
    },
    {
      "id": "samples-59",
      "title": "Entry constraints with BusinessHours",
      "description": "// This entry defers to the calendar's defined business hours Entry standup = new Entry(); standup.setTitle(\"Standup\"); standup.setConstraintToBusinessHours(); // This entry can only overlap with entries in the same group Entry teamEvent = new Entry(); teamEvent.setGroupId(\"team-a\"); teamEvent.setCo",
      "code": "// Prevent all entries from overlapping each other\ncalendar.setOption(FullCalendar.Option.ENTRY_OVERLAP, false);\n\n// Individual entries can still opt in\nEntry flexible = new Entry();\nflexible.setTitle(\"Flexible\");\nflexible.setOverlap(true);  // overrides the global false\n\n// For more complex logic, use a JS callback\ncalendar.setOption(FullCalendar.Option.ENTRY_OVERLAP, JsCallback.of(\"\"\"\n    function(stillEvent, movingEvent) {\n        // Allow overlap only with background events\n        return stillEvent.display === 'background';\n    }\"\"\"));",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "callback",
        "event"
      ]
    },
    {
      "id": "samples-60",
      "title": "Global event overlap control",
      "description": "flexible.setTitle(\"Flexible\"); flexible.setOverlap(true);  // overrides the global false // For more complex logic, use a JS callback calendar.setOption(FullCalendar.Option.ENTRY_OVERLAP, JsCallback.of(\"\"\"     function(stillEvent, movingEvent) {         // Allow overlap only with background events  ",
      "code": "calendar.setOption(Option.DAY_CELL_CLASS_NAMES, JsCallback.of(\"\"\"\n    function(arg) {\n        var dow = arg.date.getUTCDay();\n        return (dow === 0 || dow === 6) ? ['weekend-cell'] : [];\n    }\"\"\"));",
      "language": "java",
      "category": "events",
      "tags": [
        "callback",
        "event"
      ]
    },
    {
      "id": "samples-61",
      "title": "Highlight weekends in the day grid",
      "description": "```java calendar.setOption(Option.DAY_CELL_CLASS_NAMES, JsCallback.of(\"\"\"     function(arg) {         var dow = arg.date.getUTCDay();         return (dow === 0 || dow === 6) ? ['weekend-cell'] : [];     }\"\"\")); ```",
      "code": "### Custom slot labels in the time grid",
      "language": "java",
      "category": "general",
      "tags": []
    },
    {
      "id": "samples-62",
      "title": "Custom slot labels in the time grid",
      "description": "Then in your CSS: ```css .weekend-cell {     background-color: rgba(255, 200, 200, 0.15); } ``` ```",
      "code": "### Custom day header with extra info",
      "language": "java",
      "category": "general",
      "tags": []
    },
    {
      "id": "samples-63",
      "title": "Custom day header with extra info",
      "description": "function(arg) {         var h = arg.date.getUTCHours();         if (h < 9 || h >= 17) return { html: '<span style=\"color:#999\">' + arg.text + '</span>' };         return arg.text;     }\"\"\")); ``` ```",
      "code": "### Other render hooks\n\nThe same pattern applies to all other hooks. A few examples:",
      "language": "java",
      "category": "general",
      "tags": []
    },
    {
      "id": "samples-64",
      "title": "Other render hooks",
      "description": "var dayNum = d.getDate();         return { html: '<div>' + dayName + '<br><b>' + dayNum + '</b></div>' };     }\"\"\")); ``` The same pattern applies to all other hooks. A few examples: ```",
      "code": "## Resource-level display overrides (Scheduler)\n\nResources can define default display properties for all entries assigned to them. The cascade is:\n**Calendar defaults → Resource overrides → Entry overrides** (most specific wins).",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "entry",
        "resource",
        "scheduler"
      ]
    },
    {
      "id": "samples-65",
      "title": "Resource-level display overrides (Scheduler)",
      "description": "calendar.setOption(Option.NO_ENTRIES_CONTENT, JsCallback.of(     \"function() { return { html: '<em>Nothing scheduled</em>' }; }\")); ``` Resources can define default display properties for all entries assigned to them. The cascade is: **Calendar defaults → Resource overrides → Entry overrides** (most",
      "code": "## JsCallback usage\n\n`JsCallback` wraps a JavaScript function string so that FullCalendar evaluates it in the browser.\nPass a `JsCallback` value to `setOption` with any `Option` constant that accepts a function.\nThis works for render hooks, interaction guards, and any other FC option that expects a JS function.\n\n### Render hook example — custom entry content with an icon",
      "language": "java",
      "category": "scheduler",
      "tags": [
        "entry",
        "callback",
        "resource",
        "scheduler"
      ]
    },
    {
      "id": "samples-66",
      "title": "Render hook example — custom entry content with an icon",
      "description": "`JsCallback` wraps a JavaScript function string so that FullCalendar evaluates it in the browser. Pass a `JsCallback` value to `setOption` with any `Option` constant that accepts a function. This works for render hooks, interaction guards, and any other FC option that expects a JS function. ```",
      "code": "### Interaction guard example — conditional overlap via callback",
      "language": "java",
      "category": "general",
      "tags": [
        "entry",
        "callback"
      ]
    },
    {
      "id": "samples-67",
      "title": "Interaction guard example — conditional overlap via callback",
      "description": "function(info) {         var cat = info.event.getCustomProperty('category', '');         var icon = cat === 'meeting' ? '\\u{1F4C5} ' : '';         return { html: icon + '<b>' + info.event.title + '</b>' };     }\"\"\")); ``` ```",
      "code": "### Clearing a callback\n\nUse `JsCallback.clearCallback()` to explicitly clear a previously set callback:",
      "language": "java",
      "category": "general",
      "tags": [
        "callback"
      ]
    },
    {
      "id": "samples-68",
      "title": "Clearing a callback",
      "description": "function(stillEvent, movingEvent) {         return stillEvent.display === 'background';     }\"\"\")); ``` Use `JsCallback.clearCallback()` to explicitly clear a previously set callback: ```",
      "code": "Alternatively, passing `null` directly or `JsCallback.of(null)` has the same effect — useful when\nyou have a nullable string variable:",
      "language": "java",
      "category": "general",
      "tags": [
        "callback"
      ]
    },
    {
      "id": "samples-69",
      "title": "Clearing a callback",
      "description": "```java // Clear the entry-content callback calendar.setOption(Option.ENTRY_CONTENT, JsCallback.clearCallback()); ``` Alternatively, passing `null` directly or `JsCallback.of(null)` has the same effect — useful when you have a nullable string variable: ```",
      "code": "## fixedMirrorParent — controlling the drag-mirror container\n\nThe `fixedMirrorParent` option controls where the drag-mirror element is appended during drag operations.\nSet it via `Option.FIXED_MIRROR_PARENT` with a `JsCallback` that returns a DOM element.\n\n### Simple case — document.body",
      "language": "java",
      "category": "general",
      "tags": [
        "callback"
      ]
    },
    {
      "id": "samples-70",
      "title": "Simple case — document.body",
      "description": "``` The `fixedMirrorParent` option controls where the drag-mirror element is appended during drag operations. Set it via `Option.FIXED_MIRROR_PARENT` with a `JsCallback` that returns a DOM element. ```",
      "code": "### Dynamic lookup — function evaluated on each drag start",
      "language": "java",
      "category": "general",
      "tags": []
    },
    {
      "id": "samples-71",
      "title": "Dynamic lookup — function evaluated on each drag start",
      "description": "```java // The drag mirror will be appended to document.body calendar.setOption(Option.FIXED_MIRROR_PARENT,     JsCallback.of(\"function() { return document.body; }\")); ``` ```",
      "code": "To clear the option, pass `null`:",
      "language": "java",
      "category": "general",
      "tags": []
    },
    {
      "id": "samples-72",
      "title": "Dynamic lookup — function evaluated on each drag start",
      "description": "```java calendar.setOption(Option.FIXED_MIRROR_PARENT, JsCallback.of(\"\"\"     function() {         return document.querySelector('.my-drag-container');     }\"\"\")); ``` To clear the option, pass `null`: ```",
      "code": "## moreLinkClick callback\n\nWhen the number of visible entries exceeds the row limit, FullCalendar shows a \"+N more\" link.\nYou can control what happens when the user clicks it.\n\n### Static value — use Option or the convenience method",
      "language": "java",
      "category": "general",
      "tags": [
        "callback",
        "click"
      ]
    },
    {
      "id": "samples-73",
      "title": "Static value — use Option or the convenience method",
      "description": "``` When the number of visible entries exceeds the row limit, FullCalendar shows a \"+N more\" link. You can control what happens when the user clicks it. ```",
      "code": "### Function callback — use JsCallback\n\nUse `Option.MORE_LINK_CLICK` with a `JsCallback` when you need custom logic, for instance logging or\nconditionally choosing the action.",
      "language": "java",
      "category": "general",
      "tags": [
        "callback",
        "click"
      ]
    },
    {
      "id": "samples-74",
      "title": "Function callback — use JsCallback",
      "description": "// Or navigate to the day view calendar.setOption(FullCalendar.Option.MORE_LINK_CLICK, \"day\"); ``` Use `Option.MORE_LINK_CLICK` with a `JsCallback` when you need custom logic, for instance logging or conditionally choosing the action. ```",
      "code": "## Restricting navigation with valid range\n\nLimit which dates the user can navigate to. Dates outside the range are greyed out and the\nprev/next buttons are automatically disabled when the edge is reached.",
      "language": "java",
      "category": "general",
      "tags": [
        "callback"
      ]
    },
    {
      "id": "demo-democalendarwithbackgroundevent",
      "title": "Demo Calendar With Background Event",
      "description": "Demo: DemoCalendarWithBackgroundEvent",
      "code": "package org.vaadin.stefan.ui.view.demos.backgroundevent;\n\nimport com.vaadin.flow.component.orderedlayout.VerticalLayout;\nimport com.vaadin.flow.router.Route;\n\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.fullcalendar.DisplayMode;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.menu.MenuItem;\n\nimport java.time.LocalDate;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Locale;\n\nimport static org.vaadin.stefan.fullcalendar.FullCalendar.Option.*;\n\n@Route(value = \"demobackgroundevent\", layout = MainLayout.class)\n@MenuItem(label = \"Background Events\")\npublic class DemoCalendarWithBackgroundEvent extends VerticalLayout {\n    private static final long serialVersionUID = 1L;\n    \n    private FullCalendar calendar;\n\n    public DemoCalendarWithBackgroundEvent() {\n    \tinitView();\n\n        createCalendarInstance();\n        addBackgroundEvent(DisplayMode.BACKGROUND, 4, \"This special holiday\");\n        addBackgroundEvent(DisplayMode.BACKGROUND, 6, \"\");\n\n        add(calendar);\n        setFlexGrow(1, calendar);\n    }\n    \n    private void initView() {\n    \tsetSizeFull();\n        setDefaultHorizontalComponentAlignment(Alignment.STRETCH);\n    }\n\n\n    private void createCalendarInstance() {\n        calendar = new FullCalendarScheduler();\n        ((FullCalendarScheduler) calendar).setOption(FullCalendarScheduler.SchedulerOption.LICENSE_KEY, Scheduler.GPL_V3_LICENSE_KEY);\n        ((FullCalendarScheduler) calendar).setOption(FullCalendarScheduler.SchedulerOption.SLOT_MIN_WIDTH, 150);\n        calendar.setOption(LOCALE, Locale.ENGLISH);\n\n        calendar.changeView(SchedulerView.TIMELINE_MONTH);\n    }\n\n    private void addBackgroundEvent(DisplayMode displayMode, int offset, String title) {\n        LocalDate now = LocalDate.now();\n        \n        ResourceEntry entry = new ResourceEntry();\n        \n        entry.setTitle(title);\n        entry.setStart(now.withDayOfMonth(offset));\n        entry.setEnd(entry.getStart().plus(1, ChronoUnit.DAYS));\n        entry.setAllDay(true);\n        entry.setColor(\"red\");\n        entry.setDisplayMode(displayMode);\n        entry.setResourceEditable(true);\n        \n        calendar.getEntryProvider().asInMemory().addEntry(entry);\n    }\n}",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "resource",
        "scheduler",
        "event",
        "view",
        "create"
      ]
    },
    {
      "id": "demo-basicdemo",
      "title": "Basic Demo",
      "description": "Demo: BasicDemo",
      "code": "package org.vaadin.stefan.ui.view.demos.basic;\n\nimport com.vaadin.flow.router.Route;\nimport org.vaadin.stefan.ui.dialogs.DemoDialog;\nimport org.vaadin.stefan.ui.view.AbstractCalendarView;\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.fullcalendar.dataprovider.InMemoryEntryProvider;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.menu.MenuItem;\nimport org.vaadin.stefan.ui.view.demos.entryproviders.EntryService;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport java.util.Collections;\n\n@Route(value = \"basic-demo\", layout = MainLayout.class)\n@MenuItem(label = \"Basic Demo\")\npublic class BasicDemo extends AbstractCalendarView {\n\n    @Override\n    protected FullCalendar createCalendar(ObjectNode defaultInitialOptions) {\n        EntryService<Entry> simpleInstance = EntryService.createSimpleInstance();\n\n        FullCalendar calendar = new FullCalendar(defaultInitialOptions);\n        ((InMemoryEntryProvider<Entry>) calendar.getEntryProvider()).addEntries(simpleInstance.getEntries());\n        calendar.setOption(FullCalendar.Option.MAX_ENTRIES_PER_DAY, 3);\n        return calendar;\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"A simple demo, showing the basic interaction events with the calendar and allow basic modification of entries.\";\n    }\n\n    @Override\n    protected void onEntryClick(EntryClickedEvent event) {\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n\n        if (event.getEntry().getDisplayMode() != DisplayMode.BACKGROUND && event.getEntry().getDisplayMode() != DisplayMode.INVERSE_BACKGROUND) {\n            DemoDialog dialog = new DemoDialog(event.getEntry(), false);\n            dialog.setSaveConsumer(this::onEntryChanged);\n            dialog.setDeleteConsumer(e -> onEntriesRemoved(Collections.singletonList(e)));\n            dialog.open();\n        }\n    }\n\n    @Override\n    protected void onTimeslotsSelected(TimeslotsSelectedEvent event) {\n        super.onTimeslotsSelected(event);\n\n        ResourceEntry entry = new ResourceEntry();\n\n        entry.setStart(event.getStart());\n        entry.setEnd(event.getEnd());\n        entry.setAllDay(event.isAllDay());\n        entry.setCalendar(event.getSource());\n\n        DemoDialog dialog = new DemoDialog(entry, true);\n        dialog.setSaveConsumer(e -> onEntriesCreated(Collections.singletonList(e)));\n        dialog.setDeleteConsumer(e -> onEntriesRemoved(Collections.singletonList(e)));\n        dialog.open();\n    }\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "resource",
        "event",
        "click",
        "view",
        "create",
        "delete"
      ]
    },
    {
      "id": "demo-componentcolumnsdemo",
      "title": "Component Columns Demo",
      "description": "Demo view for component resource area columns (UC-024).\n<p>\nShows a scheduler with tasks assigned to resources. Each resource row has two\nDatePicker columns (Start, End) that reflect the assigned entry's time range.\nChanging a DatePicker updates the entry; dragging/resizing an entry updates the DatePickers.\nCross-resource dragging is disabled.",
      "code": "package org.vaadin.stefan.ui.view.demos.componentcolumns;\n\nimport com.vaadin.flow.component.datepicker.DatePicker;\nimport com.vaadin.flow.component.html.Span;\nimport com.vaadin.flow.component.notification.Notification;\nimport com.vaadin.flow.component.orderedlayout.VerticalLayout;\nimport com.vaadin.flow.router.Route;\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.fullcalendar.dataprovider.InMemoryEntryProvider;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.menu.MenuItem;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.util.List;\n\n/**\n * Demo view for component resource area columns (UC-024).\n * <p>\n * Shows a scheduler with tasks assigned to resources. Each resource row has two\n * DatePicker columns (Start, End) that reflect the assigned entry's time range.\n * Changing a DatePicker updates the entry; dragging/resizing an entry updates the DatePickers.\n * Cross-resource dragging is disabled.\n */\n@Route(value = \"component-columns\", layout = MainLayout.class)\n@MenuItem(label = \"Component Columns\")\npublic class ComponentColumnsDemo extends VerticalLayout {\n\n    private final FullCalendarScheduler scheduler;\n    private final ComponentResourceAreaColumn<DatePicker> startColumn;\n    private final ComponentResourceAreaColumn<DatePicker> endColumn;\n    private final InMemoryEntryProvider<Entry> entryProvider;\n\n    public ComponentColumnsDemo() {\n        setSizeFull();\n        setPadding(true);\n\n        addClassName(\"resource-component-columns-view\");\n\n        add(new Span(\"Each resource has a task with Start/End date pickers. \" +\n                \"Edit a date picker to move the entry, or drag/resize the entry to update the pickers.\"));\n\n        // Build scheduler\n        scheduler = new FullCalendarScheduler();\n        scheduler.setOption(FullCalendarScheduler.SchedulerOption.LICENSE_KEY, Scheduler.GPL_V3_LICENSE_KEY);\n        scheduler.addBrowserTimezoneObtainedListener(event -> scheduler.setTimezone(event.getTimezone()));\n\n        scheduler.addThemeVariants(FullCalendarVariant.VAADIN);\n        scheduler.setOption(\"initialView\", SchedulerView.RESOURCE_TIMELINE_MONTH.getClientSideValue());\n        scheduler.setOption(\"initialDate\", LocalDate.of(2025, 3, 1).toString());\n        scheduler.setOption(FullCalendar.Option.ENTRY_DURATION_EDITABLE, true);\n        scheduler.setOption(FullCalendar.Option.EDITABLE, true);\n        // Disable cross-resource dragging\n        scheduler.setOption(FullCalendarScheduler.SchedulerOption.ENTRY_RESOURCES_EDITABLE, false);\n        // Wider resource area to fit both date picker columns\n        scheduler.setOption(FullCalendarScheduler.SchedulerOption.RESOURCE_AREA_WIDTH, \"500px\");\n        // Taller rows for date pickers\n        scheduler.setOption(\"resourceAreaHeaderContent\", \"Project Plan\");\n\n        entryProvider = scheduler.getEntryProvider().asInMemory();\n\n        // Component columns: Start and End date pickers\n        startColumn = new ComponentResourceAreaColumn<>(\"start\", \"Start\",\n                resource -> {\n                    DatePicker picker = createCompactDatePicker();\n                    picker.addValueChangeListener(e -> {\n                        if (e.isFromClient()) {\n                            onStartDateChanged(resource, e.getValue());\n                        }\n                    });\n                    return picker;\n                });\n\n        endColumn = new ComponentResourceAreaColumn<>(\"end\", \"End\",\n                resource -> {\n                    DatePicker picker = createCompactDatePicker();\n                    picker.addValueChangeListener(e -> {\n                        if (e.isFromClient()) {\n                            onEndDateChanged(resource, e.getValue());\n                        }\n                    });\n                    return picker;\n                });\n\n        scheduler.setResourceAreaColumns(List.of(\n                new ResourceAreaColumn(\"title\", \"Task\").withWidth(\"150px\"),\n                startColumn.withWidth(\"170px\"),\n                endColumn.withWidth(\"170px\")\n        ));\n\n        // Resources with entries\n        createResourceWithEntry(\"Design Phase\", \"#3788d8\",\n                LocalDate.of(2025, 3, 3), LocalDate.of(2025, 3, 14));\n        createResourceWithEntry(\"Development\", \"#e53935\",\n                LocalDate.of(2025, 3, 10), LocalDate.of(2025, 3, 25));\n        createResourceWithEntry(\"Testing\", \"#4caf50\",\n                LocalDate.of(2025, 3, 17), LocalDate.of(2025, 3, 28));\n        createResourceWithEntry(\"Deployment\", \"#ff9800\",\n                LocalDate.of(2025, 3, 24), LocalDate.of(2025, 3, 31));\n\n        // Listen for entry drag and resize to update pickers\n        scheduler.addEntryDroppedListener(this::onEntryDropped);\n        scheduler.addEntryResizedListener(this::onEntryResized);\n\n        scheduler.setSizeFull();\n        add(scheduler);\n        setFlexGrow(1, scheduler);\n    }\n\n    private void createResourceWithEntry(String name, String color,\n                                         LocalDate start, LocalDate end) {\n        Resource resource = new Resource(null, name, color);\n        scheduler.addResource(resource);\n\n        ResourceEntry entry = new ResourceEntry();\n        entry.setTitle(name);\n        entry.setStart(start.atStartOfDay());\n        entry.setEnd(end.atStartOfDay());\n        entry.setAllDay(true);\n        entry.setColor(color);\n        entry.addResources(resource);\n        entryProvider.addEntry(entry);\n\n        // Set initial DatePicker values\n        startColumn.getComponent(resource).ifPresent(p -> p.setValue(start));\n        endColumn.getComponent(resource).ifPresent(p -> p.setValue(end));\n    }\n\n    // ---- DatePicker → Entry sync ----\n\n    private void onStartDateChanged(Resource resource, LocalDate newStart) {\n        if (newStart == null) return;\n        findEntryForResource(resource).ifPresent(entry -> {\n            entry.setStart(newStart.atStartOfDay());\n            entryProvider.refreshItem(entry);\n            Notification.show(resource.getTitle() + \" start → \" + newStart, 2000,\n                    Notification.Position.BOTTOM_START);\n        });\n    }\n\n    private void onEndDateChanged(Resource resource, LocalDate newEnd) {\n        if (newEnd == null) return;\n        findEntryForResource(resource).ifPresent(entry -> {\n            entry.setEnd(newEnd.atStartOfDay());\n            entryProvider.refreshItem(entry);\n            Notification.show(resource.getTitle() + \" end → \" + newEnd, 2000,\n                    Notification.Position.BOTTOM_START);\n        });\n    }\n\n    // ---- Entry drag/resize → DatePicker sync ----\n\n    private void onEntryDropped(EntryDroppedEvent event) {\n        event.applyChangesOnEntry();\n        syncPickersFromEntry(event.getEntry());\n    }\n\n    private void onEntryResized(EntryResizedEvent event) {\n        event.applyChangesOnEntry();\n        syncPickersFromEntry(event.getEntry());\n    }\n\n    private void syncPickersFromEntry(Entry entry) {\n        if (!(entry instanceof ResourceEntry re)) return;\n\n        for (Resource resource : re.getResources()) {\n            LocalDateTime start = entry.getStart();\n            LocalDateTime end = entry.getEnd();\n\n            startColumn.getComponent(resource).ifPresent(p ->\n                    p.setValue(start != null ? start.toLocalDate() : null));\n            endColumn.getComponent(resource).ifPresent(p ->\n                    p.setValue(end != null ? end.toLocalDate() : null));\n        }\n    }\n\n    // ---- Helper ----\n\n    private DatePicker createCompactDatePicker() {\n        DatePicker picker = new DatePicker();\n        picker.setWidth(\"130px\");\n        picker.getStyle().set(\"--vaadin-input-field-height\", \"32px\");\n        picker.getStyle().set(\"font-size\", \"var(--lumo-font-size-s)\");\n        return picker;\n    }\n\n    private java.util.Optional<ResourceEntry> findEntryForResource(Resource resource) {\n        return entryProvider.getEntries().stream()\n                .filter(e -> e instanceof ResourceEntry)\n                .map(e -> (ResourceEntry) e)\n                .filter(e -> e.getResources().contains(resource))\n                .findFirst();\n    }\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "resource",
        "scheduler",
        "timezone",
        "event",
        "listener",
        "drop",
        "resize",
        "style",
        "theme",
        "view",
        "create",
        "update"
      ]
    },
    {
      "id": "demo-democustomproperties",
      "title": "Demo Custom Properties",
      "description": "Demo: DemoCustomProperties",
      "code": "package org.vaadin.stefan.ui.view.demos.customproperties;\n\nimport java.time.LocalDate;\nimport java.time.LocalTime;\nimport java.util.UUID;\n\nimport org.vaadin.stefan.fullcalendar.CalendarViewImpl;\nimport org.vaadin.stefan.fullcalendar.Entry;\nimport org.vaadin.stefan.fullcalendar.FullCalendar;\nimport org.vaadin.stefan.fullcalendar.JsCallback;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.menu.MenuItem;\n\nimport com.vaadin.flow.component.orderedlayout.VerticalLayout;\nimport com.vaadin.flow.router.Route;\n\nimport static org.vaadin.stefan.fullcalendar.FullCalendar.Option.*;\n\n@Route(value = \"demoextendedprops\", layout = MainLayout.class)\n@MenuItem(label = \"Custom Properties\")\npublic class DemoCustomProperties extends VerticalLayout {\n\tprivate static final long serialVersionUID = -117988331031719049L;\n\n\tprivate FullCalendar calendar;\n\t\n\tprivate Entry selected;\n\n    public DemoCustomProperties() {\n    \tcreateCalendarInstance();\n    \taddDemoEntrys();\n\n        setSizeFull();\n        add(calendar);\n        setDefaultHorizontalComponentAlignment(Alignment.STRETCH);\n        setFlexGrow(1, calendar);\n    }\n    \n    private void createCalendarInstance() {\n    \tcalendar = new FullCalendar();\n    \t\n    \tcalendar.changeView(CalendarViewImpl.DAY_GRID_MONTH);\n\n        calendar.setOption(ENTRY_DID_MOUNT,\n                JsCallback.of(\"function (info) {\" +\n                \"info.el.style.backgroundColor = info.event.getCustomProperty('selected', false) ? 'lightblue' : 'lightgreen';\" +\n                \"}\"));\n\n        calendar.addEntryClickedListener(e -> {\n            Entry oldSelected = this.selected;\n            if (oldSelected != null) {\n                oldSelected.setCustomProperty(\"selected\", false);\n            }\n\n            var entryProvider = calendar.getEntryProvider().asInMemory();\n\n            this.selected = e.getEntry();\n            this.selected.setCustomProperty(\"selected\", true);\n            if (oldSelected != null) {\n                entryProvider.removeEntries(oldSelected, this.selected);\n                entryProvider.addEntries(oldSelected, this.selected);\n\n            } else {\n                entryProvider.removeEntries(this.selected);\n                entryProvider.addEntries(this.selected);\n            }\n        });\n\n        calendar.setOption(HEIGHT, \"100%\");\n    }\n    \n    private void addDemoEntrys() {\n    \tfor (int i = 1; i < 10; i++) {\n            LocalDate now = LocalDate.now();\n            LocalDate start = now.withDayOfMonth((int)(Math.random() * 28) + 1);\n            LocalDate end = start.plusDays(1);\n            Entry entry = new Entry(UUID.randomUUID().toString());\n            entry.setColor(\"lightgreen\");\n            entry.setTitle(\"Entry \" + i);\n            entry.setStart(start.atStartOfDay());\n            entry.setEnd(end.atTime(LocalTime.MAX));\n            if (i == 1) {\n                entry.setCustomProperty(\"selected\", true);\n                selected = entry;\n            }\n            calendar.getEntryProvider().asInMemory().addEntry(entry);\n        }\n    }\n    \n\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "callback",
        "inmemory",
        "event",
        "listener",
        "click",
        "style",
        "view",
        "create"
      ]
    },
    {
      "id": "demo-anonymouscustomviewdemo",
      "title": "Anonymous Custom View Demo",
      "description": "Demo: AnonymousCustomViewDemo",
      "code": "package org.vaadin.stefan.ui.view.demos.customtimeline;\n\nimport com.vaadin.flow.component.UI;\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.ui.view.AbstractSchedulerView;\nimport org.vaadin.stefan.ui.view.demos.entryproviders.EntryService;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport java.util.List;\n\n// not a registered route since it shall only provide some sample code for the \"old\" way of adding custom views\npublic class AnonymousCustomViewDemo extends AbstractSchedulerView {\n\n    private SomeCalendarView calendarView;\n\n    @Override\n    protected FullCalendar createCalendar(ObjectNode defaultInitialOptions) {\n        calendarView = new SomeCalendarView(28);\n        FullCalendarScheduler calendar = new FullCalendarScheduler(calendarView.getInitialOptions());\n        calendar.setOption(FullCalendarScheduler.SchedulerOption.LICENSE_KEY, Scheduler.GPL_V3_LICENSE_KEY);\n        calendar.setLocale(UI.getCurrent().getLocale());\n\n        List<Entry> entries = EntryService.createRandomInstance().getEntries();\n        calendar.getEntryProvider().asInMemory().addEntries(entries);\n\n        return calendar;\n    }\n\n    @Override\n    protected void postConstruct(FullCalendar calendar) {\n        calendar.changeView(calendarView);\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"This demo shows how the calendar handles the \\\"old\\\" way of adding custom views. \" +\n                \"The custom view is the same as in the Custom View Demo, but the view is created using the initial options.\";\n    }\n\n    @Override\n    protected String createTitle() {\n        return \"Anonymous Custom View Demo\";\n    }\n\n\n    private static class SomeCalendarView implements CalendarView {\n        private final int numberOfDays;\n\n        public SomeCalendarView(int numberOfDays) {\n            this.numberOfDays = numberOfDays;\n        }\n\n        @Override\n        public String getClientSideValue() {\n            return \"fixedDaysResourceTimelineAnonymous\";\n        }\n\n        public ObjectNode getInitialOptions() {\n            ObjectNode initialOptions = JsonFactory.createObject();\n\n            ObjectNode durationHolder = JsonFactory.createObject();\n            durationHolder.set(\"days\", JsonFactory.create(numberOfDays));\n\n            ObjectNode customViewHolder = JsonFactory.createObject();\n            customViewHolder.set(\"type\", JsonFactory.create(\"resourceTimeline\"));\n            customViewHolder.set(\"duration\", durationHolder);\n\n            ObjectNode viewsHolder = JsonFactory.createObject();\n            viewsHolder.set(getClientSideValue(), customViewHolder);\n\n            initialOptions.set(\"views\", viewsHolder);\n\n            return initialOptions;\n        }\n\n        @Override\n        public String getName() {\n            return \"Fixed Days Resource Timeline (anonymous)\";\n        }\n    }\n\n    @Override\n    protected boolean isToolbarViewChangeable() {\n        return false;\n    }\n}",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "resource",
        "scheduler",
        "view",
        "create"
      ]
    },
    {
      "id": "demo-customviewdemo",
      "title": "Custom View Demo",
      "description": "Demo: CustomViewDemo",
      "code": "package org.vaadin.stefan.ui.view.demos.customtimeline;\n\nimport com.vaadin.flow.component.UI;\nimport com.vaadin.flow.router.Route;\n\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.menu.MenuItem;\nimport org.vaadin.stefan.ui.view.AbstractSchedulerView;\nimport org.vaadin.stefan.ui.view.demos.entryproviders.EntryService;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport java.util.List;\n\n@Route(value = \"custom-view\", layout = MainLayout.class)\n@MenuItem(label = \"Custom View\")\npublic class CustomViewDemo extends AbstractSchedulerView {\n\n    private FixedDaysCalendarView calendarView;\n\n    @Override\n    protected FullCalendar createCalendar(ObjectNode defaultInitialOptions) {\n        calendarView = new FixedDaysCalendarView(28);\n\n        // test for duplicat registration (anonymous and named)\n//        ObjectNode initialOptions = Json.createObject();\n//        ObjectNode views = Json.createObject();\n//        views.put(calendarView.getClientSideValue(), new FixedDaysCalendarView(5).getViewSettings());\n//        initialOptions.put(\"views\", views);\n\n        FullCalendarScheduler calendar = new FullCalendarScheduler();\n        calendar.setOption(FullCalendarScheduler.SchedulerOption.LICENSE_KEY, Scheduler.GPL_V3_LICENSE_KEY);\n        calendar.setCustomCalendarViews(calendarView);\n        calendar.setLocale(UI.getCurrent().getLocale());\n\n        List<Entry> entries = EntryService.createRandomInstance().getEntries();\n        calendar.getEntryProvider().asInMemory().addEntries(entries);\n\n        return calendar;\n    }\n\n    @Override\n    protected void postConstruct(FullCalendar calendar) {\n        calendar.changeView(calendarView);\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"This demo shows how to create a custom view. The view is based on the timeline view, but only shows a\" +\n                \" fixed number of days. The view is configured to show 28 days.\";\n    }\n\n    @Override\n    protected String createTitle() {\n        return \"Custom View Demo\";\n    }\n\n    @Override\n    protected boolean isToolbarViewChangeable() {\n        return false;\n    }\n\n\n}",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "scheduler",
        "view",
        "create"
      ]
    },
    {
      "id": "demo-abstractentryproviderdemo",
      "title": "Abstract Entry Provider Demo",
      "description": "Demo: AbstractEntryProviderDemo",
      "code": "package org.vaadin.stefan.ui.view.demos.entryproviders;\n\nimport com.vaadin.flow.component.notification.Notification;\nimport lombok.AccessLevel;\nimport lombok.Getter;\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.fullcalendar.dataprovider.EntryProvider;\nimport org.vaadin.stefan.ui.dialogs.DemoDialog;\nimport org.vaadin.stefan.ui.view.AbstractCalendarView;\nimport org.vaadin.stefan.ui.view.CalendarViewToolbar;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport java.util.Collections;\n\n/**\n * An abstract demo class for the different entry provider variants. Does not provide much functionality\n * beside the loading and displayment of entries plus some simple click, dropped and resized listeners.\n * <p></p>\n * Also delegates CRUD operations of the toolbar and the calendar to the entry service and refreshes\n * the entry provider based on the modifications.\n * <p></p>\n * The entry service is always instantiated with random data.\n * @author Stefan Uebe\n */\n@Getter(AccessLevel.PROTECTED)\npublic abstract class AbstractEntryProviderDemo extends AbstractCalendarView {\n\n    private EntryService entryService;\n    private EntryProvider<Entry> entryProvider;\n\n    @Override\n    protected FullCalendar createCalendar(ObjectNode defaultInitialOptions) {\n        entryService = EntryService.createRandomInstance();\n        entryProvider = createEntryProvider(entryService);\n\n        FullCalendar calendar = new FullCalendar(defaultInitialOptions);\n        calendar.setEntryProvider(entryProvider);\n        calendar.setOption(FullCalendar.Option.MAX_ENTRIES_PER_DAY, 3);\n        return calendar;\n    }\n\n    @Override\n    protected CalendarViewToolbar createToolbar(CalendarViewToolbar.CalendarViewToolbarBuilder toolbarBuilder) {\n        return super.createToolbar(toolbarBuilder.allowAddingRandomItemsInitially(false));\n    }\n\n    /**\n     * Creates the demo's specific entry provider and initializes it with the necessary data.\n     * @param entryService entry service\n     * @return entry provider\n     */\n    protected abstract EntryProvider<Entry> createEntryProvider(EntryService<Entry> entryService);\n\n    @Override\n    protected void onTimeslotsSelected(TimeslotsSelectedEvent event) {\n        Entry entry = createNewEntry();\n\n        entry.setStart(event.getStart());\n        entry.setEnd(event.getEnd());\n        entry.setAllDay(event.isAllDay());\n\n        entry.setColor(\"green\");\n        entry.setCalendar(event.getSource());\n        DemoDialog dialog = new DemoDialog(entry, true);\n        dialog.setSaveConsumer(e -> onEntriesCreated(Collections.singletonList(e)));\n        dialog.open();\n    }\n\n    protected abstract Entry createNewEntry();\n\n    @Override\n    protected void onEntryClick(EntryClickedEvent event) {\n        DemoDialog dialog = new DemoDialog(event.getEntry(), false);\n        dialog.setSaveConsumer(this::onEntryChanged);\n        dialog.setDeleteConsumer(e -> onEntriesRemoved(Collections.singletonList(e)));\n        dialog.open();\n    }\n\n    @Override\n    protected void onEntryDropped(EntryDroppedEvent event) {\n        super.onEntryDropped(event);\n        Notification.show(\"Dropped entry \" + event.getEntry().getId());\n    }\n\n    @Override\n    protected void onEntryResized(EntryResizedEvent event) {\n        super.onEntryResized(event);\n        Notification.show(\"Resized entry \" + event.getEntry().getId());\n    }\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "event",
        "listener",
        "click",
        "drop",
        "resize",
        "view",
        "builder",
        "crud",
        "create",
        "delete"
      ]
    },
    {
      "id": "demo-backendentryproviderdemo",
      "title": "Backend Entry Provider Demo",
      "description": "This demo shows an EntryProvider implementation, that fetches its data from\na simulated database. Items are created temporary based on the respective backend entities.\n@author Stefan Uebe",
      "code": "package org.vaadin.stefan.ui.view.demos.entryproviders;\n\nimport com.vaadin.flow.router.Route;\nimport lombok.NonNull;\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.fullcalendar.dataprovider.AbstractEntryProvider;\nimport org.vaadin.stefan.fullcalendar.dataprovider.EntryProvider;\nimport org.vaadin.stefan.fullcalendar.dataprovider.EntryQuery;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\n\nimport java.util.Collection;\nimport java.util.Optional;\nimport java.util.stream.Stream;\n\n/**\n * This demo shows an EntryProvider implementation, that fetches its data from\n * a simulated database. Items are created temporary based on the respective backend entities.\n * @author Stefan Uebe\n */\n@Route(value = \"backend-entry-provider\", layout = MainLayout.class)\n@org.vaadin.stefan.ui.menu.MenuItem(label = \"Backend Entry Provider\")\npublic class BackendEntryProviderDemo extends AbstractEntryProviderDemo {\n\n    @Override\n    protected EntryProvider<Entry> createEntryProvider(EntryService<Entry> entryService) {\n        return new BackendEntryProvider(entryService);\n    }\n\n    @Override\n    protected Entry createNewEntry() {\n        return getEntryService().createNewInstance();\n    }\n\n    @Override\n    protected void onEntriesCreated(Collection<Entry> entries) {\n        getEntryService().addEntries(entries);\n        getEntryProvider().refreshAll();\n    }\n\n    protected void onEntryChanged(Entry entry) {\n        getEntryService().updateEntry(entry);\n        getEntryProvider().refreshItem(entry);\n    }\n\n    @Override\n    protected void onEntriesRemoved(Collection<Entry> entries) {\n        getEntryService().removeEntries(entries);\n        getEntryProvider().refreshAll();\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"This demo shows an EntryProvider implementation, that fetches its data from \" +\n                \"a simulated database. Items are created temporary based on the respective backend entities.\";\n    }\n\n    private static class BackendEntryProvider extends AbstractEntryProvider<Entry> {\n\n        private final EntryService service;\n\n        public BackendEntryProvider(EntryService service) {\n            this.service = service;\n        }\n\n        @Override\n        public Stream<Entry> fetch(@NonNull EntryQuery query) {\n            return service.streamEntries(query);\n        }\n\n        @Override\n        public Optional<Entry> fetchById(@NonNull String id) {\n            return service.getEntry(id);\n        }\n    }\n\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "view",
        "create",
        "update"
      ]
    },
    {
      "id": "demo-callbackentryproviderdemo",
      "title": "Callback Entry Provider Demo",
      "description": "This sample shows the usage of the CallbackEntryProvider. This variant can be instantiated on the\nfly providing a single callback to stream entries for the requested timespan.\n@author Stefan Uebe",
      "code": "package org.vaadin.stefan.ui.view.demos.entryproviders;\n\nimport com.vaadin.flow.router.Route;\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.fullcalendar.dataprovider.CallbackEntryProvider;\nimport org.vaadin.stefan.fullcalendar.dataprovider.EntryProvider;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\n\nimport java.util.Collection;\n\n/**\n * This sample shows the usage of the CallbackEntryProvider. This variant can be instantiated on the\n * fly providing a single callback to stream entries for the requested timespan.\n * @author Stefan Uebe\n */\n@Route(value = \"callback-entry-provider\", layout = MainLayout.class)\n@org.vaadin.stefan.ui.menu.MenuItem(label = \"Callback Entry Provider\")\npublic class CallbackEntryProviderDemo extends AbstractEntryProviderDemo {\n\n    @Override\n    protected EntryProvider<Entry> createEntryProvider(EntryService<Entry> entryService) {\n        // Variant A - the backend service takes care of filtering the entries before returning them\n        CallbackEntryProvider<Entry> entryProvider = EntryProvider.fromCallbacks(\n                query -> entryService.streamEntries(query),\n                entryId -> entryService.getEntry(entryId).orElse(null)\n        );\n        // Variant B - the backend service returns a plain stream an the callback takes care of filtering the returned entries (may be less performant)\n        // entryProvider = EntryProvider.fromCallbacks(query -> {\n        //     Stream<Entry> stream = entryService.streamEntries();\n        //     stream = query.applyFilter(stream); // a query built in method to filter entry streams based on the query\n        //     return stream;\n        // }, entryId -> entryService.getEntry(entryId).orElse(null));\n\n        return entryProvider;\n    }\n\n    @Override\n    protected Entry createNewEntry() {\n        return getEntryService().createNewInstance();\n    }\n\n    @Override\n    protected void onEntriesCreated(Collection<Entry> entries) {\n        getEntryService().addEntries(entries);\n        getEntryProvider().refreshAll();\n    }\n\n    @Override\n    protected void onEntryChanged(Entry entry) {\n        getEntryService().updateEntry(entry);\n        getEntryProvider().refreshItem(entry);\n    }\n\n    @Override\n    protected void onEntriesRemoved(Collection<Entry> entries) {\n        getEntryService().removeEntries(entries);\n        getEntryProvider().refreshAll();\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"This sample shows the usage of the CallbackEntryProvider. This variant can be instantiated on the \" +\n                \"fly providing a single callback to stream entries for the requested timespan.\";\n    }\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "callback",
        "view",
        "create",
        "update"
      ]
    },
    {
      "id": "demo-inmemoryentryproviderdemo",
      "title": "In Memory Entry Provider Demo",
      "description": "This demo shows the usage of the InMemoryEntryProvider. It stores all its data on the server side\nwhile the client only receives the necessary data. This allows a mixture of easy in memory editing\nvia the CRUD API without a heavy memory impact on the client.\n@author Stefan Uebe",
      "code": "package org.vaadin.stefan.ui.view.demos.entryproviders;\n\nimport com.vaadin.flow.router.Route;\nimport org.vaadin.stefan.fullcalendar.Entry;\nimport org.vaadin.stefan.fullcalendar.dataprovider.EntryProvider;\nimport org.vaadin.stefan.fullcalendar.dataprovider.InMemoryEntryProvider;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * This demo shows the usage of the InMemoryEntryProvider. It stores all its data on the server side\n * while the client only receives the necessary data. This allows a mixture of easy in memory editing\n * via the CRUD API without a heavy memory impact on the client.\n *\n * @author Stefan Uebe\n */\n@Route(value = \"in-memory-entry-provider\", layout = MainLayout.class)\n@org.vaadin.stefan.ui.menu.MenuItem(label = \"In Memory Entry Provider\")\npublic class InMemoryEntryProviderDemo extends AbstractEntryProviderDemo {\n\n\n    @Override\n    protected EntryProvider<Entry> createEntryProvider(EntryService<Entry> entryService) {\n        List<Entry> entries = entryService.streamEntries().collect(Collectors.toList());\n\n        // The list is used to initialize the in memory provider, but different to the ListDataProvider it is\n        // not used as the backing collection.\n        return EntryProvider.inMemoryFrom(entries);\n    }\n\n    @Override\n    protected Entry createNewEntry() {\n        return new Entry();\n    }\n\n    @Override\n    protected void onEntriesCreated(Collection<Entry> entries) {\n        // The lazy in memory provider provides API to modify its internal cache. To inform the client about\n        // the change a refresh call is necessary.\n        InMemoryEntryProvider<Entry> provider = getEntryProvider();\n        provider.addEntries(entries);\n        provider.refreshAll();\n    }\n\n    @Override\n    protected void onEntriesRemoved(Collection<Entry> entries) {\n        // The lazy in memory provider provides API to modify its internal cache. To inform the client about\n        // the change a refresh call is necessary.\n        InMemoryEntryProvider<Entry> provider = getEntryProvider();\n        provider.removeEntries(entries);\n        provider.refreshAll();\n    }\n\n    @Override\n    protected void onEntryChanged(Entry entry) {\n        // To inform the client about the change a refresh call is necessary.\n        getEntryProvider().refreshItem(entry);\n    }\n\n    @Override\n    protected InMemoryEntryProvider<Entry> getEntryProvider() {\n        return (InMemoryEntryProvider<Entry>) super.getEntryProvider();\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"This demo shows the usage of the InMemoryEntryProvider. It stores all its data on the server side \" +\n                \"while the client only receives the necessary data. This allows a mixture of easy in memory editing \" +\n                \"via the CRUD API without a heavy memory impact on the client.\";\n    }\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "view",
        "crud",
        "create"
      ]
    },
    {
      "id": "demo-externaldragdemo",
      "title": "External Drag Demo",
      "description": "Demonstrates the {@link Draggable} API for dragging external Vaadin components\nonto the calendar.",
      "code": "package org.vaadin.stefan.ui.view.demos.externaldrag;\n\nimport com.vaadin.flow.component.html.Div;\nimport com.vaadin.flow.component.html.Span;\nimport com.vaadin.flow.component.notification.Notification;\nimport com.vaadin.flow.component.orderedlayout.HorizontalLayout;\nimport com.vaadin.flow.router.Route;\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.fullcalendar.dataprovider.InMemoryEntryProvider;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.menu.MenuItem;\nimport org.vaadin.stefan.ui.view.AbstractCalendarView;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport java.time.LocalDateTime;\n\n/**\n * Demonstrates the {@link Draggable} API for dragging external Vaadin components\n * onto the calendar.\n */\n@Route(value = \"external-drag\", layout = MainLayout.class)\n@MenuItem(label = \"External Drag\")\npublic class ExternalDragDemo extends AbstractCalendarView {\n\n    @Override\n    protected FullCalendar createCalendar(ObjectNode defaultInitialOptions) {\n        FullCalendar calendar = new FullCalendar(defaultInitialOptions);\n        calendar.setOption(FullCalendar.Option.MAX_ENTRIES_PER_DAY, 3);\n\n        calendar.setOption(FullCalendar.Option.DROPPABLE, true);\n\n        InMemoryEntryProvider<Entry> provider = new InMemoryEntryProvider<>();\n        calendar.setEntryProvider(provider);\n\n        // --- Drop listener ---\n        calendar.addDropListener(e -> {\n            String componentInfo = e.getDraggable()\n                    .map(Draggable::getComponent)\n                    .map(c -> c.getElement().getText())\n                    .orElse(\"unknown\");\n            String entryInfo = e.getDraggable()\n                    .flatMap(Draggable::getEntryData)\n                    .map(Entry::getTitle)\n                    .orElse(\"no entry data\");\n\n            Notification.show(\n                    \"Dropped '\" + componentInfo + \"' on \" + e.getDate()\n                            + \" (entry: \" + entryInfo + \")\",\n                    3000, Notification.Position.BOTTOM_START);\n        });\n\n        // --- Entry receive listener: persist the client-created entry ---\n        calendar.addEntryReceiveListener(e -> {\n            provider.addEntry(e.getEntry());\n            provider.refreshAll();\n        });\n\n\n\n\n        return calendar;\n    }\n\n    @Override\n    protected void postConstruct(FullCalendar calendar) {\n\n        // --- Container draggable with itemSelector + eventData callback ---\n        Div taskList = new Div();\n        taskList.getStyle()\n                .set(\"border\", \"1px solid #ccc\")\n                .setBorderRadius(\"var(--vaadin-radius-m)\")\n                .set(\"padding\", \"8px\")\n                .set(\"margin-bottom\", \"8px\");\n        taskList.add(new Span(\"Task list (drag individual items):\"));\n\n        for (String task : new String[]{\"Write report\", \"Fix bug #42\", \"Review PR\", \"Deploy v2.0\"}) {\n            Div item = new Div(new Span(task));\n            item.addClassName(\"task-item\");\n            item.getStyle()\n                    .set(\"padding\", \"4px 12px\")\n                    .set(\"margin\", \"4px 0\")\n                    .set(\"background\", \"var(--vaadin-background-container-strong)\")\n                    .set(\"cursor\", \"grab\")\n                    .setBorderRadius(\"var(--vaadin-radius-m)\");\n            taskList.add(item);\n        }\n\n        // Register as container draggable: children with .task-item are draggable,\n        // eventData callback creates entry from the dragged element's text\n        calendar.addDraggable(new Draggable(taskList)\n                .withItemSelector(\".task-item\")\n                .withEventDataCallback(JsCallback.of(\n                        \"function(el) { console.info(el); return { title: el.innerText, duration: '01:00' }; }\")));\n        // Insert drag items and task list before the calendar\n\n\n        // --- Draggable items ---\n        HorizontalLayout dragItems = new HorizontalLayout();\n        dragItems.setSpacing(true);\n        dragItems.getStyle().set(\"margin-bottom\", \"8px\");\n\n        // All Day Event — green, all-day\n        Entry allDayEntry = new Entry();\n        allDayEntry.setTitle(\"All Day Event\");\n        allDayEntry.setAllDay(true);\n        allDayEntry.setColor(\"#4CAF50\");\n        Div allDayItem = createDragItem(\"All Day Event\", \"#4CAF50\");\n\n        // Lunch Break — orange, timed for 30 min (drop time determined by target slot)\n        Entry lunchEntry = new Entry();\n        lunchEntry.setTitle(\"Lunch Break\");\n        lunchEntry.setColor(\"#FF9800\");\n        lunchEntry.setAllDay(false);\n        lunchEntry.setRecurringDuration(\"00:30\");\n        Div lunchItem = createDragItem(\"Lunch Break\", \"#FF9800\");\n\n        // Task — blue, no entry data\n        Div taskItem = createDragItem(\"Task\", \"#2196F3\");\n\n        dragItems.add(allDayItem, lunchItem, taskItem);\n\n        // Register draggables on the calendar\n        calendar.addDraggable(new Draggable(allDayItem, allDayEntry));\n        calendar.addDraggable(new Draggable(lunchItem, lunchEntry));\n        calendar.addDraggable(new Draggable(taskItem));  // no entry data — title will be empty on drop\n\n        int i = indexOf(getToolbar());\n\n        addComponentAtIndex(i, taskList);\n        addComponentAtIndex(i, dragItems);\n    }\n\n    private Div createDragItem(String label, String color) {\n        Div item = new Div(new Span(label));\n        item.getStyle()\n                .set(\"padding\", \"8px 16px\")\n                .set(\"background\", color)\n                .set(\"color\", \"white\")\n                .set(\"cursor\", \"grab\")\n                .set(\"border-radius\", \"4px\")\n                .set(\"user-select\", \"none\");\n        return item;\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"Drag the colored items onto the calendar. \" +\n                \"'All Day Event' creates an all-day entry (green). \" +\n                \"'Lunch Break' creates a timed entry at 12:00 (orange). \" +\n                \"'Task' has no entry data. \" +\n                \"The task list below demonstrates container dragging with itemSelector — \" +\n                \"each item generates entry data dynamically via a JS callback.\";\n    }\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "callback",
        "inmemory",
        "recurring",
        "event",
        "listener",
        "drop",
        "style",
        "view",
        "create"
      ]
    },
    {
      "id": "demo-fulldemo",
      "title": "Full Demo",
      "description": "Demo: FullDemo",
      "code": "/*\n * Copyright 2020, Stefan Uebe\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions\n * of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\npackage org.vaadin.stefan.ui.view.demos.full;\n\nimport com.vaadin.flow.component.ClientCallable;\nimport com.vaadin.flow.component.UI;\nimport com.vaadin.flow.component.dependency.CssImport;\nimport com.vaadin.flow.component.listbox.ListBox;\nimport com.vaadin.flow.component.notification.Notification;\nimport com.vaadin.flow.component.popover.Popover;\nimport com.vaadin.flow.router.Route;\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.ui.dialogs.DemoDialog;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.view.AbstractSchedulerView;\nimport org.vaadin.stefan.util.EntryManager;\nimport org.vaadin.stefan.util.ResourceManager;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport java.time.DayOfWeek;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport static org.vaadin.stefan.fullcalendar.FullCalendar.Option.*;\n\n@Route(value = \"\", layout = MainLayout.class)\n@org.vaadin.stefan.ui.menu.MenuItem(label = \"Playground\")\npublic class FullDemo extends AbstractSchedulerView {\n\n    private Popover popup;\n\n    @Override\n    protected FullCalendar createCalendar(ObjectNode initialOptions) {\n//        initialOptions.put(\"eventContent\",\n//                \"function(arg, createElement) {\" +\n//                \" console.warn('hello');\" +\n//                \"  return 'WORLD';\" +\n//                \"}\");\n\n        FullCalendarScheduler scheduler = new FullCalendarScheduler(initialOptions);\n        scheduler.setOption(FullCalendarScheduler.SchedulerOption.LICENSE_KEY, Scheduler.GPL_V3_LICENSE_KEY);\n        scheduler.setOption(FullCalendar.Option.MAX_ENTRIES_PER_DAY, 3);\n        scheduler.addBrowserTimezoneObtainedListener(event -> scheduler.setTimezone(event.getTimezone()));\n        scheduler.setLocale(UI.getCurrent().getLocale());\n        FullCalendar calendar = scheduler;\n        scheduler.setOption(FullCalendarScheduler.SchedulerOption.RESOURCE_AREA_WIDTH, \"15%\");\n        scheduler.setOption(FullCalendarScheduler.SchedulerOption.SLOT_MIN_WIDTH, 100);\n        scheduler.setOption(FullCalendarScheduler.SchedulerOption.RESOURCES_INITIALLY_EXPANDED, false);\n\n        calendar.setOption(NOW_INDICATOR, true);\n        calendar.setOption(SELECTABLE, true);\n\n        calendar.setOption(NAV_LINKS, true);\n        calendar.addDayNumberClickedListener(event -> {\n            calendar.changeView(CalendarViewImpl.TIME_GRID_DAY);\n            calendar.gotoDate(event.getDate());\n        });\n\n        calendar.addWeekNumberClickedListener(event -> {\n            calendar.changeView(CalendarViewImpl.TIME_GRID_WEEK);\n            calendar.gotoDate(event.getDate());\n        });\n\n        // initally change the view and go to a specific date - attention: this will not fire listeners as the client side is not initialized yet\n//        calendar.changeView(CalendarViewImpl.TIME_GRID_WEEK);\n//        calendar.gotoDate(LocalDate.of(2023, Month.JUNE, 1));\n\n        calendar.setOption(SLOT_MIN_TIME, LocalTime.of(7, 0));\n        calendar.setOption(SLOT_MAX_TIME, LocalTime.of(17, 0));\n\n        calendar.setOption(BUSINESS_HOURS, new BusinessHours[]{\n                BusinessHours.businessWeek().start(9).end(17),\n                BusinessHours.of(DayOfWeek.SATURDAY).start(12).end(15),\n                BusinessHours.of(DayOfWeek.SUNDAY).start(12).end(13)\n        });\n\n        calendar.addBrowserTimezoneObtainedListener(event -> {\n            getToolbar().setTimezone(event.getTimezone());\n        });\n\n        LocalDate now = LocalDate.now();\n        EntryManager.createDayEntry(calendar, \"Test 1\", now.withDayOfMonth(12), 2, \"lightgreen\")\n                .setCustomProperty(\"count\", \"3\");\n        EntryManager.createDayEntry(calendar, \"Test 2\", now.withDayOfMonth(12), 2, \"tomato\")\n                .setCustomProperty(\"count\", \"2\");\n        EntryManager.createDayEntry(calendar, \"Test 3\", now.withDayOfMonth(12), 2, \"lightblue\")\n                .setCustomProperty(\"count\", \"1\");\n\n        scheduler.setOption(FullCalendarScheduler.SchedulerOption.ENTRY_RESOURCES_EDITABLE, false);\n\n//        calendar.setEntryClassNamesCallback(\"function(arg) {\\n\" +\n//                \"    return [ 'hello','world' ]\\n\" +\n//                \"}\");\n//        calendar.setEntryContentCallback(\"\" +\n//                \"function(arg, createElement) {\" +\n//                \" console.warn('hello');\" +\n//                \"  return 'WORLD';\" +\n//                \"}\");\n\n\n\n//        calendar.addEntryNativeEventListener(\"mouseover\", \"e => info.el.style.opacity = '0.5'\");\n//        calendar.addEntryNativeEventListener(\"mouseout\", \"e => info.el.style.opacity = ''\");\n//        calendar.addEntryNativeEventListener(\"contextmenu\", \"e => console.warn('just a context menu event')\");\n\n        calendar.addEntryNativeEventListener(\"contextmenu\",\n                \"e => {\" +\n                \"   e.preventDefault(); \" +\n                \"   this.el.parentElement.$server.openContextMenu(info.event.id);\" +\n                \"}\");\n//        calendar.setEntryDidMountCallback(\"\"\"\n//                function(info) {\n//                    info.el.id = \"entry-\" + info.event.id;\n//                }\"\"\");\n\n//\n//        scheduler.setResourceLabelContentCallback(\n//                \"function(arg, createElement) {\" +\n//                \" console.warn('hello');\" +\n//                \"  return 'Hello';\" +\n//                \"}\");\n//\n//        scheduler.setResourceLaneContentCallback(\n//                \"function(arg, createElement) {\" +\n//                \" console.warn('world');\" +\n//                \"  return 'World';\" +\n//                \"}\");\n\n        createTestEntries(calendar);\n\n//        calendar.changeView(CalendarViewImpl.MULTI_MONTH);\n//        calendar.gotoDate(LocalDate.now().plusYears(1));\n\n\n        return calendar;\n    }\n\n    private void initPopup() {\n        if (popup == null) {\n            popup = new Popover();\n//            popup.setFocusTrap(true);\n            add(popup);\n        }\n    }\n\n    @ClientCallable\n    public void openContextMenu(String id) {\n        initPopup();\n\n        popup.removeAll();\n\n        ListBox<String> listBox = new ListBox<>();\n        listBox.setItems(\"Option A\", \"Option B\", \"Option C\");\n        listBox.addValueChangeListener(event -> {\n            Notification.show(\"Selected \" + event.getValue());\n            popup.close();\n        });\n\n        popup.add(listBox);\n        popup.setFor(\"entry-\" + id);\n\n        popup.open();\n    }\n\n    private void createTestEntries(FullCalendar calendar) {\n        LocalDate now = LocalDate.now();\n\n        Resource meetingRoomRed = ResourceManager.createResource((Scheduler) calendar, \"Meetingroom Red\", \"#ff0000\");\n        Resource meetingRoomGreen = ResourceManager.createResource((Scheduler) calendar, \"Meetingroom Green\", \"green\");\n        Resource meetingRoomBlue = ResourceManager.createResource((Scheduler) calendar, \"Meetingroom Blue\", \"blue\");\n        Resource meetingRoomOrange = ResourceManager.createResource((Scheduler) calendar, \"Meetingroom Orange\", \"orange\", null,\n                BusinessHours.businessWeek().start(9).end(17));\n\n        Resource computer1A = ResourceManager.createResource((Scheduler) calendar, \"Computer 1A\", \"lightbrown\");\n        Resource computer1B = ResourceManager.createResource((Scheduler) calendar, \"Computer 1B\", \"lightbrown\");\n        Resource computer1C = ResourceManager.createResource((Scheduler) calendar, \"Computer 1C\", \"lightbrown\");\n\n        ResourceManager.createResource((Scheduler) calendar, \"Computer room 1\", \"brown\", Arrays.asList(computer1A, computer1B, computer1C));\n\n        Resource computerRoom2 = ResourceManager.createResource((Scheduler) calendar, \"Computer room 2\", \"brown\");\n        // here we must NOT use createResource, since they are added to the calendar later\n        Resource computer2A = new Resource(null, \"Computer 2A\", \"lightbrown\");\n        Resource computer2B = new Resource(null, \"Computer 2B\", \"lightbrown\");\n        Resource computer2C = new Resource(null, \"Computer 2C\", \"lightbrown\");\n\n        // not realistic, just a demonstration of automatic recursive adding\n        computer2A.addChild(new Resource(null, \"Mouse\", \"orange\"));\n        computer2A.addChild(new Resource(null, \"Screen\", \"orange\"));\n        computer2A.addChild(new Resource(null, \"Keyboard\", \"orange\"));\n\n        List<Resource> computerRoom2Children = Arrays.asList(computer2A, computer2B, computer2C);\n        computerRoom2.addChildren(computerRoom2Children);\n        ((Scheduler) calendar).addResources(computerRoom2Children);\n\n        EntryManager.createTimedEntry(calendar, \"Meeting 1\", now.withDayOfMonth(3).atTime(10, 0), 120, null, meetingRoomBlue, meetingRoomGreen, meetingRoomRed);\n\n        EntryManager.createTimedEntry(calendar, \"Meeting 2\", now.withDayOfMonth(3).atTime(10, 0), 120, null, meetingRoomOrange);\n        EntryManager.createTimedEntry(calendar, \"Meeting 3\", now.withDayOfMonth(7).atTime(11, 30), 120, null, meetingRoomRed);\n\n        HashMap<String, Object> extendedProps = new HashMap<>();\n        HashMap<String, Object> cursors = new HashMap<>();\n        cursors.put(\"enabled\", \"pointer\");\n        cursors.put(\"disabled\", \"not-allowed\");\n        extendedProps.put(\"cursors\", cursors);\n\n        EntryManager.createTimedEntry(calendar, \"Meeting 4\", now.withDayOfMonth(12).atTime(9, 0), 120, null, extendedProps, meetingRoomGreen);\n        EntryManager.createTimedEntry(calendar, \"Meeting 5\", now.withDayOfMonth(13).atTime(10, 0), 120, null, meetingRoomGreen);\n        EntryManager.createTimedEntry(calendar, \"Meeting 6\", now.withDayOfMonth(17).atTime(11, 30), 120, null, meetingRoomBlue);\n        EntryManager.createTimedEntry(calendar, \"Meeting 7\", now.withDayOfMonth(22).atTime(9, 0), 120, null, meetingRoomRed);\n        EntryManager.createTimedEntry(calendar, \"Meeting 8\", now.withDayOfMonth(4).atTime(10, 0), 120, null);\n\n        EntryManager.createTimedBackgroundEntry(calendar, now.withDayOfMonth(3).atTime(10, 0), 120, null);\n        EntryManager.createTimedEntry(calendar, \"Meeting 9\", now.withDayOfMonth(7).atTime(11, 30), 120, \"mediumseagreen\");\n        EntryManager.createTimedEntry(calendar, \"Meeting 10\", now.withDayOfMonth(15).atTime(9, 0), 120, \"mediumseagreen\");\n        EntryManager.createTimedEntry(calendar, \"Meeting 11\", now.withDayOfMonth(18).atTime(10, 0), 120, \"mediumseagreen\");\n        EntryManager.createTimedEntry(calendar, \"Meeting 12\", now.withDayOfMonth(17).atTime(11, 30), 120, \"mediumseagreen\");\n        EntryManager.createTimedEntry(calendar, \"Meeting 13\", now.withDayOfMonth(24).atTime(9, 0), 120, \"mediumseagreen\");\n\n        EntryManager.createTimedEntry(calendar, \"Grocery Store\", now.withDayOfMonth(7).atTime(17, 30), 45, \"violet\");\n        EntryManager.createTimedEntry(calendar, \"Dentist\", now.withDayOfMonth(20).atTime(11, 30), 60, \"violet\");\n        EntryManager.createTimedEntry(calendar, \"Cinema\", now.withDayOfMonth(10).atTime(20, 30), 140, \"dodgerblue\");\n        EntryManager.createDayEntry(calendar, \"Short trip\", now.withDayOfMonth(17), 2, \"dodgerblue\");\n        EntryManager.createDayEntry(calendar, \"John's Birthday\", now.withDayOfMonth(23), 1, \"gray\");\n        EntryManager.createDayEntry(calendar, \"This special holiday\", now.withDayOfMonth(4), 1, \"gray\");\n\n        EntryManager.createTimedEntry(calendar, \"Not editable\", now.withDayOfMonth(5).atTime(10, 0), 60, \"lightgray\")\n                .setEditable(false);\n\n        ResourceEntry startOnly = EntryManager.createTimedEntry(calendar, \"Only start editable\",\n                now.withDayOfMonth(5).atTime(11, 0), 60, \"lightgray\");\n        startOnly.setEditable(false);\n        startOnly.setStartEditable(true);\n\n        ResourceEntry durationOnly = EntryManager.createTimedEntry(calendar, \"Only duration editable\",\n                now.withDayOfMonth(5).atTime(12, 0), 60, \"lightgray\");\n        durationOnly.setEditable(false);\n        durationOnly.setDurationEditable(true);\n\n        EntryManager.createDayEntry(calendar, \"Multi 1\", now.withDayOfMonth(12), 2, \"tomato\");\n        EntryManager.createDayEntry(calendar, \"Multi 2\", now.withDayOfMonth(12), 2, \"tomato\");\n        EntryManager.createDayEntry(calendar, \"Multi 3\", now.withDayOfMonth(12), 2, \"tomato\");\n        EntryManager.createDayEntry(calendar, \"Multi 4\", now.withDayOfMonth(12), 2, \"tomato\");\n        EntryManager.createDayEntry(calendar, \"Multi 5\", now.withDayOfMonth(12), 2, \"tomato\");\n        EntryManager.createDayEntry(calendar, \"Multi 6\", now.withDayOfMonth(12), 2, \"tomato\");\n        EntryManager.createDayEntry(calendar, \"Multi 7\", now.withDayOfMonth(12), 2, \"tomato\");\n        EntryManager.createDayEntry(calendar, \"Multi 8\", now.withDayOfMonth(12), 2, \"tomato\");\n        EntryManager.createDayEntry(calendar, \"Multi 9\", now.withDayOfMonth(12), 2, \"tomato\");\n        EntryManager.createDayEntry(calendar, \"Multi 10\", now.withDayOfMonth(12), 2, \"tomato\");\n\n\n        EntryManager.createDayBackgroundEntry(calendar, now.withDayOfMonth(4), 6, \"#B9FFC3\");\n        EntryManager.createDayBackgroundEntry(calendar, now.withDayOfMonth(19), 2, \"#CEE3FF\");\n        EntryManager.createTimedBackgroundEntry(calendar, now.withDayOfMonth(20).atTime(11, 0), 150, \"#ff0000\");\n\n        EntryManager.createRecurringEvents(calendar);\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"Welcome to the FullCalendar demo playground. In this instance you see a basic set of different calendar entry types to play around with. \" +\n                \"You may also create new ones or delete them. Have fun :)\";\n    }\n\n    @Override\n    protected void onTimeslotsSelected(TimeslotsSelectedEvent event) {\n//        super.onTimeslotsSelected(event); // this is handled by onTimeslotSelectedScheduler\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onDayNumberClicked(DayNumberClickedEvent event) {\n        super.onDayNumberClicked(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onWeekNumberClicked(WeekNumberClickedEvent event) {\n        super.onWeekNumberClicked(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onViewSkeletonRendered(ViewSkeletonRenderedEvent event) {\n        super.onViewSkeletonRendered(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onEntryResized(EntryResizedEvent event) {\n        super.onEntryResized(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onEntryDropped(EntryDroppedEvent event) {\n//        super.onEntryDropped(event); this is handled by onEntryDroppedScheduler\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onEntryClick(EntryClickedEvent event) {\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n\n        if (event.getEntry().getDisplayMode() != DisplayMode.BACKGROUND && event.getEntry().getDisplayMode() != DisplayMode.INVERSE_BACKGROUND) {\n            DemoDialog dialog = new DemoDialog(event.getEntry(), false);\n            dialog.setSaveConsumer(this::onEntryChanged);\n            dialog.setDeleteConsumer(e -> onEntriesRemoved(Collections.singletonList(e)));\n            dialog.open();\n        }\n    }\n\n    @Override\n    protected void onBrowserTimezoneObtained(BrowserTimezoneObtainedEvent event) {\n        super.onBrowserTimezoneObtained(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onDatesRendered(DatesRenderedEvent event) {\n        super.onDatesRendered(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onMoreLinkClicked(MoreLinkClickedEvent event) {\n        super.onMoreLinkClicked(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onTimeslotClicked(TimeslotClickedEvent event) {\n//        super.onTimeslotClicked(event); // this is handled by onTimeslotClickedScheduler\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onEntryDroppedScheduler(EntryDroppedSchedulerEvent event) {\n        super.onEntryDroppedScheduler(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onTimeslotClickedScheduler(TimeslotClickedSchedulerEvent event) {\n        super.onTimeslotClickedScheduler(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n    }\n\n    @Override\n    protected void onTimeslotsSelectedScheduler(TimeslotsSelectedSchedulerEvent event) {\n        super.onTimeslotsSelectedScheduler(event);\n        System.out.println(event.getClass().getSimpleName() + \": \" + event);\n\n        System.out.println( \"ZoneId: \" + event.getSource().getTimezone().getZoneId() );\n        LocalDateTime startDate = event.getStart();\n        System.out.println( \"getStart(): \" + event.getStart() );\n        System.out.println( \"getStartWithOffset():  \" + event.getStartWithOffset() );\n\n        ResourceEntry entry = new ResourceEntry();\n\n        entry.setStart(event.getStart());\n        entry.setEnd(event.getEnd());\n        entry.setAllDay(event.isAllDay());\n\n        entry.setCalendar(event.getSource());\n\n        // Pre-assign the resource the user clicked on, if any (#164).\n        event.getResource().ifPresent(entry::addResources);\n\n        DemoDialog dialog = new DemoDialog(entry, true);\n        dialog.setSaveConsumer(e -> onEntriesCreated(Collections.singletonList(e)));\n        dialog.setDeleteConsumer(e -> onEntriesRemoved(Collections.singletonList(e)));\n        dialog.open();\n    }\n}",
      "language": "java",
      "category": "events",
      "tags": [
        "entry",
        "callback",
        "resource",
        "scheduler",
        "timezone",
        "recurring",
        "event",
        "listener",
        "click",
        "drop",
        "resize",
        "style",
        "view",
        "create",
        "delete"
      ]
    },
    {
      "id": "demo-inlinecalendardemo",
      "title": "Inline Calendar Demo",
      "description": "@author Stefan Uebe",
      "code": "package org.vaadin.stefan.ui.view.demos.multimonthselection;\n\nimport com.vaadin.flow.component.UI;\nimport com.vaadin.flow.component.dependency.JsModule;\nimport com.vaadin.flow.component.dependency.StyleSheet;\nimport com.vaadin.flow.component.orderedlayout.VerticalLayout;\nimport com.vaadin.flow.router.Route;\nimport org.vaadin.stefan.fullcalendar.*;\nimport org.vaadin.stefan.fullcalendar.dataprovider.EntryProvider;\nimport org.vaadin.stefan.fullcalendar.dataprovider.InMemoryEntryProvider;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.menu.MenuItem;\nimport org.vaadin.stefan.ui.view.AbstractCalendarView;\nimport org.vaadin.stefan.ui.view.demos.entryproviders.CallbackEntryProviderDemo;\nimport org.vaadin.stefan.ui.view.demos.entryproviders.EntryService;\n\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.Period;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport static org.vaadin.stefan.fullcalendar.FullCalendar.Option.*;\n\n/**\n * @author Stefan Uebe\n */\n@Route(value = \"inline-calendar\", layout = MainLayout.class)\n@MenuItem(label = \"Inline Calendar\")\n@JsModule(\"./multi-month-selection-utils.js\")\n@StyleSheet(\"inline-calendar.css\")\npublic class InlineCalendarDemo extends VerticalLayout {\n\n    // basic constructor with full sized items\n    public InlineCalendarDemo() {\n        setSizeFull();\n        setAlignItems(Alignment.STRETCH);\n\n        FullCalendar calendar = new FullCalendar();\n        calendar.setLocale(UI.getCurrent().getLocale());\n        calendar.addClassName(\"inline-calendar\");\n\n        // activate cross month selection\n        calendar.setOption(SELECTABLE, false); // important\n        calendar.addAttachListener(event -> // refire things, when reattached\n            calendar.getElement()\n                .executeJs(\"window.Vaadin.Flow.multiMonthCrossSelectionUtils.register(this.calendar)\")\n                .then(jsonValue -> calendar.changeView(CalendarViewImpl.MULTI_MONTH))\n        );\n\n        addAndExpand(calendar);\n\n        InMemoryEntryProvider<Entry> entryProvider = calendar.getEntryProvider().asInMemory();\n        calendar.addTimeslotsSelectedListener(event -> {\n            // fetch entries from the entryprovider using the event start and end date and map them to their start date\n            LocalDateTime start = event.getStart();\n            LocalDateTime end = event.getEnd();\n\n            System.out.println(\"start: \" + start);\n            System.out.println(\"end: \" + end);\n\n            Map<LocalDate, Entry> map = entryProvider\n                    .fetch(start, end)\n                    .collect(Collectors.toMap(entry -> entry.getStartAsLocalDate(), entry -> entry));\n\n            // calculate amount of days between event start and end\n            int days = Period.between(start.toLocalDate(), end.toLocalDate()).getDays();\n            if (days == map.size()) {\n                // unmark all days that are covered by the event period\n                entryProvider.removeEntries(map.values());\n                entryProvider.refreshAll();\n            } else {\n                // iterate over the event period and create an entry for each day, that is not in the map\n                LocalDate startDate = start.toLocalDate();\n                LocalDate endDate = end.toLocalDate();\n                LocalDate date = startDate;\n\n                while (date.isBefore(endDate)) {\n                    if (!map.containsKey(date)) {\n                        Entry entry = new Entry();\n                        entry.setStart(date.atStartOfDay());\n                        entry.setEnd(date.plusDays(1).atStartOfDay());\n                        entry.setAllDay(true);\n                        entry.setDisplayMode(DisplayMode.BACKGROUND);\n                        entryProvider.addEntry(entry);\n                    }\n\n                    date = date.plusDays(1);\n                }\n\n                entryProvider.refreshAll();\n            }\n\n            calendar.clearSelection();\n        });\n\n    }\n\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "callback",
        "inmemory",
        "event",
        "listener",
        "style",
        "view",
        "create"
      ]
    },
    {
      "id": "demo-multimonthcrossmonthselectiondemo",
      "title": "Multi Month Cross Month Selection Demo",
      "description": "@author Stefan Uebe",
      "code": "package org.vaadin.stefan.ui.view.demos.multimonthselection;\n\nimport com.vaadin.flow.component.dependency.JsModule;\nimport com.vaadin.flow.router.Route;\nimport org.vaadin.stefan.fullcalendar.CalendarViewImpl;\nimport org.vaadin.stefan.fullcalendar.FullCalendar;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.menu.MenuItem;\nimport org.vaadin.stefan.ui.view.demos.entryproviders.CallbackEntryProviderDemo;\n\nimport static org.vaadin.stefan.fullcalendar.FullCalendar.Option.*;\n\n/**\n * @author Stefan Uebe\n */\n@Route(value = \"multi-month-cross-month-selection\", layout = MainLayout.class)\n@MenuItem(label = \"Multi Month Cross Selection\")\n@JsModule(\"./multi-month-selection-utils.js\")\npublic class MultiMonthCrossMonthSelectionDemo extends CallbackEntryProviderDemo {\n\n    @Override\n    protected boolean isToolbarViewChangeable() {\n        return false;\n    }\n\n    @Override\n    protected void postConstruct(FullCalendar calendar) {\n        calendar.setOption(SELECTABLE, false); // important\n\n        calendar.addAttachListener(event -> // refire things, when reattached\n            calendar.getElement()\n                .executeJs(\"window.Vaadin.Flow.multiMonthCrossSelectionUtils.register(this.calendar)\")\n                .then(jsonValue -> calendar.changeView(CalendarViewImpl.MULTI_MONTH))\n        );\n    }\n\n    @Override\n    protected String createTitle() {\n        return \"Multi Month View - Cross Month Selection\";\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"This demo shows a sample on how to implement cross month selection for the multi month view. This feature is currently not available\" +\n                \" in the library itself and thus integrated via a custom java script\";\n    }\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "callback",
        "event",
        "listener",
        "view",
        "create"
      ]
    },
    {
      "id": "demo-demowithtooltip",
      "title": "Demo With Tooltip",
      "description": "Demo: DemoWithTooltip",
      "code": "/*\n * Copyright 2020, Stefan Uebe\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions\n * of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\npackage org.vaadin.stefan.ui.view.demos.tooltip;\n\nimport com.vaadin.flow.router.PageTitle;\nimport com.vaadin.flow.router.Route;\nimport org.vaadin.stefan.fullcalendar.Entry;\nimport org.vaadin.stefan.fullcalendar.FullCalendar;\nimport org.vaadin.stefan.fullcalendar.dataprovider.InMemoryEntryProvider;\nimport org.vaadin.stefan.ui.layouts.MainLayout;\nimport org.vaadin.stefan.ui.menu.MenuItem;\nimport org.vaadin.stefan.ui.view.AbstractCalendarView;\nimport org.vaadin.stefan.ui.view.demos.entryproviders.EntryService;\nimport tools.jackson.databind.node.ObjectNode;\n\n@Route(value = \"tooltip\", layout = MainLayout.class)\n@PageTitle(\"FC with Tooltips\")\n@MenuItem(label = \"Tooltips\")\npublic class DemoWithTooltip extends AbstractCalendarView {\n    private static final long serialVersionUID = 1L;\n    private InMemoryEntryProvider<Entry> entryProvider;\n\n\n    @Override\n    protected FullCalendar createCalendar(ObjectNode defaultInitialOptions) {\n        EntryService entryService = EntryService.createSimpleInstance();\n\n        FullCalendarWithTooltip calendar = new FullCalendarWithTooltip(defaultInitialOptions);\n        calendar.setOption(FullCalendar.Option.MAX_ENTRIES_PER_DAY, 3);\n        ((InMemoryEntryProvider<Entry>) calendar.getEntryProvider()).addEntries(entryService.getEntries());\n\n        return calendar;\n    }\n\n    @Override\n    protected String createDescription() {\n        return \"This demo shows the integration of the Tippy tooltip library. Every calendar entry will show a tooltip based on the entry's description. The integration \" +\n                \"is done in a simple client side extension of the base javascript class of the FullCalendar.\";\n    }\n}\n",
      "language": "java",
      "category": "data-provider",
      "tags": [
        "entry",
        "provider",
        "inmemory",
        "event",
        "view",
        "create"
      ]
    }
  ],
  "entryProperties": [
    {
      "name": "PROPERTIES",
      "type": "static final Set<BeanProperties<Entry>>",
      "description": "The PROPERTIES property of the entry",
      "defaultValue": "BeanProperties.read(Entry.class)",
      "clientUpdatable": false
    },
    {
      "name": "id",
      "type": "final String",
      "description": "The id property of the entry",
      "clientUpdatable": false
    },
    {
      "name": "groupId",
      "type": "String",
      "description": "The groupId property of the entry",
      "clientUpdatable": false
    },
    {
      "name": "title",
      "type": "String",
      "description": "The title property of the entry",
      "clientUpdatable": false
    },
    {
      "name": "start",
      "type": "LocalDateTime",
      "description": "The start property of the entry",
      "clientUpdatable": true
    },
    {
      "name": "end",
      "type": "LocalDateTime",
      "description": "The end property of the entry",
      "clientUpdatable": true
    },
    {
      "name": "allDay",
      "type": "boolean",
      "description": "The allDay property of the entry",
      "clientUpdatable": true
    },
    {
      "name": "interactive",
      "type": "Boolean",
      "description": "Whether this entry is editable (draggable + resizable). Internal storage is\nnullable: {\n{\n<p>\nThe public API ({\nnull as {\nwhen the calendar is editable\") is preserved. The difference is that {\nis now skipped during JSON serialization, so a calendar-level {\nis no longer overridden by every entry's per-entry {\nSee issue #212.\n/\n    \n    \n    \n    private Boolean editable;\n    private Boolean startEditable;\n    private Boolean durationEditable;\n    private String color;\n    \n    \n    private Object constraint;\n    private String backgroundColor;\n    private String borderColor;\n    private String textColor;\n    private Boolean overlap;\n\n    /** Whether the entry is keyboard-focusable (tabbable) independently of drag/drop. Null inherits the calendar-level {",
      "clientUpdatable": false
    },
    {
      "name": "url",
      "type": "String",
      "description": "A URL that FC navigates to when the event is clicked. Null means no URL navigation.\n<p>\nIf a server-side click listener is also registered, FC will navigate to the url immediately on click\nand the listener will still fire — but the page may already be unloading. Use one mechanism or the other, not both.",
      "clientUpdatable": false
    },
    {
      "name": "displayMode",
      "type": "DisplayMode",
      "description": "The displayMode property of the entry",
      "defaultValue": "DisplayMode.AUTO",
      "jsonName": "display",
      "clientUpdatable": false
    },
    {
      "name": "recurringStartDate",
      "type": "LocalDate",
      "description": "The recurringStartDate property of the entry",
      "jsonName": "startRecur",
      "clientUpdatable": false
    },
    {
      "name": "recurringEndDate",
      "type": "LocalDate",
      "description": "The recurringEndDate property of the entry",
      "jsonName": "endRecur",
      "clientUpdatable": false
    },
    {
      "name": "recurringStartTime",
      "type": "RecurringTime",
      "description": "The recurringStartTime property of the entry",
      "jsonName": "startTime",
      "clientUpdatable": false
    },
    {
      "name": "recurringEndTime",
      "type": "RecurringTime",
      "description": "The recurringEndTime property of the entry",
      "jsonName": "endTime",
      "clientUpdatable": false
    },
    {
      "name": "recurringDaysOfWeek",
      "type": "Set<DayOfWeek>",
      "description": "The recurringDaysOfWeek property of the entry",
      "jsonName": "daysOfWeek",
      "clientUpdatable": false
    },
    {
      "name": "recurringDuration",
      "type": "String",
      "description": "The duration of each occurrence for recurring events (e.g. {\nOnly meaningful when recurrence fields ({\nWithout this, each occurrence spans one day (for all-day) or uses start/end times.",
      "jsonName": "duration",
      "clientUpdatable": false
    },
    {
      "name": "rRule",
      "type": "RRule",
      "description": "Whether this entry is editable (draggable + resizable). Internal storage is\nnullable: {\n{\n<p>\nThe public API ({\nnull as {\nwhen the calendar is editable\") is preserved. The difference is that {\nis now skipped during JSON serialization, so a calendar-level {\nis no longer overridden by every entry's per-entry {\nSee issue #212.\n/\n    \n    \n    \n    private Boolean editable;\n    private Boolean startEditable;\n    private Boolean durationEditable;\n    private String color;\n    \n    \n    private Object constraint;\n    private String backgroundColor;\n    private String borderColor;\n    private String textColor;\n    private Boolean overlap;\n\n    /** Whether the entry is keyboard-focusable (tabbable) independently of drag/drop. Null inherits the calendar-level {\n    private Boolean interactive;\n\n    /**\nA URL that FC navigates to when the event is clicked. Null means no URL navigation.\n<p>\nIf a server-side click listener is also registered, FC will navigate to the url immediately on click\nand the listener will still fire — but the page may already be unloading. Use one mechanism or the other, not both.\n/\n    private String url;\n\n    \n    \n    \n    private DisplayMode displayMode = DisplayMode.AUTO;\n\n    \n    \n    private LocalDate recurringStartDate;\n\n    \n    \n    private LocalDate recurringEndDate;\n\n    \n    \n    private RecurringTime recurringStartTime; // see #139\n\n    \n    \n    private RecurringTime recurringEndTime; // see #139\n\n    \n    \n    private Set<DayOfWeek> recurringDaysOfWeek;\n\n    /**\nThe duration of each occurrence for recurring events (e.g. {\nOnly meaningful when recurrence fields ({\nWithout this, each occurrence spans one day (for all-day) or uses start/end times.\n\n/\n    \n    private String recurringDuration;\n\n    /**\nRRule-based recurrence definition. Requires the {\n<p>\n<b>Mutually exclusive</b> with FC's built-in recurrence ({\nDo not set both on the same entry.\n<p>\nUse {\n\n/\n    \n    \n    \n    \n    private RRule rrule;\n\n    /**\nDates to exclude from an RRule-based recurrence. Populated automatically from\n{\nNot part of the public API — use {\n/\n    \n    \n    \n    \n    private List<LocalDate> exdate;\n\n    /**\nRRules defining exclusion patterns for an RRule-based recurrence. Populated automatically from\n{\nNot part of the public API — use {\n/\n    \n    \n    \n    \n    private List<RRule> exrule;\n\n    /**\nReturns the RRule-based recurrence definition, or {",
      "clientUpdatable": false
    },
    {
      "name": "startAsInstant",
      "type": "Instant",
      "description": "Converts the given instance to a json object representing its inner state. This json is intended to be\ntransported to and interpreted by the client and thus should not be modified manually, except for concrete\nreasons.\n\n/\n    \n    public ObjectNode toJson() {\n        // The toJson is implemented in a dynamic fashion to not need to extend it every time a\n        // new property comes out.\n\n        ObjectNode json = JsonFactory.createObject();\n\n        streamProperties().forEach(def -> {\n            // Use cached annotation data from BeanProperties for performance\n            if (!def.isJsonIgnored()) {\n                Object value = def.getGetter().apply(this);\n\n                JsonNode jsonValue;\n\n                JsonItemPropertyConverter converter = def.getConverter();\n\n                if (converter != null && converter.supports(value)) {\n                    jsonValue = converter.toClientModel(value, this);\n                } else {\n                    jsonValue = JsonUtils.toJsonNode(value);\n                }\n\n                if (jsonValue != null && !(jsonValue instanceof NullNode)) {\n                    json.set(def.getJsonName(), jsonValue);\n                }\n            }\n        });\n\n        return json;\n    }\n\n    /**\nUpdates this instance with the given json object. Only fields, that are updateable will be overwritten.\nThrows an exception, when the given json object has not the same id as this instance.\n\n/\n    public void updateFromJson(ObjectNode jsonObject) {\n        updateFromJson(jsonObject, true);\n    }\n\n    /**\nUpdates this instance with the given json object. Only fields, that are updateable will be overwritten.\nBased on the boolean parameter, the id will be either ignored (false) or has to be the same as this instance's one\n(true), otherwise an exception will be thrown\n\n\n/\n    public void updateFromJson(ObjectNode jsonObject, boolean requiresMatchingId) {\n        checkForMatchingId(jsonObject, requiresMatchingId);\n\n        // Use cached annotation data from BeanProperties for performance\n        streamProperties()\n                .filter(def -> !def.isJsonIgnored())\n                .filter(BeanProperties::isJsonUpdateAllowed)\n                .forEach(def -> writeJsonValueToEntry(jsonObject, def));\n    }\n\n    /**\nUpdates this instance with the given json object. ALL fields will be overwritten, regardless whether they are allowed to\nbe updated or not. Ignored properties still will be not overwritten as they are intended to be invisible for the json parser.\nBased on the boolean parameter, the id will be either ignored (false) or has to be the same as this instance's one\n(true), otherwise an exception will be thrown\n\n\n/\n    public void updateAllFromJson(ObjectNode jsonObject, boolean requiresMatchingId) {\n        checkForMatchingId(jsonObject, requiresMatchingId);\n\n        // Use cached annotation data from BeanProperties for performance\n        streamProperties()\n                .filter(def -> !def.isJsonIgnored())\n                .filter(def -> def.getSetter().isPresent())\n                .forEach(def -> writeJsonValueToEntry(jsonObject, def));\n    }\n\n    private void checkForMatchingId(ObjectNode jsonObject, boolean requiresMatchingId) {\n        if (requiresMatchingId) {\n            if (!jsonObject.hasNonNull(Fields.ID)) {\n                throw new IllegalArgumentException(\"JsonObject has no id. Id matching is required.\");\n            }\n\n            String idString = jsonObject.get(Fields.ID).asString();\n            if (!id.equals(idString)) {\n                throw new IllegalArgumentException(\"Id matching is required. This id is \" + id + \" but the json object provided \" + idString);\n            }\n        }\n    }\n\n    private void writeJsonValueToEntry(ObjectNode jsonObject, BeanProperties<Entry> def) {\n        String name = def.getName();\n\n        Setter<Entry, Object> setter = def.getSetter()\n                .orElseThrow(() -> new UnsupportedOperationException(\"No setter found for field \" + name));\n\n        String jsonName = def.getJsonName();\n\n        if (jsonObject.hasNonNull(jsonName)) {\n            JsonItemPropertyConverter<Object, Object> converter = def.getConverter();\n\n            Object newValue;\n            JsonNode jsonValue = jsonObject.get(jsonName);\n\n            if (converter != null) {\n                newValue = converter.toServerModel(jsonValue, this);\n            } else {\n                newValue = JsonUtils.ofJsonNode(jsonValue);\n            }\n\n            setter.accept(this, newValue);\n        }\n    }\n\n\n    /**\nChecks whether the given json object is a valid source to update this instance.\n\n\n/\n    protected boolean isValidJsonSource(ObjectNode jsonObject) {\n        return jsonObject.hasNonNull(Fields.ID) && Objects.equals(jsonObject.get(Fields.ID).asString(), getId());\n    }\n\n    /**\nCreates a copy of this instance. Collection, Map and Array values are copied (but their values are taken\nas they are, so no deep copy).\n\n\n/\n    public <T extends Entry> T copy() {\n        try {\n            T copy = (T) getClass().getConstructor(String.class).newInstance(getId());\n            copy(this, copy, false);\n\n            return copy;\n        } catch (ReflectiveOperationException e) {\n            throw new RuntimeException(\"Failed to create copy of entry\", e);\n        }\n    }\n\n    /**\nCreates a copy of this instance. Collection, Map and Array values are copied (but their values are taken\nas they are, so no deep copy).\n<p></p>\nPlease make sure, that both types are compatible in their properties. Any property, that exists in the source\nbut not the target type might lead to an exception. Also the target type must have a public constructor, taking\nthe id as the parameter.\n\n\n/\n    public <T extends Entry> T copyAsType(Class<T> targetType) {\n        try {\n            T copy = (T) targetType.getConstructor(String.class).newInstance(getId());\n            copy(this, copy, true);\n\n            return copy;\n        } catch (ReflectiveOperationException e) {\n            throw new RuntimeException(\"Failed to create copy of entry as type \" + targetType.getName(), e);\n        }\n    }\n\n    public void copyFrom(Entry source) {\n        copyFrom(source, false);\n    }\n\n    public void copyFrom(Entry source, boolean ignoreId) {\n        if (!ignoreId && !source.getId().equals(getId())) {\n            throw new IllegalArgumentException(\"IDs must match\");\n        }\n        copy(source, this, false);\n    }\n\n    /**\nCopies all values from source to target (except for the id). When the boolean is set to false,\nboth objects have to be of the <b>same</b> type. Otherwise it is up to the developer to guarantee,\nthat the target can take all properties of the source.<br>\nProperties without a setter are ignored.\n\n\n\n/\n    \n    public static void copy(Entry source, Entry target, boolean ignoreTypeDifference) {\n        if (!ignoreTypeDifference && !source.getClass().equals(target.getClass())) {\n            throw new IllegalArgumentException(\"Both parameters must be of the SAME class.\");\n        }\n\n        source.streamProperties().forEach(def -> {\n            ValueProvider getter = def.getGetter();\n            def.getSetter().ifPresent(setter -> {\n                try {\n                    Object value = getter.apply(source);\n\n                    if (value instanceof Collection) {\n                        // fails on unmodifiable\n                        Collection collection = newInstance((Collection) value);\n                        collection.addAll((Collection) value);\n                        value = collection;\n                    } else if (value instanceof Map) {\n                        // fails on unmodifiable\n                        Map map = newInstance((Map) value);\n                        map.putAll((Map) value);\n                        value = map;\n                    } else if (value instanceof Object[]) {\n                        value = ((Object[]) value).clone();\n                    }\n\n                    setter.accept(target, value);\n                } catch (ReflectiveOperationException e) {\n                    throw new RuntimeException(\"Property \" + def.getName() + \" threw an exception during copy\", e);\n                }\n            });\n        });\n    }\n\n    \n    private static <T> T newInstance(T value) throws ReflectiveOperationException {\n        try {\n            return (T) value.getClass().getConstructor().newInstance();\n        } catch (NoSuchMethodException e) {\n            if (value instanceof Set) {\n                return (T) new LinkedHashSet<>();\n            }\n\n            if (value instanceof Collection) {\n                return (T) new ArrayList<>();\n            }\n\n            if (value instanceof Map) {\n                return (T) new HashMap<>();\n            }\n\n            throw new IllegalArgumentException(\"Type \" + value.getClass() + \" has no public no-args constructor and no fallback.\");\n        }\n    }\n\n    protected Stream<BeanProperties<Entry>> streamProperties() {\n        return PROPERTIES.stream();\n    }\n\n    /**\nStreams all properties, that are updateable. A property counts as updateable, if it is not annotated with\n{\n\n/\n    protected Stream<BeanProperties<Entry>> streamUpdateableProperties() {\n        return streamProperties().filter(def ->\n                !def.isJsonIgnored()\n                        && def.isJsonUpdateAllowed()\n                        && def.getSetter().isPresent()\n        );\n    }\n\n    /**\nConverts this instance to a json object, that only contains the id. This still represents\nthis item but without any data.\n\n/\n    public ObjectNode toJsonWithIdOnly() {\n        ObjectNode jsonObject = JsonFactory.createObject();\n        jsonObject.put(Fields.ID, getId());\n        return jsonObject;\n    }\n\n    /**\nReturns the entry's start as an {\n{",
      "clientUpdatable": false
    },
    {
      "name": "startAsLocalDate",
      "type": "LocalDate",
      "description": "Returns the entry's start date.",
      "clientUpdatable": false
    },
    {
      "name": "startWithTimezone",
      "type": "ZonedDateTime",
      "description": "Returns the start time as a zoned date time using this entry's start time zone. By default this is\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>\nCalling {",
      "clientUpdatable": false
    },
    {
      "name": "startWithOffset",
      "type": "LocalDateTime",
      "description": "Returns the start time as a local date time after applying the timezone's offset to\nthe utc based start date ({\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>\nTo get a {\n{",
      "clientUpdatable": false
    },
    {
      "name": "endAsInstant",
      "type": "Instant",
      "description": "Returns the start time as a local date time after applying the timezone's offset to\nthe utc based start date ({\n<p></p>\nThis method is intended to be used for new entries that have not yet been added to the\ncalendar and thus have no reference to its timezone.\n<p></p>\nTo get a {\n{\n\n/\n    public LocalDateTime getStartWithOffset(Timezone timezone) {\n        return timezone.applyTimezoneOffset(getStart());\n    }\n\n    /**\nSets the entry's start. The given date time will be interpreted as the UTC start time of this entry.\n\n/\n    public void setStart(LocalDateTime start) {\n        this.start = start;\n    }\n\n    /**\nSets the entry's start. The given instant will be interpreted as the UTC start time of this entry.\n\n/\n    public void setStart(Instant start) {\n        setStart(start != null ? LocalDateTime.ofInstant(start, Timezone.ZONE_ID_UTC) : null);\n    }\n\n    /**\nSets the given local date as start using the start of the day as time (utc based).\n\n/\n    public void setStart(LocalDate start) {\n        setStart(start != null ? start.atStartOfDay() : null);\n    }\n\n    /**\nSets the entry's start based on the zoned date time instance. The given date time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting start time will be ...T00:00.\n<p></p>\n\n/\n    public void setStartWithTimezone(ZonedDateTime startWithTimezone) {\n        setStart(startWithTimezone != null ? startWithTimezone.withZoneSameInstant(Timezone.ZONE_ID_UTC).toLocalDateTime() : null);\n    }\n\n    /**\nSets the entry's start. The given date time will be interpreted as having the offset of the\nstart time zone applied. The time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting start time will be ...T00:00.\n<p></p>\nThis method is intended to be used in cases where the start time is edited in relation to\nthe current time zone (like a calendar entry editor).\n<p></p>\n\n/\n    public void setStartWithOffset(LocalDateTime startWithTimezone) {\n        setStartWithOffset(startWithTimezone, getStartTimezone());\n    }\n\n    /**\nSets the entry's start. The given date time will be interpreted as having the offset of the\ngiven time zone applied. The time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting start time will be ...T00:00.\n<p></p>\nThis method is intended to be used in cases where entry is not yet added to the calendar and thus\ncannot use its timezone to interpret the offset.\n<p></p>\n\n\n/\n    public void setStartWithOffset(LocalDateTime startWithTimezone, Timezone timezone) {\n        setStart(timezone.removeTimezoneOffset(startWithTimezone));\n    }\n\n    /**\nClears the current start time. Convenience method to prevent unnecessary casting when using\nsetStart(null).\n/\n    public void clearStart() {\n        setStart((LocalDateTime) null);\n    }\n\n    /**\nReturns the entry's end as an {\n{",
      "clientUpdatable": false
    },
    {
      "name": "endAsLocalDate",
      "type": "LocalDate",
      "description": "Returns the entry's end date.",
      "clientUpdatable": false
    },
    {
      "name": "endWithTimezone",
      "type": "ZonedDateTime",
      "description": "Returns the end time as a zoned date time using this entry's end time zone. By default this is\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>\nCalling {",
      "clientUpdatable": false
    },
    {
      "name": "endWithOffset",
      "type": "LocalDateTime",
      "description": "Returns the end time as a local date time after applying the timezone's offset to\nthe utc based end date ({\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>\nTo get a {\n{",
      "clientUpdatable": false
    },
    {
      "name": "startTimezone",
      "type": "Timezone",
      "description": "Returns the end time as a local date time after applying the timezone's offset to\nthe utc based end date ({\n<p></p>\nThis method is intended to be used for new entries that have not yet been added to the\ncalendar and thus have no reference to its timezone.\n<p></p>\nTo get a {\n{\n\n/\n    public LocalDateTime getEndWithOffset(Timezone timezone) {\n        return timezone.applyTimezoneOffset(getEnd());\n    }\n\n    /**\nSets the entry's end. The given date time will be interpreted as the UTC end time of this entry.\n\n/\n    public void setEnd(LocalDateTime end) {\n        this.end = end;\n    }\n\n    /**\nSets the entry's end. The given instant will be interpreted as the UTC end time of this entry.\n\n/\n    public void setEnd(Instant end) {\n        setEnd(end != null ? LocalDateTime.ofInstant(end, Timezone.ZONE_ID_UTC) : null);\n    }\n\n    /**\nSets the given local date as end using the end of the day as time (utc based).\n\n/\n    public void setEnd(LocalDate end) {\n        setEnd(end != null ? end.atStartOfDay() : null);\n    }\n\n    /**\nSets the entry's end based on the zoned date time instance. The given date time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting end time will be ...T00:00.\n<p></p>\n\n/\n    public void setEndWithTimezone(ZonedDateTime endWithTimezone) {\n        setEnd(endWithTimezone != null ? endWithTimezone.withZoneSameInstant(Timezone.ZONE_ID_UTC).toLocalDateTime() : null);\n    }\n\n    /**\nSets the entry's end. The given date time will be interpreted as having the offset of the\nend time zone applied. The time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting end time will be ...T00:00.\n<p></p>\nThis method is intended to be used in cases where the end time is edited in relation to\nthe current time zone (like a calendar entry editor).\n<p></p>\n\n/\n    public void setEndWithOffset(LocalDateTime endWithTimezone) {\n        setEnd(getEndTimezone().removeTimezoneOffset(endWithTimezone));\n    }\n\n    /**\nSets the entry's end. The given date time will be interpreted as having the offset of the\ngiven time zone applied. The time will be converted to UTC.\n<p></p>\nFor instance, when passing an instance with ...T01:00 and the timezone is Europe/Berlin in winter,\nthe resulting end time will be ...T00:00.\n<p></p>\nThis method is intended to be used in cases where entry is not yet added to the calendar and thus\ncannot use its timezone to interpret the offset.\n<p></p>\n\n\n/\n    public void setEndWithOffset(LocalDateTime endWithTimezone, Timezone timezone) {\n        setEnd(timezone.removeTimezoneOffset(endWithTimezone));\n    }\n\n    /**\nClears the current end time. Convenience method to prevent unnecessary casting when using\nsetEnd(null).\n/\n    public void clearEnd() {\n        setEnd((LocalDateTime) null);\n    }\n\n    /**\nMoves the entry by the given delta. Negative deltas will result in moving the entry to the past.\n\n/\n    public void moveStartEnd(Delta delta) {\n        moveStart(delta);\n        moveEnd(delta);\n    }\n\n    /**\nMoves the entry's start by the given delta without modifying the end.\nNegative deltas will result in moving the start to the past.\n\n/\n    public void moveStart(Delta delta) {\n        setStart(delta.applyOn(getStart()));\n    }\n\n    /**\nMoves the entry's end by the given delta without modifying the start.\nNegative deltas will result in moving the end to the past.\n\n/\n    public void moveEnd(Delta delta) {\n        setEnd(delta.applyOn(getEnd()));\n    }\n\n    /**\nReturns the timezone which is used on the client side. It is used to convert the internal utc timestamp\nto the client side timezone. By default UTC.",
      "clientUpdatable": false
    },
    {
      "name": "endTimezone",
      "type": "Timezone",
      "description": "Returns the timezone which is used on the client side. It is used to convert the internal utc timestamp\nto the client side timezone. By default UTC.",
      "clientUpdatable": false
    },
    {
      "name": "orCreateClassNames",
      "type": "Set<String>",
      "description": "Returns the set of class names or creates a new, empty one, if none exists yet. The returned set is\nthe same as used internally, therefore any changes to it will be reflected to the client side on the\nnext refresh.",
      "clientUpdatable": false
    },
    {
      "name": "classNamesSize",
      "type": "int",
      "description": "Assign an additional className to this entry. Already assigned classNames will be kept.\n\n\n\n/\n    \n    public void assignClassName(String className) {\n        assignClassNames(Objects.requireNonNull(className));\n    }\n\n    /**\nAssign additional classNames to this entry. Already assigned classNames will be kept.\n\n\n\n/\n    \n    public void assignClassNames(String... classNames) {\n        assignClassNames(Arrays.asList(classNames));\n    }\n\n    /**\nAssign additional classNames to this entry. Already assigned classNames will be kept.\n\n\n\n/\n    \n    public void assignClassNames(Collection<String> classNames) {\n        Objects.requireNonNull(classNames);\n        getOrCreateClassNames().addAll(classNames);\n    }\n\n    /**\nAdds css class names to this entry. Duplicates will automatically be filtered out.\n\n\n/\n    public void addClassNames(String... classNames) {\n        assignClassNames(Arrays.asList(classNames));\n    }\n\n    /**\nAdds css class names to this entry. Duplicates will automatically be filtered out.\n\n\n/\n    public void addClassNames(Collection<String> classNames) {\n        Objects.requireNonNull(classNames);\n        getOrCreateClassNames().addAll(classNames);\n    }\n\n    /**\nUnassigns the given className from this entry.\n\n\n\n/\n    \n    public void unassignClassName(String className) {\n        unassignClassNames(Objects.requireNonNull(className));\n    }\n\n    /**\nUnassigns the given classNames from this entry.\n\n\n\n/\n    \n    public void unassignClassNames(String... classNames) {\n        unassignClassNames(Arrays.asList(classNames));\n    }\n\n    /**\nUnassigns the given classNames from this entry.\n\n\n\n/\n    \n    public void unassignClassNames(Collection<String> classNamesToRemove) {\n        removeClassNames(classNamesToRemove);\n    }\n\n    /**\nUnassigns all classNames from this entry.\n\n/\n    \n    public void unassignAllClassNames() {\n        removeClassNames();\n    }\n\n    /**\nRemoves the given classNames from this entry.\n\n\n/\n    public void removeClassNames(String... classNames) {\n        removeClassNames(Arrays.asList(classNames));\n    }\n\n    /**\nRemoves the given classNames from this entry.\n\n\n/\n    public void removeClassNames(Collection<String> classNamesToRemove) {\n        Set<String> classNames = getClassNames();\n        if (classNames != null) {\n            classNames.removeAll(classNamesToRemove);\n        }\n    }\n\n    /**\nRemoves the class names from this entry. Copies of the internal class name set will be unaffected;\n/\n    public void removeClassNames() {\n        setClassNames(null);\n    }\n\n    /**\nReturns the amount of assigned classNames.",
      "clientUpdatable": false
    },
    {
      "name": "overlapAllowed",
      "type": "Boolean",
      "description": "Returns, if the entry has any class name assigned.\n\n/\n    public boolean hasClassNames() {\n        Set<String> classNames = getClassNames();\n        return classNames != null && !classNames.isEmpty();\n    }\n\n    /**\nSame as {",
      "clientUpdatable": false
    },
    {
      "name": "editable",
      "type": "boolean",
      "description": "Same as {\n\n/\n    public void setOverlapAllowed(Boolean overlap) {\n        setOverlap(overlap);\n    }\n\n    /**\nChecks whether this entry is editable (draggable + resizable). Returns {\nby default — if {\ncalendar-level {\n<p>\nSemantically equivalent to the pre-7.2 getter. Internally, the field is now nullable\nso that {\na calendar-level {\n\n        explicitly set; {",
      "clientUpdatable": false
    },
    {
      "name": "durationEditable",
      "type": "boolean",
      "description": "Sets whether this entry is editable (draggable + resizable). The value is an explicit\noverride of the calendar-level {\nthe override and inherit the calendar-level setting instead.\n<p>\nBoolean parameter is used so that {\ncan discover the setter (it looks for the boxed type matching the field), so that\n{\n{\n\n                or {\n/\n    public void setEditable(Boolean editable) {\n        this.editable = editable;\n    }\n\n    /**\nChecks, if the duration of this entry is editable. This is either the case, when this entry is\neditable in general ({",
      "clientUpdatable": false
    },
    {
      "name": "startEditable",
      "type": "boolean",
      "description": "Checks, if the start of this entry is editable. This is either the case, when this entry is\neditable in general ({",
      "clientUpdatable": false
    },
    {
      "name": "constraint",
      "type": "Object",
      "description": "Returns the current constraint value. This may be a {\nor a {",
      "clientUpdatable": false
    },
    {
      "name": "description",
      "type": "String",
      "description": "Sets the entry constraint to a groupId or the literal {\nNull or empty string resets the constraint to FC's default.\n\n/\n    public void setConstraint(String constraint) {\n        this.constraint = StringUtils.trimToNull(constraint);\n    }\n\n    /**\nSets the entry constraint to a custom {\nThe entry can then only be dragged/resized within the given hours.\n\n\n\n\n/\n    public void setConstraint(BusinessHours hours) {\n        this.constraint = Objects.requireNonNull(hours).toJson();\n    }\n\n    /**\nSets the entry's constraint to business hours, meaning the entry can only be placed during business hours.\nEquivalent to {\n/\n    public void setConstraintToBusinessHours() {\n        this.constraint = \"businessHours\";\n    }\n\n    /**\nSets the color for this entry. This is interpreted as background and border color on the client side.\nNull or empty string resets the color to the FC's default.\n\n/\n    public void setColor(String color) {\n        this.color = StringUtils.trimToNull(color);\n    }\n\n    /**\nSets the background color for this entry. Null or empty string resets the color to the FC's default.\n\n/\n    public void setBackgroundColor(String backgroundColor) {\n        this.backgroundColor = StringUtils.trimToNull(backgroundColor);\n    }\n\n    /**\nSets the text color for this entry. Null or empty string resets the color to the FC's default.\n\n/\n    public void setTextColor(String textColor) {\n        this.textColor = StringUtils.trimToNull(textColor);\n    }\n\n    /**\nSets the border color for this entry. Null or empty string resets the color to the FC's default.\n\n/\n    public void setBorderColor(String borderColor) {\n        this.borderColor = StringUtils.trimToNull(borderColor);\n    }\n\n    /**\nReturns the description of this entry. Since the description is a <b>custom property</b>, it will\nnot automatically be shown on the entry.",
      "clientUpdatable": false
    },
    {
      "name": "recurring",
      "type": "boolean",
      "description": "Sets the description of this entry. Since the description is a <b>custom property</b>, it will\nnot automatically be shown on the entry.\n\n/\n    public void setDescription(String description) {\n        setCustomProperty(EntryCustomProperties.DESCRIPTION, description);\n    }\n\n    /**\nSets the display mode for this entry. Passing null will reset it to the default.\n\n/\n    public void setDisplayMode(DisplayMode displayMode) {\n        this.displayMode = displayMode != null ? displayMode : DisplayMode.AUTO;\n    }\n\n    /**\nIndicates, if this entry is recurring. This is indicated by having any \"recurring\" property set (e.g.\n{",
      "clientUpdatable": false
    },
    {
      "name": "recurringStartTimeAsLocalTime",
      "type": "LocalTime",
      "description": "Returns the recurring start time as a local time.<br>\nSince the FC allows recurring times to be above the normal 24h span of a day, using a LocalTime can lead to\nissues, as it does not support times of 24h or above.",
      "clientUpdatable": false
    },
    {
      "name": "recurringEndTimeAsLocalTime",
      "type": "LocalTime",
      "description": "Returns the recurring end time as a local time.<br>\nSince the FC allows recurring times to be above the normal 24h span of a day, using a LocalTime can lead to\nissues, as it does not support times of 24h or above.",
      "clientUpdatable": false
    },
    {
      "name": "recurringStart",
      "type": "LocalDateTime",
      "description": "Sets the end time for a recurring entry. Passing a non null value automatically marks this entry\nas recurring. Passing null may remove the recurrence or let the recurring entry extend to the\nend of day.\n\n\n/\n    public void setRecurringEndTime(RecurringTime end) {\n        this.recurringEndTime = end;\n    }\n\n    /**\nSets the end time for a recurring entry. Passing a non null value automatically marks this entry\nas recurring. Passing null may remove the recurrence or let the recurring entry extend to the\nend of day.\n\n\n/\n    public void setRecurringEndTime(LocalTime end) {\n        setRecurringEndTime(end != null ? RecurringTime.of(end) : null);\n    }\n\n    /**\nReturns the recurring start. This method is a shortcut for combining {\nand {\nWill return null, when no recurrence date is defined. When only\na start date is defined, the returned date time will be at the start of that day.\n<br>\nIn case that the recurring start time is 24h or greater, the date part will shift depending on the\nresulting additional days. See {",
      "clientUpdatable": false
    },
    {
      "name": "recurringEnd",
      "type": "LocalDateTime",
      "description": "Returns the recurring end. This method is a shortcut for combining {\nand {\nWill return null, when no recurrence date is defined. When only a\nend date is defined, the returned date time will be at the end of that day (23:59:99).<br>\n<br>\nIn case that the recurring end time is 24h or greater, the date part will shift depending on the\nresulting additional days. See {",
      "clientUpdatable": false
    },
    {
      "name": "customPropertiesOrEmpty",
      "type": "Map<String, Object>",
      "description": "Returns the custom properties map or an empty one, if none has yet been created. The map is not writable.",
      "clientUpdatable": false
    },
    {
      "name": "orCreateCustomProperties",
      "type": "Map<String, Object>",
      "description": "Returns the map of the custom properties of this instance. This map is editable and any changes\nwill be sent to the client when the entry provider is refreshed.\n<p></p>\nCreates and registers a new map, if none is there yet.\n<p></p>\nBe aware, that any non standard property you\nset via \"set(..., ...)\" is not automatically put into this map, but this is done by the client later.",
      "clientUpdatable": false
    }
  ],
  "calendarViews": [
    {
      "name": "D",
      "enumValue": "D",
      "description": "Calendar view: D",
      "isSchedulerView": false
    },
    {
      "name": "Day Grid Month",
      "enumValue": "DAY_GRID_MONTH",
      "description": "Monthly view with days displayed in a grid",
      "isSchedulerView": false
    },
    {
      "name": "T",
      "enumValue": "T",
      "description": "Calendar view: T",
      "isSchedulerView": false
    },
    {
      "name": "Time Grid Day",
      "enumValue": "TIME_GRID_DAY",
      "description": "Single day view with time slots displayed vertically",
      "isSchedulerView": false
    },
    {
      "name": "T",
      "enumValue": "T",
      "description": "Calendar view: T",
      "isSchedulerView": false
    },
    {
      "name": "Time Grid Week",
      "enumValue": "TIME_GRID_WEEK",
      "description": "Weekly view with time slots displayed vertically",
      "isSchedulerView": false
    },
    {
      "name": "D",
      "enumValue": "D",
      "description": "Calendar view: D",
      "isSchedulerView": false
    },
    {
      "name": "Day Grid Day",
      "enumValue": "DAY_GRID_DAY",
      "description": "Single day view displayed in a grid format",
      "isSchedulerView": false
    },
    {
      "name": "D",
      "enumValue": "D",
      "description": "Calendar view: D",
      "isSchedulerView": false
    },
    {
      "name": "Day Grid Week",
      "enumValue": "DAY_GRID_WEEK",
      "description": "Weekly view with days displayed in a grid",
      "isSchedulerView": false
    },
    {
      "name": "D",
      "enumValue": "D",
      "description": "Calendar view: D",
      "isSchedulerView": false
    },
    {
      "name": "Day Grid Year",
      "enumValue": "DAY_GRID_YEAR",
      "description": "Yearly view with days displayed in a grid",
      "isSchedulerView": false
    },
    {
      "name": "E",
      "enumValue": "E",
      "description": "Calendar view: E",
      "isSchedulerView": false
    },
    {
      "name": "List Week",
      "enumValue": "LIST_WEEK",
      "description": "Weekly list view of events",
      "isSchedulerView": false
    },
    {
      "name": "E",
      "enumValue": "E",
      "description": "Calendar view: E",
      "isSchedulerView": false
    },
    {
      "name": "List Day",
      "enumValue": "LIST_DAY",
      "description": "Daily list view of events",
      "isSchedulerView": false
    },
    {
      "name": "E",
      "enumValue": "E",
      "description": "Calendar view: E",
      "isSchedulerView": false
    },
    {
      "name": "List Month",
      "enumValue": "LIST_MONTH",
      "description": "Monthly list view of events",
      "isSchedulerView": false
    },
    {
      "name": "E",
      "enumValue": "E",
      "description": "Calendar view: E",
      "isSchedulerView": false
    },
    {
      "name": "List Year",
      "enumValue": "LIST_YEAR",
      "description": "Yearly list view of events",
      "isSchedulerView": false
    },
    {
      "name": "S",
      "enumValue": "S",
      "description": "Calendar view: S",
      "isSchedulerView": false
    },
    {
      "name": "Multi Month",
      "enumValue": "MULTI_MONTH",
      "description": "Multiple months displayed at once",
      "isSchedulerView": false
    },
    {
      "name": "D",
      "enumValue": "D",
      "description": "Calendar view: D",
      "isSchedulerView": true
    },
    {
      "name": "Timeline Day",
      "enumValue": "TIMELINE_DAY",
      "description": "Timeline view for a single day with resources",
      "isSchedulerView": true
    },
    {
      "name": "W",
      "enumValue": "W",
      "description": "Calendar view: W",
      "isSchedulerView": true
    },
    {
      "name": "Timeline Week",
      "enumValue": "TIMELINE_WEEK",
      "description": "Timeline view for a week with resources",
      "isSchedulerView": true
    },
    {
      "name": "M",
      "enumValue": "M",
      "description": "Calendar view: M",
      "isSchedulerView": true
    },
    {
      "name": "Timeline Month",
      "enumValue": "TIMELINE_MONTH",
      "description": "Timeline view for a month with resources",
      "isSchedulerView": true
    },
    {
      "name": "Y",
      "enumValue": "Y",
      "description": "Calendar view: Y",
      "isSchedulerView": true
    },
    {
      "name": "Timeline Year",
      "enumValue": "TIMELINE_YEAR",
      "description": "Timeline view for a year with resources",
      "isSchedulerView": true
    },
    {
      "name": "D",
      "enumValue": "D",
      "description": "Calendar view: D",
      "isSchedulerView": true
    },
    {
      "name": "Resource Timeline Day",
      "enumValue": "RESOURCE_TIMELINE_DAY",
      "description": "Calendar view: RESOURCE_TIMELINE_DAY",
      "isSchedulerView": true
    },
    {
      "name": "W",
      "enumValue": "W",
      "description": "Calendar view: W",
      "isSchedulerView": true
    },
    {
      "name": "Resource Timeline Week",
      "enumValue": "RESOURCE_TIMELINE_WEEK",
      "description": "Calendar view: RESOURCE_TIMELINE_WEEK",
      "isSchedulerView": true
    },
    {
      "name": "M",
      "enumValue": "M",
      "description": "Calendar view: M",
      "isSchedulerView": true
    },
    {
      "name": "Resource Timeline Month",
      "enumValue": "RESOURCE_TIMELINE_MONTH",
      "description": "Calendar view: RESOURCE_TIMELINE_MONTH",
      "isSchedulerView": true
    },
    {
      "name": "Y",
      "enumValue": "Y",
      "description": "Calendar view: Y",
      "isSchedulerView": true
    },
    {
      "name": "Resource Timeline Year",
      "enumValue": "RESOURCE_TIMELINE_YEAR",
      "description": "Calendar view: RESOURCE_TIMELINE_YEAR",
      "isSchedulerView": true
    },
    {
      "name": "D",
      "enumValue": "D",
      "description": "Calendar view: D",
      "isSchedulerView": true
    },
    {
      "name": "Resource Time Grid Day",
      "enumValue": "RESOURCE_TIME_GRID_DAY",
      "description": "Calendar view: RESOURCE_TIME_GRID_DAY",
      "isSchedulerView": true
    },
    {
      "name": "Agenda Day",
      "enumValue": "AGENDA_DAY",
      "description": "Calendar view: AGENDA_DAY",
      "isSchedulerView": true
    },
    {
      "name": "W",
      "enumValue": "W",
      "description": "Calendar view: W",
      "isSchedulerView": true
    },
    {
      "name": "Resource Time Grid Week",
      "enumValue": "RESOURCE_TIME_GRID_WEEK",
      "description": "Calendar view: RESOURCE_TIME_GRID_WEEK",
      "isSchedulerView": true
    },
    {
      "name": "Agenda Week",
      "enumValue": "AGENDA_WEEK",
      "description": "Calendar view: AGENDA_WEEK",
      "isSchedulerView": true
    }
  ],
  "eventTypes": [
    {
      "name": "BrowserTimezoneObtainedEvent",
      "description": "This event gets fired when the client side reported the browser's timezone to the server. Since this is\ndone after the element has been attached to the client, it will be fired after all UI attach events.",
      "properties": [],
      "source": "core"
    },
    {
      "name": "DateEvent",
      "description": "An abstract class for date events, that are not directly entry related. They are always whole day events.",
      "properties": [],
      "source": "core"
    },
    {
      "name": "DateTimeEvent",
      "description": "An abstract class for date events, that are not directly entry related.",
      "properties": [
        {
          "name": "dateTimeAsInstant",
          "type": "Instant",
          "description": "An abstract class for date events, that are not directly entry related.\n/\n\n\npublic abstract class DateTimeEvent extends ComponentEvent<FullCalendar> {\n\n    /**\nIf the event has occurred for a day slot. False means, it has been for a time slot inside a day.\n/\n    private final boolean allDay;\n\n    /**\nThe utc based date time related to this event. For day slots the time will be at start of the day.\n/\n    private final LocalDateTime dateTime;\n\n    /**\nNew instance. Awaits the date (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").\n\n\n\n\n/\n    public DateTimeEvent(FullCalendar source, boolean fromClient, String dateString, boolean allDay) {\n        super(source, fromClient);\n\n        this.allDay = allDay;\n        dateTime = JsonUtils.parseClientSideDateTime(dateString);\n    }\n\n    /**\nThe utc based date time related to this event. For day slots the time will be at start of the day."
        },
        {
          "name": "dateTimeWithOffset",
          "type": "LocalDateTime",
          "description": "The date time related to this event including the calendar timezone's offset.\nFor day slots the time will be at start of the day and ignore the timezone."
        },
        {
          "name": "date",
          "type": "LocalDate",
          "description": "Returns only the date part of the contained local date time. This method is intended to be used on\nall day entry related events."
        }
      ],
      "source": "core"
    },
    {
      "name": "DropEvent",
      "description": "Fires when any external HTML element is dropped onto the calendar (requires {\nThis fires for <em>all</em> external drops, including non-event elements.\n<br><br>\nThe created entry can be obtained via {\n<br><br>\nIf the dropped element was registered via {\nuse {\n<br><br>\nFor drops of external elements that carry event data ({\nadded to the calendar as entries, {\n<br><br>\nClient side name: drop",
      "properties": [
        {
          "name": "draggable",
          "type": "Optional<Draggable>",
          "description": "Fires when any external HTML element is dropped onto the calendar (requires {\nThis fires for <em>all</em> external drops, including non-event elements.\n<br><br>\nThe created entry can be obtained via {\n<br><br>\nIf the dropped element was registered via {\nuse {\n<br><br>\nFor drops of external elements that carry event data ({\nadded to the calendar as entries, {\n<br><br>\nClient side name: drop\n/\n\n\n\npublic class DropEvent extends ComponentEvent<FullCalendar> {\n\n    /**\nThe calendar date onto which the element was dropped.\n/\n    private final LocalDate date;\n\n    /**\nWhether the drop occurred in the all-day area.\n/\n    private final boolean allDay;\n\n    /**\nThe resolved {\nregistered via {\n/\n    private final Draggable draggable;\n    private final Entry createdEntry;\n\n    /**\nNew instance.\n\n\n\n\n\n\n/\n    public DropEvent(FullCalendar source, boolean fromClient,\n                     \n                     \n                     \n                     \n        super(source, fromClient);\n        this.date = JsonUtils.parseClientSideDate(date);\n        this.allDay = allDay;\n        this.draggable = source.resolveDraggable(draggableId).orElse(null);\n\n        createdEntry = new Entry();\n        if (draggedElData != null) {\n            createdEntry.updateAllFromJson((ObjectNode) JsonMapper.shared().readTree(draggedElData), false);\n        } else {\n            createdEntry.setAllDay(allDay);\n            createdEntry.setStart(JsonUtils.parseClientSideDate(date));\n            LocalDateTime start = createdEntry.getStart();\n            createdEntry.setEnd(allDay ? start.plusDays(1) : start.plusHours(1));\n        }\n    }\n\n    /**\nReturns the {\n{"
        },
        {
          "name": "createdEntry",
          "type": "Entry",
          "description": "Returns the entry, that has been created by the client side as a result of the drop operation. The content\nof this entry may differ from the draggable entry data, depending on restrictions or limitations of the calendar.\n<p>\n    Please note, that this entry will NOT be automatically added to your entry provider in any case.\n</p>"
        }
      ],
      "source": "core"
    },
    {
      "name": "EntryEvent",
      "description": "Simple event that occurred for a specific calendar item.",
      "properties": [],
      "source": "core"
    },
    {
      "name": "EntryReceiveEvent",
      "description": "Fires when an external element carrying event data ({\nonto the calendar and FullCalendar has created a new entry from it.\n<br><br>\nThe {\npassed by the client. This entry is <em>not</em> added to the calendar's entry provider automatically;\nthe application must do this explicitly if it wants to persist the received entry\n(e.g. via {\n<br><br>\nIf the dropped element was registered via {\n{\n<br><br>\nNote: {\nthis event fires only when the dropped element produced a new calendar entry.\n<br><br>\nClient side name: eventReceive",
      "properties": [
        {
          "name": "draggable",
          "type": "Optional<Draggable>",
          "description": "Fires when an external element carrying event data ({\nonto the calendar and FullCalendar has created a new entry from it.\n<br><br>\nThe {\npassed by the client. This entry is <em>not</em> added to the calendar's entry provider automatically;\nthe application must do this explicitly if it wants to persist the received entry\n(e.g. via {\n<br><br>\nIf the dropped element was registered via {\n{\n<br><br>\nNote: {\nthis event fires only when the dropped element produced a new calendar entry.\n<br><br>\nClient side name: eventReceive\n\n\n/\n\n\n\npublic class EntryReceiveEvent extends ComponentEvent<FullCalendar> {\n\n    /**\nThe newly created entry, constructed from the data reported by the client.\nThis entry is not tracked by the calendar's entry provider.\n/\n    private final Entry entry;\n\n    /**\nThe resolved {\nregistered via {\n/\n    private final Draggable draggable;\n\n    /**\nNew instance.\n\n\n\n\n/\n    public EntryReceiveEvent(FullCalendar source, boolean fromClient,\n                             \n                             \n        super(source, fromClient);\n        Entry e = new Entry();\n        e.updateAllFromJson(entryData, false);\n        this.entry = e;\n        this.draggable = source.resolveDraggable(draggableId).orElse(null);\n    }\n\n    /**\nReturns the {\n{"
        }
      ],
      "source": "core"
    },
    {
      "name": "EventSourceFailureEvent",
      "description": "Fires when a client-managed event source (JSON feed, Google Calendar, iCal) fails to load.\n<br><br>\nUse this to react on the server side (e.g. show an error {\nThe {\n{\n<br><br>\nClient side name: eventSourceFailure",
      "properties": [],
      "source": "core"
    },
    {
      "name": "ExternalEntryEvent",
      "description": "Base class for events fired when an entry from a <em>client-managed</em> event source\n(JSON feed, Google Calendar, iCal) is interacted with (dropped or resized).\n<br><br>\nThe {\nJS data. This entry is NOT part of any {\nUse {",
      "properties": [],
      "source": "core"
    },
    {
      "name": "MultipleEntriesEvent",
      "description": "Simple event that occurred for multiple calendar items.",
      "properties": [
        {
          "name": "entries",
          "type": "Collection<Entry>",
          "description": "Simple event that occurred for multiple calendar items.\n/\n\n\npublic abstract class MultipleEntriesEvent extends ComponentEvent<FullCalendar> {\n\n    /**\nThe entry, for which the event occurred.\n/\n    private final Set<Entry> entries;\n\n    /**\nNew instance. Awaits the entry id.\n\n\n\n/\n    public MultipleEntriesEvent(FullCalendar source, boolean fromClient, Collection<String> entryIds) {\n        super(source, fromClient);\n\n        if (entryIds == null || entryIds.isEmpty()) {\n            throw new IllegalArgumentException(\"IDs parameter must not be null nor empty\");\n        }\n\n        this.entries = entryIds\n                .stream()\n                .map(id -> {\n                    Optional<Entry> entry = source.getCachedEntryFromFetch(id);\n                    if (!entry.isPresent()) {\n                        throw new IllegalArgumentException(\"No item found with id \" + id);\n                    }\n                    return entry;\n                })\n                .map(Optional::get)\n                .collect(Collectors.toSet());\n    }\n\n    /**\nReturns the entries for which this event occurred. Never null nor empty."
        }
      ],
      "source": "core"
    },
    {
      "name": "TimeslotsSelectedEvent",
      "description": "Occurs when the user selects one or multiple timeslots on the calendar. The selected timeslots may contain\nentries.\n<br><br>\nClient side event: select",
      "properties": [
        {
          "name": "startAsInstant",
          "type": "Instant",
          "description": "Occurs when the user selects one or multiple timeslots on the calendar. The selected timeslots may contain\nentries.\n<br><br>\nClient side event: select\n/\n\n\n\npublic class TimeslotsSelectedEvent extends ComponentEvent<FullCalendar> {\n\n    /**\nIf the selection has been for day slots. False means, it has been a selection on time slots inside a day.\n/\n    private final boolean allDay;\n\n    /**\nReturns the start of the event as local date time. Represents the UTC date time this event starts, which\nmeans the time is the same as when calling {\n/\n    private final LocalDateTime start;\n\n    /**\nReturns the end of the event as local date time. Represents the UTC date time this event ends, which\nmeans the time is the same as when calling {\n/\n    private final LocalDateTime end;\n\n    /**\nNew instance. Awaits the selected dates (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").\n\n\n\n\n\n/\n    public TimeslotsSelectedEvent(FullCalendar source, boolean fromClient, \n        super(source, fromClient);\n\n        Timezone timezone = source.getTimezone();\n        this.allDay = allDay;\n        this.start = JsonUtils.parseClientSideDateTime(start);\n        this.end = JsonUtils.parseClientSideDateTime(end);\n    }\n\n    /**\nReturns the entry's start as an {\n{"
        },
        {
          "name": "endAsInstant",
          "type": "Instant",
          "description": "Returns the entry's end as an {\n{"
        },
        {
          "name": "startWithOffset",
          "type": "LocalDateTime",
          "description": "Returns the start time as a local date time after applying the timezone's offset to\nthe utc based start date ({\nthe calendar's timezone or, if no calendar is set yet, UTC.\n<p></p>"
        },
        {
          "name": "endWithOffset",
          "type": "LocalDateTime",
          "description": "Returns the end time as a local date time after applying the timezone's offset to\nthe utc based end date ({\nthe calendar's timezone or, if no calendar is set yet, UTC."
        },
        {
          "name": "startDate",
          "type": "LocalDate",
          "description": "Returns the start of the event as local date."
        },
        {
          "name": "endDate",
          "type": "LocalDate",
          "description": "Returns the end of the event as local date."
        }
      ],
      "source": "core"
    },
    {
      "name": "TimeslotsUnselectEvent",
      "description": "Fires when the current timeslot selection is cleared. This complements {\n<br><br>\nUnselect can be triggered by:\n<ul>\n  <li>The user clicking elsewhere on the calendar (when {\n  <li>The user pressing Escape</li>\n  <li>A new selection being made (which replaces the old one)</li>\n  <li>Code calling {\n</ul>\n<br>\nClient side name: unselect",
      "properties": [],
      "source": "core"
    },
    {
      "name": "ViewRenderEvent",
      "description": "Basic event for view render events. Provides information about the shown timespan.\n<br><br>\nThe values are always daybased, regardless of the current view.",
      "properties": [
        {
          "name": "calendarView",
          "type": "Optional<CalendarView>",
          "description": "Basic event for view render events. Provides information about the shown timespan.\n<br><br>\nThe values are always daybased, regardless of the current view.\n/\n\n\npublic abstract class ViewRenderEvent extends ComponentEvent<FullCalendar> {\n\n    /**\nThe client side name of the view.\n/\n    private final String viewName;\n\n    /**\nThe current shown interval's start date.\n/\n    private final LocalDate intervalStart;\n\n    /**\nThe current shown interval's end date.\n/\n    private final LocalDate intervalEnd;\n\n    /**\nThe first visible date. In month-view, this value is often before\nthe 1st day of the month, because most months do not begin on the first\nday-of-week.\n/\n    private final LocalDate start;\n\n    /**\nThe last visible date. In month-view, this value is often after\nthe last day of the month, because most months do not end on the last day of the week\n/\n    private final LocalDate end;\n\n\n    private final CalendarView calendarView;\n\n    /**\nCreates a new event using the given source and indicator whether the\nevent originated from the client side or the server side.\n\n\n/\n    public ViewRenderEvent(FullCalendar source, boolean fromClient, ObjectNode eventData) {\n        super(source, fromClient);\n\n        this.viewName = eventData.get(\"name\").asString();\n\n        this.calendarView = source.lookupViewName(viewName).orElse(null);\n\n        this.intervalStart = parseClientSideDate(eventData.get(\"intervalStart\").asString());\n        this.intervalEnd = parseClientSideDate(eventData.get(\"intervalEnd\").asString());\n        this.start = parseClientSideDate(eventData.get(\"start\").asString());\n        this.end = parseClientSideDate(eventData.get(\"end\").asString());\n    }\n\n    /**\nSame as {\n\n\n/\n    \n    public String getName() {\n        return viewName;\n    }\n\n    /**\nThe calendar view of this event. Empty, if the view name could not be matched with one of the predefined\nviews (e.g. in case of a custom view)."
        }
      ],
      "source": "core"
    },
    {
      "name": "EntryDroppedSchedulerEvent",
      "description": "Scheduler event: entry dropped scheduler event",
      "properties": [
        {
          "name": "oldResource",
          "type": "Optional<Resource>",
          "description": "New instance. Awaits the changed data object for the entry plus the json object for the delta information.\n\n\n\n\n/\n    public EntryDroppedSchedulerEvent(FullCalendarScheduler source, boolean fromClient,\n                                      \n                                      \n        super(source, fromClient, jsonEntry, jsonDelta);\n\n        if(jsonEntry.hasNonNull(\"oldResource\")) {\n            this.oldResource = source.getResourceById(jsonEntry.get(\"oldResource\").asString()).orElseThrow(IllegalArgumentException::new);\n        } else {\n            this.oldResource = null;\n        }\n\n        if(jsonEntry.has(\"newResource\")) {\n            this.newResource = source.getResourceById(jsonEntry.get(\"newResource\").asString()).orElseThrow(IllegalArgumentException::new);\n        } else {\n            this.newResource = null;\n        }\n    }\n\n    /**\nApplies the changes on the entry including updating a resource change.\n\n/\n    \n    public Entry applyChangesOnEntry() {\n        ResourceEntry entry = (ResourceEntry) super.applyChangesOnEntry();\n        ObjectNode object = getJsonObject();\n\n        updateResourcesFromEventResourceDelta(entry, object);\n\n        return entry;\n    }\n\n    public static void updateResourcesFromEventResourceDelta(ResourceEntry entry, ObjectNode object) {\n        entry.getCalendar().map(c -> (Scheduler) c).ifPresent(calendar -> {\n            Optional.ofNullable(object.get(\"oldResource\"))\n                    .filter(JsonNode::isString)\n                    .map(JsonNode::asString)\n                    .flatMap(calendar::getResourceById)\n                    .map(Collections::singleton)\n                    .ifPresent(entry::removeResources);\n\n            Optional.ofNullable(object.get(\"newResource\"))\n                    .filter(JsonNode::isString)\n                    .map(JsonNode::asString)\n                    .flatMap(calendar::getResourceById)\n                    .map(Collections::singleton)\n                    .ifPresent(entry::addResources);\n        });\n    }\n\n    /**\nIf there has been a change in the resource assignments, this method returns the previous assigned resource."
        },
        {
          "name": "newResource",
          "type": "Optional<Resource>",
          "description": "If there has been a change in the resource assignments, this method returns the newly assigned resource."
        }
      ],
      "source": "scheduler"
    },
    {
      "name": "TimeslotClickedSchedulerEvent",
      "description": "This type extends the normal timeslot clicked event by providing the selected resource (if there's one).\n<br><br>\nClient side event: dateClick",
      "properties": [
        {
          "name": "resource",
          "type": "Optional<Resource>",
          "description": "This type extends the normal timeslot clicked event by providing the selected resource (if there's one).\n<br><br>\nClient side event: dateClick\n/\n\n\npublic class TimeslotClickedSchedulerEvent extends TimeslotClickedEvent {\n\n    private Resource resource;\n\n    /**\nNew instance. Awaits the clicked date (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").\n\n\n\n\n\n/\n    public TimeslotClickedSchedulerEvent(FullCalendarScheduler source, boolean fromClient, \n        super(source, fromClient, date, allDay);\n\n        if (resourceId != null) {\n            this.resource = source.getResourceById(resourceId).orElseThrow(IllegalArgumentException::new);\n        }\n    }\n\n    /**\nIf the select event has occured in the scheduler, the selected resource will be returned."
        }
      ],
      "source": "scheduler"
    },
    {
      "name": "TimeslotsSelectedSchedulerEvent",
      "description": "This type extends the normal timeslot selected event by providing the selected resource (if there's one).\n<br><br>\nClient side event: select",
      "properties": [
        {
          "name": "resource",
          "type": "Optional<Resource>",
          "description": "This type extends the normal timeslot selected event by providing the selected resource (if there's one).\n<br><br>\nClient side event: select\n/\n\n\npublic class TimeslotsSelectedSchedulerEvent extends TimeslotsSelectedEvent {\n\n    private Resource resource;\n\n    /**\nNew instance. Awaits the selected dates (time) as iso string (e.g. \"2018-10-23\" or \"2018-10-23T13:30\").\n\n\n\n\n\n\n/\n    public TimeslotsSelectedSchedulerEvent(FullCalendarScheduler source, boolean fromClient, \n        super(source, fromClient, start, end, allDay);\n\n        if (resourceId != null) {\n            this.resource = source.getResourceById(resourceId).orElseThrow(IllegalArgumentException::new);\n        }\n    }\n\n    /**\nIf the select event has occured in the scheduler, the selected resource will be returned."
        }
      ],
      "source": "scheduler"
    }
  ],
  "version": "7.2.0",
  "extractedAt": "2026-04-21T04:33:59.629Z"
}