Extension talk:Cargo

Referential integrity?
Does Cargo enable me to restrict the contents of a column to the values contained in another table?

The desired end result is a form where the values in that column are not free-entry but rather selected from a drop down list that is populated from another table.


 * This is really a Page Forms question, but yes - in the form definition, you can have something like " ". Yaron Koren (talk) 02:05, 14 November 2016 (UTC)

Formatting of floating-point numbers
Hi Yaron,

We've come across a bit of an oddity when displaying the results of queries that contain float values that happen to be integers: the number of decimal places shown in the formatted number depends on the length of the number. For example, 6 is formatted correctly as "6", whereas 24 becomes "24.0", 100 becomes "100.00", and 1000 becomes "1,000.000".

I think the culprit is line 168 of CargoQueryDisplay:

$numDecimalPlaces = strlen( $value ) - strrpos( $value, '.' ) - 1

... which needs a special case for when '.' isn't found.

On a related note, it would be nice to be able to right-align numerical columns by default. The CSS classes based on the field names make this possible, but you have to handle each numerical field separately. If you could use CSS classes to indicate the data type, this would be easier. Also, I can't see a way to do this with dynamic tables, as there don't seem to be any classes defined there. Many thanks. Paul T (talk) 20:00, 1 November 2016 (UTC)


 * That's true... what do you think a good default number of decimal places would be - 0? 1? The CSS is also a pretty good idea. I don't think it's possible within dynamic tables, i.e. the DataTables JS library, though, unfortunately. Although numbers in dynamic tables are right-aligned automatically, no? Yaron Koren (talk) 03:19, 2 November 2016 (UTC)


 * Apologies for the slow response. The patch you've done to avoid adding decimals works nicely. I suspect use cases for floats vary so much that there's no sensible default for the number of decimal places. A nice feature (but not one that we really need) would be to be able to specify a default display format in the Cargo table definition (in a similar manner to how the "link text" and "hidden" attributes are dealt with).


 * On the CSS issue, I see that the DataTables javascript library does have a "columns.className" option. It also has an order option that it might be handy to expose: at present, it seems to sort the data by the first field, undoing any ordering specified in the cargo_query call. Paul T (talk) 13:15, 16 November 2016 (UTC)

Sparse matrix
Is it possible to implement a list field with named elements to store a sparse matrix? May be, is there any other way? --StasR (talk) 13:39, 2 November 2016 (UTC)


 * Yes - what's the extra challenge with a sparse matrix? Yaron Koren (talk) 13:52, 2 November 2016 (UTC)


 * For each row of the matrix need to store a plurality of pairs of "index (key) - value" and I need to be able to get the value for the key. Of course, I can myself organize a separate table, but it will require a lot of calls cargo_store. --StasR (talk) 14:13, 2 November 2016 (UTC)


 * Oh, I see - you want to store a sparse matrix within each page. If so, what about a multiple-instance template, where the template contains "key" and "value" fields? Yaron Koren (talk) 14:27, 2 November 2016 (UTC)


 * The tempate call looks like this: . It is logical to convert it into a function  . And you save _rowID, _key, _value in the separate table. --StasR (talk) 15:29, 2 November 2016 (UTC)


 * Alright. Is your problem solved now? Yaron Koren (talk) 16:09, 2 November 2016 (UTC)


 * Now I use an separate no-sparse table. It is useful for experiments, but it is bad for real work (especially because the number of columns will grow with time). --StasR (talk) 16:25, 2 November 2016 (UTC)


 * If so, what about a multiple-instance template, where the template contains "key" and "value" fields? — Perhaps I did not understand exactly what you advise :-( --StasR (talk) 16:31, 2 November 2016 (UTC)


 * Do you know what multiple-instance templates are? Yaron Koren (talk) 17:09, 2 November 2016 (UTC)


 * I found it in PageForms description. If I understand correctly, this is multiple cargo_store calls. This is true? --StasR (talk) 17:54, 2 November 2016 (UTC)


 * Yes. Yaron Koren (talk) 18:37, 2 November 2016 (UTC)


 * It is too prodigally for my task. I fear timeout. --StasR (talk) 18:43, 2 November 2016 (UTC)

How many key/value pairs could a single page have? I thought you said it was "sparse". :) Yaron Koren (talk) 03:12, 3 November 2016 (UTC)


 * One page is shaping up to 200-300 main table records. Each main table record usually includes 10-20 pairs. --StasR (talk) 07:42, 3 November 2016 (UTC)


 * Okay, now I don't understand again... a page holds main table records, which themselves hold key/value pairs? That sounds like you basically want to store a three-dimensional array of data on every page. What's a main table record? Yaron Koren (talk) 13:10, 3 November 2016 (UTC)

Fatal_exception_of_type_MWException_on_RunQuery_Template
Hi, was there any resolution on this issue?

Fatal_exception_of_type_MWException_on_RunQuery_Template

