Completed
Push — master ( 6dc7d8...407c40 )
by Karsten
15:45
created

formats/Exhibit/SRF_Exhibit.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Use Exhibit to print query results.
4
 *
5
 * @author Fabian Howahl
6
 * @file
7
 * @ingroup SMWQuery
8
 */
9
10
/**
11
 * Result printer using Exhibit to display query results
12
 *
13
 * @ingroup SMWQuery
14
 */
15
class SRFExhibit extends SMWResultPrinter {
16
17
	// /mapping between SMW's and Exhibit's the data types
18
	protected $m_types = [ "_wpg" => "text", "_num" => "number", "_dat" => "date", "_geo" => "text", "_uri" => "url" ];
19
20
	protected static $exhibitRunningNumber = 0; // not sufficient since there might be multiple pages rendered within one PHP run; but good enough now
21
22
	// /overwrite function to allow execution of result printer even if no results are available (in case remote query yields no results in local wiki)
23
	public function getResult( $results, $params, $outputmode ) {
24
		$this->readParameters( $params, $outputmode );
25
		$result = $this->getResultText( $results, $outputmode );
26
		return $result;
27
	}
28
29
	// /function aligns the format of SMW's property names to Exhibit's format
30
	protected function encodePropertyName( $property ) {
31
		return strtolower( str_replace( " ", "_", trim( $property ) ) );
32
	}
33
34
	// /Tries to determine the namespace in the event it got lost
35
	protected function determineNamespace( $res ) {
36
		$row = $res->getNext();
37
		if ( $row != null ) {
38
			$tmp = clone $row[0];
39
			$object = $tmp->getNextDataValue();
40
41
			if ( $object instanceof SMWWikiPageValue ) {
42
				$value = $object->getPrefixedText();
43
				if ( strpos( $value, ':' ) ) {
44
					$value = explode( ':', $value, 2 );
45
					return $value[0] . ':';
46
				}
47
			}
48
		}
49
50
		return "";
51
	}
52
53
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
54
55
		global $smwgIQRunningNumber, $wgScriptPath, $wgGoogleMapsKey, $srfgScriptPath;
56
57
		if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) {
58
			SMWOutputs::requireHeadItem( 'exhibit-compat', Html::linkedScript( "$wgScriptPath/common/wikibits.js" ) );
59
		}
60
61
		// //////////////////////////////
62
		// ///////REMOTE STUFF///////////
63
		// //////////////////////////////
64
65
		$remote = false;
66
67
		// in case the remote parameter is set, a link to the JSON export of the remote wiki is included in the header as data source for Exhibit
68
		// this section creates the link
69
		if ( array_key_exists( 'remote', $this->params ) && srfgExhibitRemote == true ) {
70
71
			$remote = true;
72
73
			// fetch interwiki link
74
			$dbr = &wfGetDB( DB_SLAVE );
75
			$cl = $dbr->tableName( 'interwiki' );
76
			$dbres = $dbr->select( $cl, 'iw_url', "iw_prefix='" . $this->params['remote'] . "'", __METHOD__, [] );
77
			$row = $dbr->fetchRow( $dbres );
78
			$extlinkpattern = $row[iw_url];
79
			$dbr->freeResult( $dbres );
80
81
			$newheader = '<link rel="exhibit/data" type="application/jsonp" href="';
82
			$link = $res->getQueryLink( 'JSON Link' );
83
			$link->setParameter( 'json', 'format' );
84
85
			if ( array_key_exists(
86
				'callback',
87
				$this->params
88
			) ) { // check if a special name for the callback function is set, if not stick with 'callback'
89
				$callbackfunc = $this->params['callback'];
90
			} else {
91
				$callbackfunc = 'callback';
92
			}
93
94
			if ( array_key_exists( 'limit', $this->params ) ) {
95
				$link->setParameter( $this->params['limit'], 'limit' );
96
			}
97
98
			$link->setParameter( $callbackfunc, 'callback' );
99
			$link = $link->getText( 2, $this->mLinker );
100
101
			list( $link, $trash ) = explode( '|', $link );
102
			$link = str_replace( '[[:', '', $link );
103
104
			$newheader .= str_replace( '$1', $link, $extlinkpattern );
105
			$newheader .= '" ex:jsonp-callback="' . $callbackfunc . '"';
106
			$newheader .= '/>';
107
108
			SMWOutputs::requireHeadItem( 'REMOTE', $newheader );
109
		}
