diff --git a/cms/pages/modules/cms_calendar.php b/cms/pages/modules/cms_calendar.php
index 40ede75..b185771 100644
--- a/cms/pages/modules/cms_calendar.php
+++ b/cms/pages/modules/cms_calendar.php
@@ -586,13 +586,17 @@ class Module_cms_calendar extends Standard_crud_module
         $fields->attach(form_input_list(do_lang_tempcode('TYPE'), do_lang_tempcode('DESCRIPTION_EVENT_TYPE'), 'type', $type_list));
 
         // Priority
-        $priority_list = new Tempcode();
-        $priority_list->attach(form_input_list_entry('1', $priority == 1, do_lang_tempcode('PRIORITY_1')));
-        $priority_list->attach(form_input_list_entry('2', $priority == 2, do_lang_tempcode('PRIORITY_2')));
-        $priority_list->attach(form_input_list_entry('3', $priority == 3, do_lang_tempcode('PRIORITY_3')));
-        $priority_list->attach(form_input_list_entry('4', $priority == 4, do_lang_tempcode('PRIORITY_4')));
-        $priority_list->attach(form_input_list_entry('5', $priority == 5, do_lang_tempcode('PRIORITY_5')));
-        $fields->attach(form_input_list(do_lang_tempcode('PRIORITY'), '', 'priority', $priority_list));
+        if (get_value('event_priorities') !== '0') {
+            $priority_list = new Tempcode();
+            $priority_list->attach(form_input_list_entry('1', $priority == 1, do_lang_tempcode('PRIORITY_1')));
+            $priority_list->attach(form_input_list_entry('2', $priority == 2, do_lang_tempcode('PRIORITY_2')));
+            $priority_list->attach(form_input_list_entry('3', $priority == 3, do_lang_tempcode('PRIORITY_3')));
+            $priority_list->attach(form_input_list_entry('4', $priority == 4, do_lang_tempcode('PRIORITY_4')));
+            $priority_list->attach(form_input_list_entry('5', $priority == 5, do_lang_tempcode('PRIORITY_5')));
+            $fields->attach(form_input_list(do_lang_tempcode('PRIORITY'), '', 'priority', $priority_list));
+        } else {
+            $hidden->attach(form_input_hidden('priority', '3'));
+        }
 
         // Validation
         if ($validated == 0) {
diff --git a/themes/default/templates_custom/CALENDAR_MAIN_SCREEN.tpl b/themes/default/templates_custom/CALENDAR_MAIN_SCREEN.tpl
new file mode 100644
index 0000000..01e2170
--- /dev/null
+++ b/themes/default/templates_custom/CALENDAR_MAIN_SCREEN.tpl
@@ -0,0 +1,188 @@
+{TITLE}
+
+{$REQUIRE_JAVASCRIPT,ajax}
+{$REQUIRE_JAVASCRIPT,sets}
+
+<div class="calendar_top_navigation">
+	<div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
+		{+START,IF_NON_EMPTY,{YEAR_URL}}
+			<a href="{YEAR_URL*}">{!YEARLY}</a>
+		{+END}
+		{+START,IF_EMPTY,{YEAR_URL}}
+			<span>{!YEARLY}</span>
+		{+END}
+
+		{+START,IF_PASSED,ALL_YEARS}
+			{+START,INCLUDE,CALENDAR_JUMP_SET}
+				VARIABLE=ALL_YEARS
+				ID=year
+				COLUMNS=3
+			{+END}
+		{+END}
+	</div></div><div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
+		{+START,IF_NON_EMPTY,{MONTH_URL}}
+			<a href="{MONTH_URL*}">{!MONTHLY}</a>
+		{+END}
+		{+START,IF_EMPTY,{MONTH_URL}}
+			<span>{!MONTHLY}</span>
+		{+END}
+
+		{+START,IF_PASSED,ALL_MONTHS}
+			{+START,INCLUDE,CALENDAR_JUMP_SET}
+				VARIABLE=ALL_MONTHS
+				ID=month
+				COLUMNS=3
+			{+END}
+		{+END}
+	</div></div><div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
+		{+START,IF_NON_EMPTY,{WEEK_URL}}
+			<a href="{WEEK_URL*}">{!WEEKLY}</a>
+		{+END}
+		{+START,IF_EMPTY,{WEEK_URL}}
+			<span>{!WEEKLY}</span>
+		{+END}
+
+		{+START,IF_PASSED,ALL_WEEKS}
+			{+START,INCLUDE,CALENDAR_JUMP_SET}
+				VARIABLE=ALL_WEEKS
+				ID=week
+				COLUMNS=3
+			{+END}
+		{+END}
+	</div></div><div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
+		{+START,IF_NON_EMPTY,{DAY_URL}}
+			<a href="{DAY_URL*}">{!DAILY}</a>
+		{+END}
+		{+START,IF_EMPTY,{DAY_URL}}
+			<span>{!DAILY}</span>
+		{+END}
+
+		{+START,IF_PASSED,ALL_DAYS}
+			{+START,INCLUDE,CALENDAR_JUMP_SET}
+				VARIABLE=ALL_DAYS
+				ID=day
+				COLUMNS=2
+			{+END}
+		{+END}
+	</div></div>
+</div>
+
+<div class="trinav_wrap nograd">
+	<div class="trinav_left">
+		<a onclick="return goto_set_page(this.href);" class="button_screen buttons__previous" href="{PREVIOUS_URL*}" rel="{+START,IF,{PREVIOUS_NO_FOLLOW}}nofollow {+END}prev" accesskey="j"><span>{!PREVIOUS}</span></a>
+	</div>
+	<div class="trinav_right">
+		<a onclick="return goto_set_page(this.href);" class="button_screen buttons__next" href="{NEXT_URL*}" rel="{+START,IF,{NEXT_NO_FOLLOW}}nofollow {+END}next" accesskey="k"><span>{!NEXT}</span></a>
+	</div>
+	{+START,IF,{$NOT,{$MOBILE}}}
+		<div class="trinav_mid">
+			{+START,IF_NON_EMPTY,{ADD_URL}}
+				<a class="button_screen menu___generic_admin__add_one" rel="add" href="{ADD_URL*}"><span>{!ADD_CALENDAR_EVENT}</span></a>
+			{+END}
+		</div>
+	{+END}
+</div>
+
+<div class="horizontal_scrolling">
+	{MAIN}
+</div>
+
+{+START,IF_NON_EMPTY,{ADD_URL}}
+	<p class="buttons_group">
+		<a class="button_screen menu___generic_admin__add_one" rel="add" href="{ADD_URL*}"><span>{!ADD_CALENDAR_EVENT}</span></a>
+	</p>
+{+END}
+
+<div class="box box___calendar_main_screen_interests">
+	<h2 class="toggleable_tray_title">
+		<a class="toggleable_tray_button" href="#" onclick="return toggleable_tray(this.parentNode.parentNode);"><img alt="{!EXPAND}: {!INTERESTS}" title="{!EXPAND}" src="{$IMG*,1x/trays/expand2}" srcset="{$IMG*,2x/trays/expand2} 2x" /></a>
+		<a class="toggleable_tray_button" href="#" onclick="return toggleable_tray(this.parentNode.parentNode);">{!INTERESTS}</a>
+	</h2>
+
+	<div class="toggleable_tray" style="{$JS_ON,display: none,}" aria-expanded="false">
+		<div class="float_surrounder">
+			{+START,IF_NON_EMPTY,{EVENT_TYPES_1}}
+				<div class="right event_interest_box"><section class="box"><div class="box_inner">
+					<form title="{!INTERESTS}" method="post" action="{INTERESTS_URL*}" autocomplete="off">
+						{$INSERT_SPAMMER_BLACKHOLE}
+
+						<p><strong>{!DESCRIPTION_INTERESTS}</strong></p>
+
+						<div class="calendar_main_page_hidden_data">
+							{EVENT_TYPES_1}
+						</div>
+
+						<p class="proceed_button">
+							<input onclick="disable_button_just_clicked(this);" class="button_screen buttons__choose" type="submit" value="{!INTERESTS}" />
+						</p>
+					</form>
+				</div></section></div>
+			{+END}
+			{+START,IF_NON_EMPTY,{EVENT_TYPES_2}}
+				<div class="left event_interest_box"><section class="box"><div class="box_inner">
+					<form title="{!FILTER}" action="{$URL_FOR_GET_FORM*,{FILTER_URL}}" method="get" autocomplete="off">
+						{$INSERT_SPAMMER_BLACKHOLE}
+
+						{$HIDDENS_FOR_GET_FORM,{FILTER_URL}}
+
+						<p><strong>{!DESCRIPTION_INTERESTS_2}</strong></p>
+
+						<div class="calendar_main_page_hidden_data">
+							{EVENT_TYPES_2}
+						</div>
+
+						<p class="proceed_button">
+							<input onclick="disable_button_just_clicked(this);" class="button_screen buttons__filter" type="submit" value="{!FILTER}" />
+						</p>
+					</form>
+				</div></section></div>
+			{+END}
+		</div>
+	</div>
+</div>
+
+{$, Commented out... bloat
+{+START,IF,{$ADDON_INSTALLED,syndication_blocks}}
+	<div class="box box___calendar_main_screen_feeds_to_overlay">
+		<h2 class="toggleable_tray_title">
+			<a class="toggleable_tray_button" href="#" onclick="return toggleable_tray(this.parentNode.parentNode);"><img alt="{!EXPAND}: {!FEEDS_TO_OVERLAY}" title="{!EXPAND}" src="{$IMG*,1x/trays/expand2}" srcset="{$IMG*,2x/trays/expand2} 2x" /></a>
+			<a class="toggleable_tray_button" href="#" onclick="return toggleable_tray(this.parentNode.parentNode);">{!FEEDS_TO_OVERLAY}</a>
+		</h2>
+
+		<div class="toggleable_tray" style="{$JS_ON,display: none,}" aria-expanded="false">
+			{RSS_FORM}
+		</div>
+	</div>
+{+END}
+}
+
+<script>// <![CDATA[
+	function open_jump_set(id)
+	{
+		var e;
+
+		var sets=['year','month','week','day'];
+		for (var i=0;i<sets.length;i++) {
+			if (sets[i]!=id) {
+				e=document.getElementById('calendar_jump_set_'+sets[i]);
+				if (e) e.className=e.className.replace(/ active/,'');
+			}
+		}
+
+		e=document.getElementById('calendar_jump_set_'+id);
+		if (e.className.indexOf('active')==-1) {
+			e.className+=' active';
+		} else {
+			e.className=e.className.replace(/ active/,'');
+		}
+	}
+//]]></script>
+
+<script>// <![CDATA[
+	window.addEventListener('load', function() {
+		cache_set_page('{PREVIOUS_URL;/}');
+		cache_set_page('{NEXT_URL;/}');
+	});
+//]]></script>
diff --git a/themes/default/templates/CALENDAR_MONTH_ENTRY.tpl b/themes/default/templates/CALENDAR_MONTH_ENTRY.tpl
index 12d73c1..e07f51f 100644
--- a/themes/default/templates/CALENDAR_MONTH_ENTRY.tpl
+++ b/themes/default/templates/CALENDAR_MONTH_ENTRY.tpl
@@ -1,3 +1,10 @@
 <div class="calendar_month_entry">
-	<a title="{TITLE*}{+START,IF,{$LT,{$LENGTH,{ID}},10}}: #{ID*}{+END}" href="{URL*}"><img src="{$IMG*,{ICON}}" title="{+START,IF_NON_EMPTY,{TIME}}{TIME*} &ndash; {+END}{TITLE*}" alt="{+START,IF_NON_EMPTY,{TIME}}{TIME*} &ndash; {+END}{TITLE*}" /></a>{+START,IF,{RECURRING}} {!REPEAT_SUFFIX}{+END}
+	{+START,IF,{$LT,{NEIGHBOURS},1}}
+		{+START,IF_NON_EMPTY,{ICON}}<img class="calendar_day_icon" src="{$IMG*,{ICON}}" title="{T_TITLE*}" alt="{T_TITLE*}" />{+END}
+		<a title="{TIME_FULL*} &ndash; {TITLE*}" href="{URL*}">{TITLE*}</a>
+		{+START,IF,{RECURRING}}{!REPEAT_SUFFIX}{+END}
+	{+END}
+	{+START,IF,{$GT,{NEIGHBOURS},0}}
+		<a title="{TIME_FULL*} &ndash; {TITLE*} &ndash; {T_TITLE*}" href="{URL*}"><img src="{$IMG*,{ICON}}" alt="{T_TITLE*}" /></a>
+	{+END}
 </div>
diff --git a/themes/default/templates/CALENDAR_WEEK_ENTRY.tpl b/themes/default/templates/CALENDAR_WEEK_ENTRY.tpl
index 9f8bc93..9eb0082 100644
--- a/themes/default/templates/CALENDAR_WEEK_ENTRY.tpl
+++ b/themes/default/templates/CALENDAR_WEEK_ENTRY.tpl
@@ -1 +1,6 @@
-<a title="{TITLE*}{+START,IF,{$LT,{$LENGTH,{ID}},10}}: #{ID*}{+END}" href="{URL*}"><img src="{$IMG*,{ICON}}" title="{+START,IF_NON_EMPTY,{TIME}}{TIME*} &ndash; {+END}{TITLE*}" alt="{+START,IF_NON_EMPTY,{TIME}}{TIME*} &ndash; {+END}{TITLE*}" /></a>{+START,IF,{RECURRING}} {!REPEAT_SUFFIX}{+END}
+<div class="float_surrounder">
+	{+START,IF_NON_EMPTY,{ICON}}<img class="calendar_day_icon" src="{$IMG*,{ICON}}" title="{T_TITLE*}" alt="{T_TITLE*}" />{+END}
+	<a title="{TIME_FULL*} &ndash; {TITLE*}" href="{URL*}" class="calendar_day_entry_title">{TITLE*}</a>
+	{+START,IF,{RECURRING}} {!REPEAT_SUFFIX}{+END}
+	<span class="calendar_day_entry_time">{TIME*}</span>
+</div>
diff --git a/themes/default/templates/CALENDAR_YEAR_MONTH_DAY_ACTIVE.tpl b/themes/default/templates/CALENDAR_YEAR_MONTH_DAY_ACTIVE.tpl
index a20d49f..d391d91 100644
--- a/themes/default/templates/CALENDAR_YEAR_MONTH_DAY_ACTIVE.tpl
+++ b/themes/default/templates/CALENDAR_YEAR_MONTH_DAY_ACTIVE.tpl
@@ -1,4 +1,4 @@
-<td class="calendar_active calendar_year_month_day{+START,IF,{CURRENT}} calendar_current{+END}">
-	<img src="{$IMG*,led_off}" title="{DATE*}: {EVENTS_AND_PRIORITY_LANG}" alt="{DATE*}: {EVENTS_AND_PRIORITY_LANG}" />
-	<a href="{DAY_URL*}" title="{DAY*}: {DATE*}: {EVENTS_AND_PRIORITY_LANG}">{DAY*}</a>
+<td class="calendar_active calendar_year_month_day{+START,IF,{CURRENT}} calendar_current{+END}" title="{DATE*}: {+START,IF_PASSED,TITLE}{TITLE*}{+END}{+START,IF_NON_PASSED,TITLE}{!TOTAL_EVENTS,{COUNT*}}{+END}{+START,IF,{$NEQ,{$VALUE_OPTION,event_priorities},0}} {!EVENTS_PRIORITY,{HIGHEST_PRIORITY*}}{+END}">
+	<img src="{$IMG*,led_off}" alt="" />
+	<a href="{DAY_URL*}">{DAY*}</a>
 </td>
diff --git a/themes/default/templates/CALENDAR_JUMP_SET.tpl b/themes/default/templates/CALENDAR_JUMP_SET.tpl
new file mode 100644
index 0000000..54eedcb
--- /dev/null
+++ b/themes/default/templates/CALENDAR_JUMP_SET.tpl
@@ -0,0 +1,16 @@
+<div class="calendar_jump_set_expander">
+	<span onclick="open_jump_set('{ID;*}');"></span>
+	<div id="calendar_jump_set_{ID*}" class="calendar_jump_set columns_{COLUMNS*}">
+		{+START,LOOP,{VARIABLE}}
+			<span>
+				{+START,IF,{JUMP_IS_CURRENT}}
+					<span>{JUMP_TEXT*}</span>
+				{+END}
+				{+START,IF,{$NOT,{JUMP_IS_CURRENT}}}
+					<a href="{JUMP_URL*}">{JUMP_TEXT*}</a>
+				{+END}
+				{+START,IF_PASSED,JUMP_EVENT_COUNT}<span class="associated_details">({JUMP_EVENT_COUNT*})</span>{+END}
+			</span>
+		{+END}
+	</div>
+</div>
diff --git a/themes/default/templates/CALENDAR_MAIN_SCREEN.tpl b/themes/default/templates/CALENDAR_MAIN_SCREEN.tpl
index 0089d54..a78ea9e 100644
--- a/themes/default/templates/CALENDAR_MAIN_SCREEN.tpl
+++ b/themes/default/templates/CALENDAR_MAIN_SCREEN.tpl
@@ -1,48 +1,75 @@
 {TITLE}
 
-<div class="float_surrounder">
-	<div class="calendar_top_navigation">
-		<div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
-			{+START,IF_NON_EMPTY,{YEAR_URL}}
-				<a href="{YEAR_URL*}">{!YEARLY}</a>
-			{+END}
-			{+START,IF_EMPTY,{YEAR_URL}}
-				<span>{!YEARLY}</span>
-			{+END}
-		</div></div>
-		<div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
-			{+START,IF_NON_EMPTY,{MONTH_URL}}
-				<a href="{MONTH_URL*}">{!MONTHLY}</a>
-			{+END}
-			{+START,IF_EMPTY,{MONTH_URL}}
-				<span>{!MONTHLY}</span>
-			{+END}
-		</div></div>
-		<div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
-			{+START,IF_NON_EMPTY,{WEEK_URL}}
-				<a href="{WEEK_URL*}">{!WEEKLY}</a>
+<div class="calendar_top_navigation">
+	<div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
+		{+START,IF_NON_EMPTY,{YEAR_URL}}
+			<a href="{YEAR_URL*}">{!YEARLY}</a>
+		{+END}
+		{+START,IF_EMPTY,{YEAR_URL}}
+			<span>{!YEARLY}</span>
+		{+END}
+
+		{+START,IF_PASSED,ALL_YEARS}
+			{+START,INCLUDE,CALENDAR_JUMP_SET}
+				VARIABLE=ALL_YEARS
+				ID=year
+				COLUMNS=3
 			{+END}
-			{+START,IF_EMPTY,{WEEK_URL}}
-				<span>{!WEEKLY}</span>
+		{+END}
+	</div></div><div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
+		{+START,IF_NON_EMPTY,{MONTH_URL}}
+			<a href="{MONTH_URL*}">{!MONTHLY}</a>
+		{+END}
+		{+START,IF_EMPTY,{MONTH_URL}}
+			<span>{!MONTHLY}</span>
+		{+END}
+
+		{+START,IF_PASSED,ALL_MONTHS}
+			{+START,INCLUDE,CALENDAR_JUMP_SET}
+				VARIABLE=ALL_MONTHS
+				ID=month
+				COLUMNS=3
 			{+END}
-		</div></div>
-		<div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
-			{+START,IF_NON_EMPTY,{DAY_URL}}
-				<a href="{DAY_URL*}">{!DAILY}</a>
+		{+END}
+	</div></div><div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
+		{+START,IF_NON_EMPTY,{WEEK_URL}}
+			<a href="{WEEK_URL*}">{!WEEKLY}</a>
+		{+END}
+		{+START,IF_EMPTY,{WEEK_URL}}
+			<span>{!WEEKLY}</span>
+		{+END}
+
+		{+START,IF_PASSED,ALL_WEEKS}
+			{+START,INCLUDE,CALENDAR_JUMP_SET}
+				VARIABLE=ALL_WEEKS
+				ID=week
+				COLUMNS=3
 			{+END}
-			{+START,IF_EMPTY,{DAY_URL}}
-				<span>{!DAILY}</span>
+		{+END}
+	</div></div><div class="calendar_date_span_link"><div class="calendar_date_span_link_inner">
+		{+START,IF_NON_EMPTY,{DAY_URL}}
+			<a href="{DAY_URL*}">{!DAILY}</a>
+		{+END}
+		{+START,IF_EMPTY,{DAY_URL}}
+			<span>{!DAILY}</span>
+		{+END}
+
+		{+START,IF_PASSED,ALL_DAYS}
+			{+START,INCLUDE,CALENDAR_JUMP_SET}
+				VARIABLE=ALL_DAYS
+				ID=day
+				COLUMNS=2
 			{+END}
-		</div></div>
-	</div>
+		{+END}
+	</div></div>
 </div>
 
 <div class="trinav_wrap nograd">
 	<div class="trinav_left">
-		<a class="button_screen buttons__previous" href="{PREVIOUS_URL*}" rel="{+START,IF,{PREVIOUS_NO_FOLLOW}}nofollow {+END}prev" accesskey="j"><span>{!PREVIOUS}</span></a>
+		<a class="button_screen buttons__previous" title="{!PREVIOUS}" href="{PREVIOUS_URL*}" rel="{+START,IF,{PREVIOUS_NO_FOLLOW}}nofollow {+END}prev" accesskey="j"><span>{PREVIOUS_LABEL*}</span></a>
 	</div>
 	<div class="trinav_right">
-		<a class="button_screen buttons__next" href="{NEXT_URL*}" rel="{+START,IF,{NEXT_NO_FOLLOW}}nofollow {+END}next" accesskey="k"><span>{!NEXT}</span></a>
+		<a class="button_screen buttons__next" title="{!NEXT}" href="{NEXT_URL*}" rel="{+START,IF,{NEXT_NO_FOLLOW}}nofollow {+END}next" accesskey="k"><span>{NEXT_LABEL*}</span></a>
 	</div>
 	{+START,IF,{$NOT,{$MOBILE}}}
 		<div class="trinav_mid">
@@ -125,3 +152,25 @@
 	</div>
 {+END}
 }
