diff --git a/LinkTitles.i18n.php b/LinkTitles.i18n.php index 94d2157..9321540 100755 --- a/LinkTitles.i18n.php +++ b/LinkTitles.i18n.php @@ -5,6 +5,7 @@ $messages = array(); $messages['en'] = array( + 'linktitles' => 'LinkTitles', 'linktitles-desc' => 'Automatically adds links to existing pages whenever a page is saved.', ); diff --git a/LinkTitles.php b/LinkTitles.php index 575adbd..73ae8b1 100755 --- a/LinkTitles.php +++ b/LinkTitles.php @@ -43,6 +43,7 @@ $wgLinkTitlesWordStartOnly = true; $wgLinkTitlesWordEndOnly = true; $wgLinkTitlesSmartMode = true; + $wgLinkTitlesTimeLimit = 0.2; $wgExtensionCredits['parserhook'][] = array( 'path' => __FILE__, @@ -56,7 +57,10 @@ $wgExtensionMessagesFiles['LinkTitles'] = dirname( __FILE__ ) . '/LinkTitles.i18n.php'; $wgExtensionMessagesFiles['LinkTitlesMagic'] = dirname( __FILE__ ) . '/LinkTitles.i18n.magic.php'; $wgAutoloadClasses['LinkTitles'] = dirname( __FILE__ ) . '/LinkTitles.body.php'; + $wgAutoloadClasses['SpecialLinkTitles'] = dirname( __FILE__ ) . '/SpecialLinkTitles.php'; $wgExtensionFunctions[] = 'LinkTitles::setup'; + $wgSpecialPages['LinkTitles'] = 'SpecialLinkTitles'; + $wgSpecialPageGroups['LinkTitles'] = 'other'; // vim: ts=2:sw=2:noet diff --git a/SpecialLinkTitles.php b/SpecialLinkTitles.php new file mode 100644 index 0000000..c7a4deb --- /dev/null +++ b/SpecialLinkTitles.php @@ -0,0 +1,219 @@ +getRequest(); + $output = $this->getOutput(); + $this->setHeaders(); + + // Determine whether this page was requested via GET or POST. + // If GET, display information and a button to start linking. + // If POST, start or continue the linking process. + if ( $request->wasPosted() ) { + if ( array_key_exists('s', $request->getValues()) ) { + $this->process($request, $output); + } + else + { + $this->buildInfoPage($request, $output); + } + } + else + { + $this->buildInfoPage($request, $output); + } + + } + + + /// Processes wiki articles, starting at the page indicated by + /// $startTitle. If $wgLinkTitlesTimeLimit is reached before all pages are + /// processed, returns the title of the next page that needs processing. + private function process(&$request, &$output) { + global $wgLinkTitlesTimeLimit; + + // Start the stopwatch + $startTime = microtime(true); + + // Connect to the database + $dbr = wfGetDB( DB_SLAVE ); + + // Fetch the start index and max number of records from the POST + // request. + $postValues = $request->getValues(); + + // Convert the start index to an integer; this helps preventing + // SQL injection attacks via forged POST requests. + $start = intval($postValues['s']); + + // If an end index was given, we don't need to query the database + if ( array_key_exists('e', $postValues) ) { + $end = intval($postValues['e']); + } + else + { + // No end index was given. Therefore, count pages now. + $end = $this->countPages($dbr); + }; + + array_key_exists('r', $postValues) ? + $reloads = $postValues['r'] : + $reloads = 0; + + // Retrieve page names from the database. + $res = $dbr->select( + 'page', + 'page_title', + array( + 'page_namespace = 0', + ), + __METHOD__, + array( + 'OFFSET' => $start, + 'LIMIT' => '1' + ) + ); + + // Iterate through the pages; break if a time limit is exceeded. + foreach ( $res as $row ) { + $curTitle = $row->page_title; + $this->processPage($curTitle); + $start += 1; + + // Check if the time limit is exceeded + if ( microtime(true)-$startTime > $wgLinkTitlesTimeLimit ) + { + $reloads += 1; + break; + } + } + + $this->addProgressInfo($output, $curTitle, $start, $end); + + // If we have not reached the last page yet, produce code to reload + // the extension's special page. + if ( $start <= $end ) + { + // Build a form with hidden values and output JavaScript code that + // immediately submits the form in order to continue the process. + $output->addHTML($this->getReloaderForm($request->getRequestURL(), + $start, $end, $reloads)); + } + } + + /// Processes a single page, given a $title Title object. + private function processPage($title) { + // TODO: make this namespace-aware + $titleObj = Title::makeTitle(0, $title); + $page = WikiPage::factory($titleObj); + $article = Article::newFromWikiPage($page, $this->getContext()); + $text = $article->getContent(); + LinkTitles::parseContent($article, $text); + $content = new WikitextContent($text); + $page->doEditContent($content, + "Parsed for page titles by LinkTitles bot.", + EDIT_MINOR | EDIT_FORCE_BOT + ); + + } + + /// Adds WikiText to the output containing information about the extension + /// and a form and button to start linking. + private function buildInfoPage(&$request, &$output) { + $url = $request->getRequestURL(); + + // TODO: Put the page contents in messages in the i18n file. + $output->addWikiText( +<<addHTML( +<< + + + +EOF + ); + } + + /// Produces informative output in WikiText format to show while working. + private function addProgressInfo($output, $curTitle, $start, $end) { + $progress = $start / $end * 100; + $percent = sprintf("%01.1f", $progress); + + $output->addWikiText( +<<addHTML( +<<Page ${start} of ${end}.

+
+ + ${percent}% + +
+
+EOF + ); + $output->addWikiText( +<< + + + + + +EOF + ; + } + + /// Counts the number of pages in a read-access wiki database ($dbr). + private function countPages($dbr) { + $res = $dbr->select( + 'page', + 'page_id', + array( + 'page_namespace = 0', + ), + __METHOD__ + ); + return $res->numRows(); + } +} +// vim: ts=2:sw=2:noet