110
111
		// the following variables indicate the use of special views
112
		// the variable's values define the way Exhibit is called
113
		$timeline = false;
114
		$map = false;
115
116
		/*The javascript file adopted from Wibbit uses a bunch of javascript variables in the header to store information about the Exhibit markup.
117
		 The following code sequence creates these variables*/
118
119
		// prepare sources (the sources holds information about the table which contains the information)
120
		$colstack = [];
121
		foreach ( $res->getPrintRequests() as $pr ) {
122
			$colstack[] = $this->encodePropertyName( $pr->getLabel() ) . ':' . ( array_key_exists(
123
					$pr->getTypeID(),
124
					$this->m_types
125
				) ? $this->m_types[$pr->getTypeID()] : 'text' );
126
		}
127
		array_shift( $colstack );
128
		array_unshift( $colstack, 'label' );
129
130
		if ( SRFExhibit::$exhibitRunningNumber == 0 ) {
131
			$sourcesrc = "var ex_sources = { source" . ( $smwgIQRunningNumber - 1 ) . ": { id:  'querytable" . $smwgIQRunningNumber . "' , columns: '" . implode(
132
					',',
133
					$colstack
134
				) . "'.split(','), hideTable: '1', type: 'Item', label: 'Item', pluralLabel: 'Items' } };";
135
		} else {
136
			$sourcesrc = "sources.source" . $smwgIQRunningNumber . " =  { id:  'querytable" . $smwgIQRunningNumber . "' , columns: '" . implode(
137
					',',
138
					$colstack
139
				) . "'.split(','), hideTable: '1', type: 'Item', label: 'Item', pluralLabel: 'Items' };";
140
		}
141
		$sourcesrc = "<script type=\"text/javascript\">" . $sourcesrc . "</script>";
142
143
		// prepare facets
144
		$facetcounter = 0;
145
		if ( array_key_exists( 'facets', $this->params ) ) {
146
			$facets = explode( ',', $this->params['facets'] );
147
			$facetstack = [];
148
			$params = [ 'height' ];
149
			$facparams = [];
150
			foreach ( $params as $param ) {
151
				if ( array_key_exists( $param, $this->params ) ) {
152
					$facparams[] = 'ex:' . $param . '="' . $this->encodePropertyName( $this->params[$param] ) . '" ';
153
				}
154
			}
155
			foreach ( $facets as $facet ) {
156
				$facet = trim( $facet );
157
				if ( strtolower( $facet ) == "search" ) { // special facet (text search)
158
					$facetstack[] = ' facet' . $facetcounter++ . ': { position : "right", innerHTML: \'ex:role="facet" ex:showMissing="false" ex:facetClass="TextSearch" ex:facetLabel="' . $facet . '"\'}';
159
				} else { // usual facet
160
					foreach ( $res->getPrintRequests() as $pr ) {
161
						if ( $this->encodePropertyName( $pr->getLabel() ) == $this->encodePropertyName( $facet ) ) {
162
							switch ( $pr->getTypeID() ) {
163
								case '_num':
164
									$facetstack[] = ' facet' . $facetcounter++ . ': { position : "right", innerHTML: \'ex:role="facet" ex:showMissing="false" ex:expression=".' . $this->encodePropertyName(
165
											$facet
166
										) . '" ex:facetLabel="' . $facet . '" ex:facetClass="Slider"\'}';
167
									break;
168
								default:
169
									$facetstack[] = ' facet' . $facetcounter++ . ': { position : "right", innerHTML: \'ex:role="facet" ex:showMissing="false" ' . implode(
170
											" ",
171
											$facparams
172
										) . ' ex:expression=".' . $this->encodePropertyName(
173
											$facet
174
										) . '" ex:facetLabel="' . $facet . '"\'}';
175
							}
176
						}
177
178
					}
179
				}
180
			}
181
			$facetstring = implode( ',', $facetstack );
182
		} else {
183
			$facetstring = '';
184
		}