+
+<script>// <![CDATA[
+	function open_jump_set(id)
+	{
+		var e;
+
+		var sets=['year','month','week','day'];
+		for (var i=0;i<sets.length;i++) {
+			if (sets[i]!=id) {
+				e=document.getElementById('calendar_jump_set_'+sets[i]);
+				if (e) e.className=e.className.replace(/ active/,'');
+			}
+		}
+
+		e=document.getElementById('calendar_jump_set_'+id);
+		if (e.className.indexOf('active')==-1) {
+			e.className+=' active';
+		} else {
+			e.className=e.className.replace(/ active/,'');
+		}
+	}
+//]]></script>
diff --git a/themes/default/templates/CALENDAR_EVENT_SCREEN.tpl b/themes/default/templates/CALENDAR_EVENT_SCREEN.tpl
index 1319262..65645d1 100644
--- a/themes/default/templates/CALENDAR_EVENT_SCREEN.tpl
+++ b/themes/default/templates/CALENDAR_EVENT_SCREEN.tpl
@@ -121,10 +121,12 @@
 						<td class="category">{TYPE*}</td>
 					</tr>
 
-					<tr>
-						<th>{!PRIORITY}</th>
-						<td>{PRIORITY_LANG*}</td>
-					</tr>
+					{+START,IF,{$NEQ,{$VALUE_OPTION,event_priorities},0}}
+						<tr>
+							<th>{!PRIORITY}</th>
+							<td>{PRIORITY_LANG*}</td>
+						</tr>
+					{+END}
 
 					{+START,IF_PASSED,MEMBER_CALENDAR}
 						<tr>
