From 7495a34b32fdf1ea08bd2eaa378b216345077f7f Mon Sep 17 00:00:00 2001
From: rabuzarus <>
Date: Sun, 19 Jun 2016 22:04:34 +0200
Subject: [PATCH] implement a public calendar for vistors of someones profile
 page

---
 include/event.php                             | 187 ++++++++++++
 include/identity.php                          |  18 +-
 mod/cal.php                                   | 279 ++++++++++++++++++
 mod/events.php                                | 147 ++-------
 view/templates/event_head.tpl                 |  12 +-
 view/theme/frio/templates/event_head.tpl      |  14 +-
 view/theme/frost-mobile/js/theme.js           |  10 +-
 .../frost-mobile/templates/event_head.tpl     |   2 +
 view/theme/frost/js/theme.js                  |  12 +-
 view/theme/frost/templates/event_head.tpl     |   2 +
 10 files changed, 542 insertions(+), 141 deletions(-)
 create mode 100644 mod/cal.php

diff --git a/include/event.php b/include/event.php
index c5e5ff18d7..df9b958570 100644
--- a/include/event.php
+++ b/include/event.php
@@ -1,7 +1,12 @@
 <?php
+/**
+ * @file include/event.php
+ * @brief functions specific to event handling
+ */
 
 require_once('include/bbcode.php');
 require_once('include/map.php');
+require_once('include/datetime.php');
 
 function format_event_html($ev, $simple = false) {
 
@@ -427,3 +432,185 @@ function event_store($arr) {
 		return $item_id;
 	}
 }