185
		$facetsrc = "var ex_facets = {" . $facetstring . " };";
186
187
		// prepare views
188
		$stylesrc = '';
189
		if ( array_key_exists( 'views', $this->params ) ) {
190
			$views = explode( ',', $this->params['views'] );
191
		} else {
192
			$views[] = 'tiles';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$views was never initialized. Although not strictly required by PHP, it is generally a good practice to add $views = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
193
		}
194
195
		foreach ( $views as $view ) {
196
			switch ( trim( $view ) ) {
197
				case 'tabular':// table view (the columns are automatically defined by the selected properties)
198
					$thstack = [];
199
					foreach ( $res->getPrintRequests() as $pr ) {
200
						$thstack[] = "." . $this->encodePropertyName( $pr->getLabel() );
201
					}
202
					array_shift( $thstack );
203
					array_unshift( $thstack, '.label' );
204
					$stylesrc = 'var myStyler = function(table, database) {table.className=\'smwtable\';};'; // assign SMWtable CSS to Exhibit tabular view
205
					$viewstack[] = 'ex:role=\'view\' ex:viewClass=\'Tabular\' ex:showSummary=\'false\' ex:sortAscending=\'true\' ex:tableStyler=\'myStyler\'  ex:label=\'Table\' ex:columns=\'' . implode(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$viewstack was never initialized. Although not strictly required by PHP, it is generally a good practice to add $viewstack = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
206
							',',
207
							$thstack
208
						) . '\' ex:sortAscending=\'false\'';
209
					break;
210
				case 'timeline':// timeline view
211
					$timeline = true;
212
					$exparams = [
213
						'start',
214
						'end',
215
						'proxy',
216
						'colorkey' ]; // parameters expecting an Exhibit graph expression
217
					$usparams = [
218
						'timelineheight',
219
						'topbandheight',
220
						'bottombandheight',
221
						'bottombandunit',
222
						'topbandunit' ]; // parametes expecting a textual or numeric value
223
					$tlparams = [];
224
					foreach ( $exparams as $param ) {
225
						if ( array_key_exists( $param, $this->params ) ) {
226
							$tlparams[] = 'ex:' . $param . '=\'.' . $this->encodePropertyName(
227
									$this->params[$param]
228
								) . '\' ';
229
						}
230
					}
231
					foreach ( $usparams as $param ) {
232
						if ( array_key_exists( $param, $this->params ) ) {
233
							$tlparams[] = 'ex:' . $param . '=\'' . $this->encodePropertyName(
234
									$this->params[$param]
235
								) . '\' ';
236
						}
237
					}
238
					if ( !array_key_exists(
239
						'start',
240
						$this->params
241
					) ) {// find out if a start and/or end date is specified
242
						$dates = [];
243
						foreach ( $res->getPrintRequests() as $pr ) {
244
							if ( $pr->getTypeID() == '_dat' ) {
245
								$dates[] = $pr;
246
								if ( sizeof( $dates ) > 2 ) {
247
									break;
248
								}
249
							}
250
						}
251
						if ( sizeof( $dates ) == 1 ) {
252
							$tlparams[] = 'ex:start=\'.' . $this->encodePropertyName( $dates[0]->getLabel() ) . '\' ';
253
						} elseif ( sizeof( $dates ) == 2 ) {
254
							$tlparams[] = 'ex:start=\'.' . $this->encodePropertyName( $dates[0]->getLabel() ) . '\' ';
255
							$tlparams[] = 'ex:end=\'.' . $this->encodePropertyName( $dates[1]->getLabel() ) . '\' ';
256
						}
257
					}
258
					$viewstack[] = 'ex:role=\'view\' ex:viewClass=\'Timeline\' ex:label=\'Timeline\' ex:showSummary=\'false\' ' . implode(
259
							" ",
260
							$tlparams
261
						);
262
					break;
263
				case 'map':// map view
264
					if ( isset( $wgGoogleMapsKey ) ) {
265
						$map = true;
266
						$exparams = [ 'latlng', 'colorkey' ];
267
						$usparams = [
268
							'type',
269
							'center',
270
							'zoom',
271
							'size',
272
							'scalecontrol',
273
							'overviewcontrol',
274
							'mapheight' ];
275
						$mapparams = [];
276
						foreach ( $exparams as $param ) {
277
							if ( array_key_exists( $param, $this->params ) ) {
278
								$mapparams[] = 'ex:' . $param . '=\'.' . $this->encodePropertyName(
279
										$this->params[$param]
280
									) . '\' ';
281
							}
282
						}
283
						foreach ( $usparams as $param ) {
284
							if ( array_key_exists( $param, $this->params ) ) {
285
								$mapparams[] = 'ex:' . $param . '=\'' . $this->encodePropertyName(
286
										$this->params[$param]
287
									) . '\' ';
288
							}
289
						}
290
						if ( !array_key_exists( 'start', $this->params ) && !array_key_exists(
291
								'end',
292
								$this->params
293
							) ) { // find out if a geographic coordinate is available
294
							foreach ( $res->getPrintRequests() as $pr ) {
295
								if ( $pr->getTypeID() == '_geo' ) {
296
									$mapparams[] = 'ex:latlng=\'.' . $this->encodePropertyName(
297
											$pr->getLabel()
298
										) . '\' ';
299
									break;
300
								}
301
							}
302
						}
303
						$viewstack[] .= 'ex:role=\'view\' ex:viewClass=\'Map\' ex:showSummary=\'false\' ex:label=\'Map\' ' . implode(
304
								" ",
305
								$mapparams
306
							);
307
					}
308
					break;
309
				default:
310
				case 'tiles':// tile view
311
					$sortstring = '';
312
					if ( array_key_exists( 'sort', $this->params ) ) {
313
						$sortfields = explode( ",", $this->params['sort'] );
314
						foreach ( $sortfields as $field ) {
315
							$sortkeys[] = "." . $this->encodePropertyName( trim( $field ) );
316
						}
317
						$sortstring = 'ex:orders=\'' . implode( ",", $sortkeys ) . '\' ';
318
						if ( array_key_exists( 'order', $this->params ) ) {
319
							$sortstring .= ' ex:directions=\'' . $this->encodePropertyName(
320
									$this->params['order']
321
								) . '\'';
322
						}
323
						if ( array_key_exists( 'grouped', $this->params ) ) {
324
							$sortstring .= ' ex:grouped=\'' . $this->encodePropertyName(
325
									$this->params['grouped']
326
								) . '\'';
327
						}
328
					}
329
					$viewstack[] = 'ex:role=\'view\' ex:showSummary=\'false\' ' . $sortstring;
330
					break;
331
			}
332
		}
