Статьи

Добавление динамического календаря в HarpJS

Еще один день, еще один рецепт HarpJS . Можете ли вы сказать, что меня волнует в последнее время? Для сегодняшней демонстрации я создал простой динамический календарь для HarpJS. Вероятно, есть много разных способов справиться с этим (вы можете просто встроить Календарь Google, как я здесь опишу ), но вот как я это решил.

Я решил использовать плагин FullCalendar jQuery для отображения календаря. Я использовал его раньше с демонстрацией ColdFusion, и мне нравится, как легко это использовать. Я также знал, что он поддерживает загрузку событий из источника Ajax. HarpJS позволяет создавать больше, чем просто динамические HTML-страницы. Вы также можете создавать динамические файлы XML и JSON. Этот рецепт описывает, как вы можете генерировать XML для RSS-канала. Аналогичный метод может быть использован для генерации JSON.

Я начал с создания папки событий. Внутри этой папки я создал несколько файлов для представления моих событий. Я не делаю с этим ничего особенного, поэтому не стану делиться кодом. Затем я создал файл _data.json. Это то, что будет управлять подачей JSON.

{
	"a":{
		"title":"Event A",
		"date":"2/14/2014",
		"allDay":true
	},
	"b":{
		"title":"Event B",
		"date":"2/13/2014 2:00 PM"
	},
	"events":{
		"layout":false
	}
}

Первые два пункта представляют мои события. Название и дата должны иметь смысл. Я объясню весь день через секунду. Последний элемент представляет файл, который будет генерировать мой канал JSON. По умолчанию Harp оборачивает ваши страницы в шаблоны макета. Но для фида JSON этот макет нарушит код, который его анализирует. Добавляя layout: false, я говорю Harp’у не переносить этот файл с обычным макетом сайта. (Это вызывает еще одну небольшую проблему, и в конце я расскажу об этом подробнее.)

Далее — я создал свой интерфейс. Это взято прямо из файлов примеров FullCalendar, так что это не слишком волнует, но вот оно:

<link href='/fullcalendar/fullcalendar.css' rel='stylesheet' />
<link href='/fullcalendar/fullcalendar.print.css' rel='stylesheet' media='print' />
<script src='/lib/moment.min.js'></script>
<script src='/lib/jquery.min.js'></script>
<script src='/lib/jquery-ui.custom.min.js'></script>
<script src='/fullcalendar/fullcalendar.min.js'></script>
<script>

	$(document).ready(function() {
	
		$('#calendar').fullCalendar({
			header: {
				left: 'prev,next today',
				center: 'title',
				right: 'month,agendaWeek,agendaDay'
			},
			editable: true,
			timezone:"America/Chicago",
			events: {
				url: '/events/events.json',
				error: function() {
					$('#script-warning').show();
				}
			},
			loading: function(bool) {
				$('#loading').toggle(bool);
			}
		});
		
	});

</script>


<div id='script-warning'>
	crap broke.
</div>

<div id='loading'>loading...</div>

<div id='calendar'></div>

Единственное, что здесь действительно интересно, это опция URL в полном календаре. Обратите внимание, что я указываю на /events/events.json. Мой настоящий файл — events / events.json.ejs. Harp обслужит его без расширения EJS и даже автоматически использует правильный тип контента на основе расширения JSON. Прохладно! Теперь давайте посмотрим на код.

[
	<% 
	var events = Object.keys(public.events._data);
	for(var i=0; i<events.length; i++) { 
		if(events[i] !== "events") {
			event = public.events._data[events[i]];
	%>
		{
			"title":"<%- event.title %>",
			"start":"<%- event.date %>",
			"url":"/events/<%- events[i] %>.html"
			<% if(event.allDay) { %>
			,"allDay":<%- event.allDay %>
			<% } %>
		}
			<% if(i+2 < events.length) { %>,<% } %>
	<% 
		}
	} 
	%>
]

Хорошо, не самый красивый код, но давайте разберем его. Я начинаю с того, что получаю ключи от моих данных и зацикливаюсь на них. Я пропускаю ключ событий — помните, он есть только для того, чтобы я мог отключить макет. Для каждого события я вывожу название и дату. Начальная метка используется там, потому что именно этого хочет FullCalendar. Говоря о — FullCalendar также требует, чтобы вы сообщили ему, когда событие заканчивается в течение всего дня. Если вы этого не сделаете, он делает предположение о времени. Вот почему я включил allDay в свои данные JSON, и вы можете увидеть меня здесь. Наконец, я использую немного логики, чтобы определить, нахожусь ли я в конце цикла. Если я не, я вывожу запятую.

Так что да — это безобразно — и мне было довольно легко это сломать. Вывод был хорош — но код был грубым. Затем я понял, что для меня будет глупо создавать JSON, когда сервер может сделать это вместо этого. Вот вторая версия:

<%
var eventData = [];
var events = Object.keys(public.events._data);
for(var i=0; i<events.length;i++) {
	if(events[i] !== "events") {
		var eventOb = {};
		event = public.events._data[events[i]];
		eventOb.title = event.title;
		eventOb.start = event.date;
		eventOb.url = "/events/" + events[i] + ".html";
		if(event.allDay) {
			eventOb.allDay = event.allDay;	
		}
		eventData.push(eventOb);
	}
}

%>

<%- JSON.stringify(eventData) %>

Черт побольше чище, верно? И тогда я заканчиваю простым вызовом JSON.stringify. Гораздо проще Вот и все! Вот снимок экрана с календарем, отображающим события, поддерживаемые HarpJS, и динамический канал JSON.