UNPKG

@lemonadejs/timeline

Version:

LemonadeJS timeline component

216 lines (179 loc) 7.54 kB
if (!lemonade && typeof (require) === 'function') { var lemonade = require('lemonadejs'); } ; (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : global.Timeline = factory(); }(this, (function () { let dateSignature = null; // Dispatcher const Dispatch = function (type, option) { if (typeof this[type] === 'function') { this[type](this, option); } } const TimelineEvents = function () { this.onload = function () { if (this.borderColor) { this.el.style.setProperty('--lm-border-color', this.borderColor); } if (this.borderStyle) { this.el.style.setProperty('--lm-border-style', this.borderStyle); } } return `<div class="lm-timeline-item" data-bullet="{{self.day}}"> <div class="lm-timeline-title">{{self.title}}</div> <div class="lm-timeline-subtitle">{{self.subtitle}}</div> <div class="lm-timeline-description">{{self.description}}</div> </div>`; } const Timeline = function () { let self = this; let date = new Date(); self.result = []; if (!Array.isArray(self.data)) { self.data = []; } self.year = date.getFullYear(); self.month = 1 + date.getMonth(); self.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; // Error message if (!self.message) { self.message = 'No records found'; } if (!self.order) { self.order = 'asc'; } // Make sure to align has a default if (!['top', 'right', 'bottom', 'left'].includes(self.align)) { self.align = 'left'; } const isRemote = function() { return self.remote && self.url && self.type === 'monthly'; } const getDate = function(d) { let date = d && d === dateSignature ? '' : d; dateSignature = d; return date; } self.next = function () { if (self.month === 12) { self.year++; self.month = 1; } else { self.month++; } } self.prev = function () { if (self.month === 1) { self.year--; self.month = 12; } else { self.month--; } } self.updateResult = function () { let result = []; if (self.type === 'monthly') { for (let i = 0; i < self.data.length; i++) { if ((self.data[i].date.getMonth() + 1) === self.month && self.data[i].date.getFullYear() === self.year) { result.push(self.data[i]); } } } else { result = self.data; } result = result.sort((a, b) => (self.order === 'desc' ? -1 : 1) * (a.date.getTime() - b.date.getTime())); for (let i = 0; i < result.length; i++) { result[i].day = getDate(result[i].date.toLocaleDateString('en-GB', { year: 'numeric', month: 'short', day: '2-digit' })); } self.result = result; // Reset the date signature to avoid interference in the next rendering dateSignature = null; // Event Dispatch.call(self, 'onupdate', self, result); } self.fetchRemote = function () { const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { let res = JSON.parse(xhr.responseText); let result = []; if (Array.isArray(res.result)) { result = res.result; } else if (Array.isArray(res)) { result = res } for (let i = 0; i < result.length; i++) { result[i].date = new Date(result[i].date); result[i].day = getDate(result[i].date.toLocaleDateString('en-GB', { year: 'numeric', month: 'short', day: '2-digit' })); } if (isRemote()) { self.result = result; } else { self.data = result; } } else { console.error('Failed to fetch data. Status code: ' + xhr.status); } } }; let url = self.url; if (isRemote()) { url += `?year=${self.year}&month=${self.month}`; url += `&asc=${self.order === 'asc'}` } xhr.open('GET', url, true); xhr.setRequestHeader('Content-Type', 'text/json') xhr.send(); } lemonade.onchange(function(prop) { if (prop === 'data' || prop === 'month' || prop === 'order') { if (isRemote()) { self.fetchRemote(); } else { self.updateResult(); } } }) lemonade.onload(function () { if (self.url) { self.fetchRemote(); } else { self.updateResult(); } if (typeof (self.width) !== 'undefined') { self.el.style.width = parseInt(self.width) + 'px'; } if (typeof (self.height) !== 'undefined') { self.el.style.height = parseInt(self.height) + 'px'; } }); return render => render`<div class="lm-timeline" :d="self.data" :d-order="self.order"> <div class="lm-timeline-header" data-visible="{{self.controls}}" data-type="{{self.type}}"> <div class="lm-timeline-label"> <div class="lm-timeline-month">{{self.months[self.month - 1]}}</div> <div class="lm-timeline-year">{{self.year}}</div> </div> <div class="lm-timeline-navigation"> <i class="material-icons" onclick="self.prev">keyboard_arrow_left</i> <i class="material-icons" onclick="self.next">keyboard_arrow_right</i> </div> </div> <div class="lm-timeline-data" data-message="{{self.message}}" data-mode="{{self.position}}" data-align="{{self.align}}"> <TimelineEvents :loop="self.result" /> </div> </div>`; } lemonade.setComponents({ Timeline: Timeline, TimelineEvents: TimelineEvents }); return function (root, options) { if (typeof (root) === 'object') { lemonade.render(Timeline, root, options); return options; } else { return Timeline.call(this, root); } } })));