333
334
		$viewsrc = 'var ex_views = "' . implode( "/", $viewstack ) . '".split(\'/\');;';
335
336
		// prepare automatic lenses
337
338
		global $wgParser;
339
		$lenscounter = 0;
340
		$linkcounter = 0;
341
		$imagecounter = 0;
342
343
		if ( array_key_exists(
344
			'lens',
345
			$this->params
346
		) ) {// a customized lens is specified via the lens parameter within the query
347
			$lenstitle = Title::newFromText( "Template:" . $this->params['lens'] );
348
			$lensarticle = new Article( $lenstitle );
349
			$lenswikitext = $lensarticle->getContent();
350
351
			if ( preg_match_all(
352
				"/[\[][\[][Ii][m][a][g][e][:][{][{][{][1-9A-z\-[:space:]]*[}][}][}][\]][\]]/u",
353
				$lenswikitext,
354
				$matches
355
			) ) {
356
				foreach ( $matches as $match ) {
357
					foreach ( $match as $value ) {
358
						$strippedvalue = trim( substr( $value, 8 ), "[[{}]]" );
359
						$lenswikitext = str_replace(
360
							$value,
361
							'<div class="inlines" id="imagecontent' . $imagecounter . '">' . $this->encodePropertyName(
362
								strtolower( str_replace( "\n", "", $strippedvalue ) )
363
							) . '</div>',
364
							$lenswikitext
365
						);
366
						$imagecounter++;
367
					}
368
				}
369
			}
370
371
			if ( preg_match_all(
372
				"/[\[][\[][{][{][{][1-9A-z\-[:space:]]*[}][}][}][\]][\]]/u",
373
				$lenswikitext,
374
				$matches
375
			) ) {
376
				foreach ( $matches as $match ) {
377
					foreach ( $match as $value ) {
378
						$strippedvalue = trim( $value, "[[{}]]" );
379
						$lenswikitext = str_replace(
380
							$value,
381
							'<div class="inlines" id="linkcontent' . $linkcounter . '">' . $this->encodePropertyName(
382
								strtolower( str_replace( "\n", "", $strippedvalue ) )
383
							) . '</div>',
384
							$lenswikitext
385
						);
386
						$linkcounter++;
387
					}
388
				}
389
			}
390
391
			if ( preg_match_all( "/[{][{][{][1-9A-z\:\|\/\=\-[:space:]]*[}][}][}]/u", $lenswikitext, $matches ) ) {
392
				foreach ( $matches as $match ) {
393
					foreach ( $match as $value ) {
394
						$strippedvalue = trim( $value, "{}" );
395
						$lenswikitext = str_replace(
396
							$value,
397
							'<div class="inlines" id="lenscontent' . $lenscounter . '">' . $this->encodePropertyName(
398
								strtolower( str_replace( "\n", "", $strippedvalue ) )
399
							) . '</div>',
400
							$lenswikitext
401
						);
402
						$lenscounter++;
403
					}
404
				}
405
			}
406
407
			$lenshtml = $wgParser->internalParse(
408
				$lenswikitext
409
			);// $wgParser->parse($lenswikitext, $lenstitle, new ParserOptions(), true, true)->getText();
410
411
			$lenssrc = "var ex_lens = '" . str_replace(
412
					"\n",
413
					"",
414
					$lenshtml
415
				) . "';ex_lenscounter =" . $lenscounter . ";ex_linkcounter=" . $linkcounter . ";ex_imagecounter=" . $imagecounter . ";";
416
		} else {// generic lens (creates links to further content (property-pages, pages about values)
417
			foreach ( $res->getPrintRequests() as $pr ) {
418
				if ( $remote ) {
419
					$wikiurl = str_replace( "$1", "", $extlinkpattern );
420
				} else {
421
					$wikiurl = $wgScriptPath . "/index.php?title=";
422
				}
423
				if ( $pr->getTypeID() == '_wpg' ) {
424
					$prefix = '';
425
					if ( $pr->getLabel() == 'Category' ) {
426
						$prefix = "Category:";
427
					}
428
					$lensstack[] = '<tr ex:if-exists=".' . $this->encodePropertyName(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$lensstack was never initialized. Although not strictly required by PHP, it is generally a good practice to add $lensstack = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
429
							$pr->getLabel()
430
						) . '"><td width="20%">' . $pr->getText(
431
							0,
432
							$this->mLinker
433
						) . '</td><td width="80%" ex:content=".' . $this->encodePropertyName(
434
							$pr->getLabel()
435
						) . '"><a ex:href-subcontent="' . $wikiurl . $prefix . '{{urlencval(value)}}"><div ex:content="value" class="name"></div></a></td></tr>';
436
				} else {
437
					$lensstack[] = '<tr ex:if-exists=".' . $this->encodePropertyName(
438
							$pr->getLabel()
439
						) . '"><td width="20%">' . $pr->getText(
440
							0,
441
							$this->mLinker
442
						) . '</td><td width="80%"><div ex:content=".' . $this->encodePropertyName(
443
							$pr->getLabel()
444
						) . '" class="name"></div></td></tr>';
445
				}
446
			}
447
			array_shift( $lensstack );
448
			$lenssrc = 'var ex_lens = \'<table width=100% cellpadding=3><tr><th class="head" align=left bgcolor="#DDDDDD"><a ex:href-subcontent="' . $wikiurl . $this->determineNamespace(
449
					clone $res
450
				) . '{{urlenc(.label)}}" class="linkhead"><div ex:content=".label" class="name"></div></a></th></tr></table><table width="100%" cellpadding=3>' . implode(
451
					"",
452
					$lensstack
453
				) . '</table>\'; ex_lenscounter = 0; ex_linkcounter=0; ex_imagecounter=0;';
454
		}
