r90263 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r90262‎ | r90263 | r90264 >
Date:11:09, 17 June 2011
Author:devayon
Status:deferred (Comments)
Tags:
Comment:
Code cleanup for Query Creator
Modified paths:
  • /trunk/extensions/SemanticMediaWiki/specials/AskSpecial/SMW_SpecialQueryCreator.php (modified) (history)

Diff [purge]

Index: trunk/extensions/SemanticMediaWiki/specials/AskSpecial/SMW_SpecialQueryCreator.php
@@ -22,10 +22,10 @@
2323 */
2424 class SMWQueryCreatorPage extends SpecialPage {
2525
26 - protected $m_querystring = '';
 26+ //protected $m_querystring = '';
2727 protected $m_params = array();
28 - protected $m_printouts = array();
29 - protected $m_editquery = false;
 28+ //protected $m_printouts = array();
 29+ //protected $m_editquery = false;
3030
3131 /**
3232 * Constructor.
@@ -44,301 +44,163 @@
4545 global $wgOut, $wgRequest, $smwgQEnabled;
4646
4747 $this->setHeaders();
48 - wfProfileIn( 'doSpecialAsk (SMW)' );
4948
5049 if ( !$smwgQEnabled ) {
5150 $wgOut->addHTML( '<br />' . wfMsg( 'smw_iq_disabled' ) );
5251 } else {
53 - if ( $wgRequest->getCheck( 'showformatoptions' ) ) {
54 - // handle Ajax action
55 - $format = $wgRequest->getVal( 'showformatoptions' );
56 - $params = $wgRequest->getArray( 'params' );
57 - $wgOut->disable();
58 - echo $this->showFormatOptions( $format, $params );
59 - } else {
60 - $this->extractQueryParameters( $p );
61 - $this->makeHTMLResult();
62 - }
 52+ $this->makeHTMLForm();
6353 }
64 -
6554 SMWOutputs::commitToOutputPage( $wgOut ); // make sure locally collected output data is pushed to the output!
66 - wfProfileOut( 'doSpecialAsk (SMW)' );
6755 }
68 -
6956 /**
70 - * Extracts Query and option parameters, especially q (the query),
71 - * offset and limit (number of results per-page), p (the result format and options), po (printouts) and
72 - * eq(show/hide the query editor).
73 - *
74 - * This code rather hacky since there are many ways to call that special page, the most involved of
75 - * which is the way that this page calls itself when data is submitted via the form (since the shape
76 - * of the parameters then is governed by the UI structure, as opposed to being governed by reason).
77 - *
78 - * @param string $p
 57+ * Adds the input query form
7958 */
80 - protected function extractQueryParameters( $p ) {
81 - global $wgRequest, $smwgQMaxInlineLimit;
82 -
83 - // First make all inputs into a simple parameter list that can again be parsed into components later.
84 - if ( $wgRequest->getCheck( 'q' ) ) { // called by own Special, ignore full param string in that case
85 - $query_val = $wgRequest->getVal( 'p' );
86 -
87 - if ( !empty( $query_val ) )
88 - // p is used for any additional parameters in certain links.
89 - $rawparams = SMWInfolink::decodeParameters( $query_val, false );
90 - else {
91 - $query_values = $wgRequest->getArray( 'p' );
92 -
93 - if ( is_array( $query_values ) ) {
94 - foreach ( $query_values as $key => $val ) {
95 - if ( empty( $val ) ) unset( $query_values[$key] );
96 - }
97 - }
98 -
99 - // p is used for any additional parameters in certain links.
100 - $rawparams = SMWInfolink::decodeParameters( $query_values, false );
101 - }
102 - } else { // called from wiki, get all parameters
103 - $rawparams = SMWInfolink::decodeParameters( $p, true );
 59+ protected function makeHTMLForm(){
 60+ global $wgOut, $smwgQSortingSupport, $smwgResultFormats, $smwgAutocompleteInSpecialAsk;
 61+ $result= "";
 62+ $spectitle = $this->getTitleFor( 'Ask' );
 63+ $result .= '<form name="ask" action="' . $spectitle->escapeLocalURL() . '" method="get">' . "\n" .
 64+ '<input type="hidden" name="title" value="' . $spectitle->getPrefixedText() . '"/>';
 65+
 66+ $result .= wfMsg('smw_qc_query_help');
 67+ // Main query and printouts.
 68+ $result .= '<p><strong>' . wfMsg( 'smw_ask_queryhead' ) . "</strong></p>\n";
 69+ $result .= '<p><textarea name="q" rows="6"></textarea></p>';
 70+ //show|hide additional options and querying help
 71+ $result .= '<span id="show_additional_options" style="display:inline"><a href="#addtional" rel="nofollow" onclick="' .
 72+ "document.getElementById('additional_options').style.display='block';" .
 73+ "document.getElementById('show_additional_options').style.display='none';" .
 74+ "document.getElementById('hide_additional_options').style.display='inline';" . '">' .
 75+ wfMsg( 'smw_show_addnal_opts' ) . '</a></span>';
 76+ $result .= '<span id="hide_additional_options" style="display:none"><a href="#" rel="nofollow" onclick="' .
 77+ "document.getElementById('additional_options').style.display='none';" .
 78+ "document.getElementById('hide_additional_options').style.display='none';" .
 79+ "document.getElementById('show_additional_options').style.display='inline';" . '">' .
 80+ wfMsg( 'smw_hide_addnal_opts' ) . '</a></span>';
 81+ $result .=' | <a href="' . htmlspecialchars( wfMsg( 'smw_ask_doculink' ) ) . '">' . wfMsg( 'smw_ask_help' ) . '</a>';
 82+ //additional options
 83+ $result .= '<div id="additional_options" style="display:none">';
 84+ $result .= '<p><strong>' . wfMsg( 'smw_ask_printhead' ) . "</strong></p>\n" .
 85+ '<span style="font-weight: normal;">' . wfMsg( 'smw_ask_printdesc' ) . '</span>' . "\n" .
 86+ '<p><textarea id = "add_property" name="po" cols="20" rows="6"></textarea></p>' . "\n";
 87+
 88+ // sorting inputs
 89+ if ( $smwgQSortingSupport ) {
 90+ $result .= $this->addSortingOptions($result);
10491 }
10592
106 - // Check for q= query string, used whenever this special page calls itself (via submit or plain link):
107 - $this->m_querystring = $wgRequest->getText( 'q' );
108 - if ( $this->m_querystring != '' ) {
109 - $rawparams[] = $this->m_querystring;
110 - }
 93+ $printer = SMWQueryProcessor::getResultPrinter( 'broadtable', SMWQueryProcessor::SPECIAL_PAGE );
 94+ $url = SpecialPage::getSafeTitleFor( 'Ask' )->getLocalURL( "showformatoptions=' + this.value + '" );
 95+ //@TODO //$url .= '&showformatoptions=broadtable&params[title]=Special:Ask&params[offset]=0&params[limit]=20';
 96+ $url .= '&params[title]=Special:Ask&params[offset]=0&params[limit]=20';
11197
112 - // Check for param strings in po (printouts), appears in some links and in submits:
113 - $paramstring = $wgRequest->getText( 'po' );
 98+ $result .= "<br /><br />\n<p>" . wfMsg( 'smw_ask_format_as' ) . ' <input type="hidden" name="eq" value="yes"/>' . "\n" .
 99+ '<select id="formatSelector" name="p[format]" onChange="JavaScript:updateOtherOptions(\'' . $url . '\')">' . "\n" .
 100+ ' <option value="broadtable"' . ( $this->m_params['format'] == 'broadtable' ? ' selected' : '' ) . '>' .
 101+ $printer->getName() . ' (' . wfMsg( 'smw_ask_defaultformat' ) . ')</option>' . "\n";
114102
115 - if ( $paramstring != '' ) { // parameters from HTML inputs
116 - $ps = explode( "\n", $paramstring ); // params separated by newlines here (compatible with text-input for printouts)
 103+ $formats = array();
117104
118 - foreach ( $ps as $param ) { // add initial ? if omitted (all params considered as printouts)
119 - $param = trim( $param );
120 -
121 - if ( ( $param != '' ) && ( $param { 0 } != '?' ) ) {
122 - $param = '?' . $param;
123 - }
124 -
125 - $rawparams[] = $param;
 105+ foreach ( array_keys( $smwgResultFormats ) as $format ) {
 106+ // Special formats "count" and "debug" currently not supported.
 107+ if ( $format != 'broadtable' && $format != 'count' && $format != 'debug' ) {
 108+ $printer = SMWQueryProcessor::getResultPrinter( $format, SMWQueryProcessor::SPECIAL_PAGE );
 109+ $formats[$format] = $printer->getName();
126110 }
127111 }
128112
129 - // Now parse parameters and rebuilt the param strings for URLs.
130 - SMWQueryProcessor::processFunctionParams( $rawparams, $this->m_querystring, $this->m_params, $this->m_printouts );
 113+ natcasesort( $formats );
131114
132 - // Try to complete undefined parameter values from dedicated URL params.
133 - if ( !array_key_exists( 'format', $this->m_params ) ) {
134 - $this->m_params['format'] = 'broadtable';
 115+ foreach ( $formats as $format => $name ) {
 116+ $result .= ' <option value="' . $format . '"' . ( $this->m_params['format'] == $format ? ' selected' : '' ) . '>' . $name . "</option>\n";
135117 }
 118+ //add javascript for updating formating options by ajax
 119+ $default_format_url = SpecialPage::getSafeTitleFor( 'Ask' )->getLocalURL( "showformatoptions=broadtable" );
 120+ $default_format_url .= '&params[title]=Special:Ask&params[offset]=0&params[limit]=20';
 121+ $javascript = <<<END
 122+<script type="text/javascript">
 123+function updateOtherOptions(strURL) {
 124+ jQuery.ajax({ url: strURL, context: document.body, success: function(data){
 125+ jQuery("#other_options").html(data);
 126+ }});
 127+}
 128+jQuery(document).ready(updateOtherOptions("{$default_format_url}"));
 129+</script>
 130+END;
136131
137 - if ( !array_key_exists( 'order', $this->m_params ) ) {
138 - $order_values = $wgRequest->getArray( 'order' );
 132+ $wgOut->addScript( $javascript );
139133
140 - if ( is_array( $order_values ) ) {
141 - $this->m_params['order'] = '';
 134+ $result .= "</select></p>\n";
 135+ $result .= '<fieldset><legend>' . wfMsg( 'smw_ask_otheroptions' ) . "</legend>\n";
 136+ $result .= "<div id=\"other_options\"></div>";
 137+ $result .= "</fieldset>\n";
 138+ $urltail = str_replace( '&eq=yes', '', $urltail ) . '&eq=no';
 139+ $result .= '</div>';
 140+ $result .= '<br /><input type="submit" value="' . wfMsg( 'smw_ask_submit' ) . '"/>' .
 141+ '<input type="hidden" name="eq" value="no"/>' .
 142+ "\n</form>";
142143
143 - foreach ( $order_values as $order_value ) {
144 - if ( $order_value == '' ) $order_value = 'ASC';
145 - $this->m_params['order'] .= ( $this->m_params['order'] != '' ? ',' : '' ) . $order_value;
146 - }
147 - }
148 - }
 144+ $wgOut->addHTML($result);
149145
150 - $this->m_num_sort_values = 0;
151 -
152 - if ( !array_key_exists( 'sort', $this->m_params ) ) {
153 - $sort_values = $wgRequest->getArray( 'sort' );
154 - if ( is_array( $sort_values ) ) {
155 - $this->m_params['sort'] = implode( ',', $sort_values );
156 - $this->m_num_sort_values = count( $sort_values );
157 - }
158 - }
159 -
160 - // Find implicit ordering for RSS -- needed for downwards compatibility with SMW <=1.1
161 - /*
162 - if ( ($this->m_params['format'] == 'rss') && ($this->m_params['sort'] == '') && ($sortcount==0)) {
163 - foreach ($this->m_printouts as $printout) {
164 - if ((strtolower($printout->getLabel()) == "date") && ($printout->getTypeID() == "_dat")) {
165 - $this->m_params['sort'] = $printout->getTitle()->getText();
166 - $this->m_params['order'] = 'DESC';
167 - }
168 - }
169 - }
170 - */
171 -
172 - if ( !array_key_exists( 'offset', $this->m_params ) ) {
173 - $this->m_params['offset'] = $wgRequest->getVal( 'offset' );
174 - if ( $this->m_params['offset'] == '' ) $this->m_params['offset'] = 0;
175 - }
176 -
177 - if ( !array_key_exists( 'limit', $this->m_params ) ) {
178 - $this->m_params['limit'] = $wgRequest->getVal( 'limit' );
179 -
180 - if ( $this->m_params['limit'] == '' ) {
181 - $this->m_params['limit'] = ( $this->m_params['format'] == 'rss' ) ? 10 : 20; // Standard limit for RSS.
182 - }
183 - }
184 -
185 - $this->m_params['limit'] = min( $this->m_params['limit'], $smwgQMaxInlineLimit );
186 -
187 - $this->m_editquery = ( $wgRequest->getVal( 'eq' ) == 'no' ) || ( $this->m_querystring == '' );
188146 }
189147
190148 /**
191 - * Creates and adds the JavaScript and JS needed for autocompletion to $wgOut.
 149+ * Javascript and HTML code to enable sorting over columns.
192150 *
193 - * @bug This method asks the store for all used and unused property names, which can be very expensive. It does not even use a limit to restrict the number of results. Cheaper ways to get the labels need to be sought. What sense does it make to add unused properties to the options on autocomplete for a query interface?
194 - * @since 1.5.2
 151+ * @return string
195152 */
196 - protected static function addAutocompletionJavascriptAndCSS() {
197 - global $wgOut, $smwgScriptPath, $smwgJQueryIncluded, $smwgJQueryUIIncluded;
198153
199 - // Add CSS and JavaScript for jQuery and jQuery UI.
200 - $wgOut->addExtensionStyle( "$smwgScriptPath/skins/jquery-ui/base/jquery.ui.all.css" );
 154+ protected function addSortingOptions(){
 155+ global $wgRequest, $wgOut, $smwgJQueryIncluded;
201156
202 - $scripts = array();
203157
204 - if ( !$smwgJQueryIncluded ) {
205 - $realFunction = array( 'OutputPage', 'includeJQuery' );
206 - if ( is_callable( $realFunction ) ) {
207 - $wgOut->includeJQuery();
208 - } else {
209 - $scripts[] = "$smwgScriptPath/libs/jquery-1.4.2.min.js";
210 - }
211 -
212 - $smwgJQueryIncluded = true;
 158+ $result='';
 159+ if ( ! array_key_exists( 'sort', $this->m_params ) || ! array_key_exists( 'order', $this->m_params ) ) {
 160+ $orders = array(); // do not even show one sort input here
 161+ } else {
 162+ $sorts = explode( ',', $this->m_params['sort'] );
 163+ $orders = explode( ',', $this->m_params['order'] );
 164+ reset( $sorts );
213165 }
214166
215 - if ( !$smwgJQueryUIIncluded ) {
216 - $scripts[] = "$smwgScriptPath/libs/jquery-ui/jquery.ui.core.min.js";
217 - $scripts[] = "$smwgScriptPath/libs/jquery-ui/jquery.ui.widget.min.js";
218 - $scripts[] = "$smwgScriptPath/libs/jquery-ui/jquery.ui.position.min.js";
219 - $scripts[] = "$smwgScriptPath/libs/jquery-ui/jquery.ui.autocomplete.min.js";
220 - $smwgJQueryUIIncluded = true;
221 - }
 167+ foreach ( $orders as $i => $order ) {
 168+ $result .= "<div id=\"sort_div_$i\">" . wfMsg( 'smw_ask_sortby' ) . ' <input type="text" name="sort[' . $i . ']" value="' .
 169+ htmlspecialchars( $sorts[$i] ) . "\" size=\"35\"/>\n" . '<select name="order[' . $i . ']"><option ';
 170+ if ( $order == 'ASC' ) $result .= 'selected="selected" ';
 171+ $result .= 'value="ASC">' . wfMsg( 'smw_ask_ascorder' ) . '</option><option ';
 172+ if ( $order == 'DESC' ) $result .= 'selected="selected" ';
222173
223 - foreach ( $scripts as $js ) {
224 - $wgOut->addScriptFile( $js );
 174+ $result .= 'value="DESC">' . wfMsg( 'smw_ask_descorder' ) . "</option></select>\n";
 175+ $result .= '[<a href="javascript:removeInstance(\'sort_div_' . $i . '\')">' . wfMsg( 'delete' ) . '</a>]' . "\n";
 176+ $result .= "</div>\n";
225177 }
226178
227 - /* collect property names for autocomplete */
228 - $propertyNames[] = array();
229 - $results = smwfGetStore()->getPropertiesSpecial();
 179+ $result .= '<div id="sorting_starter" style="display: none">' . wfMsg( 'smw_ask_sortby' ) . ' <input type="text" name="sort_num" size="35" />' . "\n";
 180+ $result .= ' <select name="order_num">' . "\n";
 181+ $result .= ' <option value="ASC">' . wfMsg( 'smw_ask_ascorder' ) . "</option>\n";
 182+ $result .= ' <option value="DESC">' . wfMsg( 'smw_ask_descorder' ) . "</option>\n</select>\n";
 183+ $result .= "</div>\n";
 184+ $result .= '<div id="sorting_main"></div>' . "\n";
 185+ $result .= '<a href="javascript:addInstance(\'sorting_starter\', \'sorting_main\')">' . wfMsg( 'smw_add_sortcondition' ) . '</a>' . "\n";
 186+
 187+
230188
231 - foreach ( $results as $result ) {
232 - $propertyNames[] = $result[0]->getLabel();
233 - }
234189
235 - $results = smwfGetStore()->getUnusedPropertiesSpecial();
 190+ $this->m_num_sort_values = 0;
236191
237 - foreach ( $results as $result ) {
238 - $propertyNames[] = $result->getLabel();
239 - }
240 -
241 - sort( $propertyNames );
242 -
243 - $properties_po = "[";
244 - foreach ( $propertyNames as $i => $property ) {
245 - if ( $i > 0 ) {
246 - $properties_po .= ", ";
 192+ if ( !array_key_exists( 'sort', $this->m_params ) ) {
 193+ $sort_values = $wgRequest->getArray( 'sort' );
 194+ if ( is_array( $sort_values ) ) {
 195+ $this->m_params['sort'] = implode( ',', $sort_values );
 196+ $this->m_num_sort_values = count( $sort_values );
247197 }
248 - $properties_po .= "'?" . $property . "'";
249198 }
250 - $properties_po .= "]";
251 -
252 - $javascript_autocomplete_text = <<<END
253 -<script type="text/javascript">
254 -function split(val) {
255 - return val.split('\\n');
256 -}
257 -function extractLast(term) {
258 - return split(term).pop();
259 -}
260 -function escapeQuestion(term){
261 - if (term.substring(0, 1) == "?") {
262 - return term.substring(1);
263 - } else {
264 - return term;
265 - }
266 -}
267 -
268 -jQuery.noConflict();
269 -/* extending jQuery functions for custom highligting */
270 -jQuery.ui.autocomplete.prototype._renderItem = function( ul, item) {
271 - var term_without_q = escapeQuestion(extractLast(this.term));
272 - var re = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term_without_q.replace("/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi", "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi");
273 - var loc = item.label.search(re);
274 - if (loc >= 0) {
275 - var t = item.label.substr(0, loc) + '<strong>' + item.label.substr(loc, term_without_q.length) + '</strong>' + item.label.substr(loc + term_without_q.length);
276 - } else {
277 - var t = item.label;
278 - }
279 - jQuery( "<li></li>" )
280 - .data( "item.autocomplete", item )
281 - .append( " <a>" + t + "</a>" )
282 - .appendTo( ul );
283 -};
284 -
285 -///* extending jquery functions for custom autocomplete matching */
286 -jQuery.extend( jQuery.ui.autocomplete, {
287 - filter: function(array, term) {
288 - var matcher = new RegExp("\\\b" + jQuery.ui.autocomplete.escapeRegex(term), "i" );
289 - return jQuery.grep( array, function(value) {
290 - return matcher.test( value.label || value.value || value );
291 - });
292 - }
293 -});
294 -
295 -jQuery(document).ready(function(){
296 - jQuery("#add_property").autocomplete({
297 - minLength: 1,
298 - source: function(request, response) {
299 - // delegate back to autocomplete, but extract the last term
300 - response(jQuery.ui.autocomplete.filter({$properties_po}, escapeQuestion(extractLast(request.term))));
301 - },
302 - focus: function() {
303 - // prevent value inserted on focus
304 - return false;
305 - },
306 - select: function(event, ui) {
307 - var terms = split( this.value );
308 - // remove the current input
309 - terms.pop();
310 - // add the selected item
311 - terms.push( ui.item.value );
312 - // add placeholder to get the comma-and-space at the end
313 - terms.push("");
314 - this.value = terms.join("\\n");
315 - return false;
316 - }
317 - });
318 -});
319 -</script>
320 -
321 -END;
322 -
323 - $wgOut->addScript( $javascript_autocomplete_text );
324 - }
325 -
326 - /**
327 - * TODO: document
328 - */
329 - protected function makeHTMLResult() {
330 - global $wgOut, $smwgAutocompleteInSpecialAsk;
331 -
 199+ // Javascript code for handling adding and removing the "sort" inputs
332200 $delete_msg = wfMsg( 'delete' );
333201
334 - // Javascript code for the dynamic parts of the page
 202+
335203 $javascript_text = <<<END
336204 <script type="text/javascript">
337 -function updateOtherOptions(strURL) {
338 - jQuery.ajax({ url: strURL, context: document.body, success: function(data){
339 - jQuery("#other_options").html(data);
340 - }});
341 -}
342 -
343205 // code for handling adding and removing the "sort" inputs
344206 var num_elements = {$this->m_num_sort_values};
345207
@@ -381,490 +243,63 @@
382244
383245 $wgOut->addScript( $javascript_text );
384246
385 - if ( $smwgAutocompleteInSpecialAsk ) {
386 - self::addAutocompletionJavascriptAndCSS();
387 - }
388 -
389 - $result = '';
390 - $result_mime = false; // output in MW Special page as usual
391 -
392 - // build parameter strings for URLs, based on current settings
393 - $urltail = '&q=' . urlencode( $this->m_querystring );
394 -
395 - $tmp_parray = array();
396 - foreach ( $this->m_params as $key => $value ) {
397 - if ( !in_array( $key, array( 'sort', 'order', 'limit', 'offset', 'title' ) ) ) {
398 - $tmp_parray[$key] = $value;
399 - }
400 - }
401 -
402 - $urltail .= '&p=' . urlencode( SMWInfolink::encodeParameters( $tmp_parray ) );
403 - $printoutstring = '';
404 -
405 - foreach ( $this->m_printouts as $printout ) {
406 - $printoutstring .= $printout->getSerialisation() . "\n";
407 - }
408 -
409 - if ( $printoutstring != '' ) $urltail .= '&po=' . urlencode( $printoutstring );
410 - if ( array_key_exists( 'sort', $this->m_params ) ) $urltail .= '&sort=' . $this->m_params['sort'];
411 - if ( array_key_exists( 'order', $this->m_params ) ) $urltail .= '&order=' . $this->m_params['order'];
412 -
413 - if ( $this->m_querystring != '' ) {
414 - $queryobj = SMWQueryProcessor::createQuery( $this->m_querystring, $this->m_params, SMWQueryProcessor::SPECIAL_PAGE , $this->m_params['format'], $this->m_printouts );
415 - $res = smwfGetStore()->getQueryResult( $queryobj );
416 -
417 - // Try to be smart for rss/ical if no description/title is given and we have a concept query:
418 - if ( $this->m_params['format'] == 'rss' ) {
419 - $desckey = 'rssdescription';
420 - $titlekey = 'rsstitle';
421 - } elseif ( $this->m_params['format'] == 'icalendar' ) {
422 - $desckey = 'icalendardescription';
423 - $titlekey = 'icalendartitle';
424 - } else { $desckey = false; }
425 -
426 - if ( ( $desckey ) && ( $queryobj->getDescription() instanceof SMWConceptDescription ) &&
427 - ( !isset( $this->m_params[$desckey] ) || !isset( $this->m_params[$titlekey] ) ) ) {
428 - $concept = $queryobj->getDescription()->getConcept();
429 -
430 - if ( !isset( $this->m_params[$titlekey] ) ) {
431 - $this->m_params[$titlekey] = $concept->getText();
432 - }
433 -
434 - if ( !isset( $this->m_params[$desckey] ) ) {
435 - $dv = end( smwfGetStore()->getPropertyValues( SMWWikiPageValue::makePageFromTitle( $concept ), new SMWDIProperty( '_CONC' ) ) );
436 - if ( $dv instanceof SMWConceptValue ) {
437 - $this->m_params[$desckey] = $dv->getDocu();
438 - }
439 - }
440 - }
441 -
442 - $printer = SMWQueryProcessor::getResultPrinter( $this->m_params['format'], SMWQueryProcessor::SPECIAL_PAGE );
443 - $result_mime = $printer->getMimeType( $res );
444 -
445 - global $wgRequest;
446 -
447 - $hidequery = $wgRequest->getVal( 'eq' ) == 'no';
448 -
449 - // if it's an export format (like CSV, JSON, etc.),
450 - // don't actually export the data if 'eq' is set to
451 - // either 'yes' or 'no' in the query string - just
452 - // show the link instead
453 - if ( $this->m_editquery || $hidequery ) $result_mime = false;
454 -
455 - if ( $result_mime == false ) {
456 - if ( $res->getCount() > 0 ) {
457 - if ( $this->m_editquery ) $urltail .= '&eq=yes';
458 - if ( $hidequery ) $urltail .= '&eq=no';
459 -
460 - $navigation = $this->getNavigationBar( $res, $urltail );
461 - $result .= '<div style="text-align: center;">' . "\n" . $navigation . "\n</div>\n";
462 - $query_result = $printer->getResult( $res, $this->m_params, SMW_OUTPUT_HTML );
463 -
464 - if ( is_array( $query_result ) ) {
465 - $result .= $query_result[0];
466 - } else {
467 - $result .= $query_result;
468 - }
469 -
470 - $result .= '<div style="text-align: center;">' . "\n" . $navigation . "\n</div>\n";
471 - } else {
472 - $result = '<div style="text-align: center;">' . wfMsg( 'smw_result_noresults' ) . '</div>';
473 - }
474 - } else { // make a stand-alone file
475 - $result = $printer->getResult( $res, $this->m_params, SMW_OUTPUT_FILE );
476 - $result_name = $printer->getFileName( $res ); // only fetch that after initialising the parameters
477 - }
478 - }
479 -
480 - if ( $result_mime == false ) {
481 - if ( $this->m_querystring ) {
482 - $wgOut->setHTMLtitle( $this->m_querystring );
 247+ if ( !$smwgJQueryIncluded ) {
 248+ $realFunction = array( 'OutputPage', 'includeJQuery' );
 249+ if ( is_callable( $realFunction ) ) {
 250+ $wgOut->includeJQuery();
483251 } else {
484 - $wgOut->setHTMLtitle( wfMsg( 'ask' ) );
 252+ $scripts[] = "$smwgScriptPath/libs/jquery-1.4.2.min.js";
485253 }
486254
487 - $result = $this->getInputForm( $printoutstring, 'offset=' . $this->m_params['offset'] . '&limit=' . $this->m_params['limit'] . $urltail ) . $result;
488 - $wgOut->addHTML( $result );
489 - } else {
490 - $wgOut->disable();
491 -
492 - header( "Content-type: $result_mime; charset=UTF-8" );
493 -
494 - if ( $result_name !== false ) {
495 - header( "content-disposition: attachment; filename=$result_name" );
496 - }
497 -
498 - echo $result;
 255+ $smwgJQueryIncluded = true;
499256 }
500 - }
501257
502 - /**
503 - * Generates the search box UI
504 - *
505 - * @param string $printoutstring
506 - * @param string $urltail
507 - *
508 - * @return string
509 - */
510 - protected function getInputForm( $urltail ) {
511 - global $smwgQSortingSupport, $smwgResultFormats;
512 -
513 - $result = '';
514 -
515 - if ( $this->m_editquery ) {
516 - $spectitle = $this->getTitleFor( 'Ask' );
517 - $result .= '<form name="ask" action="' . $spectitle->escapeLocalURL() . '" method="get">' . "\n" .
518 - '<input type="hidden" name="title" value="' . $spectitle->getPrefixedText() . '"/>';
519 -
520 - $result .= wfMsg('smw_qc_query_help');
521 -
522 - // Main query and printouts.
523 - $result .= '<p><strong>' . wfMsg( 'smw_ask_queryhead' ) . "</strong></p>\n";
524 - $result .= '<p><textarea name="q" rows="6">' . htmlspecialchars( $this->m_querystring ) . '</textarea></p>';
525 - //show|hide additional options and querying help
526 - $result .= '<span id="show_additional_options" style="display:inline"><a href="#addtional" rel="nofollow" onclick="' .
527 - "document.getElementById('additional_options').style.display='block';" .
528 - "document.getElementById('show_additional_options').style.display='none';" .
529 - "document.getElementById('hide_additional_options').style.display='inline';" . '">' .
530 - wfMsg( 'smw_show_addnal_opts' ) . '</a></span>';
531 - $result .= '<span id="hide_additional_options" style="display:none"><a href="#" rel="nofollow" onclick="' .
532 - "document.getElementById('additional_options').style.display='none';" .
533 - "document.getElementById('hide_additional_options').style.display='none';" .
534 - "document.getElementById('show_additional_options').style.display='inline';" . '">' .
535 - wfMsg( 'smw_hide_addnal_opts' ) . '</a></span>';
536 - $result .=' | <a href="' . htmlspecialchars( wfMsg( 'smw_ask_doculink' ) ) . '">' . wfMsg( 'smw_ask_help' ) . '</a>';
537 - //additional options
538 - $result .= '<div id="additional_options" style="display:none">';
539 - $result .= '<p><strong>' . wfMsg( 'smw_ask_printhead' ) . "</strong></p>\n" .
540 - '<span style="font-weight: normal;">' . wfMsg( 'smw_ask_printdesc' ) . '</span>' . "\n" .
541 - '<p><textarea id = "add_property" name="po" cols="20" rows="6"></textarea></p>' . "\n";
542 -// @TODO
543 - // sorting inputs
544 - if ( $smwgQSortingSupport ) {
545 - if ( ! array_key_exists( 'sort', $this->m_params ) || ! array_key_exists( 'order', $this->m_params ) ) {
546 - $orders = array(); // do not even show one sort input here
547 - } else {
548 - $sorts = explode( ',', $this->m_params['sort'] );
549 - $orders = explode( ',', $this->m_params['order'] );
550 - reset( $sorts );
551 - }
552 -
553 - foreach ( $orders as $i => $order ) {
554 - $result .= "<div id=\"sort_div_$i\">" . wfMsg( 'smw_ask_sortby' ) . ' <input type="text" name="sort[' . $i . ']" value="' .
555 - htmlspecialchars( $sorts[$i] ) . "\" size=\"35\"/>\n" . '<select name="order[' . $i . ']"><option ';
556 -
557 - if ( $order == 'ASC' ) $result .= 'selected="selected" ';
558 - $result .= 'value="ASC">' . wfMsg( 'smw_ask_ascorder' ) . '</option><option ';
559 - if ( $order == 'DESC' ) $result .= 'selected="selected" ';
560 -
561 - $result .= 'value="DESC">' . wfMsg( 'smw_ask_descorder' ) . "</option></select>\n";
562 - $result .= '[<a href="javascript:removeInstance(\'sort_div_' . $i . '\')">' . wfMsg( 'delete' ) . '</a>]' . "\n";
563 - $result .= "</div>\n";
564 - }
565 -
566 - $result .= '<div id="sorting_starter" style="display: none">' . wfMsg( 'smw_ask_sortby' ) . ' <input type="text" name="sort_num" size="35" />' . "\n";
567 - $result .= ' <select name="order_num">' . "\n";
568 - $result .= ' <option value="ASC">' . wfMsg( 'smw_ask_ascorder' ) . "</option>\n";
569 - $result .= ' <option value="DESC">' . wfMsg( 'smw_ask_descorder' ) . "</option>\n</select>\n";
570 - $result .= "</div>\n";
571 - $result .= '<div id="sorting_main"></div>' . "\n";
572 - $result .= '<a href="javascript:addInstance(\'sorting_starter\', \'sorting_main\')">' . wfMsg( 'smw_add_sortcondition' ) . '</a>' . "\n";
573 - }
574 -
575 - $printer = SMWQueryProcessor::getResultPrinter( 'broadtable', SMWQueryProcessor::SPECIAL_PAGE );
576 - $url = SpecialPage::getSafeTitleFor( 'Ask' )->getLocalURL( "showformatoptions=' + this.value + '" );
577 -
578 - foreach ( $this->m_params as $param => $value ) {
579 - if ( $param !== 'format' ) {
580 - $url .= '&params[' . Xml::escapeJsString( $param ) . ']=' . Xml::escapeJsString( $value );
581 - }
582 - }
583 -
584 - $result .= "<br /><br />\n<p>" . wfMsg( 'smw_ask_format_as' ) . ' <input type="hidden" name="eq" value="yes"/>' . "\n" .
585 - '<select id="formatSelector" name="p[format]" onChange="JavaScript:updateOtherOptions(\'' . $url . '\')">' . "\n" .
586 - ' <option value="broadtable"' . ( $this->m_params['format'] == 'broadtable' ? ' selected' : '' ) . '>' .
587 - $printer->getName() . ' (' . wfMsg( 'smw_ask_defaultformat' ) . ')</option>' . "\n";
588 -
589 - $formats = array();
590 -
591 - foreach ( array_keys( $smwgResultFormats ) as $format ) {
592 - // Special formats "count" and "debug" currently not supported.
593 - if ( $format != 'broadtable' && $format != 'count' && $format != 'debug' ) {
594 - $printer = SMWQueryProcessor::getResultPrinter( $format, SMWQueryProcessor::SPECIAL_PAGE );
595 - $formats[$format] = $printer->getName();
596 - }
597 - }
598 -
599 - natcasesort( $formats );
600 -
601 - foreach ( $formats as $format => $name ) {
602 - $result .= ' <option value="' . $format . '"' . ( $this->m_params['format'] == $format ? ' selected' : '' ) . '>' . $name . "</option>\n";
603 - }
604 -
605 - $result .= "</select></p>\n";
606 - $result .= '<fieldset><legend>' . wfMsg( 'smw_ask_otheroptions' ) . "</legend>\n";
607 - $result .= "<div id=\"other_options\">" . $this->showFormatOptions( $this->m_params['format'], $this->m_params ) . "</div>";
608 - $result .= "</fieldset>\n";
609 - $urltail = str_replace( '&eq=yes', '', $urltail ) . '&eq=no';
610 - $result .= '</div>';
611 -
612 - $result .= '<br /><input type="submit" value="' . wfMsg( 'smw_ask_submit' ) . '"/>' .
613 - '<input type="hidden" name="eq" value="no"/>' .
614 - "\n</form>";
615 - } else { // if $this->m_editquery == false
616 - $urltail = str_replace( '&eq=no', '', $urltail ) . '&eq=yes';
617 - $result .= '<p>' .
618 - Html::element(
619 - 'a',
620 - array(
621 - 'href' => SpecialPage::getSafeTitleFor( 'Ask' )->getLocalURL( $urltail ),
622 - 'rel' => 'nofollow'
623 - ),
624 - wfMsg( 'smw_ask_editquery' )
625 - ) .
626 - '| ' . SMWAskPage::getEmbedToggle() .
627 - '</p>';
628 - }
629 -
630 - return $result;
 258+ return $result;
631259 }
632260
633 - /**
634 - * TODO: document
635 - *
636 - * @return string
637 - */
638 - protected static function getEmbedToggle() {
639 - return '<span id="embed_show"><a href="#" rel="nofollow" onclick="' .
640 - "document.getElementById('inlinequeryembed').style.display='block';" .
641 - "document.getElementById('embed_hide').style.display='inline';" .
642 - "document.getElementById('embed_show').style.display='none';" .
643 - "document.getElementById('inlinequeryembedarea').select();" .
644 - '">' . wfMsg( 'smw_ask_show_embed' ) . '</a></span>' .
645 - '<span id="embed_hide" style="display: none"><a href="#" rel="nofollow" onclick="' .
646 - "document.getElementById('inlinequeryembed').style.display='none';" .
647 - "document.getElementById('embed_show').style.display='inline';" .
648 - "document.getElementById('embed_hide').style.display='none';" .
649 - '">' . wfMsg( 'smw_ask_hide_embed' ) . '</a></span>';
650 - }
651261
652262 /**
653 - * Build the navigation for some given query result, reuse url-tail parameters.
654 - *
655 - * @param SMWQueryResult $res
656 - * @param string $urltail
657 - *
658 - * @return string
659 - */
660 - protected function getNavigationBar( SMWQueryResult $res, $urltail ) {
661 - global $smwgQMaxInlineLimit;
662 -
663 - $offset = $this->m_params['offset'];
664 - $limit = $this->m_params['limit'];
665 -
666 - // Prepare navigation bar.
667 - if ( $offset > 0 ) {
668 - $navigation = Html::element(
669 - 'a',
670 - array(
671 - 'href' => SpecialPage::getSafeTitleFor( 'Ask' )->getLocalURL(
672 - 'offset=' . max( 0, $offset - $limit ) .
673 - '&limit=' . $limit . $urltail
674 - ),
675 - 'rel' => 'nofollow'
676 - ),
677 - wfMsg( 'smw_result_prev' )
678 - );
679 -
680 - } else {
681 - $navigation = wfMsg( 'smw_result_prev' );
682 - }
683 -
684 - $navigation .=
685 - '&#160;&#160;&#160;&#160; <b>' .
686 - wfMsg( 'smw_result_results' ) . ' ' . ( $offset + 1 ) .
687 - '&#150; ' .
688 - ( $offset + $res->getCount() ) .
689 - '</b>&#160;&#160;&#160;&#160;';
690 -
691 - if ( $res->hasFurtherResults() ) {
692 - $navigation .= Html::element(
693 - 'a',
694 - array(
695 - 'href' => SpecialPage::getSafeTitleFor( 'Ask' )->getLocalURL(
696 - 'offset=' . ( $offset + $limit ) .
697 - '&limit=' . $limit . $urltail
698 - ),
699 - 'rel' => 'nofollow'
700 - ),
701 - wfMsg( 'smw_result_next' )
702 - );
703 - } else {
704 - $navigation .= wfMsg( 'smw_result_next' );
705 - }
706 -
707 - $first = true;
708 -
709 - foreach ( array( 20, 50, 100, 250, 500 ) as $l ) {
710 - if ( $l > $smwgQMaxInlineLimit ) break;
711 -
712 - if ( $first ) {
713 - $navigation .= '&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;(';
714 - $first = false;
715 - } else {
716 - $navigation .= ' | ';
717 - }
718 -
719 - if ( $limit != $l ) {
720 - $navigation .= Html::element(
721 - 'a',
722 - array(
723 - 'href' => SpecialPage::getSafeTitleFor( 'Ask' )->getLocalURL(
724 - 'offset=' . $offset .
725 - '&limit=' . $l . $urltail
726 - ),
727 - 'rel' => 'nofollow'
728 - ),
729 - $l
730 - );
731 - } else {
732 - $navigation .= '<b>' . $l . '</b>';
733 - }
734 - }
735 -
736 - $navigation .= ')';
737 -
738 - return $navigation;
739 - }
740 -
741 - /**
742 - * Display a form section showing the options for a given format,
743 - * based on the getParameters() value for that format's query printer.
744 - *
745 - * @param string $format
746 - * @param array $paramValues The current values for the parameters (name => value)
747 - *
748 - * @return string
749 - */
750 - protected function showFormatOptions( $format, array $paramValues ) {
751 - $text = '';
752 -
753 - $printer = SMWQueryProcessor::getResultPrinter( $format, SMWQueryProcessor::SPECIAL_PAGE );
754 -
755 - $params = method_exists( $printer, 'getParameters' ) ? $printer->getParameters() : array();
756 -
757 - // Ignore the format parameter, as we got a special control in the GUI for it already.
758 - unset( $params['format'] );
759 -
760 - $optionsHtml = array();
761 -
762 - foreach ( $params as $param ) {
763 - $param = $this->toValidatorParam( $param );
764 - $currentValue = array_key_exists( $param->getName(), $paramValues ) ? $paramValues[$param->getName()] : false;
765 -
766 - $optionsHtml[] =
767 - Html::rawElement(
768 - 'div',
769 - array(
770 - 'style' => 'width: 30%; padding: 5px; float: left;'
771 - ),
772 - htmlspecialchars( $param->getName() ) . ': ' .
773 - $this->showFormatOption( $param, $currentValue ) .
774 - '<br />' .
775 - Html::element( 'em', array(), $param->getDescription() )
776 - );
777 - }
778 -
779 - for ( $i = 0, $n = count( $optionsHtml ); $i < $n; $i++ ) {
780 - if ( $i % 3 == 2 || $i == $n - 1 ) {
781 - $optionsHtml[$i] .= "<div style=\"clear: both\";></div>\n";
782 - }
783 - }
784 -
785 - $i = 0;
786 - $rowHtml = '';
787 - $resultHtml = '';
788 -
789 - while ( $option = array_shift( $optionsHtml ) ) {
790 - $rowHtml .= $option;
791 - $i++;
792 -
793 - if ( $i % 3 == 0 ) {
794 - $resultHtml .= Html::rawElement(
795 - 'div',
796 - array(
797 - 'style' => 'background: ' . ( $i % 6 == 0 ? 'white' : '#dddddd' ) . ';'
798 - ),
799 - $rowHtml
800 - );
801 - $rowHtml = '';
802 - }
803 - }
804 -
805 - return $resultHtml;
806 - }
807 -
808 - /**
809263 * Returns a Validator style Parameter definition.
810264 * SMW 1.5.x style definitions are converted.
811 - *
 265+ *
812266 * @since 1.6
813 - *
 267+ *
814268 * @param mixed $param
815 - *
 269+ *
816270 * @return Parameter
817271 */
818272 protected function toValidatorParam( $param ) {
819273 static $typeMap = array(
820274 'int' => Parameter::TYPE_INTEGER
821275 );
822 -
 276+
823277 if ( !( $param instanceof Parameter ) ) {
824278 if ( !array_key_exists( 'type', $param ) ) {
825279 $param['type'] = 'string';
826280 }
827 -
 281+
828282 $paramClass = $param['type'] == 'enum-list' ? 'ListParameter' : 'Parameter';
829283 $paramType = array_key_exists( $param['type'], $typeMap ) ? $typeMap[$param['type']] : Parameter::TYPE_STRING;
830 -
 284+
831285 $parameter = new $paramClass( $param['name'], $paramType );
832 -
 286+
833287 if ( array_key_exists( 'description', $param ) ) {
834288 $parameter->setDescription( $param['description'] );
835289 }
836 -
 290+
837291 if ( array_key_exists( 'values', $param ) && is_array( $param['values'] ) ) {
838292 $parameter->addCriteria( new CriterionInArray( $param['values'] ) );
839293 }
840 -
 294+
841295 return $parameter;
842296 }
843297 else {
844298 return $param;
845299 }
846300 }
847 -
848 - /**
849 - * Get the HTML for a single parameter input.
850 - *
851 - * @since 1.6
852 - *
853 - * @param Parameter $parameter
854 - * @param mixed $currentValue
855 - *
856 - * @return string
857 - */
858 - protected function showFormatOption( Parameter $parameter, $currentValue ) {
859 - $input = new ParameterInput( $parameter );
860 - $input->setInputName( 'p[' . $parameter->getName() . ']' );
861 -
862 - if ( $currentValue !== false ) {
863 - $input->setCurrentValue( $currentValue );
864 - }
865 -
866 - return $input->getHtml();
867 - }
868301
 302+
 303+
869304 /**
870305 * Compatibility method to get the skin; MW 1.18 introduces a getSkin method in SpecialPage.
871306 *
@@ -873,13 +308,13 @@
874309 * @return Skin
875310 */
876311 public function getSkin() {
877 - if ( method_exists( 'SpecialPage', 'getSkin' ) ) {
878 - return parent::getSkin();
879 - }
880 - else {
881 - global $wgUser;
882 - return $wgUser->getSkin();
883 - }
 312+ if ( method_exists( 'SpecialPage', 'getSkin' ) ) {
 313+ return parent::getSkin();
 314+ }
 315+ else {
 316+ global $wgUser;
 317+ return $wgUser->getSkin();
 318+ }
884319 }
885320
886321 }

Follow-up revisions

RevisionCommit summaryAuthorDate
r90456Removed some notices caused in r90263devayon12:06, 20 June 2011

Comments

#Comment by Nikerabbit (talk | contribs)   12:43, 17 June 2011

Could you use Xml:: or Html:: functions (depending in which version of MediaWiki you need to support). Currently it is very difficult to review if the code does enough escaping on html output.

#Comment by Devayon (talk | contribs)   13:59, 17 June 2011

Sure, I'll have a chat with Markus Krötzsch regarding this and see if we can reduce escaped html in the next commit. Right now the code you see is mostly a scaled down version of that in Special:Ask

#Comment by Jeroen De Dauw (talk | contribs)   15:38, 18 June 2011

I agree (and am sure Markus will to), these functions should definitely be used, and they can without any compatibility worries. The oldest we need to support is MW 1.15, and while Html was added in 1.16, SMW has it's own copy to fall back on.