+
+function get_event_strings() {
+	// First day of the week (0 = Sunday)
+	$firstDay = get_pconfig(local_user(),'system','first_day_of_week');
+	if ($firstDay === false) $firstDay=0;
+
+	$i18n = array(
+			"firstDay" => $firstDay,
+			"Sun" => t("Sun"),
+			"Mon" => t("Mon"),
+			"Tue" => t("Tue"),
+			"Wed" => t("Wed"),
+			"Thu" => t("Thu"),
+			"Fri" => t("Fri"),
+			"Sat" => t("Sat"),
+			"Sunday" => t("Sunday"),
+			"Monday" => t("Monday"),
+			"Tuesday" => t("Tuesday"),
+			"Wednesday" => t("Wednesday"),
+			"Thursday" => t("Thursday"),
+			"Friday" => t("Friday"),
+			"Saturday" => t("Saturday"),
+			"Jan" => t("Jan"),
+			"Feb" => t("Feb"),
+			"Mar" => t("Mar"),
+			"Apr" => t("Apr"),
+			"May" => t("May"),
+			"Jun" => t("Jun"),
+			"Jul" => t("Jul"),
+			"Aug" => t("Aug"),
+			"Sep" => t("Sept"),
+			"Oct" => t("Oct"),
+			"Nov" => t("Nov"),
+			"Dec" => t("Dec"),
+			"January" => t("January"),
+			"February" => t("February"),
+			"March" => t("March"),
+			"April" => t("April"),
+			"May" => t("May"),
+			"June" => t("June"),
+			"July" => t("July"),
+			"August" => t("August"),
+			"September" => t("September"),
+			"October" => t("October"),
+			"November" => t("November"),
+			"December" => t("December"),
+			"today" => t("today"),
+			"month" => t("month"),
+			"week" => t("week"),
+			"day" => t("day"),
+		);
+
+	return $i18n;
+}
+
+/**
+ * @brief Get an event by its event ID
+ * 
+ * @param type $owner_uid The User ID of the owner of the event
+ * @param type $event_params An assoziative array with
+ *	int 'event_id' => The ID of the event in the event table
+ * @param type $sql_extra
+ * @return array Query result
+ */
+function event_by_id($owner_uid = 0, $event_params, $sql_extra = '') {
+	// ownly allow events if there is a valid owner_id
+	if($owner_uid == 0)
+		return;
+
+	// query for the event by event id
+	$r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
+			`item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
+		LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
+		WHERE `event`.`uid` = %d AND `event`.`id` = %d $sql_extra",
+		intval($owner_uid),
+		intval($event_params["event_id"])
+	);
+
+	if(count($r))
+		return $r;
+
+}
+
+/**
+ * @brief Get all events in a specific timeframe
+ * 
+ * @param int $owner_uid The User ID of the owner of the events
+ * @param array $event_params An assoziative array with
+ *	int 'ignored' => 
+ *	string 'start' => Start time of the timeframe
+ *	string 'finish' => Finish time of the timeframe
+ *	string 'adjust_start' => 
+ *	string 'adjust_start' =>
+ *	
+ * @param string $sql_extra Additional sql conditions (e.g. permission request)
+ * @return array Query results
+ */
+function events_by_date($owner_uid = 0, $event_params, $sql_extra = '') {
+	// ownly allow events if there is a valid owner_id
+	if($owner_uid == 0)
+		return;
+
+	// query for the event by date
+	$r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
+				`item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
+			LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
+			WHERE `event`.`uid` = %d AND event.ignore = %d
+			AND ((`adjust` = 0 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s')
+			OR  (`adjust` = 1 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s'))
+			$sql_extra ",
+			intval($owner_uid),
+			intval($event_params["ignored"]),
+			dbesc($event_params["start"]),
+			dbesc($event_params["start"]),
+			dbesc($event_params["finish"]),
+			dbesc($event_params["adjust_start"]),
+			dbesc($event_params["adjust_start"]),
+			dbesc($event_params["adjust_finish"])
+	);
+
+	if(count($r))
+		return $r;
+}
+
+/**
+ * @brief Convert an array query results in an arry which could be used by the events template
+ * 
+ * @param array $arr Event query array
+ * @return array Event array for the template
+ */
+function process_events ($arr) {
+	$events=array();
+
+	$last_date = '';
+	$fmt = t('l, F j');
+	if (count($arr)) {
+		foreach($arr as $rr) {
+
+			$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j'));
+			$d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], $fmt) : datetime_convert('UTC','UTC',$rr['start'],$fmt));
+			$d = day_translate($d);
+
+			$start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'c') : datetime_convert('UTC','UTC',$rr['start'],'c'));
+			if ($rr['nofinish']){
+				$end = null;
+			} else {
+				$end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['finish'], 'c') : datetime_convert('UTC','UTC',$rr['finish'],'c'));
+			}
+
+
+			$is_first = ($d !== $last_date);
+
+			$last_date = $d;
+			$edit = ((! $rr['cid']) ? array(App::get_baseurl().'/events/event/'.$rr['id'],t('Edit event'),'','') : null);
+			$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
+			if(! $title) {
+				list($title, $_trash) = explode("<br",bbcode($rr['desc']),2);
+				$title = strip_tags(html_entity_decode($title,ENT_QUOTES,'UTF-8'));
+			}
+
+			$html = format_event_html($rr);
+			$rr['desc'] = bbcode($rr['desc']);
+			$rr['location'] = bbcode($rr['location']);
+			$events[] = array(
+				'id'=>$rr['id'],
+				'start'=> $start,
+				'end' => $end,
+				'allDay' => false,
+				'title' => $title,
+
+				'j' => $j,
+				'd' => $d,
+				'is_first'=>$is_first,
+				'item'=>$rr,
+				'html'=>$html,
+				'plink' => array($rr['plink'],t('link to source'),'',''),
+			);
+		}
+	}
+
+	return $events;
+}
diff --git a/include/identity.php b/include/identity.php
index 48a6c5bbf7..136452e787 100644
--- a/include/identity.php
+++ b/include/identity.php
@@ -740,8 +740,8 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){
 		),
 	);
 