455
456
		if ( $remote ) {
457
			$varremote = 'true';
458
		} else {
459
			$varremote = 'false';
460
		}
461
462
		// Handling special formats like date
463
		$formatssrc = 'var formats =\'\'';
464
		if ( array_key_exists( 'date', $this->params ) ) {
465
			$formatssrc = 'var formats = \'ex:formats="date { mode:' . $this->params['date'] . '; show:date }"\';';
466
		}
467
468
		// create a URL pointing to the corresponding JSON feed
469
		$label = '';
470
		$JSONlink = $res->getQueryLink( $label );
471
		if ( $this->getSearchLabel( SMW_OUTPUT_WIKI ) != '' ) { // used as a file name
472
			$link->setParameter( $this->getSearchLabel( SMW_OUTPUT_WIKI ), 'searchlabel' );
473
		}
474
		if ( array_key_exists( 'limit', $this->params ) ) {
475
			$JSONlink->setParameter( htmlspecialchars( $this->params['limit'] ), 'limit' );
476
		}
477
		$JSONlink->setParameter( 'json', 'format' );
478
		$stringtoedit = explode( "|", $JSONlink->getText( $outputmode, $this->mLinker ) );
479
		$stringtoedit = substr( $stringtoedit[0], 3 );
480
		$JSONlinksrc = "var JSONlink = '" . $stringtoedit . "';";
