@forcecalendar/interface 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -272,10 +272,15 @@ export class ForceCalendar extends BaseComponent {
|
|
|
272
272
|
flex-direction: column;
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
-
/* Ensure view
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
275
|
+
/* Ensure view container has proper dimensions */
|
|
276
|
+
#calendar-view-container {
|
|
277
|
+
display: block;
|
|
278
|
+
width: 100%;
|
|
279
|
+
height: 100%;
|
|
280
|
+
flex: 1;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
#calendar-view-container > * {
|
|
279
284
|
display: block;
|
|
280
285
|
width: 100%;
|
|
281
286
|
height: 100%;
|
|
@@ -421,31 +426,41 @@ export class ForceCalendar extends BaseComponent {
|
|
|
421
426
|
}
|
|
422
427
|
|
|
423
428
|
renderView() {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const tagName = `forcecal-${this.currentView}`;
|
|
429
|
-
return `<${tagName} id="calendar-view"></${tagName}>`;
|
|
429
|
+
// Use a plain div container - we'll manually instantiate view classes
|
|
430
|
+
// This bypasses Locker Service's custom element restrictions
|
|
431
|
+
return '<div id="calendar-view-container"></div>';
|
|
430
432
|
}
|
|
431
433
|
|
|
432
434
|
afterRender() {
|
|
433
|
-
//
|
|
434
|
-
const
|
|
435
|
-
console.log('[ForceCalendar] afterRender -
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
435
|
+
// Manually instantiate and mount view component (bypasses Locker Service)
|
|
436
|
+
const container = this.$('#calendar-view-container');
|
|
437
|
+
console.log('[ForceCalendar] afterRender - container:', !!container, 'stateManager:', !!this.stateManager, 'currentView:', this.currentView);
|
|
438
|
+
|
|
439
|
+
if (container && this.stateManager && this.currentView) {
|
|
440
|
+
// Clean up previous view if exists
|
|
441
|
+
if (this._currentViewInstance) {
|
|
442
|
+
if (this._currentViewInstance.cleanup) {
|
|
443
|
+
this._currentViewInstance.cleanup();
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
console.log('[ForceCalendar] Creating view for:', this.currentView);
|
|
448
|
+
|
|
449
|
+
// Create a simple view renderer that doesn't use custom elements
|
|
450
|
+
const viewRenderer = this._createViewRenderer(this.currentView);
|
|
451
|
+
if (viewRenderer) {
|
|
452
|
+
this._currentViewInstance = viewRenderer;
|
|
453
|
+
viewRenderer.stateManager = this.stateManager;
|
|
454
|
+
viewRenderer.container = container;
|
|
455
|
+
viewRenderer.render();
|
|
456
|
+
|
|
457
|
+
// Subscribe to state changes
|
|
458
|
+
this.stateManager.subscribe((newState, oldState) => {
|
|
459
|
+
if (viewRenderer && viewRenderer.render) {
|
|
460
|
+
viewRenderer.render();
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
}
|
|
449
464
|
}
|
|
450
465
|
|
|
451
466
|
// Add event listeners for buttons using tracked addListener
|
|
@@ -491,6 +506,138 @@ export class ForceCalendar extends BaseComponent {
|
|
|
491
506
|
}
|
|
492
507
|
}
|
|
493
508
|
|
|
509
|
+
_createViewRenderer(viewName) {
|
|
510
|
+
// Create a simple view renderer that bypasses custom elements
|
|
511
|
+
// This is necessary for Salesforce Locker Service compatibility
|
|
512
|
+
const self = this;
|
|
513
|
+
|
|
514
|
+
return {
|
|
515
|
+
stateManager: null,
|
|
516
|
+
container: null,
|
|
517
|
+
_listeners: [],
|
|
518
|
+
|
|
519
|
+
cleanup() {
|
|
520
|
+
this._listeners.forEach(({ element, event, handler }) => {
|
|
521
|
+
element.removeEventListener(event, handler);
|
|
522
|
+
});
|
|
523
|
+
this._listeners = [];
|
|
524
|
+
},
|
|
525
|
+
|
|
526
|
+
addListener(element, event, handler) {
|
|
527
|
+
element.addEventListener(event, handler);
|
|
528
|
+
this._listeners.push({ element, event, handler });
|
|
529
|
+
},
|
|
530
|
+
|
|
531
|
+
render() {
|
|
532
|
+
if (!this.container || !this.stateManager) return;
|
|
533
|
+
|
|
534
|
+
const viewData = this.stateManager.getViewData();
|
|
535
|
+
if (!viewData || !viewData.weeks) {
|
|
536
|
+
this.container.innerHTML = '<div style="padding: 20px; text-align: center;">Loading calendar...</div>';
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
this.cleanup();
|
|
541
|
+
const config = this.stateManager.getState().config;
|
|
542
|
+
const html = this._renderMonthView(viewData, config);
|
|
543
|
+
this.container.innerHTML = html;
|
|
544
|
+
this._attachEventHandlers();
|
|
545
|
+
},
|
|
546
|
+
|
|
547
|
+
_renderMonthView(viewData, config) {
|
|
548
|
+
const weekStartsOn = config.weekStartsOn || 0;
|
|
549
|
+
const dayNames = [];
|
|
550
|
+
for (let i = 0; i < 7; i++) {
|
|
551
|
+
const dayIndex = (weekStartsOn + i) % 7;
|
|
552
|
+
dayNames.push(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][dayIndex]);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
let html = `
|
|
556
|
+
<style>
|
|
557
|
+
.fc-month-view { display: flex; flex-direction: column; height: 100%; background: #fff; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 13px; }
|
|
558
|
+
.fc-month-header { display: grid; grid-template-columns: repeat(7, 1fr); background: #fafafa; border-bottom: 1px solid #e5e7eb; }
|
|
559
|
+
.fc-month-header-cell { padding: 8px; text-align: left; font-weight: 600; font-size: 10px; color: #9ca3af; text-transform: uppercase; letter-spacing: 0.5px; }
|
|
560
|
+
.fc-month-body { flex: 1; display: flex; flex-direction: column; }
|
|
561
|
+
.fc-month-week { flex: 1; display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid #e5e7eb; }
|
|
562
|
+
.fc-month-week:last-child { border-bottom: none; }
|
|
563
|
+
.fc-month-day { background: #fff; padding: 4px; position: relative; border-right: 1px solid #e5e7eb; min-height: 80px; cursor: pointer; }
|
|
564
|
+
.fc-month-day:last-child { border-right: none; }
|
|
565
|
+
.fc-month-day:hover { background: #f9fafb; }
|
|
566
|
+
.fc-month-day.other-month { background: #f9fafb; }
|
|
567
|
+
.fc-month-day.other-month .fc-day-number { color: #d1d5db; }
|
|
568
|
+
.fc-month-day.today .fc-day-number { background: #ef4444; color: white; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; }
|
|
569
|
+
.fc-day-number { font-size: 12px; font-weight: 500; color: #111827; padding: 4px; }
|
|
570
|
+
.fc-day-events { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
|
|
571
|
+
.fc-event { font-size: 11px; padding: 2px 6px; border-radius: 2px; background: #2563eb; color: white; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
|
|
572
|
+
.fc-event:hover { opacity: 0.9; }
|
|
573
|
+
.fc-more-events { font-size: 10px; color: #6b7280; padding: 2px 4px; cursor: pointer; }
|
|
574
|
+
.fc-more-events:hover { color: #111827; text-decoration: underline; }
|
|
575
|
+
</style>
|
|
576
|
+
<div class="fc-month-view">
|
|
577
|
+
<div class="fc-month-header">
|
|
578
|
+
${dayNames.map(d => `<div class="fc-month-header-cell">${d}</div>`).join('')}
|
|
579
|
+
</div>
|
|
580
|
+
<div class="fc-month-body">
|
|
581
|
+
`;
|
|
582
|
+
|
|
583
|
+
viewData.weeks.forEach(week => {
|
|
584
|
+
html += '<div class="fc-month-week">';
|
|
585
|
+
week.days.forEach(day => {
|
|
586
|
+
const classes = ['fc-month-day'];
|
|
587
|
+
if (!day.isCurrentMonth) classes.push('other-month');
|
|
588
|
+
if (day.isToday) classes.push('today');
|
|
589
|
+
|
|
590
|
+
const events = day.events || [];
|
|
591
|
+
const visibleEvents = events.slice(0, 3);
|
|
592
|
+
const moreCount = events.length - 3;
|
|
593
|
+
|
|
594
|
+
html += `
|
|
595
|
+
<div class="${classes.join(' ')}" data-date="${day.date}">
|
|
596
|
+
<div class="fc-day-number">${day.dayOfMonth}</div>
|
|
597
|
+
<div class="fc-day-events">
|
|
598
|
+
${visibleEvents.map(evt => `
|
|
599
|
+
<div class="fc-event" data-event-id="${evt.id}" style="background-color: ${evt.backgroundColor || '#2563eb'}">
|
|
600
|
+
${evt.title}
|
|
601
|
+
</div>
|
|
602
|
+
`).join('')}
|
|
603
|
+
${moreCount > 0 ? `<div class="fc-more-events">+${moreCount} more</div>` : ''}
|
|
604
|
+
</div>
|
|
605
|
+
</div>
|
|
606
|
+
`;
|
|
607
|
+
});
|
|
608
|
+
html += '</div>';
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
html += '</div></div>';
|
|
612
|
+
return html;
|
|
613
|
+
},
|
|
614
|
+
|
|
615
|
+
_attachEventHandlers() {
|
|
616
|
+
const stateManager = this.stateManager;
|
|
617
|
+
|
|
618
|
+
// Day click handlers
|
|
619
|
+
this.container.querySelectorAll('.fc-month-day').forEach(dayEl => {
|
|
620
|
+
this.addListener(dayEl, 'click', (e) => {
|
|
621
|
+
const date = new Date(dayEl.dataset.date);
|
|
622
|
+
stateManager.selectDate(date);
|
|
623
|
+
});
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
// Event click handlers
|
|
627
|
+
this.container.querySelectorAll('.fc-event').forEach(eventEl => {
|
|
628
|
+
this.addListener(eventEl, 'click', (e) => {
|
|
629
|
+
e.stopPropagation();
|
|
630
|
+
const eventId = eventEl.dataset.eventId;
|
|
631
|
+
const event = stateManager.getEvents().find(ev => ev.id === eventId);
|
|
632
|
+
if (event) {
|
|
633
|
+
stateManager.selectEvent(event);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
494
641
|
handleNavigation(event) {
|
|
495
642
|
const action = event.currentTarget.dataset.action;
|
|
496
643
|
switch (action) {
|