-	if ($is_owner){
-		if ($a->theme_events_in_profile)
+	// the calendar link for the full featured events calendar
+	if ($is_owner && $a->theme_events_in_profile) {
 			$tabs[] = array(
 				'label' => t('Events'),
 				'url'	=> $a->get_baseurl() . '/events',
@@ -750,6 +750,20 @@ function profile_tabs($a, $is_owner=False, $nickname=Null){
 				'id' => 'events-tab',
 				'accesskey' => 'e',
 			);
+	// if the user is not the owner of the calendar we only show a calendar
+	// with the public events of the calendar owner
+	} elseif (! $is_owner) {
+		$tabs[] = array(
+				'label' => t('Events'),
+				'url'	=> $a->get_baseurl() . '/cal/' . $nickname,
+				'sel' 	=>((!isset($tab)&&$a->argv[0]=='cal')?'active':''),
+				'title' => t('Events and Calendar'),
+				'id' => 'events-tab',
+				'accesskey' => 'e',
+			);
+	}
+
+	if ($is_owner){
 		$tabs[] = array(
 			'label' => t('Personal Notes'),
 			'url'	=> $a->get_baseurl() . '/notes',
diff --git a/mod/cal.php b/mod/cal.php
new file mode 100644
index 0000000000..0cde2a6ece
--- /dev/null
+++ b/mod/cal.php
@@ -0,0 +1,279 @@
+<?php
+/**
+ * @file mod/cal.php
+ * @brief The calendar module
+ *	This calendar is for profile visitors and contains only the events
+ *	of the profile owner
+ */
+
+require_once('include/event.php');
+require_once('include/redir.php');
+
+function cal_init(&$a) {
+	if($a->argc > 1)
+		auto_redir($a, $a->argv[1]);
+
+	if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) {
+		return;
+	}
+
+	nav_set_selected('events');
+
+	$o = '';
+
+	if($a->argc > 1) {
+		$nick = $a->argv[1];
+		$user = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `blocked` = 0 LIMIT 1",
+			dbesc($nick)
+		);
+
+		if(! count($user))
+			return;
+
+		$a->data['user'] = $user[0];
+		$a->profile_uid = $user[0]['uid'];
+
+		$profile = get_profiledata_by_nick($nick, $a->profile_uid);
+
+		if((intval($profile['page-flags']) == PAGE_COMMUNITY) || (intval($profile['page-flags']) == PAGE_PRVGROUP))
+			$account_type = t('Forum');
+		else
+			$account_type = "";
+
+		$tpl = get_markup_template("vcard-widget.tpl");
+
+		$vcard_widget .= replace_macros($tpl, array(
+			'$name' => $profile['name'],
+			'$photo' => $profile['photo'],
+			'$addr' => (($profile['addr'] != "") ? $profile['addr'] : ""),
+			'$account_type' => $account_type,
+			'$pdesc' => (($profile['pdesc'] != "") ? $profile['pdesc'] : ""),
+		));
+
+		if(! x($a->page,'aside'))
+			$a->page['aside'] = '';
+
+		$a->page['aside'] .= $vcard_widget;
+	}
+
+	return;
+}
+
+function cal_content(&$a) {
+	nav_set_selected('events');
+
+	$editselect = 'none';
+	if( feature_enabled(local_user(), 'richtext') )
+		$editselect = 'textareas';
+
+	// First day of the week (0 = Sunday)
+	$firstDay = get_pconfig(local_user(),'system','first_day_of_week');
+	if ($firstDay === false) $firstDay=0;
+
+	// get the translation strings for the callendar
+	$i18n = get_event_strings();
+
+	$htpl = get_markup_template('event_head.tpl');
+	$a->page['htmlhead'] .= replace_macros($htpl,array(
+		'$baseurl' => $a->get_baseurl(),
+		'$module_url' => '/cal/' . $a->data['user']['nickname'],
+		'$modparams' => 2,
+		'$i18n' => $i18n,
+		'$editselect' => $editselect
+	));
+
+	$etpl = get_markup_template('event_end.tpl');
+	$a->page['end'] .= replace_macros($etpl,array(
+		'$baseurl' => $a->get_baseurl(),
+		'$editselect' => $editselect
+	));
+
+	$o ="";
+
+	$mode = 'view';
+	$y = 0;
+	$m = 0;
+	$ignored = ((x($_REQUEST,'ignored')) ? intval($_REQUEST['ignored']) : 0);
+
+	//
+	// Setup permissions structures
+	//
+
+	$contact = null;
+	$remote_contact = false;
+	$contact_id = 0;
+
+	$owner_uid = $a->data['user']['uid'];
+
+	if(is_array($_SESSION['remote'])) {
+		foreach($_SESSION['remote'] as $v) {
+			if($v['uid'] == $a->profile['profile_uid']) {
+				$contact_id = $v['cid'];
+				break;
+			}
+		}
+	}
+	if($contact_id) {
+		$groups = init_groups_visitor($contact_id);
+		$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
+			intval($contact_id),
+			intval($a->profile['profile_uid'])
+		);
+		if(count($r)) {
+			$contact = $r[0];
+			$remote_contact = true;
+		}
+	}
+	if(! $remote_contact) {
+		if(local_user()) {
+			$contact_id = $_SESSION['cid'];
+			$contact = $a->contact;
+		}
+	}
+	$is_owner = ((local_user()) && (local_user() == $a->profile['profile_uid']) ? true : false);
+
+	if($a->profile['hidewall'] && (! $is_owner) && (! $remote_contact)) {
+		notice( t('Access to this profile has been restricted.') . EOL);
+		return;
+	}
+
+	$sql_extra = item_permissions_sql($owner_uid,$remote_contact,$groups);
+
+	// get the tab navigation bar
+	$tabs .= profile_tabs($a,false, $a->data['user']['nickname']);
+
+	// The view mode part is similiar to /mod/events.php
+	if($mode == 'view') {
+
+
+		$thisyear = datetime_convert('UTC',date_default_timezone_get(),'now','Y');
+		$thismonth = datetime_convert('UTC',date_default_timezone_get(),'now','m');
+		if(! $y)
+			$y = intval($thisyear);
+		if(! $m)
+			$m = intval($thismonth);
+
+		// Put some limits on dates. The PHP date functions don't seem to do so well before 1900.
+		// An upper limit was chosen to keep search engines from exploring links millions of years in the future.
+
+		if($y < 1901)
+			$y = 1900;
+		if($y > 2099)
+			$y = 2100;
+
+		$nextyear = $y;
+		$nextmonth = $m + 1;
+		if($nextmonth > 12) {
+				$nextmonth = 1;
+			$nextyear ++;
+		}
+
+		$prevyear = $y;
+		if($m > 1)
+			$prevmonth = $m - 1;
+		else {
+			$prevmonth = 12;
+			$prevyear --;
+		}
+
+		$dim    = get_dim($y,$m);
+		$start  = sprintf('%d-%d-%d %d:%d:%d',$y,$m,1,0,0,0);
+		$finish = sprintf('%d-%d-%d %d:%d:%d',$y,$m,$dim,23,59,59);
+
+
+		if ($a->argv[2] === 'json'){
+			if (x($_GET,'start'))	$start = date("Y-m-d h:i:s", $_GET['start']);
+			if (x($_GET,'end'))	$finish = date("Y-m-d h:i:s", $_GET['end']);
+		}
+
+		$start  = datetime_convert('UTC','UTC',$start);
+		$finish = datetime_convert('UTC','UTC',$finish);
+
+		$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
+		$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
+
+		// put the event parametes in an array so we can better transmit them
+		$event_params = array(
+			'event_id' => (x($_GET,'id') ? $_GET["id"] : 0),
+			'start' => $start,
+			'finish' => $finish,
+			'adjust_start' => $adjust_start,
+			'adjust_finish' => $adjust_finish,
+			'ignored' => $ignored,
+		);
+
+		// get events by id or by date
+		if (x($_GET,'id')){
+			$r = event_by_id($owner_uid, $event_params, $sql_extra);
+		} else {
+			$r = events_by_date($owner_uid, $event_params, $sql_extra);
+		}
+
+		$links = array();
+
+		if(count($r)) {
+			$r = sort_by_date($r);
+			foreach($r as $rr) {
+				$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j'));
+				if(! x($links,$j))
+					$links[$j] = $a->get_baseurl() . '/' . $a->cmd . '#link-' . $j;
+			}
+		}
+
+
+		$events=array();
+
+		// transform the event in a usable array
+		if(count($r))
+			$r = sort_by_date($r);
+			$events = process_events($r);
+
+		if ($a->argv[2] === 'json'){
+			echo json_encode($events); killme();
+		}
+
+		// links: array('href', 'text', 'extra css classes', 'title')
+		if (x($_GET,'id')){
+			$tpl =  get_markup_template("event.tpl");
+		} else {
+//			if (get_config('experimentals','new_calendar')==1){
+				$tpl = get_markup_template("events-js.tpl");
+//			} else {
+//				$tpl = get_markup_template("events.tpl");
+//			}
+		}
+
+		// Get rid of dashes in key names, Smarty3 can't handle them
+		foreach($events as $key => $event) {
+			$event_item = array();
+			foreach($event['item'] as $k => $v) {
+				$k = str_replace('-','_',$k);
+				$event_item[$k] = $v;
+			}
+			$events[$key]['item'] = $event_item;
+		}
+
+		$o = replace_macros($tpl, array(
+			'$baseurl'	=> $a->get_baseurl(),
+			'$tabs'		=> $tabs,
+			'$title'	=> t('Events'),
+			'$view'		=> t('View'),
+			'$previus'	=> array($a->get_baseurl()."/events/$prevyear/$prevmonth",t('Previous'),'',''),
+			'$next'		=> array($a->get_baseurl()."/events/$nextyear/$nextmonth",t('Next'),'',''),
+			'$calendar' => cal($y,$m,$links, ' eventcal'),
+
+			'$events'	=> $events,
+
+			"today" => t("today"),
+			"month" => t("month"),
+			"week" => t("week"),
+			"day" => t("day"),
+
+
+		));
+
+		if (x($_GET,'id')){ echo $o; killme(); }
+
+		return $o;
+	}
+}
diff --git a/mod/events.php b/mod/events.php
index e4526ac594..617627ac4c 100644
--- a/mod/events.php
+++ b/mod/events.php
@@ -1,5 +1,8 @@
 <?php
-
+/**
+ * @fiel mod/events.php
+ * @brief The events module
+ */
 require_once('include/bbcode.php');
 require_once('include/datetime.php');
 require_once('include/event.php');
@@ -193,59 +196,14 @@ function events_content(&$a) {
 	if( feature_enabled(local_user(), 'richtext') )
 		$editselect = 'textareas';
 
-	// First day of the week (0 = Sunday)
-	$firstDay = get_pconfig(local_user(),'system','first_day_of_week');
-	if ($firstDay === false) $firstDay=0;
-
-	$i18n = array(
-			"firstDay" => $firstDay,
-			"Sun" => t("Sun"),
-			"Mon" => t("Mon"),
-			"Tue" => t("Tue"),
-			"Wed" => t("Wed"),
-			"Thu" => t("Thu"),
-			"Fri" => t("Fri"),
-			"Sat" => t("Sat"),
-			"Sunday" => t("Sunday"),
-			"Monday" => t("Monday"),
-			"Tuesday" => t("Tuesday"),
-			"Wednesday" => t("Wednesday"),
-			"Thursday" => t("Thursday"),
-			"Friday" => t("Friday"),
-			"Saturday" => t("Saturday"),
-			"Jan" => t("Jan"),
-			"Feb" => t("Feb"),
-			"Mar" => t("Mar"),
-			"Apr" => t("Apr"),
-			"May" => t("May"),
-			"Jun" => t("Jun"),
-			"Jul" => t("Jul"),
-			"Aug" => t("Aug"),
-			"Sep" => t("Sept"),
-			"Oct" => t("Oct"),
-			"Nov" => t("Nov"),
-			"Dec" => t("Dec"),
-			"January" => t("January"),
-			"February" => t("February"),
-			"March" => t("March"),
-			"April" => t("April"),
-			"May" => t("May"),
-			"June" => t("June"),
-			"July" => t("July"),
-			"August" => t("August"),
-			"September" => t("September"),
-			"October" => t("October"),
-			"November" => t("November"),
-			"December" => t("December"),
-			"today" => t("today"),
-			"month" => t("month"),
-			"week" => t("week"),
-			"day" => t("day"),
-		);
+	// get the translation strings for the callendar
+	$i18n = get_event_strings();
 
 	$htpl = get_markup_template('event_head.tpl');
 	$a->page['htmlhead'] .= replace_macros($htpl,array(
 		'$baseurl' => $a->get_baseurl(),
+		'$module_url' => '/events',
+		'$modparams' => 1,
 		'$i18n' => $i18n,
 		'$editselect' => $editselect
 	));
@@ -284,6 +242,7 @@ function events_content(&$a) {
 		}
 	}
 
+	// The view mode part is similiar to /mod/cal.php
 	if($mode == 'view') {
 
 
@@ -333,31 +292,21 @@ function events_content(&$a) {
 		$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
 		$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
 
+		// put the event parametes in an array so we can better transmit them
+		$event_params = array(
+			'event_id' => (x($_GET,'id') ? $_GET["id"] : 0),
+			'start' => $start,
+			'finish' => $finish,
+			'adjust_start' => $adjust_start,
+			'adjust_finish' => $adjust_finish,
+			'ignored' => $ignored,
+		);
 
+		// get events by id or by date
 		if (x($_GET,'id')){
-			$r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
-				`item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
-				LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
-				WHERE `event`.`uid` = %d AND `event`.`id` = %d",
-				intval(local_user()),
-				intval($_GET['id'])
-			);
+			$r = event_by_id(local_user(), $event_params);
 		} else {
-			$r = q("SELECT `event`.*, `item`.`id` AS `itemid`,`item`.`plink`,
-				`item`.`author-name`, `item`.`author-avatar`, `item`.`author-link` FROM `event`
-				LEFT JOIN `item` ON `item`.`event-id` = `event`.`id` AND `item`.`uid` = `event`.`uid`
-				WHERE `event`.`uid` = %d and event.ignore = %d
-				AND ((`adjust` = 0 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s')
-				OR  (`adjust` = 1 AND (`finish` >= '%s' OR (nofinish AND start >= '%s')) AND `start` <= '%s')) ",
-				intval(local_user()),
-				intval($ignored),
-				dbesc($start),
-				dbesc($start),
-				dbesc($finish),
-				dbesc($adjust_start),
-				dbesc($adjust_start),
-				dbesc($adjust_finish)
-			);
+			$r = events_by_date(local_user(), $event_params);
 		}
 
 		$links = array();
@@ -371,60 +320,12 @@ function events_content(&$a) {
 			}
 		}
 
-
 		$events=array();
 
-		$last_date = '';
-		$fmt = t('l, F j');
-
-		if(count($r)) {
+		// transform the event in a usable array
+		if(count($r))
 			$r = sort_by_date($r);
-			foreach($r as $rr) {
-
-
-				$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j'));
-				$d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], $fmt) : datetime_convert('UTC','UTC',$rr['start'],$fmt));
-				$d = day_translate($d);
-
-				$start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'c') : datetime_convert('UTC','UTC',$rr['start'],'c'));
-				if ($rr['nofinish']){
-					$end = null;
-				} else {
-					$end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['finish'], 'c') : datetime_convert('UTC','UTC',$rr['finish'],'c'));
-				}
-
-
-				$is_first = ($d !== $last_date);
-
-				$last_date = $d;
-				$edit = ((! $rr['cid']) ? array($a->get_baseurl().'/events/event/'.$rr['id'],t('Edit event'),'','') : null);
-				$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
-				if(! $title) {
-					list($title, $_trash) = explode("<br",bbcode($rr['desc']),2);
-					$title = strip_tags(html_entity_decode($title,ENT_QUOTES,'UTF-8'));
-				}
-				$html = format_event_html($rr);
-				$rr['desc'] = bbcode($rr['desc']);
-				$rr['location'] = bbcode($rr['location']);
-				$events[] = array(
-					'id'=>$rr['id'],
-					'start'=> $start,
-					'end' => $end,
-					'allDay' => false,
-					'title' => $title,
-
-					'j' => $j,
-					'd' => $d,
-					'edit' => $edit,
-					'is_first'=>$is_first,
-					'item'=>$rr,
-					'html'=>$html,
-					'plink' => array($rr['plink'],t('link to source'),'',''),
-				);
-
-
-			}
-		}
+			$events = process_events($r);
 
 		if ($a->argv[1] === 'json'){
 			echo json_encode($events); killme();
diff --git a/view/templates/event_head.tpl b/view/templates/event_head.tpl
index 01c69b8b31..99a320a895 100644
--- a/view/templates/event_head.tpl
+++ b/view/templates/event_head.tpl
@@ -6,7 +6,7 @@
 <script>
 	function showEvent(eventid) {
 		$.get(
-			'{{$baseurl}}/events/?id='+eventid,
+			'{{$baseurl}}{{$module_url}}/?id='+eventid,
 			function(data){
 				$.colorbox({html:data});
 			}
@@ -47,7 +47,7 @@
 				week: '{{$i18n.week}}',
 				day: '{{$i18n.day}}'
 			},
-			events: '{{$baseurl}}/events/json/',
+			events: '{{$baseurl}}{{$module_url}}/json/',
 			header: {
 				left: 'prev,next today',
 				center: 'title',
@@ -100,9 +100,15 @@
 		
 		// center on date
 		var args=location.href.replace(baseurl,"").split("/");
+		{{if $modparams == 2}}
+		if (args.length>=5) {
+			$("#events-calendar").fullCalendar('gotoDate',args[3] , args[4]-1);
+		}
+		{{else}}
 		if (args.length>=4) {
 			$("#events-calendar").fullCalendar('gotoDate',args[2] , args[3]-1);
-		} 
+		}
+		{{/if}} 
 		
 		// show event popup
 		var hash = location.hash.split("-")
diff --git a/view/theme/frio/templates/event_head.tpl b/view/theme/frio/templates/event_head.tpl
index 3e7dfc1c5c..4d14a3884a 100644
--- a/view/theme/frio/templates/event_head.tpl
+++ b/view/theme/frio/templates/event_head.tpl
@@ -6,7 +6,7 @@
 <script>
 	// loads the event into a modal
 	function showEvent(eventid) {
-			addToModal('{{$baseurl}}/events/?id='+eventid);
+			addToModal('{{$baseurl}}{{$module_url}}/?id='+eventid);
 	}
 
 	function changeView(action, viewName) {
@@ -33,7 +33,7 @@
 				week: '{{$i18n.week}}',
 				day: '{{$i18n.day}}'
 			},
-			events: '{{$baseurl}}/events/json/',
+			events: '{{$baseurl}}{{$module_url}}/json/',
 			header: {
 				left: '',
 			//	center: 'title',
@@ -83,12 +83,18 @@
 			}
 			
 		})
-		
+
 		// center on date
 		var args=location.href.replace(baseurl,"").split("/");
+		{{if $modparams == 2}}
+		if (args.length>=5) {
+			$("#events-calendar").fullCalendar('gotoDate',args[3] , args[4]-1);
+		}
+		{{else}}
 		if (args.length>=4) {
 			$("#events-calendar").fullCalendar('gotoDate',args[2] , args[3]-1);
-		} 
+		}
+		{{/if}} 
 
 		// echo the title
 		var view = $('#events-calendar').fullCalendar('getView');
diff --git a/view/theme/frost-mobile/js/theme.js b/view/theme/frost-mobile/js/theme.js
index 7d7e8259c6..3017263b6b 100644
--- a/view/theme/frost-mobile/js/theme.js
+++ b/view/theme/frost-mobile/js/theme.js
@@ -156,7 +156,7 @@ $(document).ready(function() {
 
 	if(window.aclType == "event_head") {
 		$('#events-calendar').fullCalendar({
-			events: baseurl + '/events/json/',
+			events: baseurl + window.eventModuleUrl +'/json/',
 			header: {
 				left: 'prev,next today',
 				center: 'title',
@@ -204,9 +204,11 @@ $(document).ready(function() {
 		
 		// center on date
 		var args=location.href.replace(baseurl,"").split("/");
-		if (args.length>=4) {
+		if (args.length>=5 && window.eventModeParams == 2) {
+			$("#events-calendar").fullCalendar('gotoDate',args[3] , args[4]-1);
+		} else if (args.length>=4 && window.eventModeParams == 1) {
 			$("#events-calendar").fullCalendar('gotoDate',args[2] , args[3]-1);
-		} 
+		}
 		
 		// show event popup
 		var hash = location.hash.split("-")
@@ -264,7 +266,7 @@ function initCrop() {
 
 function showEvent(eventid) {
 /*	$.get(
-		baseurl + '/events/?id='+eventid,
+		baseurl + window.eventModuleUrl + '/?id=' + eventid,
 		function(data){
 			$.colorbox({html:data});
 		}
diff --git a/view/theme/frost-mobile/templates/event_head.tpl b/view/theme/frost-mobile/templates/event_head.tpl
index 11c8f99fb2..ccd88f6c86 100644
--- a/view/theme/frost-mobile/templates/event_head.tpl
+++ b/view/theme/frost-mobile/templates/event_head.tpl
@@ -3,5 +3,7 @@
 
 <script language="javascript" type="text/javascript">
 window.aclType = 'event_head';
+window.eventModuleUrl = "{{$module_url}}";
+window.eventModeParams = "{{$modparams}}" ;
 </script>
 
diff --git a/view/theme/frost/js/theme.js b/view/theme/frost/js/theme.js
index 038f83e0e5..eb8bb51cc2 100644
--- a/view/theme/frost/js/theme.js
+++ b/view/theme/frost/js/theme.js
@@ -149,7 +149,7 @@ $(document).ready(function() {
 
 	if(window.aclType == "event_head") {
 		$('#events-calendar').fullCalendar({
-			events: baseurl + '/events/json/',
+			events: baseurl + window.eventModuleUrl +'/json/',
 			header: {
 				left: 'prev,next today',
 				center: 'title',
@@ -202,10 +202,12 @@ $(document).ready(function() {
 		
 		// center on date
 		var args=location.href.replace(baseurl,"").split("/");
-		if (args.length>=4) {
+		if (args.length>=5 && window.eventModeParams == 2) {
+			$("#events-calendar").fullCalendar('gotoDate',args[3] , args[4]-1);
+		} else if (args.length>=4 && window.eventModeParams == 1) {
 			$("#events-calendar").fullCalendar('gotoDate',args[2] , args[3]-1);
-		} 
-		
+		}
+
 		// show event popup
 		var hash = location.hash.split("-")
 		if (hash.length==2 && hash[0]=="#link") showEvent(hash[1]);
@@ -352,7 +354,7 @@ if(typeof window.photoEdit != 'undefined') {
 
 function showEvent(eventid) {
 	$.get(
-		baseurl + '/events/?id='+eventid,
+		baseurl + window.eventModuleUrl + '/?id=' + eventid,
 		function(data){
 			$.colorbox({html:data});
 			$.colorbox.resize();
diff --git a/view/theme/frost/templates/event_head.tpl b/view/theme/frost/templates/event_head.tpl
index f33f7fce23..47efb56ae9 100644
--- a/view/theme/frost/templates/event_head.tpl
+++ b/view/theme/frost/templates/event_head.tpl
@@ -4,5 +4,7 @@
 <script language="javascript" type="text/javascript">
 window.aclType = 'event_head';
 window.editSelect = "{{$editselect}}";
+window.eventModuleUrl = "{{$module_url}}";
+window.eventModeParams = "{{$modparams}}" ;
 </script>
 
-- 
2.39.5