481
482
		// create script header with variables containing the Exhibit markup
483
		$headervars = "<script type='text/javascript'>\n\t\t\t" . $facetsrc . "\n\t\t\t" . $viewsrc . "\n\t\t\t" . $lenssrc . "\n\t\t\t" . $stylesrc . "\n\t\t\t" . $formatssrc . "\n\t\t\t" . $JSONlinksrc . "\n\t\t\t var remote=" . $varremote . ";</script>";
484
485
		// To run Exhibit some links to the scripts of the API need to be included in the header
486
487
		$ExhibitScriptSrc1 = '<script type="text/javascript" src="' . $srfgScriptPath . '/Exhibit/exhibit/exhibit-api.js?autoCreate=false&safe=true&bundle=false';
488
		if ( $timeline ) {
489
			$ExhibitScriptSrc1 .= '&views=timeline';
490
		}
491
		if ( $map ) {
492
			$ExhibitScriptSrc1 .= '&gmapkey=' . $wgGoogleMapsKey;
493
		}
494
		$ExhibitScriptSrc1 .= '"></script>';
495
		$ExhibitScriptSrc2 = '<script type="text/javascript" src="' . $srfgScriptPath . '/Exhibit/SRF_Exhibit.js"></script>';
496
		$CSSSrc = '<link rel="stylesheet" type="text/css" href="' . $srfgScriptPath . '/Exhibit/SRF_Exhibit.css"></link>';
497
498
		SMWOutputs::requireHeadItem( 'CSS', $CSSSrc ); // include CSS
499
		SMWOutputs::requireHeadItem( 'EXHIBIT1', $ExhibitScriptSrc1 ); // include Exhibit API
500
		SMWOutputs::requireHeadItem(
501
			'EXHIBIT2',
502
			$ExhibitScriptSrc2
503
		); // includes javascript overwriting the Exhibit start-up functions
504
		SMWOutputs::requireHeadItem( 'SOURCES' . $smwgIQRunningNumber, $sourcesrc );// include sources variable
505
		SMWOutputs::requireHeadItem( 'VIEWSFACETS', $headervars );// include views and facets variable