diff --git a/themes/default/templates/CALENDAR_DAY_ENTRY.tpl b/themes/default/templates/CALENDAR_DAY_ENTRY.tpl
index 5d36b9f..1de6af5 100644
--- a/themes/default/templates/CALENDAR_DAY_ENTRY.tpl
+++ b/themes/default/templates/CALENDAR_DAY_ENTRY.tpl
@@ -1,8 +1,8 @@
 <div class="calendar_day_entry">
 	<div class="float_surrounder">
 		{+START,IF_NON_EMPTY,{ICON}}<img class="calendar_day_icon" src="{$IMG*,{ICON}}" title="{T_TITLE*}" alt="{T_TITLE*}" />{+END}
-		<img class="calendar_day_priority" src="{$IMG*,{PRIORITY_ICON}}" title="{PRIORITY_LANG*}" alt="{PRIORITY_LANG*}" />
-		<a title="{TITLE*}{+START,IF,{$LT,{$LENGTH,{ID}},10}}: #{ID*}{+END}" href="{URL*}" class="calendar_day_entry_title">{TITLE*}</a>
+		{+START,IF,{$NEQ,{$VALUE_OPTION,event_priorities},0}}<img class="calendar_day_priority" src="{$IMG*,{PRIORITY_ICON}}" title="{PRIORITY_LANG*}" alt="{PRIORITY_LANG*}" />{+END}
+		<a title="{TIME_FULL*} &ndash; {TITLE*}" href="{URL*}" class="calendar_day_entry_title">{TITLE*}</a>
 		{+START,IF,{RECURRING}} {!REPEAT_SUFFIX}{+END}
 		<span class="calendar_day_entry_time">{TIME*}</span>
 	</div>
