@forcecalendar/interface 1.0.9 → 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,50 +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
|
-
// Try to force custom element upgrade (Locker Service may prevent auto-upgrade)
|
|
444
|
-
if (typeof customElements !== 'undefined' && customElements.upgrade) {
|
|
445
|
-
console.log('[ForceCalendar] Forcing custom element upgrade');
|
|
446
|
-
customElements.upgrade(viewElement);
|
|
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
|
+
}
|
|
447
445
|
}
|
|
448
446
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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
|
+
});
|
|
465
463
|
}
|
|
466
|
-
} else {
|
|
467
|
-
console.log('[ForceCalendar] Could not set stateManager - viewElement:', !!viewElement, 'stateManager:', !!this.stateManager);
|
|
468
464
|
}
|
|
469
465
|
|
|
470
466
|
// Add event listeners for buttons using tracked addListener
|
|
@@ -510,6 +506,138 @@ export class ForceCalendar extends BaseComponent {
|
|
|
510
506
|
}
|
|
511
507
|
}
|
|
512
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
|
+
|
|
513
641
|
handleNavigation(event) {
|
|
514
642
|
const action = event.currentTarget.dataset.action;
|
|
515
643
|
switch (action) {
|