506
507
		if ( !$remote ) {
508
509
			// print input table
510
			// print header
511
			$result = "<table style=\"display:none\" class=\"smwtable\" id=\"querytable" . $smwgIQRunningNumber . "\">\n";
512
			if ( $this->mShowHeaders ) { // building headers
513
				$result .= "\t<tr>\n";
514
				foreach ( $res->getPrintRequests() as $pr ) {
515
					if ( $pr->getText( $outputmode, $this->getLinker( 0 ) ) == '' ) {
516
						$headerlabel = "Name";
517
					} else {
518
						$headerlabel = $pr->getText( $outputmode, $this->getLinker( 0 ) );
519
					}
520
					$result .= "\t\t<th>" . $headerlabel . "</th>\n";
521
				}
522
				$result .= "\t</tr>\n";
523
			}
524
525
			// print all result rows
526
			while ( $row = $res->getNext() ) {
527
				$result .= "\t<tr>\n";
528
				foreach ( $row as $field ) {
529
					$result .= "\t\t<td>";
530
					$textstack = [];
531
					while ( ( $object = $field->getNextDataValue() ) !== false ) {
532
						switch ( $object->getTypeID() ) {
533
							case '_wpg':
534
								$textstack[] = $object->getLongText( $outputmode, $this->getLinker( 0 ) );
535
								break;
536
							case '_geo':
537
								$c = $object->getDBKeys();
538
								$textstack[] = $c[0] . "," . $c[1];
539
								break;
540
							case '_num':
541
								if ( method_exists( $object, 'getValueKey' ) ) {
542
									$textstack[] = $object->getValueKey( $outputmode, $this->getLinker( 0 ) );
543
								} else {
544
									$textstack[] = $object->getNumericValue( $outputmode, $this->getLinker( 0 ) );
545
								}
546
								break;
547
							case '_dat':
548
								$textstack[] = $object->getYear() . "-" . str_pad(
549
										$object->getMonth(),
550
										2,
551
										'0',
552
										STR_PAD_LEFT
553
									) . "-" . str_pad(
554
										$object->getDay(),
555
										2,
556
										'0',
557
										STR_PAD_LEFT
558
									) . " " . $object->getTimeString();
559
								break;
560
							case '_ema':
561
								$textstack[] = $object->getShortWikiText( $this->getLinker( 0 ) );
562
								break;
563
							case '_tel':
564
							case '_anu':
565
							case '_uri':
566
								$textstack[] = $object->getWikiValue();
567
								break;
568
							case '__sin':
569
								$tmp = $object->getShortText( $outputmode, null );
570
								if ( strpos( $tmp, ":" ) ) {
571
									$tmp = explode( ":", $tmp, 2 );
572
									$tmp = $tmp[1];
573
								}
574
								$textstack[] = $tmp;
575
								break;
576
							case '_txt':
577
							case '_cod':
578
							case '_str':
579
								$textstack[] = $object->getWikiValue();
580
								break;
581
							default:
582
								$textstack[] = $object->getLongHTMLText( $this->getLinker( 0 ) );
583
						}
584
					}
585
586
					if ( $textstack != null ) {
587
						$result .= implode( ';', $textstack ) . "</td>\n";
588
					} else {
589
						$result .= "</td>\n";
590
					}
591
				}
592
				$result .= "\t</tr>\n";
593
			}
594
			$result .= "</table>\n";
595
		}
596
597
		if ( SRFExhibit::$exhibitRunningNumber == 0 ) {
598
			$result .= "<div id=\"exhibitLocation\"></div>";
599
		} // print placeholder (just print it one time)
600
		$this->isHTML = ( $outputmode == SMW_OUTPUT_HTML ); // yes, our code can be viewed as HTML if requested, no more parsing needed
601
		SRFExhibit::$exhibitRunningNumber++;
602
		return $result;
603
	}
604
605
	/**
606
	 * @see SMWResultPrinter::getParamDefinitions
607
	 *
608
	 * @since 1.8
609
	 *
610
	 * @param $definitions array of IParamDefinition
611
	 *
612
	 * @return array of IParamDefinition|array
613
	 */
614
	public function getParamDefinitions( array $definitions ) {
615
		$params = parent::getParamDefinitions( $definitions );
616
617
		$params[] = [
618
			'name' => 'views',
619
			'message' => 'srf_paramdesc_views',
620
			'islist' => true,
621
			'values' => [ 'tiles', 'tabular', 'timeline', 'maps' ] ];
622
		$params[] = [ 'name' => 'facets', 'message' => 'srf_paramdesc_facets' ];
623
		$params[] = [ 'name' => 'lens', 'message' => 'srf_paramdesc_lens' ];
624
625
		return $params;
626
	}
627
628
}
629