diff --git a/themes/default/css/calendar.css b/themes/default/css/calendar.css
index 971529a..8a57cad 100644
--- a/themes/default/css/calendar.css
+++ b/themes/default/css/calendar.css
@@ -28,6 +28,10 @@ abbr.dtstart, abbr.dtend {
 		display: block;
 	}
 
+	.calendar_year_wrap>tbody {
+		display: block;
+	}
+
 	.calendar_year_wrap>tbody>tr {
 		display: block;
 	}
@@ -48,11 +52,16 @@ abbr.dtstart, abbr.dtend {
 	text-align: center;
 	padding: 0.5em;
 }
+{+START,IF,{$MOBILE}}
+	.calendar_year_month {
+		height: auto;
+	}
+{+END}
 
 .calendar_year_month table {
 	border-collapse: collapse;
 	width: 100%;
-	table-layout: fixed;
+	table-layout: fixed !important;
 }
 
 .calendar_year_month th {
@@ -85,7 +94,7 @@ abbr.dtstart, abbr.dtend {
 .calendar_month {
 	width: 100%;
 	border-collapse: collapse;
-	table-layout: fixed;
+	table-layout: fixed !important;
 }
 
 .calendar_month th {
@@ -95,17 +104,11 @@ abbr.dtstart, abbr.dtend {
 	vertical-align: middle;
 }
 
-.calendar_month_entry {
-	display: inline;
-	width: 100%;
-	height: 2em;
-}
-
 .calendar_month_day {
 	height: 6em;
 }
 
-.calendar_month_day div {
+.calendar_month_day>div:first-child {
 	z-index: 10;
 	float: {!en_right};
 }
@@ -196,13 +199,13 @@ abbr.dtstart, abbr.dtend {
 	margin-left: 1px;
 	margin-bottom: 1em;
 	padding-left: 1px; /* To compensate for -1px offset on calendar_date_span_link_inner */
-	overflow: hidden;
 }
 
 .calendar_date_span_link {
-	float: {!en_left};
+	display: inline-block;
 	width: 25%;
 	text-align: center;
+	position: relative;
 }
 
 .calendar_date_span_link_inner {
@@ -213,7 +216,12 @@ abbr.dtstart, abbr.dtend {
 	padding: 0.3em;
 	margin-left: -1px; /* To stop the double borders at join points */
 	padding: 0.5em 0;
-	min-height: 1.3em;
+	box-sizing: border-box;
+	height: 2.6em;
+}
+
+.calendar_date_span_link_inner * {
+	vertical-align: top;
 }
 
 .calendar_date_span_link:first-child .calendar_date_span_link_inner {
@@ -229,6 +237,54 @@ abbr.dtstart, abbr.dtend {
 	font-weight: bold;
 }
 
+.calendar_jump_set_expander {
+	display: inline-block;
+	padding-top: 4px;
+}
+
+.calendar_jump_set_expander>span {
+	display: inline-block;
+	cursor: pointer;
+	user-select: none;
+	background: url('{$IMG;,simple_down_arrow}') no-repeat;
+	background-size: 100% 100%;
+	width: 20px;
+	height: 20px;
+}
+
+.calendar_jump_set {
+	border: 1px solid {$GET,standard_border};
+	background-color: {$GET,area_background};
+	opacity: 0.0;
+	display: none;
+	transition: opacity 0.5s;
+	text-align: left;
+	padding: 0.5em;
+	position: absolute;
+	z-index: 1000;
+	top: 2.5em;
+	left: -1px;
+	box-sizing: border-box;
+	width: calc(100% + 1px);
+}
+.calendar_jump_set * {
+	vertical-align: middle;
+}
+.calendar_jump_set.columns_2 {
+	column-count: 2;
+}
+.calendar_jump_set.columns_3 {
+	column-count: 3;
+}
+.calendar_jump_set.active {
+	opacity: 1.0;
+	display: block;
+}
+.calendar_jump_set>span {
+	display: block;
+	padding: 0.25em 0;
+}
+
 .box___calendar_main_screen_interests {
 	margin-top: 2em;
 }
@@ -240,6 +296,12 @@ abbr.dtstart, abbr.dtend {
 		{$BETA_CSS_PROPERTY,box-sizing: border-box;}
 	}
 /*{+END}*/
+/*{+START,IF,{$MOBILE}}*/
+	.event_interest_box {
+		float: none;
+	}
+/*{+END}*/
+
 
 .calendar_main_page_hidden_data {
 	padding: 0.5em;
@@ -317,6 +379,10 @@ abbr.dtstart, abbr.dtend {
 	background-color: {$GET,area_current_background} !important;
 }
 
+.calendar_active {
+	background-color: {$GET,area_hover_background} !important;
+}
+
 .calendar_day_table td, .calendar_week td, .calendar_month td, .calendar_year_wrap td {
 	border: 1px solid {$GET,standard_border};
 }
diff --git a/sources/hooks/systems/addon_registry/core.php b/sources/hooks/systems/addon_registry/core.php
index eec66a0..69b2730 100644
--- a/sources/hooks/systems/addon_registry/core.php
+++ b/sources/hooks/systems/addon_registry/core.php
@@ -111,6 +111,7 @@ class Hook_addon_registry_core
         return array(
             'data/empty.php',
             'adminzone/pages/comcode/EN/_modsecurity.txt',
+            'themes/default/images/simple_down_arrow.png',
             'themes/default/images/icons/24x24/menu/_generic_admin/merge.png',
             'themes/default/images/icons/48x48/menu/_generic_admin/merge.png',
             'themes/default/images/icons/24x24/menu/rich_content.png',
diff --git a/sources/hooks/systems/addon_registry/calendar.php b/sources/hooks/systems/addon_registry/calendar.php
index 759cce5..51a5b7b 100644
--- a/sources/hooks/systems/addon_registry/calendar.php
+++ b/sources/hooks/systems/addon_registry/calendar.php
@@ -147,6 +147,7 @@ class Hook_addon_registry_calendar
             'themes/default/templates/BLOCK_SIDE_CALENDAR.tpl',
             'themes/default/templates/BLOCK_SIDE_CALENDAR_LISTING.tpl',
             'themes/default/templates/CALENDAR_EVENT_BOX.tpl',
+            'themes/default/templates/CALENDAR_JUMP_SET.tpl',
             'sources/hooks/systems/trackback/events.php',
             'cms/pages/modules/cms_calendar.php',
             'lang/EN/calendar.ini',
@@ -228,7 +229,8 @@ class Hook_addon_registry_calendar
             'templates/CALENDAR_YEAR_MONTH.tpl' => 'calendar_year_view',
             'templates/CALENDAR_YEAR.tpl' => 'calendar_year_view',
             'templates/CALENDAR_EVENT_SCREEN.tpl' => 'calendar_event_screen',
-            'templates/CALENDAR_EVENT_BOX.tpl' => 'calendar_event_box'
+            'templates/CALENDAR_EVENT_BOX.tpl' => 'calendar_event_box',
+            'templates/CALENDAR_JUMP_SET.tpl' => 'calendar_month_view',
         );
     }
 
@@ -324,7 +326,7 @@ class Hook_addon_registry_calendar
                     'DAY' => placeholder_number(),
                     'ICON' => '',
                     'COUNT' => placeholder_number(),
-                    'EVENTS_AND_PRIORITY_LANG' => lorem_phrase(),
+                    'HIGHEST_PRIORITY' => lorem_phrase(),
                 )));
             }
 
@@ -474,6 +476,7 @@ class Hook_addon_registry_calendar
                             'ID' => placeholder_id(),
                             'URL' => placeholder_url(),
                             'TIME' => placeholder_date(),
+                            'TIME_FULL' => placeholder_date(),
                             'T_TITLE' => lorem_phrase(),
                             'TITLE' => lorem_word(),
                             'DESCRIPTION' => lorem_word_2(),
@@ -518,6 +521,7 @@ class Hook_addon_registry_calendar
                                 'ID' => placeholder_id(),
                                 'URL' => placeholder_url(),
                                 'TIME' => placeholder_date(),
+                                'TIME_FULL' => placeholder_date(),
                                 'TITLE' => lorem_word(),
                                 'E' => lorem_word(),
                                 'ICON' => 'calendar/general',
@@ -579,11 +583,13 @@ class Hook_addon_registry_calendar
                             'T_TITLE' => lorem_phrase(),
                             'PRIORITY' => lorem_word(),
                             'ICON' => 'calendar/' . placeholder_img_code('calendar'),
-                            'TIME' => placeholder_number(),
+                            'TIME' => placeholder_date(),
+                            'TIME_FULL' => placeholder_date(),
                             'TITLE' => lorem_word(),
                             'URL' => placeholder_url(),
                             'VALIDATED' => true,
                             'RECURRING' => false,
+                            'NEIGHBOURS' => '0',
                         )));
                     }
 
