also released into the public domain, which does not impair the obligations of
users under the GPL for use of the whole code or other sections thereof.
+[2] MediaWiki makes use of the Sajax Toolkit by modernmethod,
+ http://www.modernmethod.com/sajax/
+ which has the following license:
+
+ 'This work is licensed under the Creative Commons Attribution
+ License. To view a copy of this license, visit
+ http://creativecommons.org/licenses/by/2.0/ or send a letter
+ to Creative Commons, 559 Nathan Abbott Way,
+ Stanford, California 94305, USA.'
+
Many thanks to the Wikipedia regulars for testing and suggestions.
The official website for mediawiki is located at:
* (bug 4729) Add user preference that marks a user's edits as patrolled if user is able to
* (bug 4497,4704,5010) Added some new language codes.
* (bug 4630) Add user preference to prompt users when entering blank edit summaries
+* Added optional suggest feature for the search box. Set wgUseAjax to true to
+ enable it.
=== Caveats ===
--- /dev/null
+<?php
+
+$wgRequestTime = microtime();
+
+unset( $IP );
+@ini_set( 'allow_url_fopen', 0 ); # For security...
+
+# Valid web server entry point, enable includes.
+# Please don't move this line to includes/Defines.php. This line essentially defines
+# a valid entry point. If you put it in includes/Defines.php, then any script that includes
+# it becomes an entry point, thereby defeating its purpose.
+define( 'MEDIAWIKI', true );
+require_once( './includes/Defines.php' );
+require_once( './LocalSettings.php' );
+require_once( 'includes/Setup.php' );
+require_once( 'includes/AjaxFunctions.php' );
+
+if ( ! $wgUseAjax ) {
+ die ( -1 );
+}
+
+wfProfileIn( 'main-misc-setup' );
+
+header( 'Content-Type: text/html; charset=utf-8', true );
+
+// List of exported PHP functions
+$sajax_export_list = array( 'wfSajaxSearch' );
+
+$mode = "";
+
+$wgAjaxCachePolicy = new AjaxCachePolicy();
+
+if (! empty($_GET["rs"])) {
+ $mode = "get";
+}
+
+if (!empty($_POST["rs"])) {
+ $mode = "post";
+}
+
+if (empty($mode)) {
+ return;
+}
+
+if ($mode == "get") {
+ $func_name = $_GET["rs"];
+ if (! empty($_GET["rsargs"])) {
+ $args = $_GET["rsargs"];
+ } else {
+ $args = array();
+ }
+} else {
+ $func_name = $_POST["rs"];
+ if (! empty($_POST["rsargs"])) {
+ $args = $_POST["rsargs"];
+ } else {
+ $args = array();
+ }
+}
+
+if (! in_array($func_name, $sajax_export_list)) {
+ echo "-:$func_name not callable";
+} else {
+ echo "+:";
+ $result = call_user_func_array($func_name, $args);
+ $wgAjaxCachePolicy->writeHeader();
+ echo $result;
+}
+exit;
+
+?>
--- /dev/null
+<?php
+
+if( !defined( 'MEDIAWIKI' ) )
+ die( -1 );
+
+require_once('WebRequest.php');
+
+/**
+ * Function converts an Javascript escaped string back into a string with specified charset (default is UTF-8).
+ * Modified function from http://pure-essence.net/stuff/code/utf8RawUrlDecode.phps
+ *
+ * @param string $source escaped with Javascript's escape() function
+ * @param string $iconv_to destination character set will be used as second paramether in the iconv function. Default is UTF-8.
+ * @return string
+ */
+function js_unescape($source, $iconv_to = 'UTF-8') {
+ $decodedStr = '';
+ $pos = 0;
+ $len = strlen ($source);
+ while ($pos < $len) {
+ $charAt = substr ($source, $pos, 1);
+ if ($charAt == '%') {
+ $pos++;
+ $charAt = substr ($source, $pos, 1);
+ if ($charAt == 'u') {
+ // we got a unicode character
+ $pos++;
+ $unicodeHexVal = substr ($source, $pos, 4);
+ $unicode = hexdec ($unicodeHexVal);
+ $decodedStr .= code2utf($unicode);
+ $pos += 4;
+ }
+ else {
+ // we have an escaped ascii character
+ $hexVal = substr ($source, $pos, 2);
+ $decodedStr .= chr (hexdec ($hexVal));
+ $pos += 2;
+ }
+ }
+ else {
+ $decodedStr .= $charAt;
+ $pos++;
+ }
+ }
+
+ if ($iconv_to != "UTF-8") {
+ $decodedStr = iconv("UTF-8", $iconv_to, $decodedStr);
+ }
+
+ return $decodedStr;
+}
+
+/**
+ * Function coverts number of utf char into that character.
+ * Function taken from: http://sk2.php.net/manual/en/function.utf8-encode.php#49336
+ *
+ * @param int $num
+ * @return utf8char
+ */
+function code2utf($num){
+ if ( $num<128 )
+ return chr($num);
+ if ( $num<2048 )
+ return chr(($num>>6)+192).chr(($num&63)+128);
+ if ( $num<65536 )
+ return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128);
+ if ( $num<2097152 )
+ return chr(($num>>18)+240).chr((($num>>12)&63)+128).chr((($num>>6)&63)+128) .chr(($num&63)+128);
+ return '';
+}
+
+class AjaxCachePolicy {
+ var $policy;
+
+ function AjaxCachePolicy( $policy = null ) {
+ $this->policy = $policy;
+ }
+
+ function setPolicy( $policy ) {
+ $this->policy = $policy;
+ }
+
+ function writeHeader() {
+ header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+ if ( is_null( $this->policy ) ) {
+ // Bust cache in the head
+ header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
+ // always modified
+ header ("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
+ header ("Pragma: no-cache"); // HTTP/1.0
+ } else {
+ header ("Expires: " . gmdate( "D, d M Y H:i:s", time() + $this->policy ) . " GMT");
+ header ("Cache-Control: public,max-age={$this->policy}");
+ }
+ }
+}
+
+
+function wfSajaxSearch( $term ) {
+ global $wgContLang, $wgUser, $wgRequest, $wgAjaxCachePolicy;
+ $limit = 16;
+
+ $l = new Linker;
+
+ $term = str_replace( ' ', '_', $wgContLang->ucfirst(
+ $wgContLang->checkTitleEncoding( $wgContLang->recodeInput( js_unescape( $term ) ) )
+ ) );
+
+ if ( strlen( str_replace( '_', '', $term ) )<3 )
+ return;
+
+ $wgAjaxCachePolicy->setPolicy( 30*60 );
+
+ $db =& wfGetDB( DB_SLAVE );
+ $res = $db->select( 'page', 'page_title',
+ array( 'page_namespace' => 0,
+ "page_title LIKE '". $db->strencode( $term) ."%'" ),
+ "wfSajaxSearch",
+ array( 'LIMIT' => $limit+1 )
+ );
+
+ $r = "";
+
+ $i=0;
+ while ( ( $row = $db->fetchObject( $res ) ) && ( ++$i <= $limit ) ) {
+ $nt = Title::newFromDBkey( $row->page_title );
+ $r .= '<li>' . $l->makeKnownLinkObj( $nt ) . "</li>\n";
+ }
+ if ( $i > $limit ) {
+ $more = '<i>' . $l->makeKnownLink( $wgContLang->specialPage( "Allpages" ),
+ wfMsg('moredotdotdot'),
+ "namespace=0&from=" . wfUrlEncode ( $term ) ) .
+ '</i>';
+ } else {
+ $more = '';
+ }
+
+ $term = htmlspecialchars( $term );
+ return '<div style="float:right; border:solid 1px black;background:gainsboro;padding:2px;"><a onclick="Searching_Hide_Results();">'
+ . wfMsg( 'hideresults' ) . '</a></div>'
+ . '<h1 class="firstHeading">'.wfMsg('search')
+ . '</h1><div id="contentSub">'.wfMsg('searchquery', $term) . '</div><ul><li>'
+ . $l->makeKnownLink( $wgContLang->specialPage( 'Search' ),
+ wfMsg( 'searchcontaining', $term ),
+ "search=$term&fulltext=Search" )
+ . '</li><li>' . $l->makeKnownLink( $wgContLang->specialPage( 'Search' ),
+ wfMsg( 'searchnamed', $term ) ,
+ "search=$term&go=Go" )
+ . "</li></ul><h2>" . wfMsg( 'articletitles', $term ) . "</h2>"
+ . '<ul>' .$r .'</ul>'.$more;
+}
+
+?>
}
$revision = Revision::newFromId( $this->mLatest );
if( is_null( $revision ) ) {
- wfDebug( "$fname failed to retrieve current page, rev_id $data->page_latest\n" );
+ wfDebug( "$fname failed to retrieve current page, rev_id {$data->page_latest}\n" );
return false;
}
}
*/
$wgJobLogFile = false;
+/**
+ * Enable use of AJAX features, currently auto suggestion for the search bar
+ */
+$wgUseAjax = false;
+
?>
function output() {
global $wgUser, $wgOutputEncoding;
global $wgContLanguageCode, $wgDebugRedirects, $wgMimeType, $wgProfiler;
+ global $wgJsMimeType, $wgStylePath, $wgUseAjax, $wgScriptPath, $wgServer;
if( $this->mDoNothing ){
return;
wfProfileIn( $fname );
$sk = $wgUser->getSkin();
+ if ( $wgUseAjax ) {
+ $this->addScript( "<script type=\"{$wgJsMimeType}\">
+ var wgScriptPath=\"{$wgScriptPath}\";
+ var wgServer=\"{$wgServer}\";
+ </script>" );
+ $this->addScript( "<script type=\"{$wgJsMimeType}\" src=\"{$wgStylePath}/common/ajax.js\"></script>\n" );
+ }
+
if ( '' != $this->mRedirect ) {
if( substr( $this->mRedirect, 0, 4 ) != 'http' ) {
# Standards require redirect URLs to be absolute
'youhavenewmessagesmulti' => "You have new messages on $1",
'newtalkseperator' => ',_',
+'searchcontaining' => "Search for articles containing ''$1''.",
+'searchnamed' => "Search for articles named ''$1''.",
+'articletitles' => "Articles starting with ''$1''",
+'hideresults' => 'Hide results',
);
Wenn Sie *nicht* $2 sind, folgen Sie dem Link bitte nicht.
Der Bestätigungskode läuft am $4 ab.
-"
+",
+'searchcontaining' => "Suche nach Artikeln, in denen ''$1'' vorkommt.",
+'searchnamed' => "Suche nach Artikeln, deren Name ''$1'' enthält.",
+'articletitles' => "Artikel, die mit ''$1'' beginnen",
+'hideresults' => 'Verbergen',
+
);
-?>
\ No newline at end of file
+?>
<head>
<meta http-equiv="Content-Type" content="<?php $this->text('mimetype') ?>; charset=<?php $this->text('charset') ?>" />
<?php $this->html('headlinks') ?>
- <?php $this->html('headscripts') ?>
<title><?php $this->text('pagetitle') ?></title>
<style type="text/css" media="screen,projection">/*<![CDATA[*/ @import "<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/main.css?5"; /*]]>*/</style>
<link rel="stylesheet" type="text/css" <?php if(empty($this->data['printable']) ) { ?>media="print"<?php } ?> href="<?php $this->text('stylepath') ?>/common/commonPrint.css" />
<script type="<?php $this->text('jsmimetype') ?>"><?php $this->html('userjsprev') ?></script>
<?php }
if($this->data['trackbackhtml']) print $this->data['trackbackhtml']; ?>
+ <!-- Head Scripts -->
+ <?php $this->html('headscripts') ?>
</head>
<body <?php if($this->data['body_ondblclick']) { ?>ondblclick="<?php $this->text('body_ondblclick') ?>"<?php } ?>
<?php if($this->data['body_onload' ]) { ?>onload="<?php $this->text('body_onload') ?>"<?php } ?>
--- /dev/null
+// remote scripting library
+// (c) copyright 2005 modernmethod, inc
+var sajax_debug_mode = false;
+var sajax_request_type = "GET";
+
+var started;
+var typing;
+var memory=null;
+var body=null;
+var oldbody=null;
+
+function sajax_debug(text) {
+ if (sajax_debug_mode)
+ alert("RSD: " + text)
+}
+
+
+function sajax_init_object() {
+ sajax_debug("sajax_init_object() called..")
+ var A;
+ try {
+ A=new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (e) {
+ try {
+ A=new ActiveXObject("Microsoft.XMLHTTP");
+ } catch (oc) {
+ A=null;
+ }
+ }
+ if(!A && typeof XMLHttpRequest != "undefined")
+ A = new XMLHttpRequest();
+ if (!A)
+ sajax_debug("Could not create connection object.");
+ return A;
+}
+
+
+function sajax_do_call(func_name, args) {
+ var i, x, n;
+ var uri;
+ var post_data;
+ uri = wgServer + "/" + wgScriptPath + "/ajax.php";
+ if (sajax_request_type == "GET") {
+ if (uri.indexOf("?") == -1)
+ uri = uri + "?rs=" + escape(func_name);
+ else
+ uri = uri + "&rs=" + escape(func_name);
+ for (i = 0; i < args.length-1; i++)
+ uri = uri + "&rsargs[]=" + escape(args[i]);
+ uri = uri + "&rsrnd=" + new Date().getTime();
+ post_data = null;
+ } else {
+ post_data = "rs=" + escape(func_name);
+ for (i = 0; i < args.length-1; i++)
+ post_data = post_data + "&rsargs[]=" + escape(args[i]);
+ }
+ x = sajax_init_object();
+ x.open(sajax_request_type, uri, true);
+ if (sajax_request_type == "POST") {
+ x.setRequestHeader("Method", "POST " + uri + " HTTP/1.1");
+ x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+ }
+ x.setRequestHeader("Pragma", "cache=yes");
+ x.setRequestHeader("Cache-Control", "no-transform");
+ x.onreadystatechange = function() {
+ if (x.readyState != 4)
+ return;
+ sajax_debug("received " + x.responseText);
+ var status;
+ var data;
+ status = x.responseText.charAt(0);
+ data = x.responseText.substring(2);
+ if (status == "-")
+ alert("Error: " + data);
+ else
+ args[args.length-1](data);
+ }
+ x.send(post_data);
+ sajax_debug(func_name + " uri = " + uri + "/post = " + post_data);
+ sajax_debug(func_name + " waiting..");
+ delete x;
+}
+
+// Remove the typing barrier to allow call() to complete
+function Search_doneTyping()
+{
+ typing=false;
+}
+
+// Wait 500ms to run call()
+function Searching_Go()
+{
+ setTimeout("Searching_Call()", 500);
+}
+
+// If the user is typing wait until they are done.
+function Search_Typing() {
+ started=true;
+ typing=true;
+ window.status = "Waiting until you're done typing...";
+ setTimeout("Search_doneTyping()", 500);
+
+ // I believe these are needed by IE for when the users press return?
+ if (window.event)
+ {
+ if (event.keyCode == 13)
+ {
+ event.cancelBubble = true;
+ event.returnValue = false;
+ }
+ }
+}
+
+// Set the body div to the results
+function Searching_SetResult(result)
+{
+ //body.innerHTML = result;
+ t = document.getElementById("searchTarget");
+ if ( t == null ) {
+ oldbody=body.innerHTML;
+ body.innerHTML= '<div id="searchTargetContainer"><div id="searchTarget" ></div></div>' ;
+ t = document.getElementById("searchTarget");
+ }
+ t.innerHTML = result;
+ t.style.display='block';
+}
+
+function Searching_Hide_Results()
+{
+ t = document.getElementById("searchTarget");
+ t.style.display='none';
+ body.innerHTML = oldbody;
+}
+
+
+// This will call the php function that will eventually
+// return a results table
+function Searching_Call()
+{
+ var x;
+ Searching_Go();
+
+ //Don't proceed if user is typing
+ if (typing)
+ return;
+
+ x = document.getElementById("searchInput").value;
+
+ // Don't search again if the query is the same
+ if (x==memory)
+ return;
+
+ memory=x;
+ if (started) {
+ // Don't search for blank or < 3 chars.
+ if ((x=="") || (x.length < 3))
+ {
+ return;
+ }
+ x_wfSajaxSearch(x, Searching_SetResult);
+ }
+}
+
+function x_wfSajaxSearch() {
+ sajax_do_call( "wfSajaxSearch", x_wfSajaxSearch.arguments );
+}
+
+
+//Initialize
+function sajax_onload() {
+ x = document.getElementById( 'searchInput' );
+ x.onkeypress= function() { Search_Typing(); };
+ Searching_Go();
+ body = document.getElementById("content");
+}
+
+hookEvent("load", sajax_onload);