We are finding the same problem - CONCAT is breaking when used in a query form, but works otherwise. We're using Semantic Forms 3.7 and Cargo 1.0.1. --Bgrenon (talk) 19:12, 4 November 2016 (UTC)


 * Try upgrading Cargo. You might as well upgrade Semantic Forms while you're at it, i.e. switch to Page Forms. Yaron Koren (talk) 20:23, 4 November 2016 (UTC)


 * Upgrading Cargo seemed to work. (Haven't tried upgrading to Page forms yet).  Thanks! --Bgrenon (talk) 10:44, 10 November 2016 (UTC)

Problem with the Cargo Query Calendar format
Hi

I've been trying to get this to work with Cargo 1.1.1 and MW1.26.4 and encountered a few problems.

The page call I'm using is

Firstly CargoExport was failing with:

A database query error has occurred. This may indicate a bug in the software. Query: SELECT `_pageName`,`Event_Start_Date_Time` AS `Event Start Date  Time`,`Event_Start_Date_Time__precision` AS `Event Start Date Time__precision` FROM `cargo__Articles` WHERE DATEDIFF(Event_Start_Date_Time,NOW) >= -30 AND ((Event_Start_Date_Time >= '2016-10-30' AND Event_Start_Date_Time <= '2016-12-11)) ORDER BY `_pageName` LIMIT 100 Function: CargoSQLQuery::run Error: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''2016-12-11)) ORDER BY `_pageName` LIMIT 100' at line 1 (localhost)

I managed to fix this in function displayCalendarData by adding an apostrophe before the final ')' on the following line:

$where .= "($dateField >= '$datesLowerLimit' AND $dateField <= '$datesUpperLimit)";

The calendar was still not displaying events and gave the following warning:

Notice: Undefined index: Event_Start_Date_Time__precision in /var/www/vhosts/cmswiki.farm/httpdocs/x/mw-1.26/extensions/Cargo/specials/CargoExport.php on line 131

I managed to fix this by removing the str_replace clause from the following line in the same function:

$startDatePrecisionField = str_replace( ' ', '_', $startDateField ). '__precision';

I am also having problems getting the Calendar Format to recognise the color parameter although I've yet to work out this one.

Finally I have tried to use an alternative Cargo field for the calendar event title by using the following field parameter.

fields=_pageName=Title,Description,Event_Start_Date_Time

This works if I use the default table format but not within the Calendar format. I'd like to do this because I'm using Semantic Title where the Cargo field Title is the semantic title for the page.

I wondered if I might have been doing something wrong to cause the above issues or whether the fixes I've made are OK?

Many thanks

Duncan, 11 Nov 2016

Hi

I've now had a look at the problem displaying colours in the calendar format and found a possible fix for that too. In CargoCalendarFormat.php function queryAndDisplay there is a block of code:

if ( $querySpecificParams != null ) { if ( array_key_exists( 'color', $querySpecificParams[$i] ) ) { $queryParams['color'][] = $querySpecificParams[$i]['color']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['color'][] = 'red'; }

If this is changed to the following then colours display OK:

if ( $displayParams != null ) { if ( array_key_exists( 'color', $displayParams ) ) { $queryParams['color'][] = $displayParams['color']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['color'][] = ''; }

As before I'm not really sure I understand this code fully so this change may mess up something else. Would you advise?

Kind regards

Duncan 12 Nov 2016


 * Sorry about all the problems you ran into!
 * The missing-parenthesis problem: I actually discovered this bug about a week ago, and checked in a fix for it then (it was the same fix you found).
 * Problem with underscores in date fields: thanks for that fix; I'll probably check it in soon.
 * Alternative title field: there's a way to do this, and it's actually mentioned in the documentation, though it's easy to miss. Instead of an "=Title" alias, I think you just need to set the alias to be "=name".
 * The multiple-colors problem: I have no idea where that 'red' value came from; it's not now, and doesn't look like it ever was, in the Cargo code. Could it be that you changed that line yourself during testing? Anyway, this, at least, looks like a non-bug. Yaron Koren (talk) 02:22, 14 November 2016 (UTC)


 * Hi Yaron


 * Thank you for your responses and fixes. You do a fantastic job producing all this great code, so I'm glad if I can help identify the occasional minor problems. On the colours question, you are right the 'red' was part of my testing trying to track down how colors were being set, although I am not sure this effects the problem I was encountering.  What my testing seemed to show is that the colour parameter is being passed to the function as part of the $displayParams variable rather than in the $querySpecificParams array variable.  As a result, the following line never found the colour parameter being passed from the cargo query:

if ( array_key_exists( 'color', $querySpecificParams[$i] ) ) { $queryParams['color'][] = $querySpecificParams[$i]['color']; } else ...


 * When I changed that line to the following it seems to pick up the colour OK:

if ( array_key_exists( 'color', $displayParams ) ) { $queryParams['color'][] = $displayParams['color']; } else ...


 * Is it possible I've inadvertently affected how the color parameter is passed to the queryAndDisplay function?.


 * Many thanks


 * Duncan 15 Nov 2016


 * Oh, I didn't notice the rest of the code changes. Could it be that you're putting the 'color' parameter in the wrong place in the #cargo_compound_query call? It should be within each "sub-query". Yaron Koren (talk) 14:39, 16 November 2016 (UTC)


 * Ah now I see where I may be going wrong. Perhaps if I explain what I'm trying to do maybe you will tell me if it is possible?


 * What I'd like is to display pages from an Articles table on the calendar. Each Article has an Event Type field that looks up on a separate Event Types table.  Each Event Type has a Colour field associated with it.


 * By joining the Articles and Event Types table, I hope to find the colour associated with each and then have the Calendar format use this to select the background colour for each calendar entry. Originally I assumed I wouldn't need to use Cargo's compound query which would leave me with a simple query such as:


 * From what you say above, the Calendar format requires you use Cargo's compound query to use the colour parameter. I have tried this using a literal value for the colour parameter and this does indeed work .  However, if I try to use a variable, such as Event_types.Colour which changes for each calendar entry, this doesn't seem to work. For example:


 * I wonder if what I am trying to do is possible and, if so, where I'm going wrong? I was able to do this when I used SMW as the data source but I know quite a lot changed in the query function for Cargo.  It looks like it might be possible if I do a compound query on the same table to select each event type and set its colour using a literal value, but this seems a bit inefficient and probably makes maintenance more complicated.


 * If it is not possible to use a field variable to set the background colour, is this a feature you might consider for the future? It would also be useful to send other parameters to the calendar for each event such as the end date and time so that it displays events that span several hours or days.


 * Many thanks


 * Duncan 17 Nov 2016


 * Ah, now it makes sense. No, you can't get the color value from the database. I know Semantic Result Formats has such a feature, with the "Has color" special property, but I decided against it for Cargo, because it seemed like the query was the more natural place to set that information. If you want the same page to be displayed with a different color in two different calendars, and the color information is set in the page itself, it's awkward (though possible). But I'm curious - in what way do you think setting the color info in the query is less efficient? Yaron Koren (talk) 14:53, 17 November 2016 (UTC)


 * Thanks Yaron, my thinking is this. Say I have two types of event - Show and Race.  I want the calendar events with type Show to have a green background and those of type Race to be red. I imagine (although this is just speculation as I haven't tried it yet) that the compound query would look like this?


 * The reason I supposed this to be inefficient was because I thought it may have to perform the join and then select the right type of articles twice, once for each parameter of the compound query. If it had been possible to pick up the colour for each calendar event from the join, then I had imagined I would only have to perform the join once and there would be no need to select a subset of the records for each event type. You've probably realised I'm a bit of a novice so apologies if I've go the wrong end of the stick but I'd be interested to know how this works.


 * Kind regards


 * Duncan 17 Nov 2016


 * Hi again. I now tested a version of the compound query that tests for the colour of the event type and sets the background colour as follows.  This does achieve the effect I want, although I don't really have enough data to tell about its efficiency:


 * I also thought about the use case that you gave whereby one might want to display the same events with different colours on different calendars. This might still be possible in the same way as it is now whilst still allowing the query to pick up a variable (database value) if one was set.  This might be done if the code could distinguish between whether a literal or variable database value was passed with the Color parameter.  If the Color parameter was a literal it could function as now and apply that value to each calendar event. On the other hand, if the Color parameter was a variable database value that might be used instead for each calendar event. That way one might achieve both use cases depending on the type of value passed in the Color parameter.


 * As mentioned I am out of my depth here but if you pointed me to the place where the programme sets the values for each of the calendar event entries I could see if I can get this working, if you think this might be a useful feature?


 * Many thanks, Duncan 17 Nov 2016


 * That's true, this approach of getting the color from the database would indeed be more efficient. And I think your first instinct was right, that this sort of thing should be handled via #cargo_query and not #cargo_compound_query - since it's not a compound query at all. The only thing I would change is that there should be a new parameter for this, probably named "color field=", to avoid confusion with "color=", which would keep only taking hardcoded colors. It does sound like a possibly useful feature, and if you want to have a go at creating a patch for it, feel free - I'll add it in to the code. Yaron Koren (talk) 20:02, 17 November 2016 (UTC)


 * Thanks Yaron. It's taken me a while to work this out but it's been an interesting journey.  I'm not sure I know how to create a patch so I've just included the code changes below.  I've tested them and they seem to work OK.  Also the Color parameter still seems to function as before.  However as mentioned I am a novice so you might want to check I haven't done anything daft!


 * I've also enabled cargo query with calendar format to display events that span more than one day correctly if an end date is supplied (see query example below). And to round things off I've enabled the text colour to be specified (also see example below).  This was necessary in case one used light background colours to ensure sufficient contrast for the text.


 * I'm hoping you will be able to adopt these changes so I can feel I've given somthing back to the Cargo community!


 * This is the updated version of the queryAndDisplay function in CargoCalendarFormat.php

function queryAndDisplay( $sqlQueries, $displayParams, $querySpecificParams = null ) { $this->mOutput->addModules( 'ext.cargo.calendar' ); $ce = SpecialPage::getTitleFor( 'CargoExport' ); $queryParams = $this->sqlQueriesToQueryParams( $sqlQueries ); $queryParams['format'] = 'fullcalendar'; $queryParams['color'] = array; foreach ( $sqlQueries as $i => $sqlQuery ) { if ( $querySpecificParams != null ) { if ( array_key_exists( 'color', $querySpecificParams[$i] ) ) { $queryParams['color'][] = $querySpecificParams[$i]['color']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['color'][] = ''; }			}			if ( $displayParams != null ) { if ( array_key_exists( 'color field', $displayParams ) ) { $queryParams['color field'][] = $displayParams['color field']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['color field'][] = ''; }			}			if ( $displayParams != null ) { if ( array_key_exists( 'text color', $displayParams ) ) { $queryParams['text color'][] = $displayParams['text color']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['text color'][] = ''; }			}		}		if ( array_key_exists( 'width', $displayParams ) ) { $width = $displayParams['width']; // Add on "px", if no unit is defined. if ( is_numeric( $width ) ) { $width .= "px"; }		} else { $width = "100%"; }

$attrs = array(			'class' => 'cargoCalendar',			'dataurl' => $ce->getFullURL( $queryParams ),			'style' => "width: $width"		);

if ( array_key_exists( 'view', $displayParams ) ) { $view = $displayParams['view']; // Enable simpler view names. if ( $view == 'day' ) { $view = 'basicDay'; } elseif ( $view == 'week' ) { $view = 'basicWeek'; }			$attrs['startview'] = $view; } else { $attrs['startview'] = 'month'; }		if ( array_key_exists( 'start date', $displayParams ) ) { $attrs['startdate'] = $displayParams['start date']; }		$text = Html::rawElement( 'div', $attrs, '' );

return $text; }

}


 * This is the updated version of the displayCalendarDatafunction in CargoExport.php

/**	 * Used for calendar format */	function displayCalendarData( $sqlQueries ) { $req = $this->getRequest;

$colorArray = $req->getArray( 'color' ); $textColorArray = $req->getArray( 'text_color' ); $colorFieldArray = $req->getArray( 'color_field' );

$datesLowerLimit = $req->getVal( 'start' ); $datesUpperLimit = $req->getVal( 'end' );

$displayedArray = array; foreach ( $sqlQueries as $i => $sqlQuery ) { foreach( $sqlQuery->mFieldStringAliases as $fieldName => $fieldAlias ) { if ( $fieldName == $colorFieldArray[0] ) { $colorFieldName = $fieldAlias ; }			}

$dateFieldRealNames = array; $dateFieldAliases = array; foreach( $sqlQuery->mFieldDescriptions as $alias => $description ) { if ( $description->mType == 'Date' || $description->mType == 'Datetime' ) { $dateFieldAliases[] = $alias; $realFieldName = $sqlQuery->mAliasedFieldNames[$alias]; $dateFieldRealNames[] = $realFieldName; }			}			$where = $sqlQuery->mWhereStr; if ( $where != '' ) { $where .= " AND "; }			$where .= "(";			foreach ( $dateFieldRealNames as $j => $dateField ) {				if ( $j > 0 ) {					$where .= " OR ";				}				$where .= "($dateField >= '$datesLowerLimit' AND $dateField <= '$datesUpperLimit')";			}			$where .= ")"; $sqlQuery->mWhereStr = $where;

$queryResults = $sqlQuery->run; foreach ( $queryResults as $queryResult ) { if ( array_key_exists( 'name', $queryResult ) ) { $eventTitle = $queryResult['name']; } else { $eventTitle = reset( $queryResult ); }				$title = Title::newFromText( $queryResult['_pageName'] ); $startDateField = $dateFieldAliases[0]; $startDate = $queryResult[$startDateField]; $startDatePrecisionField = $startDateField. '__precision'; $startDatePrecision = $queryResult[$startDatePrecisionField]; if ( array_key_exists( $colorFieldName, $queryResult ) ) { $eventColor = $queryResult[$colorFieldName]; } else { $eventColor = $colorArray[$i]; }

$curEvent = array(					// Get first field for the title - not					// necessarily the page name.					'title' => $eventTitle,					'url' => $title->getLocalURL,					'start' => $queryResult[$dateFieldAliases[0]],					'end' => $queryResult[$dateFieldAliases[1]],					'color' => $eventColor,					'textColor' => $textColorArray[$i]				); if ( $startDatePrecision != CargoStore::DATE_AND_TIME ) { $curEvent['allDay'] = true; }

$displayedArray[] = $curEvent; }		}		print json_encode( $displayedArray ); }
 * This is an example of cargo query using the new capabilities


 * Many thanks


 * Duncan 18 Nov 2016

Oh wow, great! I'll add this in. One question: the "text color" parameter certainly seems like it could have its uses, but, if "color field" is going to be used, shouldn't there really be a corresponding "text color field" parameter? Yaron Koren (talk) 16:17, 18 November 2016 (UTC)


 * Seems logical - I'll look into it over the weekend :-) Duncan 18th November 2016


 * Ok, I think I've done this. Fortunately I hadn't had time to forget everything!


 * The code for the queryAndDisplay function in CargoCalendarFormat.php is:

/**	 *	 * @param array $sqlQueries * @param array $displayParams * @param array $querySpecificParams * @return string */	function queryAndDisplay( $sqlQueries, $displayParams, $querySpecificParams = null ) { $this->mOutput->addModules( 'ext.cargo.calendar' ); $ce = SpecialPage::getTitleFor( 'CargoExport' ); $queryParams = $this->sqlQueriesToQueryParams( $sqlQueries ); $queryParams['format'] = 'fullcalendar'; $queryParams['color'] = array; foreach ( $sqlQueries as $i => $sqlQuery ) { if ( $querySpecificParams != null ) { if ( array_key_exists( 'color', $querySpecificParams[$i] ) ) { $queryParams['color'][] = $querySpecificParams[$i]['color']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['color'][] = ''; }			}			if ( $displayParams != null ) { if ( array_key_exists( 'color field', $displayParams ) ) { $queryParams['color field'][] = $displayParams['color field']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['color field'][] = ''; }			}			if ( $displayParams != null ) { if ( array_key_exists( 'text color field', $displayParams ) ) { $queryParams['text color field'][] = $displayParams['text color field']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['text color field'][] = ''; }			}			if ( $displayParams != null ) { if ( array_key_exists( 'text color', $displayParams ) ) { $queryParams['text color'][] = $displayParams['text color']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['text color'][] = ''; }			}		}		if ( array_key_exists( 'width', $displayParams ) ) { $width = $displayParams['width']; // Add on "px", if no unit is defined. if ( is_numeric( $width ) ) { $width .= "px"; }		} else { $width = "100%"; }

$attrs = array(			'class' => 'cargoCalendar',			'dataurl' => $ce->getFullURL( $queryParams ),			'style' => "width: $width"		);

if ( array_key_exists( 'view', $displayParams ) ) { $view = $displayParams['view']; // Enable simpler view names. if ( $view == 'day' ) { $view = 'basicDay'; } elseif ( $view == 'week' ) { $view = 'basicWeek'; }			$attrs['startview'] = $view; } else { $attrs['startview'] = 'month'; }		if ( array_key_exists( 'start date', $displayParams ) ) { $attrs['startdate'] = $displayParams['start date']; }		$text = Html::rawElement( 'div', $attrs, '' );

return $text; }

}
 * And the code for function displayCalendarData in CargoExport.php is:

/**	 * Used for calendar format */	function displayCalendarData( $sqlQueries ) { $req = $this->getRequest;

$colorArray = $req->getArray( 'color' ); $textColorArray = $req->getArray( 'text_color' ); $colorFieldArray = $req->getArray( 'color_field' ); $textColorFieldArray = $req->getArray( 'text_color_field' );

$datesLowerLimit = $req->getVal( 'start' ); $datesUpperLimit = $req->getVal( 'end' );

$displayedArray = array; foreach ( $sqlQueries as $i => $sqlQuery ) { foreach( $sqlQuery->mFieldStringAliases as $fieldName => $fieldAlias ) { if ( $fieldName == $colorFieldArray[0] ) { $colorFieldName = $fieldAlias ; }				if ( $fieldName == $textColorFieldArray[0] ) { $textColorFieldName = $fieldAlias ; }			}

$dateFieldRealNames = array; $dateFieldAliases = array; foreach( $sqlQuery->mFieldDescriptions as $alias => $description ) { if ( $description->mType == 'Date' || $description->mType == 'Datetime' ) { $dateFieldAliases[] = $alias; $realFieldName = $sqlQuery->mAliasedFieldNames[$alias]; $dateFieldRealNames[] = $realFieldName; }			}			$where = $sqlQuery->mWhereStr; if ( $where != '' ) { $where .= " AND "; }			$where .= "(";			foreach ( $dateFieldRealNames as $j => $dateField ) {				if ( $j > 0 ) {					$where .= " OR ";				}				$where .= "($dateField >= '$datesLowerLimit' AND $dateField <= '$datesUpperLimit')";			}			$where .= ")"; $sqlQuery->mWhereStr = $where;

$queryResults = $sqlQuery->run; foreach ( $queryResults as $queryResult ) { if ( array_key_exists( 'name', $queryResult ) ) { $eventTitle = $queryResult['name']; } else { $eventTitle = reset( $queryResult ); }				$title = Title::newFromText( $queryResult['_pageName'] ); $startDateField = $dateFieldAliases[0]; $startDate = $queryResult[$startDateField]; $startDatePrecisionField = $startDateField. '__precision'; $startDatePrecision = $queryResult[$startDatePrecisionField]; if ( array_key_exists( $colorFieldName, $queryResult ) ) { $eventColor = $queryResult[$colorFieldName]; } else { $eventColor = $colorArray[$i]; }				if ( array_key_exists( $textColorFieldName, $queryResult ) ) { $eventTextColor = $queryResult[$textColorFieldName]; } else { $eventTextColor = $textColorArray[$i]; }

$curEvent = array(					// Get first field for the title - not					// necessarily the page name.					'title' => $eventTitle,					'url' => $title->getLocalURL,					'start' => $queryResult[$dateFieldAliases[0]],					'end' => $queryResult[$dateFieldAliases[1]],					'color' => $eventColor,					'textColor' => $eventTextColor 				); if ( $startDatePrecision != CargoStore::DATE_AND_TIME ) { $curEvent['allDay'] = true; }

$displayedArray[] = $curEvent; }		}		print json_encode( $displayedArray ); }
 * I suggest using with caution - all those colours can hurt one's eyes!


 * Duncan 18th November 2016


 * Wow, thank you! I'll look into this later, but everything here looks reasonable. And I'll try to test it tastefully. :) How should I credit you - as Duncan? Yaron Koren (talk) 19:24, 18 November 2016 (UTC)


 * That's kind you want to Credit my very small contribution. Perhaps Duncan Crane?


 * Many thanks - Duncan 19, Nov 2016

Looking up a single feild
Hi, I'm sure I'm just missing something obvious, but I can't see how to insert the value from a single field lookup into wiki text.

The situation is this. I have a Boat table, with fields for Sail Number and Owner Name. I have another table for Race Result with fields for Race Position, Sail Number and Score. When I display a page corresponding to a Race Result, I want to display the Owner Name via a lookup on the Boat table using the Sail Number into the page.

What I wondered is do I use Cargo Query and, if so, how to insert the value into the page without any formatting (table, list etc)?

Many thanks

Duncan November 18, 2016


 * Would this work?
 * Yaron Koren (talk) 19:29, 18 November 2016 (UTC)
 * Yaron Koren (talk) 19:29, 18 November 2016 (UTC)


 * Thanks Yaron, I'll give that a try. Duncan, 19th Nov 2016

Display map from address rather than coordinates?
I see that coordinates are mandatory for  With Extension:Maps it is possible to insert any address into   Is there any way to use Cargo to achieve the same end? Thanks Jonathan3 (talk) 23:08, 18 November 2016 (UTC)


 * No - I deliberately didn't include geocoding, because I figured that it was always better for the user to get the coordinates when they were entering the location into the form. Assuming that this location is stored in a template, and edited with a form. Is that not the case here? Yaron Koren (talk) 23:19, 20 November 2016 (UTC)


 * The potential users are unlikely to know how to obtain coordinates, and unlikely to do it even if the form explained how. I can use the Maps extension to show the address on the template page (for one location), but your maps display format (showing many locations) is very impressive and in an ideal world I'd like to be able to use it, or something similar, without requiring coordinates. Would there be any way to achieve this or similar? I've tried putting a Cargo query (list display format, semicolon delimiter) as a parameter to  but it just shows a blank blue screen. Manually pasting the same Cargo output into  works fine so it may not be a Cargo problem. Thank you. Jonathan3 (talk) 23:41, 20 November 2016 (UTC)


 * Just to be sure, do you know about the "googlemaps" input type in Page Forms? Yaron Koren (talk) 23:47, 20 November 2016 (UTC)


 * To be honest I had been using an old Cargo version, and the "googlemaps" options didn't work because the Google key variable wasn't being used. I have tried it out now, and it works well. I have two questions though. (1) It would be good if the "Enter address here/Look up coordinates" box saved the address as well as the coordinates. Is this possible? Otherwise the user has to enter the address twice (in my case anyway - for an "Address" field and the "Coordinates" field. (2) On the "googlemaps" input type, if I click a new location it updates the coordinates, but if I move an existing red pointer it doesn't update the coordinates. Is this something that can be changed? I would like both actions to update the coordinates. I'm using MW 1.27.1, Cargo 1.2, and Page Forms 4.0.2. Thank you very much again. Jonathan3 (talk) 22:59, 21 November 2016 (UTC)


 * No on the first one, unfortunately - people have been asking about that for a long time, but there's no easy way to do it. The second one sounds like a bug that may be fixable. Yaron Koren (talk) 03:18, 22 November 2016 (UTC)


 * In relation to the first point, I was able to make the "Enter address here/Look up coordinates" auto-update each time the (separate) "Address" text input box was updated. This achieves a similar end by a different means. It only does anything when there is a text input box called "Address", so I guess if you were to go with it there would be internationalisation considerations. Anyway, here's what I came up with, for PF_TextInput.php, in public static function getHTML, just before "$text = ...":


 * This perhaps really belongs on the Extension:Page Forms talk page but it seemed better to continue the conversation here. Jonathan3 (talk) 23:13, 22 November 2016 (UTC)


 * In relation to the second point, it seems that you have a listener for clicking (and creating/moving a marker) but not for dragging. The quickest solution is to amend function googleMapsSetMarker so that draggable is set to false (which requires a click to move the marker) but I'll look into it further as soon as I get a chance. Jonathan3 (talk) 23:45, 22 November 2016 (UTC)

Error with some formats (json, csv) but not with default format: Table "..." is not included within the join conditions

 * MW 1.27.1
 * PHP 5.6.11
 * MySQL 5.6.28
 * Cargo 1.2

The same query raises an error when the json or csv formats are used but it works fine if no format is specified:

For example, the query at http://discoursedb.org/wiki/Item_query raises an error if the format is changed to csv


 * Sorry about that! I think I just fixed it. Yaron Koren (talk) 04:31, 22 November 2016 (UTC)


 * Thanks, Yaron. Yes. I think it's fixed now. --Lmorillas (talk) 19:53, 22 November 2016 (UTC)

Problem using Where in Cargo Query with Calendar format
Hi

I have a query as follows which correctly displays in the calendar format (sorry its a bit complex):

The Event table includes a list field Events.Calendar_Groups. When I introduce a 'where' clause including a 'HOLDS' operator to test for a value in the list field the calendar is empty. If I remove the calendar format parameters and display, the resulting table is correct.

I wondered if there was reason why the Where/Holds operator might be disallowed in queries with the calendar format?

Many thanks

Duncan 22nd Nov 2016


 * You may be seeing the same issue as the section directly above this one. Could you try upgrading to the very latest Cargo code, and see if the problem is still there? Yaron Koren (talk) 15:59, 22 November 2016 (UTC)


 * Thanks Yaron.


 * I gave this a try but it still didn't seem to work. However, I did apply the Calendar changes I'd done over the weekend to version 1.2 so maybe this overwrote some of your changes.  Do you think this is possible?  I don't have much time to investigate for now but if you have any thoughts it might help speed things when I do.


 * Kind regards Duncan, 22 Nov 2016


 * I'd recommend looking at the HTML source of the non-working calendar page, finding the URL that includes "Special:CargoExport", replacing the "&amp;amp;"s there with just "&", and then going to that URL, and seeing if there are any error messages. Yaron Koren (talk) 20:06, 22 November 2016 (UTC)


 * Thanks Yaron - that was certainly helpful. I have now tried a few options looking at the HTML request produced for CargoExport.  The problem seem to arise when the helper table for a List Field is added to the sql request.  For example the following request produces a pair of brackets "[]" which I take to mean that CargoExport did something with it:

https://cmswiki.farm/x/mw-1.26/index.php?title=Special:CargoExport&tables=Events%2CCodes%2CPage_properties&join+on=Events.Event_Type%3DCodes._pageName%2CEvents._pageName%3DPage_properties._pageName&fields=Events._pageName%2CEvents.Event_Start_Date_Time%2CEvents.Event_End_Date_Time%2CEvents.Event_Type%2CEvents.Calendar_Groups%2CCodes.Colour%2CCodes.Text_Colour%2CPage_properties.Title%3Dname&&order+by=%60cargo__Events%60.%60_pageName%60&limit=100&format=fullcalendar

However the following request produces an HTTP 500 Internal Server Error:

https://cmswiki.farm/x/mw-1.26/index.php?title=Special:CargoExport&tables=Events%2CEvents__Calendar_Groups%2CCodes%2CPage_properties&join+on=Events.Event_Type%3DCodes._pageName%2CEvents._pageName%3DPage_properties._pageName&fields=Events._pageName%2CEvents.Event_Start_Date_Time%2CEvents.Event_End_Date_Time%2CEvents.Event_Type%2CEvents.Calendar_Groups%2CCodes.Colour%2CCodes.Text_Colour%2CPage_properties.Title%3Dname&&order+by=%60cargo__Events%60.%60_pageName%60&limit=100&format=fullcalendar


 * The difference between them being the following table being added to the join:

Events__Calendar_Groups


 * Unfortunately I can't look into this more until tomorrow but if you've any more suggestions I'd be grateful?


 * Many thanks, Duncan, 24th Nov 2016


 * Hi again


 * I think I now understand the problem but I haven't been able to find a proper fix although I do have a hack that seems to work.


 * The problem is with the data url that is created for the calendar html to send to CargoExport to populate the calendar with data. If one is using a cargo list field in a Where clause then the data url includes the data table for the list field in its Tables parameter and references this in the Where clause.  For example if an Events table contains  a list field Calendar_Groups the data url is as follows (I put in some line feeds to make it clearer):

https://cmswiki.farm/x/mw-1.26/index.php?title=Special:CargoExport &tables=Events%2CEvents__Calendar_Groups%2CCodes%2CPage_properties &join+on=Events.Event_Type%3DCodes._pageName%2CEvents._pageName%3DPage_properties._pageName &fields=Events._pageName%2CEvents.Event_Start_Date_Time%2CEvents.Event_End_Date_Time%2CEvents.Event_Type %2CEvents.Calendar_Groups%2CCodes.Colour%2CCodes.Text_Colour%2CPage_properties.Title%3Dname &where=`cargo__Events__Calendar_Groups`.`_value`%3D%27Admin%3AGP0000003%27 &order+by=`cargo__Events`.`_pageName` &limit=100 &format=fullcalendar &&color+field[0]=Codes.Colour &text+color+field[0]=Codes.Text_Colour &text+color[0]= &start=2016-10-30 &end=2016-12-11 &_=1480097788550


 * However CargoExport seems to want the data url as it is in the Cargo Query without expanding the list field in the Table and Where clauses as follows:

https://cmswiki.farm/x/mw-1.26/index.php?title=Special:CargoExport &tables=Events%2CCodes%2CPage_properties &join+on=Events.Event_Type%3DCodes._pageName%2CEvents._pageName%3DPage_properties._pageName &fields=Events._pageName%2CEvents.Event_Start_Date_Time%2CEvents.Event_End_Date_Time%2CEvents.Event_Type %2CEvents.Calendar_Groups%2CCodes.Colour%2CCodes.Text_Colour%2CPage_properties.Title%3Dname &where=Events.Calendar_Groups+HOLDS+%27Admin%3AGP0000003%27 &order+by=`cargo__Events`.`_pageName` &limit=100 &format=fullcalendar &&color+field[0]=Codes.Colour &text+color+field[0]=Codes.Text_Colour &text+color[0]= &start=2016-10-30 &end=2016-12-11 &_=1480098232918


 * The Cargo Query that is used to generate these data urls is as follows:


 * It appears that this creation of the parameters used by the data url is happening in the newFromValues function in CargoSQLQuery when it calls the handleVirtualFields function. However it seems to do this more than once and the modified parameters appear after the first call but I haven't been able to work out why.


 * I have created a hack which is very ugly. In the sqlQueriesToQueryParams function of CargoDeferredFormat, I test $sqlQuery->mWhereStr to see if it is different to $sqlQuery->mOrigWhereStr  If it is I set $queryParams['where'] to $sqlQuery->mOrigWhereStr and $queryParams['tables'] to $sqlQuery->mTablesStr as these two variables contain what was in the original CargoQuery in my wiki page.  If I do this then the Calendar format appears to work correctly.


 * I am very nervous of this hack as I don't know if it will upset anything else, so if you've any thoughts where I might put a proper fix that would be fantastic.


 * Many thanks, Duncan, 25th November 2016

How to use a constant (not a field value) in the field list of a query?
Older cargo versions supported queries like:

But now it raises an error

--Lmorillas (talk) 10:49, 23 November 2016 (UTC)

CargoUtils.php on line 47
Hello Yaron,

I'm trying to update my mediawiki/cargo site from (cargo 0.10) to (cargo 1.2) on mediawiki (1.24.1). In my query pages or executing the cargoRecreateData.php I've got the following error message : Parse error: syntax error, unexpected '[' in /var/www/html/wiki/extensions/Cargo-1.2/CargoUtils.php on line 47 Any Idea ? Thanks for answer --Guillaume Prêcheur (talk) 09:18, 25 November 2016 (UTC)
 * Ah - at some point a few months ago, that line was changed to use the relatively new syntax for arrays, "[]", which doesn't work for PHP versions before 5.4. I think that was a mistake; I just changed the syntax back, so the latest code should work for you. Yaron Koren (talk) 16:10, 25 November 2016 (UTC)

Using the result of a #cargo_query in an #expr
I'm trying to do different things depending on how many results there are to a query: if there are just a few, display them all; if there are many, show only the results of a more restrictive query, and provide a link to a drilldown that shows the larger result set. I've run into a problem feeding the result from a #cargo_query into an expression. (I have the ParserFunctions and Variables extensions installed). Here's an example:

There are results.

This produces the following output:

There are 100 results. Expression error: Unrecognized punctuation character "".

(The question mark there seems to be some special character. It's not actually visible in the error message, but it shows up when pasted here. It shows as an upside-down question mark in a text editor. I don't know where it's coming from. The correct 100 value shown at the beginning of the output seems to consist of just those three characters -- nothing weird in there.)

If I replace the #cargo_query call with a simple number, the #ifexpr call works as expected, so it seems to be an issue with the #cargo_query result. I have tried specifying format=list, which I imagine gives the simplest output, but it makes no difference. I have also tried putting the #cargo_query call directly inside an #expr call (avoiding the use of Variables and #ifexpr), but this also still results in the same error.

I have also tried passing the output of #cargo_query to #number_format (from the NumberFormat extension). This gives the error:

First argument to "number_format" must be a number.

So the issue seems to be that what #cargo_query returns looks like a number, but is not treated as such by other functions. I'd be grateful for any hints you can give for how to avoid this error. This is with Cargo 1.2 and ParserFunctions 1.6.0 on MediaWiki 1.27.0 on PHP 5.6.24. Many thanks. Paul T (talk) 18:05, 25 November 2016 (UTC)


 * Adding the "no html" parameter to the #cargo_query call might help. Yaron Koren (talk) 19:47, 25 November 2016 (UTC)


 * Thank you! That works. Apologies for overlooking that option. Paul T (talk) 19:58, 25 November 2016 (UTC)


 * Great! Yaron Koren (talk) 02:57, 26 November 2016 (UTC)

Cargo Calendar Format - two features and a problem possibly solved
Hi Yaron

I've been playing with the cargo calendar format some more and have added a couple of features which I wondered if you might incorporate?

The first enables one to set the aspect ratio of the calendar so effectively setting its height relative to its width. This uses fullCalendar's aspect ratio parameter. The second allows one to identify a field to be displayed in a pop up box when the mouse is over an event. This is done by aliasing the field with "=description" in a similar way that '=name' is used to identify an alternative field to use as an event's title in the calendar.

This is achieved by changes to ext.cargo.alendar.js as follows:

/* global moment */

$(document).ready(function {

// page is now ready, initialize the calendar... $('.cargoCalendar').each( function {		var dataURL = decodeURI( $(this).attr('dataurl') );		var startView = $(this).attr('startview');		var startDate = moment( $(this).attr('startdate') );		var aspectRatio = $(this).attr('aspectratio');		$(this).fullCalendar({ // put your options and callbacks here events: dataURL, header: { left: 'today prev,next', center: 'title', right: 'month,basicWeek,basicDay' },			aspectRatio: aspectRatio, defaultView: startView, defaultDate: startDate, // add event name to title attribute on mouseover eventMouseover: function(event, jsEvent, view) { if (view.name !== 'agendaDay') { $(jsEvent.target).attr('title', event.description); }			},		});	});

});

Changes to the displayCalendarData function in CargoExport as follows:

/**	 * Used for calendar format */	function displayCalendarData( $sqlQueries ) { $req = $this->getRequest; $colorArray = $req->getArray( 'color' ); $textColorArray = $req->getArray( 'text_color' ); $colorFieldArray = $req->getArray( 'color_field' ); $textColorFieldArray = $req->getArray( 'text_color_field' );

$datesLowerLimit = $req->getVal( 'start' ); $datesUpperLimit = $req->getVal( 'end' );

$displayedArray = array; foreach ( $sqlQueries as $i => $sqlQuery ) { foreach( $sqlQuery->mFieldStringAliases as $fieldName => $fieldAlias ) { if ( $fieldName == $colorFieldArray[0] ) { $colorFieldName = $fieldAlias ; }				if ( $fieldName == $textColorFieldArray[0] ) { $textColorFieldName = $fieldAlias ; }			}

$dateFieldRealNames = array; $dateFieldAliases = array; foreach( $sqlQuery->mFieldDescriptions as $alias => $description ) { if ( $description->mType == 'Date' || $description->mType == 'Datetime' ) { $dateFieldAliases[] = $alias; $realFieldName = $sqlQuery->mAliasedFieldNames[$alias]; $dateFieldRealNames[] = $realFieldName; }			}			$where = $sqlQuery->mWhereStr; if ( $where != '' ) { $where .= " AND "; }			$where .= "(";			foreach ( $dateFieldRealNames as $j => $dateField ) {				if ( $j > 0 ) {					$where .= " OR ";				}				$where .= "($dateField >= '$datesLowerLimit' AND $dateField <= '$datesUpperLimit')";			}			$where .= ")"; $sqlQuery->mWhereStr = $where;

$queryResults = $sqlQuery->run; foreach ( $queryResults as $queryResult ) { if ( array_key_exists( 'name', $queryResult ) ) { $eventTitle = $queryResult['name']; } else { $eventTitle = reset( $queryResult ); }				if ( array_key_exists( 'description', $queryResult ) ) { $eventDescription = $queryResult['description']; } else { $eventDescription = null; }				$title = Title::newFromText( $queryResult['_pageName'] ); $startDateField = $dateFieldAliases[0]; $startDate = $queryResult[$startDateField]; $startDatePrecisionField = $startDateField. '__precision'; $startDatePrecision = $queryResult[$startDatePrecisionField]; if ( array_key_exists( $colorFieldName, $queryResult ) ) { $eventColor = $queryResult[$colorFieldName]; } else { $eventColor = $colorArray[$i]; }				if ( array_key_exists( $textColorFieldName, $queryResult ) ) { $eventTextColor = $queryResult[$textColorFieldName]; } else { $eventTextColor = $textColorArray[$i]; }

$curEvent = array(					// Get first field for the title - not					// necessarily the page name.					'title' => $eventTitle,					'url' => $title->getLocalURL,					'start' => $queryResult[$dateFieldAliases[0]],					'end' => $queryResult[$dateFieldAliases[1]],					'color' => $eventColor,					'textColor' => $eventTextColor,					'description' => $eventDescription 				); if ( $startDatePrecision != CargoStore::DATE_AND_TIME ) { $curEvent['allDay'] = true; }				$displayedArray[] = $curEvent; }		}		print json_encode( $displayedArray ); }

And changes to the queryAndDisplay function of CargoCalendarFormats as follows:

/**	 *	 * @param array $sqlQueries * @param array $displayParams * @param array $querySpecificParams * @return string */	function queryAndDisplay( $sqlQueries, $displayParams, $querySpecificParams = null ) { $this->mOutput->addModules( 'ext.cargo.calendar' ); $ce = SpecialPage::getTitleFor( 'CargoExport' ); $queryParams = $this->sqlQueriesToQueryParams( $sqlQueries ); $queryParams['format'] = 'fullcalendar'; $queryParams['color'] = array; foreach ( $sqlQueries as $i => $sqlQuery ) { if ( $querySpecificParams != null ) { if ( array_key_exists( 'color', $querySpecificParams[$i] ) ) { $queryParams['color'][] = $querySpecificParams[$i]['color']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['color'][] = ''; }			}			if ( $displayParams != null ) { if ( array_key_exists( 'color field', $displayParams ) ) { $queryParams['color field'][] = $displayParams['color field']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['color field'][] = ''; }			}			if ( $displayParams != null ) { if ( array_key_exists( 'text color field', $displayParams ) ) { $queryParams['text color field'][] = $displayParams['text color field']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['text color field'][] = ''; }			}			if ( $displayParams != null ) { if ( array_key_exists( 'text color', $displayParams ) ) { $queryParams['text color'][] = $displayParams['text color']; } else { // Stick an empty value in there, to					// preserve the order for the queries // that do contain a color. $queryParams['text color'][] = ''; }			}		}		if ( array_key_exists( 'width', $displayParams ) ) { $width = $displayParams['width']; // Add on "px", if no unit is defined. if ( is_numeric( $width ) ) { $width .= "px"; }		} else { $width = "100%"; }		if ( array_key_exists( 'aspect ratio', $displayParams ) ) { $aspectRatio = $displayParams['aspect ratio']; // check tha aspect ratio is numeric and set default if not. if ( !is_numeric( $aspectRatio ) ) { $aspectRatio = 1.35; }		} else { $aspectRatio = 1.35; }

$attrs = array(			'class' => 'cargoCalendar',			'dataurl' => $ce->getFullURL( $queryParams ),			'style' => "width: $width",			'aspectratio' => $aspectRatio		);

if ( array_key_exists( 'view', $displayParams ) ) { $view = $displayParams['view']; // Enable simpler view names. if ( $view == 'day' ) { $view = 'basicDay'; } elseif ( $view == 'week' ) { $view = 'basicWeek'; }			$attrs['startview'] = $view; } else { $attrs['startview'] = 'month'; }		if ( array_key_exists( 'start date', $displayParams ) ) { $attrs['startdate'] = $displayParams['start date']; }		$text = Html::rawElement( 'div', $attrs, '' );

return $text; }

}

An example Cargo Query using these new features is:

Finally in an earlier topic [here] I though I'd hit a problem with the calendar format when it tries to display a Cargo Query which includes a 'where ... HOLDS..." condition. You may have missed the update as there have been a number of new topics since that one was started. I managed to get an error print out of this as follows:

A database query error has occurred. This may indicate a bug in the software.

Query: SELECT `cargo__Events`.`_pageName` AS `_pageName`,`cargo__Events`.`Event_Start_Date_Time` AS `Event Start Date Time`,`cargo__Events`.`Event_End_Date_Time` AS `Event End Date Time`,`cargo__Events`.`Event_Type` AS `Event Type`,`Calendar_Groups__full` AS `Calendar Groups`,`cargo__Codes`.`Colour` AS `Colour`,`cargo__Codes`.`Text_Colour` AS `Text Colour`,`cargo__Page_properties`.`Title` AS `name`,`cargo__Events`.`Event_Start_Date_Time__precision` AS `Event Start Date Time__precision`,`cargo__Events`.`Event_End_Date_Time__precision` AS `Event End Date Time__precision` FROM `cargo__Events` LEFT OUTER JOIN `cargo__Codes` ON ((`cargo__Events`.Event_Type=`cargo__Codes`._pageName)) LEFT OUTER JOIN `cargo__Page_properties` ON ((`cargo__Events`._pageName=`cargo__Page_properties`._pageName)) WHERE `cargo__Events__Calendar_Groups`.`_value`='Admin:GP0000003' AND ((`cargo__Events`.`Event_Start_Date_Time` >= '2016-10-30' AND `cargo__Events`.`Event_Start_Date_Time` <= '2016-12-11') OR (`cargo__Events`.`Event_End_Date_Time` >= '2016-10-30' AND `cargo__Events`.`Event_End_Date_Time` <= '2016-12-11')) ORDER BY `cargo__Events`.`_pageName` LIMIT 100 Function: CargoSQLQuery::run Error: 1054 Unknown column 'cargo__Events__Calendar_Groups._value' in 'where clause' (localhost)

I'd updated the previous topic with what I thought might be a fix. In the sqlQueriesToQueryParams function of CargoDeferredFormat, I test $sqlQuery->mWhereStr to see if it is different to $sqlQuery->mOrigWhereStr If it is I set $queryParams['where'] to $sqlQuery->mOrigWhereStr as this variable contains what was in the original CargoQuery in my wiki page. If I do this then the Calendar format appears to work correctly.

I am nervous of this hack as I don't know if it will upset anything else, so I wondered what you thought?.

Many thanks, Duncan 26th November 2016