@@ -654,7 +660,7 @@ class Hook_addon_registry_calendar
                                 'DAY' => placeholder_number(),
                                 'ICON' => '',
                                 'COUNT' => placeholder_number(),
-                                'EVENTS_AND_PRIORITY_LANG' => lorem_phrase(),
+                                'HIGHEST_PRIORITY' => lorem_phrase(),
                             )));
                         }
 
@@ -710,6 +716,16 @@ class Hook_addon_registry_calendar
             'TYPE' => lorem_phrase(),
             'TYPE_ID' => placeholder_id(),
         ));
+
+        $all = array();
+        $all[] = array(
+            'JUMP_URL' => placeholder_url(),
+            'JUMP_TEXT' => lorem_phrase(),
+            'JUMP_EVENT_COUNT' => placeholder_number(),
+            '_JUMP_EVENT_COUNT' => placeholder_number(),
+            'JUMP_IS_CURRENT' => false,
+        );
+
         return do_lorem_template('CALENDAR_MAIN_SCREEN', array(
             'RSS_FORM' => placeholder_form(),
             'DAY_URL' => placeholder_url(),
@@ -728,6 +744,11 @@ class Hook_addon_registry_calendar
             'EVENT_TYPES_2' => $events2,
             'PREVIOUS_NO_FOLLOW' => true,
             'NEXT_NO_FOLLOW' => true,
+
+            'ALL_YEARS' => $all,
+            'ALL_MONTHS' => $all,
+            'ALL_WEEKS' => $all,
+            'ALL_DAYS' => $all,
         ));
     }
 
diff --git a/sources/calendar.php b/sources/calendar.php
index d0a8583..2cb6fe1 100644
--- a/sources/calendar.php
+++ b/sources/calendar.php
@@ -620,9 +620,10 @@ function regenerate_event_reminder_jobs($id, $force = false)
  * @param  boolean $do_time Whether time is included in this date range
  * @param  boolean $force_absolute Whether to force absolute display
  * @param  string $timezone Display timezone
+ * @param  boolean $date_is_known Whether the user understands the date from context
  * @return string Textual specially-formatted range
  */
-function date_range($from, $to, $do_time = true, $force_absolute = false, $timezone = '')
+function date_range($from, $to, $do_time = true, $force_absolute = false, $timezone = '', $date_is_known = false)
 {
     if (is_null($to)) {
         return get_timezoned_date($from, true, true, false, true);
@@ -667,7 +668,11 @@ function date_range($from, $to, $do_time = true, $force_absolute = false, $timez
             $date2 = $_date2;
         }
         $date = cms_strftime(do_lang('calendar_date_verbose'), $from);
-        return do_lang('EVENT_TIME_RANGE_WITHIN_DAY' . (($timezone == '') ? '' : '_WITH_TIMEZONE'), $date, $date1, array($date2, $_length, $timezone));
+        $written = do_lang('EVENT_TIME_RANGE_WITHIN_DAY' . (($timezone == '') ? '' : '_WITH_TIMEZONE'), $date, $date1, array($date2, $_length, $timezone));
+        if (!$date_is_known) {
+            $written = do_lang('EVENT_TIME_WITH_DATE', $date, $written);
+        }
+        return $written;
     }
 
     return do_lang('EVENT_TIME_RANGE' . (($timezone == '') ? '' : '_WITH_TIMEZONE'), $date1, $date2, array($_length, $timezone));
diff --git a/sources/blocks/side_calendar.php b/sources/blocks/side_calendar.php
index 3ceb8bd..098d938 100644
--- a/sources/blocks/side_calendar.php
+++ b/sources/blocks/side_calendar.php
@@ -165,12 +165,10 @@ class Block_side_calendar
                     $__entries->attach(do_template('CALENDAR_YEAR_MONTH_DAY_FREE', array('_GUID' => 'd9ac194adf9fef87f3ee0161f0582b88', 'CURRENT' => date('Y-m-d', utctime_to_usertime()) == $date, 'DAY_URL' => $day_url, 'DATE' => $date_formatted, 'DAY' => strval($j), 'CLASS' => $class)));
                 } elseif (is_array($entries[$j])) {
                     $class = 'single';
-                    $events_and_priority_lang = do_lang_tempcode('TOTAL_EVENTS_AND_HIGHEST_PRIORITY', '1', do_lang_tempcode('PRIORITY_' . strval($priorities[$j])));
-                    $__entries->attach(do_template('CALENDAR_YEAR_MONTH_DAY_ACTIVE', array_merge(array('CURRENT' => date('Y-m-d', utctime_to_usertime()) == $date, 'DAY_URL' => $day_url, 'DATE' => $date_formatted, 'DAY' => strval($j), 'CLASS' => $class, 'COUNT' => '1', 'EVENTS_AND_PRIORITY_LANG' => $events_and_priority_lang), $entries[$j])));
+                    $__entries->attach(do_template('CALENDAR_YEAR_MONTH_DAY_ACTIVE', array_merge(array('CURRENT' => date('Y-m-d', utctime_to_usertime()) == $date, 'DAY_URL' => $day_url, 'DATE' => $date_formatted, 'DAY' => strval($j), 'CLASS' => $class, 'COUNT' => '1', 'HIGHEST_PRIORITY' => do_lang_tempcode('PRIORITY_' . strval($priorities[$j]))), $entries[$j])));
                 } else {
                     $class = 'multiple';
                     $e_count = integer_format($entries[$j]);
-                    $events_and_priority_lang = do_lang_tempcode('TOTAL_EVENTS_AND_HIGHEST_PRIORITY', make_string_tempcode($e_count), do_lang_tempcode('PRIORITY_' . strval($priorities[$j])));
                     $__entries->attach(do_template('CALENDAR_YEAR_MONTH_DAY_ACTIVE', array(
                         '_GUID' => '2190cdba146d5d18c01033fd0d9a09a1',
                         'CURRENT' => date('Y-m-d', utctime_to_usertime()) == $date,
@@ -184,7 +182,7 @@ class Block_side_calendar
                         'DAY' => strval($j),
                         'ICON' => '',
                         'COUNT' => $e_count,
-                        'EVENTS_AND_PRIORITY_LANG' => $events_and_priority_lang,
+                        'HIGHEST_PRIORITY' => do_lang_tempcode('PRIORITY_' . strval($priorities[$j])),
                     )));
                 }
 
diff --git a/site/pages/modules/calendar.php b/site/pages/modules/calendar.php
index ff7d28d..17fe3b7 100644
--- a/site/pages/modules/calendar.php
+++ b/site/pages/modules/calendar.php
@@ -283,7 +283,7 @@ class Module_calendar
             $filter = $this->get_filter();
 
             // Read row
-            $rows = $GLOBALS['SITE_DB']->query_select('calendar_events e LEFT JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'calendar_types t ON t.id=e.e_type', array('*'), array('e.id' => $id), '', 1);
+            $rows = $GLOBALS['SITE_DB']->query_select('calendar_events e LEFT JOIN ' . $GLOBALS['SITE_DB']->get_table_prefix() . 'calendar_types t ON t.id=e.e_type', array('e.*', 't.t_title', 't.t_logo'), array('e.id' => $id), '', 1);
             if (!array_key_exists(0, $rows)) {
                 warn_exit(do_lang_tempcode('MISSING_RESOURCE', 'event'));
             }
@@ -521,8 +521,10 @@ class Module_calendar
                 $back_view = 'week';
                 $previous_timestamp = mktime(0, 0, 0, intval($explode[1]), intval($explode[2]), intval($explode[0])) - 60 * 60 * 24;
                 $previous = date('Y-m-d', $previous_timestamp);
+                $previous_label = cms_strftime('%a', $previous_timestamp);
                 $next_timestamp = mktime(0, 0, 0, intval($explode[1]), intval($explode[2]), intval($explode[0])) + 60 * 60 * 24;
                 $next = date('Y-m-d', $next_timestamp);
+                $next_label = cms_strftime('%a', $next_timestamp);
 
                 $title_date = cms_strftime(do_lang('calendar_date_verbose'), $timestamp);
                 if ($private !== 1) {
@@ -547,8 +549,10 @@ class Module_calendar
                 $back_view = 'month';
                 $previous_timestamp = mktime(0, 0, 0, $start_month, $start_day, $start_year) - 60 * 60 * 24 * 7;
                 $previous = get_week_number_for($previous_timestamp);
+                $previous_label = do_lang('WEEK', get_week_number_for($previous_timestamp, true));
                 $next_timestamp = mktime(0, 0, 0, $start_month, $start_day, $start_year) + 60 * 60 * 24 * 7;
                 $next = get_week_number_for($next_timestamp);
+                $next_label = do_lang('WEEK', get_week_number_for($next_timestamp, true));
 
                 if ($private !== 1) {
                     $this->title = get_screen_title('CALENDAR_SPECIFIC_WEEK', true, array(escape_html($explode[0]), escape_html($explode[1]), escape_html(cms_strftime('%b', $timestamp))));
@@ -575,16 +579,18 @@ class Module_calendar
                     $previous_month = 12;
                     $previous_year = $previous_year - 1;
                 }
+                $previous_timestamp = mktime(0, 0, 0, $previous_month, 1, $previous_year);
+                $previous = date('Y-m', $previous_timestamp);
+                $previous_label = cms_strftime('%b', $previous_timestamp);
                 $next_month = intval($explode[1]) + 1;
                 $next_year = intval($explode[0]);
                 if ($next_month == 13) {
                     $next_month = 1;
                     $next_year = $next_year + 1;
                 }
-                $previous_timestamp = mktime(0, 0, 0, $previous_month, 1, $previous_year);
-                $previous = date('Y-m', $previous_timestamp);
                 $next_timestamp = mktime(0, 0, 0, $next_month, 1, $next_year);
                 $next = date('Y-m', $next_timestamp);
+                $next_label = cms_strftime('%b', $next_timestamp);
 
                 $title_date = cms_strftime(do_lang('calendar_month_in_year_verbose'), $timestamp);
                 if ($private !== 1) {
@@ -607,8 +613,10 @@ class Module_calendar
                 $back_url = $GLOBALS['FORUM_DRIVER']->member_profile_url($member_id);
                 $previous_timestamp = mktime(0, 0, 0, 1, 1, intval($explode[0]) - 1);
                 $previous = date('Y', $previous_timestamp);
+                $previous_label = cms_strftime('%Y', $previous_timestamp);
                 $next_timestamp = mktime(0, 0, 0, 1, 1, intval($explode[0]) + 1);
                 $next = date('Y', $next_timestamp);
+                $next_label = cms_strftime('%Y', $next_timestamp);
 
                 if ($private !== 1) {
                     $this->title = get_screen_title('CALENDAR_SPECIFIC', true, array(escape_html($id)));
@@ -662,7 +670,7 @@ class Module_calendar
 
         $interests_url = build_url(array('page' => '_SELF', 'type' => 'interests', 'view' => $view, 'id' => $id), '_SELF');
         $event_types_1 = new Tempcode();
-        $types = $GLOBALS['SITE_DB']->query_select('calendar_types', array('id', 't_title'));
+        $types = $GLOBALS['SITE_DB']->query_select('calendar_types', array('id', 't_title'), array(), 'ORDER BY ' . $GLOBALS['SITE_DB']->translate_field_ref('t_title'));
         $member_interests = collapse_1d_complexity('t_type', $GLOBALS['SITE_DB']->query_select('calendar_interests', array('t_type'), array('i_member_id' => get_member())));
         foreach ($types as $type) {
             if ($type['id'] == db_get_first_id()) {
@@ -727,6 +735,8 @@ class Module_calendar
         }
         $rss_form = do_template('FORM', array('_GUID' => '1756a3c6a5a105ef8b2b9d2ebc9e4e86', 'HIDDEN' => '', 'TEXT' => do_lang_tempcode('DESCRIPTION_FEEDS_TO_OVERLAY'), 'URL' => get_self_url(), 'FIELDS' => $fields, 'SUBMIT_ICON' => 'buttons__proceed', 'SUBMIT_NAME' => do_lang_tempcode('PROCEED')));
 
+        list($all_years, $all_months, $all_weeks, $all_days) = $this->generate_calendar_jump_set($view, $timestamp, $filter);
+
         return do_template('CALENDAR_MAIN_SCREEN', array(
             '_GUID' => '147a58dbe05366ac37698a8cdd501d12',
             'RSS_FORM' => $rss_form,
@@ -738,6 +748,8 @@ class Module_calendar
             'YEAR_URL' => $year_url,
             'PREVIOUS_URL' => $previous_url,
             'NEXT_URL' => $next_url,
+            'PREVIOUS_LABEL' => $previous_label,
+            'NEXT_LABEL' => $next_label,
             'ADD_URL' => $add_url,
             'TITLE' => $this->title,
             'BACK_URL' => $back_url,
@@ -746,9 +758,134 @@ class Module_calendar
             'EVENT_TYPES_1' => $event_types_1,
             'INTERESTS_URL' => $interests_url,
             'EVENT_TYPES_2' => $event_types_2,
+
+            'ALL_YEARS' => $all_years,
+            'ALL_MONTHS' => $all_months,
+            'ALL_WEEKS' => $all_weeks,
+            'ALL_DAYS' => $all_days,
         ));
     }
 
+    /**
+     * Find calendar events within jumpable ranges.
+     *
+     * @param  string $view The calendar view currently in
+     * @set year month week day
+     * @param  TIME $timestamp The timestamp of the start of the range the user is currently in
+     * @param  ?array $filter The type filter (null: none)
+     * @return array A tuple: years, months, weeks, days
+     */
+    public function generate_calendar_jump_set($view, $timestamp, $filter)
+    {
+        $find_event_counts = (get_value('calendar_deep_jump_set_counts') === '1');
+
+        $all_years = array();
+        $first_year = $GLOBALS['SITE_DB']->query_select_value('calendar_events', 'MIN(e_start_year)');
+        $last_year = max(intval(date('Y')), $GLOBALS['SITE_DB']->query_select_value('calendar_events', 'MIN(e_end_year)'));
+        for ($year = $first_year; $year <= $last_year; $year++) {
+            if ($find_event_counts) {
+                $period_start = mktime(0, 0, 0, 1, 1, $year);
+                $period_end = mktime(0, 0, 0, 1, 1, $year + 1) - 1;
+                $event_count = count(calendar_matches(get_member(), get_member(), true, $period_start, $period_end, $filter));
+            } else {
+                $event_count = null;
+            }
+
+            $map = array_merge($filter, array('page' => '_SELF', 'view' => 'year', 'id' => strval($year)));
+            $url = build_url($map, '_SELF');
+
+            $all_years[] = array(
+                'JUMP_URL' => $url,
+                'JUMP_TEXT' => strval($year),
+                'JUMP_EVENT_COUNT' => integer_format($event_count),
+                '_JUMP_EVENT_COUNT' => strval($event_count),
+                'JUMP_IS_CURRENT' => ($view == 'year') && ($period_start == $timestamp),
+            );
+        }
+
+        $all_months = array();
+        $year = intval(date('Y', $timestamp));
+        for ($month = 1; $month <= 12; $month++) {
+            if ($find_event_counts) {
+                $period_start = mktime(0, 0, 0, $month, 1, $year);
+                $period_end = mktime(0, 0, 0, $month + 1, 1, $year) - 1;
+                $event_count = count(calendar_matches(get_member(), get_member(), true, $period_start, $period_end, $filter));
+            } else {
+                $event_count = null;
+            }
+
+            $map = array_merge($filter, array('page' => '_SELF', 'view' => 'month', 'id' => strval($year) . '-' . strval($month)));
+            $url = build_url($map, '_SELF');
+
+            $all_months[] = array(
+                'JUMP_URL' => $url,
+                'JUMP_TEXT' => cms_strftime('%b', $period_start),
+                'JUMP_EVENT_COUNT' => integer_format($event_count),
+                '_JUMP_EVENT_COUNT' => strval($event_count),
+                'JUMP_IS_CURRENT' => ($view == 'month') && ($period_start == $timestamp),
+            );
+        }
+
+        $all_weeks = array();
+        $year = intval(date('Y', $timestamp + 7 * 60 * 60 * 24/*Ensure truly in correct year as our weeks start in previous year usually*/));
+        $num_weeks = intval(date('W', mktime(0, 0, 0, 12, 31 - 6, $year)));
+        $day = 0;
+        for ($week = 1; $week <= $num_weeks; $week++) {
+            if ($find_event_counts) {
+                list($_month, $_day, $_year) = date_from_week_of_year($year, $week);
+                $period_start = mktime(0, 0, 0, $_month, $_day, $_year);
+                $period_end = mktime(0, 0, 0, $_month, $_day + 7, $_year);
+                $event_count = count(calendar_matches(get_member(), get_member(), true, $period_start, $period_end, $filter));
+            } else {
+                $event_count = null;
+            }
+
+            $map = array_merge($filter, array('page' => '_SELF', 'view' => 'week', 'id' => strval($year) . '-' . strval($week)));
+            $url = build_url($map, '_SELF');
+
+            $all_weeks[] = array(
+                'JUMP_URL' => $url,
+                'JUMP_TEXT' => strval($week),
+                'JUMP_EVENT_COUNT' => integer_format($event_count),
+                '_JUMP_EVENT_COUNT' => strval($event_count),
+                'JUMP_IS_CURRENT' => ($view == 'week') && ($period_start == $timestamp),
+            );
+
+            $day += 7;
+        }
+
+        if (!in_array($view, array('year'))) {
+            $all_days = array();
+            $year = intval(date('Y', $timestamp));
+            $month = intval(date('m', $timestamp));
+            $num_days = date('d', mktime(0, 0, 0, $month + 1, 1, $year) - 1);
+            for ($day = 1; $day <= $num_days; $day++) {
+                if ($find_event_counts) {
+                    $period_start = mktime(0, 0, 0, $month, $day, $year);
+                    $period_end = mktime(0, 0, 0, $month, $day + 1, $year) - 1;
+                    $event_count = count(calendar_matches(get_member(), get_member(), true, $period_start, $period_end, $filter));
+                } else {
+                    $event_count = null;
+                }
+
+                $map = array_merge($filter, array('page' => '_SELF', 'view' => 'day', 'id' => strval($year) . '-' . strval($month) . '-' . strval($day)));
+                $url = build_url($map, '_SELF');
+
+                $all_days[] = array(
+                    'JUMP_URL' => $url,
+                    'JUMP_TEXT' => strval($day),
+                    'JUMP_EVENT_COUNT' => integer_format($event_count),
+                    '_JUMP_EVENT_COUNT' => strval($event_count),
+                    'JUMP_IS_CURRENT' => ($view == 'day') && ($period_start == $timestamp),
+                );
+            }
+        } else {
+            $all_days = null;
+        }
+
+        return array($all_years, $all_months, $all_weeks, $all_days);
+    }
+
     /**
      * The calendar area view for viewing a single day.
      *
@@ -787,7 +924,7 @@ class Module_calendar
             $icon = $event['t_logo'];
             $from_h = intval(date('H', $from));
             if (!is_null($to)) {
-                $date = date_range($real_from, $real_to, !is_null($event['e_start_hour']));
+                $date = date_range($real_from, $real_to, !is_null($event['e_start_hour']), false, '', true);
                 if ($to >= $period_end - 60/*1 minute gap we use to stop stuff spanning to start of next day*/) {
                     $to_h = 24;
                 } else {
@@ -833,7 +970,23 @@ class Module_calendar
             }
             $priority_lang = do_lang_tempcode('PRIORITY_' . strval($event['e_priority']));
             $priority_icon = 'calendar/priority_' . strval($event['e_priority']);
-            $streams[$found_stream][$from_h] = array('TPL' => 'CALENDAR_DAY_ENTRY', 'DESCRIPTION' => $description, 'DOWN' => $down, 'ID' => is_string($event['e_id']) ? $event['e_id'] : strval($event['e_id']), 'T_TITLE' => array_key_exists('t_title', $event) ? (is_string($event['t_title']) ? $event['t_title'] : get_translated_text($event['t_title'])) : 'RSS', 'PRIORITY' => strval($event['e_priority']), 'ICON' => $icon, 'TIME' => $date, 'TITLE' => $_title, 'URL' => $url, 'PRIORITY_LANG' => $priority_lang, 'PRIORITY_ICON' => $priority_icon, 'RECURRING' => $event['e_recurrence'] != 'none', 'VALIDATED' => $event['validated'] == 1);
+            $streams[$found_stream][$from_h] = array(
+                'TPL' => 'CALENDAR_DAY_ENTRY',
+                'DESCRIPTION' => $description,
+                'DOWN' => $down,
+                'ID' => is_string($event['e_id']) ? $event['e_id'] : strval($event['e_id']),
+                'T_TITLE' => array_key_exists('t_title', $event) ? (is_string($event['t_title']) ? $event['t_title'] : get_translated_text($event['t_title'])) : 'RSS',
+                'PRIORITY' => strval($event['e_priority']),
+                'ICON' => $icon,
+                'TIME' => $date,
+                'TIME_FULL' => get_timezoned_date($real_from, true, false, true),
+                'TITLE' => $_title,
+                'URL' => $url,
+                'PRIORITY_LANG' => $priority_lang,
+                'PRIORITY_ICON' => $priority_icon,
+                'RECURRING' => $event['e_recurrence'] != 'none',
+                'VALIDATED' => $event['validated'] == 1,
+            );
             for ($h = $from_h + 1; $h < $to_h; $h++) {
                 $streams[$found_stream][$h] = array('TPL' => '-1');
             }
@@ -947,7 +1100,7 @@ class Module_calendar
                         }
                         $icon = $event['t_logo'];
                         if (!is_null($to)) {
-                            $date = date_range($real_from, $real_to, !is_null($event['e_start_hour']));
+                            $date = date_range($real_from, $real_to, !is_null($event['e_start_hour']), false, '', true);
                             if ((!is_null($to)) && ($to >= mktime(0, 0, 0, $start_month, $start_day + $j + 1, $start_year))) {
                                 $continuation = 24;
                                 $ntime = mktime(0, 0, 0, $start_month, $start_day + $j + 1, $start_year);
@@ -966,6 +1119,7 @@ class Module_calendar
                             'PRIORITY' => strval($event['e_priority']),
                             'ICON' => $icon,
                             'TIME' => $date,
+                            'TIME_FULL' => get_timezoned_date($real_from, true, false, true),
                             'TITLE' => $_title,
                             'URL' => $url,
                             'RECURRING' => $event['e_recurrence'] != 'none',
@@ -1175,6 +1329,16 @@ class Module_calendar
                 list($e_id, $event, $from, $to, $real_from, $real_to, $utc_real_from) = $happening;
                 $date = date('d', $from);
                 if (intval($date) == $i) {
+                    $neighbours = 0;
+                    for ($hap_j = 0; $hap_j < $cnt; $hap_j++) {
+                        if ($hap_i != $hap_j) {
+                            $_date = date('d', $from);
+                            if (intval($_date) == $i) {
+                                $neighbours++;
+                            }
+                        }
+                    }
+
                     $date = is_null($event['e_start_hour']) ? '' : cms_strftime(do_lang('calendar_minute'), $real_from);
 
                     if (is_numeric($e_id)) {
@@ -1185,7 +1349,7 @@ class Module_calendar
                     }
                     $icon = $event['t_logo'];
                     if (!is_null($to)) {
-                        $date = date_range($real_from, $real_to, !is_null($event['e_start_hour']));
+                        $date = date_range($real_from, $real_to, !is_null($event['e_start_hour']), false, '', true);
                     }
                     $_title = is_integer($event['e_title']) ? get_translated_text($event['e_title']) : $event['e_title'];
                     $entries->attach(do_template('CALENDAR_MONTH_ENTRY', array(
@@ -1195,10 +1359,12 @@ class Module_calendar
                         'PRIORITY' => strval($event['e_priority']),
                         'ICON' => $icon,
                         'TIME' => $date,
+                        'TIME_FULL' => get_timezoned_date($real_from, true, false, true),
                         'TITLE' => $_title,
                         'URL' => $url,
                         'RECURRING' => $event['e_recurrence'] != 'none',
                         'VALIDATED' => $event['validated'] == 1,
+                        'NEIGHBOURS' => strval($neighbours),
                     )));
 
                     if ($event['e_priority'] < $worst_priority) {
@@ -1362,12 +1528,10 @@ class Module_calendar
                     $__entries->attach(do_template('CALENDAR_YEAR_MONTH_DAY_FREE', array('_GUID' => 'cccf839895121ae14fd1948ed4024d4b', 'CURRENT' => date('Y-m-d') == $date, 'DAY_URL' => $day_url, 'DATE' => $date_formatted, 'DAY' => strval($j), 'CLASS' => $class)));
                 } elseif (is_array($entries[$j])) {
                     $class = 'single';
-                    $events_and_priority_lang = do_lang_tempcode('TOTAL_EVENTS_AND_HIGHEST_PRIORITY', '1', do_lang_tempcode('PRIORITY_' . strval($priorities[$j])));
-                    $__entries->attach(do_template('CALENDAR_YEAR_MONTH_DAY_ACTIVE', array_merge(array('CURRENT' => date('Y-m-d') == $date, 'DAY_URL' => $day_url, 'DATE' => $date_formatted, 'DAY' => strval($j), 'CLASS' => $class, 'COUNT' => '1', 'EVENTS_AND_PRIORITY_LANG' => $events_and_priority_lang), $entries[$j])));
+                    $__entries->attach(do_template('CALENDAR_YEAR_MONTH_DAY_ACTIVE', array_merge(array('CURRENT' => date('Y-m-d') == $date, 'DAY_URL' => $day_url, 'DATE' => $date_formatted, 'DAY' => strval($j), 'CLASS' => $class, 'COUNT' => '1', 'HIGHEST_PRIORITY' => do_lang_tempcode('PRIORITY_' . strval($priorities[$j]))), $entries[$j])));
                 } else {
                     $class = 'multiple';
                     $e_count = integer_format($entries[$j]);
-                    $events_and_priority_lang = do_lang_tempcode('TOTAL_EVENTS_AND_HIGHEST_PRIORITY', make_string_tempcode($e_count), do_lang_tempcode('PRIORITY_' . strval($priorities[$j])));
                     $__entries->attach(do_template('CALENDAR_YEAR_MONTH_DAY_ACTIVE', array(
                         '_GUID' => '9f016773fce6402eca1a7a0afa6bb89f',
                         'CURRENT' => date('Y-m-d') == $date,
@@ -1381,7 +1545,7 @@ class Module_calendar
                         'DAY' => strval($j),
                         'ICON' => '',
                         'COUNT' => $e_count,
-                        'EVENTS_AND_PRIORITY_LANG' => $events_and_priority_lang,
+                        'HIGHEST_PRIORITY' => do_lang_tempcode('PRIORITY_' . strval($priorities[$j])),
                     )));
                 }
 
diff --git a/lang/EN/calendar.ini b/lang/EN/calendar.ini
index 37fa456..f7640bb 100644
--- a/lang/EN/calendar.ini
+++ b/lang/EN/calendar.ini
@@ -143,12 +143,14 @@ CALENDAR_EVENT_VCAL=<span class="summary">{1}</span>
 _CALENDAR_EVENT_VCAL={1}'s calendar: <span class="summary">{2}</span>
 PRIVATE_HIDDEN=(private)
 EVENT_TIME_RANGE_WITH_TIMEZONE={1} - {2} {4} ({3})
-EVENT_TIME_RANGE_WITHIN_DAY_WITH_TIMEZONE={1}, {2} - {3} {5} ({4})
+EVENT_TIME_RANGE_WITHIN_DAY_WITH_TIMEZONE={2} - {3} {5} ({4})
 EVENT_TIME_RANGE={1} - {2} ({3})
-EVENT_TIME_RANGE_WITHIN_DAY={1}, {2} - {3} ({4})
+EVENT_TIME_RANGE_WITHIN_DAY={2} - {3} ({4})
+EVENT_TIME_WITH_DATE={1}, {2}
 EVENT_TYPE=Event type
 EVENT_CANNOT_AROUND=An event cannot finish before it starts!
-TOTAL_EVENTS_AND_HIGHEST_PRIORITY=There are {1} {1|event|events} on this day. At least one event is &lsquo;{2}&rsquo;.
+TOTAL_EVENTS=There {1|is|are} {1} {1|event|events} on this day.
+EVENTS_PRIORITY=At least one event is &lsquo;{1}&rsquo;.
 REPEAT_SUFFIX=(R)
 RECURRENCE_ITERATION={1} (x{2})
 MODULE_TRANS_NAME_cms_calendar=Calendar
