tosfos has submitted this change and it was merged.

Change subject: initial commit
......................................................................


initial commit

Change-Id: Id26042493c12f9f31495bb8be86ced53625afbee
---
A .gitmodules
A .jshintrc
A PagesList.class.php
A PagesList.hooks.php
A PagesList.i18n.alias.php
A PagesList.magic.php
A PagesList.php
A i18n/en.json
A i18n/qqq.json
A modules/DataTables
A modules/ext.PagesList.datatables.js
A specials/PagesListOptions.php
A specials/SpecialPagesList.php
A specials/SpecialPagesListQueryPage.php
14 files changed, 1,038 insertions(+), 0 deletions(-)

Approvals:
  tosfos: Verified; Looks good to me, approved



diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..2087e08
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "modules/DataTables"]
+       path = modules/DataTables
+       url = https://github.com/DataTables/DataTables.git
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..4cd914b
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,8 @@
+{
+       "predef": [
+               "mediaWiki",
+               "jQuery"
+       ],
+       "browser": true,
+       "smarttabs": true
+}
diff --git a/PagesList.class.php b/PagesList.class.php
new file mode 100644
index 0000000..4256ed3
--- /dev/null
+++ b/PagesList.class.php
@@ -0,0 +1,409 @@
+<?php
+
+/**
+ *
+ *
+ * @author Ike Hecht
+ */
+class PagesList extends ContextSource {
+       /**
+        * Namespace to target
+        *
+        * @var int Namespace constant
+        */
+       private $namespace;
+
+       /**
+        * Invert the namesace selection - select every namespace other than 
the one stored in
+        * $namespace
+        *
+        * @var boolean
+        */
+       private $nsInvert;
+
+       /**
+        * Include the associated namespace of $namespace - its Talk page
+        *
+        * @var boolean
+        */
+       private $associated;
+
+       /**
+        * Category name to target
+        *
+        * @var Title
+        */
+       private $category;
+
+       /**
+        * Base Page to target
+        *
+        * @var Title
+        */
+       private $basePage;
+
+       /**
+        * A read-only database object
+        *
+        * @var DatabaseBase
+        */
+       private $db;
+
+       /**
+        * Flag to indicated that the DataTables JS & CSS should later be 
loaded because there is a
+        * DataTables item on this page
+        *
+        * @var Boolean
+        */
+       public static $loadDataTables = false;
+
+       /**
+        * The index to actually be used for ordering. This is a single column,
+        * for one ordering, even if multiple orderings are supported.
+        * @todo fixme
+        * @var string
+        */
+       protected $indexField = 'rev_timestamp';
+
+       /**
+        * Result object for the query. Warning: seek before use.
+        *
+        * @var ResultWrapper
+        */
+       public $result;
+
+       /**
+        *
+        * @param DatabaseBase $db
+        * @param string $namespace
+        * @param boolean $nsInvert
+        * @param boolean $associated
+        * @param Title $category
+        * @param Title $basePage
+        * @param IContextSource $context
+        */
+       function __construct( DatabaseBase $db, $namespace = null, $nsInvert = 
false, $associated = false,
+               Title $category = null, Title $basePage = null, IContextSource 
$context = null ) {
+
+               if ( $context ) {
+                       $this->setContext( $context );
+               }
+
+               $this->db = $db;
+               $this->namespace = $namespace;
+               $this->nsInvert = $nsInvert;
+               $this->associated = $associated;
+               $this->category = $category;
+               $this->basePage = $basePage;
+
+               $this->doQuery();
+       }
+
+       /**
+        * Perform the db query
+        * The query code is based on ContribsPager
+        */
+       protected function doQuery() {
+               # Use the child class name for profiling
+               $fname = __METHOD__ . ' (' . get_class( $this ) . ')';
+               wfProfileIn( $fname );
+
+               list( $tables, $fields, $conds, $fname, $options, $join_conds ) 
= $this->buildQueryInfo();
+               $this->result = $this->db->select(
+                       $tables, $fields, $conds, $fname, $options, $join_conds
+               );
+               $this->result->rewind(); // Paranoia
+
+               wfProfileOut( $fname );
+       }
+
+       /**
+        * Generate an array to be turned into the full and final query.
+        *
+        * @return array
+        */
+       protected function buildQueryInfo() {
+               $fname = __METHOD__ . ' (' . $this->getSqlComment() . ')';
+               $info = $this->getQueryInfo();
+               $tables = $info['tables'];
+               $fields = $info['fields'];
+               $conds = isset( $info['conds'] ) ? $info['conds'] : array();
+               $options = isset( $info['options'] ) ? $info['options'] : 
array();
+               $join_conds = isset( $info['join_conds'] ) ? 
$info['join_conds'] : array();
+
+               #$options['ORDER BY'] = $this->indexField . ' DESC';
+
+               return array( $tables, $fields, $conds, $fname, $options, 
$join_conds );
+       }
+
+       /**
+        * Generate an array of basic query info.
+        *
+        * @return array
+        */
+       function getQueryInfo() {
+               $tables = array( 'revision', 'page' );
+               $fields = array(
+                       'namespace' => 'page_namespace',
+                       'title' => 'page_title',
+                       'value' => 'rev_timestamp',
+                       'userId' => 'rev_user',
+                       'userName' => 'rev_user_text'
+               );
+               $join_cond = array();
+
+               $conds = array(
+                       'page_is_redirect' => 0,
+                       'page_latest=rev_id'
+               );
+
+               if ( is_int( $this->namespace ) ) {
+                       $conds = array_merge( $conds, $this->getNamespaceCond() 
);
+               }
+
+               if ( $this->category instanceof Title ) {
+                       $tables[] = 'categorylinks';
+                       $conds = array_merge( $conds, array( 'cl_to' => 
$this->category->getDBkey() ) );
+                       $join_cond['categorylinks'] = array( 'INNER JOIN', 
'cl_from = page_id' );
+               }
+
+               if ( $this->basePage instanceof Title ) {
+                       $conds = array_merge( $conds,
+                               array( 'page_title' . $this->db->buildLike( 
$this->basePage->getDBkey() .
+                                       '/', $this->db->anyString() ),
+                               'page_namespace' => 
$this->basePage->getNamespace() )
+                       );
+               }
+
+               $options = array();
+               $index = false; #todo
+               if ( $index ) {
+                       $options['USE INDEX'] = array( 'revision' => $index );
+               }
+               $queryInfo = array(
+                       'tables' => $tables,
+                       'fields' => $fields,
+                       'conds' => $conds,
+                       'options' => $options,
+                       'join_conds' => $join_cond
+               );
+
+               return $queryInfo;
+       }
+
+       /**
+        * Limit the results to specific namespaces
+        *
+        * @return array
+        */
+       function getNamespaceCond() {
+               $selectedNS = $this->db->addQuotes( $this->namespace );
+               $eq_op = $this->nsInvert ? '!=' : '=';
+               $bool_op = $this->nsInvert ? 'AND' : 'OR';
+
+               if ( !$this->associated ) {
+                       return array( "page_namespace $eq_op $selectedNS" );
+               }
+
+               $associatedNS = $this->db->addQuotes(
+                       MWNamespace::getAssociated( $this->namespace )
+               );
+
+               return array(
+                       "page_namespace $eq_op $selectedNS " .
+                       $bool_op .
+                       " page_namespace $eq_op $associatedNS"
+               );
+       }
+
+       /**
+        * @return string
+        */
+       function getSqlComment() {
+               return get_class( $this );
+       }
+
+       function getList( $format, $showLastUser, $showLastModification, 
OutputPage $out = null ) {
+               if ( !isset( $out ) ) {
+                       $out = $this->getOutput();
+               }
+               switch ( $format ) {
+                       case 'datatable':
+                               /** @todo modify to check if DataTables 
submodule exists */
+                               self::$loadDataTables = true;
+                       case 'table':
+                               return $this->getResultTable( $showLastUser, 
$showLastModification );
+                       case 'ol':
+                       case 'ul':
+                               return $this->getResultList( $format, 
$showLastUser, $showLastModification );
+                       case 'plain':
+                               return $this->getResultPlain( $showLastUser, 
$showLastModification );
+                       default:
+                               /** @todo maybe return an error or something */
+                               return 'invalid format';
+               }
+       }
+
+       /**
+        * Get the fields to sort by title
+        *
+        * @return array
+        */
+       public function getOrderFields() {
+               return array( 'page_namespace', 'page_title' );
+       }
+
+       /**
+        * Borrowed from AncientPagesPage
+        *
+        * @param Skin $skin Unused
+        * @param object $result Result row
+        * @param boolean $showLastUser
+        * @param boolean $showLastModification
+        * @return string
+        */
+       protected function getResultTableRow( $skin, $result, $showLastUser = 
false,
+               $showLastModification = false ) {
+               $output = Html::openElement( 'tr' );
+               $output .= Html::rawElement( 'td', array(), 
$this->getLinkedTitle( $result ) );
+               if ( $showLastUser ) {
+                       $output .= Html::rawElement( 'td', array(), 
$this->getLastUser( $result ) );
+               }
+               if ( $showLastModification ) {
+                       $output .= Html::element( 'td', array(), 
$this->getLastModification( $result ) );
+               }
+               $output .= Html::closeElement( 'tr' );
+               return $output;
+       }
+
+       /**
+        *
+        * @param boolean $showLastUser
+        * @param boolean $showLastModification
+        * @return string HTML table
+        */
+       protected function getResultTable( $showLastUser = false, 
$showLastModification = false ) {
+               $output = Html::openElement( 'table',
+                               array( 'class' => 'pages-list stripe row-border 
hover' ) );
+               $output .= Html::openElement( 'thead' );
+               $output .= Html::openElement( 'tr' );
+               $output .= Html::rawElement( 'th', array(), $this->msg( 
'pageslist-title' ) );
+               if ( $showLastUser ) {
+                       $output .= Html::rawElement( 'th', array(), $this->msg( 
'pageslist-last-user' ) );
+               }
+               if ( $showLastModification ) {
+                       $output .= Html::rawElement( 'th', array(), $this->msg( 
'pageslist-last-modified' ) );
+               }
+               $output .= Html::closeElement( 'tr' );
+               $output .= Html::closeElement( 'thead' );
+               $output .= Html::openElement( 'tbody' );
+               while ( $resultRow = $this->result->fetchObject() ) {
+                       $output .= $this->getResultTableRow( $this->getSkin(), 
$resultRow, $showLastUser,
+                               $showLastModification );
+               }
+               $output .= Html::closeElement( 'tbody' );
+               $output .= Html::closeElement( 'table' );
+               return $output;
+       }
+
+
+       /**
+        * Add all necessary DataTables scripts and styles to output
+        *
+        * @param OutputPage $out
+        */
+       public static function addDataTablesToOutput( OutputPage &$out ) {
+               $out->addModules( 'ext.PagesList' );
+       }
+
+       /**
+        * Get an HTML link to the user page
+        *
+        * @param object $result
+        * @return string HTML
+        */
+       protected function getLastUser( $result ) {
+               return Linker::userLink( $result->userId, $result->userName );
+       }
+
+       /**
+        * Get a linked page title
+        *
+        * @global Language $wgContLang
+        * @param object $result
+        * @return string HTML
+        */
+       protected function getLinkedTitle( $result ) {
+               global $wgContLang;
+               $title = Title::makeTitle( $result->namespace, $result->title );
+               return Linker::linkKnown(
+                               $title, htmlspecialchars( $wgContLang->convert( 
$title->getPrefixedText() ) )
+               );
+       }
+
+       /**
+        * Get the date of the last modification
+        *
+        * @param object $result
+        * @return string HTML
+        */
+       protected function getLastModification( $result ) {
+               return $this->getLanguage()->userDate( $result->value, 
$this->getUser() );
+       }
+
+       /**
+        *
+        * @param string $format
+        * @param boolean $showLastUser
+        * @param boolean $showLastModification
+        * @return string HTML list
+        */
+       protected function getResultList( $format, $showLastUser = false, 
$showLastModification = false ) {
+               $html = Html::openElement( $format, array( 'class' => 
'pageslist' ) );
+               while ( $resultRow = $this->result->fetchObject() ) {
+                       $html .= Html::rawElement( 'li', array(),
+                                       $this->getListItem( $resultRow, 
$showLastUser, $showLastModification ) );
+               }
+               $html .= Html::closeElement( $format );
+
+               return $html;
+       }
+
+       /**
+        *
+        * @param boolean $showLastUser
+        * @param boolean $showLastModification
+        * @return string HTML comma separated list
+        */
+       protected function getResultPlain( $showLastUser = false, 
$showLastModification = false ) {
+               $html = Html::openElement( 'div', array( 'class' => 'pageslist' 
) );
+               $list = array();
+               while ( $resultRow = $this->result->fetchObject() ) {
+                       $list[] = $this->getListItem( $resultRow, 
$showLastUser, $showLastModification );
+               }
+               $html .= $this->getLanguage()->commaList( $list );
+               $html .= Html::closeElement( 'div' );
+
+               return $html;
+       }
+
+       /**
+        * Get a single list item
+        *
+        * @param object $resultRow
+        * @param boolean $showLastUser
+        * @param boolean $showLastModification
+        * @return string HTML list item
+        */
+       protected function getListItem( $resultRow, $showLastUser, 
$showLastModification ) {
+               $extras = array();
+               if ( $showLastUser ) {
+                       $extras[] = $this->getLastUser( $resultRow );
+               }
+               if ( $showLastModification ) {
+                       $extras[] = $this->getLastModification( $resultRow );
+               }
+               $commaList = $this->getLanguage()->commaList( $extras );
+               return $this->getLanguage()->specialList( 
$this->getLinkedTitle( $resultRow ), $commaList );
+       }
+}
diff --git a/PagesList.hooks.php b/PagesList.hooks.php
new file mode 100644
index 0000000..5723a48
--- /dev/null
+++ b/PagesList.hooks.php
@@ -0,0 +1,135 @@
+<?php
+
+/**
+ * Hooks for PagesList extension
+ *
+ * @file
+ * @ingroup Extensions
+ */
+class PagesListHooks {
+
+       /**
+        * Make PagesList vars available to JS
+        *
+        * @global array $wgPagesListDataTablesOptions
+        * @param array $vars
+        * @return boolean
+        */
+       public static function onResourceLoaderGetConfigVars( Array &$vars ) {
+               global $wgPagesListDataTablesOptions;
+
+               $vars['wgPagesList'] = array(
+                       'dataTablesOptions' => FormatJson::encode( 
$wgPagesListDataTablesOptions )
+               );
+
+               return true;
+       }
+
+       /**
+        * If there is a DataTables format on this page, load those modules
+        *
+        * @param OutputPage $out
+        * @param Skin $skin Unused
+        * @return boolean
+        */
+       public static function onBeforePageDisplay( OutputPage &$out, Skin 
&$skin ) {
+               if ( PagesList::$loadDataTables ) {
+                       PagesList::addDataTablesToOutput( $out );
+               }
+
+               return true;
+       }
+
+       /**
+        * Set up the #pageslist parser function
+        *
+        * @param Parser $parser
+        * @return boolean
+        */
+       public static function setupParserFunction( Parser &$parser ) {
+               $parser->setFunctionHook( 'pageslist', __CLASS__ . 
'::pageslistParserFunction', SFH_OBJECT_ARGS );
+
+               return true;
+       }
+
+       /**
+        * The parser function is called with the form:
+        * {{#pageslist:
+        *    namespace=namespacename | invert=yes/NO | associated=yes/NO | 
category=categoryname |
+        *    format=plain/ol/ul/table/DATATABLE }}
+        *
+        * For the main namespace, use namespace=main.
+        *
+        * @global boolean $wgPagesListShowLastUser
+        * @global boolean $wgPagesListShowLastModification
+        * @param Parser $parser Unused
+        * @param PPFrame $frame
+        * @param array $args
+        * @return string
+        */
+       public static function pageslistParserFunction(
+       Parser $parser, PPFrame $frame, array $args ) {
+               global $wgPagesListShowLastUser, 
$wgPagesListShowLastModification;
+
+               $params = self::extractOptions( $args, $frame );
+               $options = array( 'namespace', 'invert', 'associated', 
'category', 'basepage', 'format' );
+               foreach ( $options as $option ) {
+                       $params[$option] = isset( $params[$option] ) ? 
$params[$option] : null;
+               }
+
+               $categoryTitle = Title::makeTitleSafe( NS_CATEGORY, 
$params['category'] );
+               $basePageTitle = Title::newFromText( $params['basepage'] );
+
+               if ( strtolower( $params['namespace'] ) === 'main' ) {
+                       $params['namespace'] = '';
+               }
+               if ( is_null( $params['namespace'] ) ) {
+                       $namespaceId = null;
+               } else {
+                       $namespaceId = MWNamespace::getCanonicalIndex( 
strtolower( $params['namespace'] ) );
+               }
+
+               $bools = array( 'invert', 'associated' );
+               foreach ( $bools as $bool ) {
+                       if ( strtolower( $params[$bool] ) == 'yes' ) {
+                               $params[$bool] = true;
+                       } else {
+                               $params[$bool] = false;
+                       }
+               }
+
+               $pagesList = new PagesList( wfGetDB( DB_SLAVE ), $namespaceId, 
$params['invert'],
+                       $params['associated'], $categoryTitle, $basePageTitle );
+
+               if ( is_null( $params['format'] ) ) {
+                       $params['format'] = 'datatable';
+               }
+
+               $output = $pagesList->getList( $params['format'], 
$wgPagesListShowLastUser,
+                       $wgPagesListShowLastModification );
+               return array( $output, 'noparse' => true, 'isHTML' => true );
+       }
+
+       /**
+        * Converts an array of values in form [0] => "name=value" into a real
+        * associative array in form [name] => value
+        *
+        * @param array $options
+        * @param PPFrame $frame
+        * @return array
+        */
+       public static function extractOptions( array $options, PPFrame $frame ) 
{
+               $results = array();
+
+               foreach ( $options as $option ) {
+                       $pair = explode( '=', $frame->expand( $option ), 2 );
+                       if ( count( $pair ) == 2 ) {
+                               $name = strtolower( trim( $pair[0] ) );
+                               $value = trim( $pair[1] );
+                               $results[$name] = $value;
+                       }
+               }
+
+               return $results;
+       }
+}
diff --git a/PagesList.i18n.alias.php b/PagesList.i18n.alias.php
new file mode 100644
index 0000000..e47e554
--- /dev/null
+++ b/PagesList.i18n.alias.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Aliases for special pages of the PagesList extension
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+$specialPageAliases = array();
+
+/** English (English) */
+$specialPageAliases['en'] = array(
+       'PagesList' => array( 'PagesList' ),
+       'PagesListQueryPage' => array( 'PagesListQueryPage' ),
+);
diff --git a/PagesList.magic.php b/PagesList.magic.php
new file mode 100644
index 0000000..37c72ce
--- /dev/null
+++ b/PagesList.magic.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * Magic words
+ *
+ * @author Ike Hecht
+ */
+$magicWords = array();
+
+/** English
+ * @author Ike Hecht
+ */
+$magicWords['en'] = array(
+       'pageslist' => array( 0, 'pageslist' ),
+);
diff --git a/PagesList.php b/PagesList.php
new file mode 100644
index 0000000..c332498
--- /dev/null
+++ b/PagesList.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * PagesList extension
+ *
+ * For more info see http://mediawiki.org/wiki/Extension:PagesList
+ *
+ * @file
+ * @ingroup Extensions
+ * @author Ike Hecht, 2014
+ * @license GNU General Public Licence 2.0 or later
+ */
+$wgExtensionCredits['other'][] = array(
+       'path' => __FILE__,
+       'name' => 'PagesList',
+       'author' => array(
+               'Ike Hecht',
+       ),
+       'version' => '0.1.0',
+       'url' => 'https://www.mediawiki.org/wiki/Extension:PagesList',
+       'descriptionmsg' => 'pageslist-desc',
+);
+
+$wgAutoloadClasses['PagesList'] = __DIR__ . '/PagesList.class.php';
+$wgAutoloadClasses['PagesListHooks'] = __DIR__ . '/PagesList.hooks.php';
+$wgAutoloadClasses['PagesListOptions'] = __DIR__ . 
'/specials/PagesListOptions.php';
+$wgAutoloadClasses['SpecialPagesList'] = __DIR__ . 
'/specials/SpecialPagesList.php';
+$wgAutoloadClasses['SpecialPagesListQueryPage'] = __DIR__ .
+       '/specials/SpecialPagesListQueryPage.php';
+$wgMessagesDirs['PagesList'] = __DIR__ . '/i18n';
+$wgExtensionMessagesFiles['PagesListAlias'] = __DIR__ . 
'/PagesList.i18n.alias.php';
+$wgExtensionMessagesFiles['PagesListMagic'] = __DIR__ . '/PagesList.magic.php';
+
+$wgSpecialPages['PagesList'] = 'SpecialPagesList';
+$wgSpecialPages['PagesListQueryPage'] = 'SpecialPagesListQueryPage';
+
+$wgHooks['ParserFirstCallInit'][] = 'PagesListHooks::setupParserFunction';
+$wgHooks['BeforePageDisplay'][] = 'PagesListHooks::onBeforePageDisplay';
+$wgHooks['ResourceLoaderGetConfigVars'][] = 
'PagesListHooks::onResourceLoaderGetConfigVars';
+
+$wgResourceModules['ext.PagesList'] = array(
+       'scripts' => 'modules/ext.PagesList.datatables.js',
+       'localBasePath' => __DIR__,
+       'remoteExtPath' => 'PagesList',
+       'dependencies' => 'ext.PagesList.datatables'
+);
+
+$wgResourceModules['ext.PagesList.datatables'] = array(
+       'scripts' => 'modules/DataTables/media/js/jquery.dataTables.js',
+       'styles' => 'modules/DataTables/media/css/jquery.dataTables.css',
+       'localBasePath' => __DIR__,
+       'remoteExtPath' => 'PagesList'
+);
+
+/* Configuration */
+/**
+ * Show a column on Special:PagesList that shows who the page was last 
modified by
+ */
+$wgPagesListShowLastUser = false;
+
+/**
+ * Show a column on Special:PagesList that shows when the page was last 
modified
+ */
+$wgPagesListShowLastModification = false;
+
+/**
+ * An array of options for the DataTables plugin. See 
https://datatables.net/reference/option/ for
+ * more information.
+ *
+ * Example:
+ * $wgPagesListDataTablesOptions = array(
+ *     'iDisplayLength' => 25
+ * );
+ */
+$wgPagesListDataTablesOptions = array();
diff --git a/i18n/en.json b/i18n/en.json
new file mode 100644
index 0000000..2784328
--- /dev/null
+++ b/i18n/en.json
@@ -0,0 +1,16 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Ike Hecht"
+               ]
+       },
+       "pageslist-desc": "Shows a list of pages",
+       "pageslist": "Pages List",
+       "pageslistquerypage": "Pages List",
+       "pageslist-legend": "Pages list options",
+       "pageslist-categories": "Category:",
+       "pageslist-title": "Title",
+       "pageslist-last-modified": "Last modified",
+       "pageslist-last-user": "Last modified by",
+       "pageslist-basepage": "Subpages of (include namespace):"
+}
\ No newline at end of file
diff --git a/i18n/qqq.json b/i18n/qqq.json
new file mode 100644
index 0000000..97eecd7
--- /dev/null
+++ b/i18n/qqq.json
@@ -0,0 +1,16 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Ike Hecht"
+               ]
+       },
+       "pageslist-desc": 
"{{desc|name=PagesList|url=http://www.mediawiki.org/wiki/Extension:PagesList}}";,
+       "pageslist": "Title of Special:PagesList",
+       "pageslistquerypage": "Title of Special:PagesListQueryPage",
+       "pageslist-legend": "Legend for PagesList special page options header",
+       "pageslist-categories": "{{Identical|Categories}}",
+       "pageslist-basepage": "Label for the basepage field",
+       "pageslist-title": "Table header for the Page Title column",
+       "pageslist-last-modified": "Table header for the Last modified column",
+       "pageslist-last-user": "Table header for the Last modified by column"
+}
diff --git a/modules/DataTables b/modules/DataTables
new file mode 160000
index 0000000..24b2d11
--- /dev/null
+++ b/modules/DataTables
+Subproject commit 24b2d114606725d05c1e79155284babc47d728ca
diff --git a/modules/ext.PagesList.datatables.js 
b/modules/ext.PagesList.datatables.js
new file mode 100644
index 0000000..5ab1cfe
--- /dev/null
+++ b/modules/ext.PagesList.datatables.js
@@ -0,0 +1,4 @@
+jQuery( document ).ready( function( $ ) {
+    conf = mw.config.get( 'wgPagesList' );
+    $( 'table.pages-list' ).dataTable( JSON.parse( conf.dataTablesOptions ) );
+} );
diff --git a/specials/PagesListOptions.php b/specials/PagesListOptions.php
new file mode 100644
index 0000000..e452bef
--- /dev/null
+++ b/specials/PagesListOptions.php
@@ -0,0 +1,175 @@
+<?php
+
+/**
+ * PagesListOptions
+ *
+ * @author Ike Hecht
+ */
+class PagesListOptions extends ContextSource {
+       /**
+        *
+        * @var Title
+        */
+       private $pageTitle;
+
+       /**
+        *
+        * @var FormOptions
+        */
+       private $opts;
+
+       /**
+        *
+        * @param Title $pageTitle
+        * @param FormOptions $opts
+        * @param IContextSource $context
+        */
+       function __construct( Title $pageTitle, FormOptions $opts, 
IContextSource $context = null ) {
+               $this->pageTitle = $pageTitle;
+               $this->opts = $opts;
+
+               if ( $context ) {
+                       $this->setContext( $context );
+               }
+       }
+
+       /**
+        * Get a header for this page that allows selection of namespace & 
category
+        * borrowed from SpecialRecentChanges
+        *
+        * @global string $wgScript
+        * @return string HTML header
+        */
+       public function getPageHeader() {
+               global $wgScript;
+               $opts = $this->opts;
+
+               $extraOpts = $this->getExtraOptions( $opts );
+               $extraOptsCount = count( $extraOpts );
+               $count = 0;
+               $submit = ' ' . Xml::submitbutton( $this->msg( 'allpagessubmit' 
)->text() );
+
+               $out = Xml::openElement( 'table', array( 'id' => 
'pageslist-header' ) );
+               foreach ( $extraOpts as $name => $optionRow ) {
+                       # Add submit button to the last row only
+                       ++$count;
+                       $addSubmit = ( $count === $extraOptsCount ) ? $submit : 
'';
+
+                       $out .= Xml::openElement( 'tr' );
+                       if ( is_array( $optionRow ) ) {
+                               $out .= Xml::tags(
+                                               'td', array( 'class' => 
'mw-label mw-' . $name . '-label' ), $optionRow[0]
+                               );
+                               $out .= Xml::tags(
+                                               'td', array( 'class' => 
'mw-input' ), $optionRow[1] . $addSubmit
+                               );
+                       } else {
+                               $out .= Xml::tags(
+                                               'td', array( 'class' => 
'mw-input', 'colspan' => 2 ), $optionRow . $addSubmit
+                               );
+                       }
+                       $out .= Xml::closeElement( 'tr' );
+               }
+               $out .= Xml::closeElement( 'table' );
+
+               $unconsumed = $opts->getUnconsumedValues();
+               foreach ( $unconsumed as $key => $value ) {
+                       $out .= Html::hidden( $key, $value );
+               }
+
+               $t = $this->pageTitle;
+               $out .= Html::hidden( 'title', $t->getPrefixedText() );
+
+               $form = Xml::tags( 'form', array( 'action' => $wgScript ), $out 
);
+
+               return Xml::fieldset(
+                               $this->msg( 'pageslist-legend' )->text(), 
$form, array( 'class' => 'ploptions' )
+               );
+       }
+
+       /**
+        * Get options to be displayed in a form
+        *
+        * @param FormOptions $opts
+        * @return array
+        */
+       function getExtraOptions( $opts ) {
+               $opts->consumeValues( array(
+                       'namespace', 'invert', 'associated', 'categories', 
'basepage'
+               ) );
+
+               $extraOpts = array();
+               $extraOpts['namespace'] = $this->namespaceFilterForm( $opts );
+               $extraOpts['category'] = $this->categoryFilterForm( $opts );
+               $extraOpts['basepage'] = $this->basepageFilterForm( $opts );
+
+               return $extraOpts;
+       }
+
+       /**
+        * Creates the choose namespace selection
+        *
+        * @param FormOptions $opts
+        * @return string
+        */
+       protected function namespaceFilterForm( FormOptions $opts ) {
+               $nsSelect = Html::namespaceSelector(
+                               array( 'selected' => $opts['namespace'], 'all' 
=> '' ),
+                               array( 'name' => 'namespace', 'id' => 
'namespace' )
+               );
+               $nsLabel = Xml::label( $this->msg( 'namespace' )->text(), 
'namespace' );
+               $invert = Xml::checkLabel(
+                               $this->msg( 'invert' )->text(), 'invert', 
'nsinvert', $opts['invert'],
+                               array( 'title' => $this->msg( 'tooltip-invert' 
)->text() )
+               );
+               $associated = Xml::checkLabel(
+                               $this->msg( 'namespace_association' )->text(), 
'associated', 'nsassociated',
+                               $opts['associated'], array( 'title' => 
$this->msg( 'tooltip-namespace_association' )->text() )
+               );
+
+               return array( $nsLabel, "$nsSelect $invert $associated" );
+       }
+
+       /**
+        * Create an input to filter changes by categories
+        * Borrowed from SpecialRecentChanges
+        *
+        * @param FormOptions $opts
+        * @return array
+        */
+       protected function categoryFilterForm( FormOptions $opts ) {
+               list( $label, $input ) = Xml::inputLabelSep( $this->msg( 
'pageslist-categories' )->text(),
+                               'categories', 'mw-categories', false, 
$opts['categories'] );
+
+               return array( $label, $input );
+       }
+
+       /**
+        * @param FormOptions $opts
+        * @return array
+        */
+       protected function basepageFilterForm( FormOptions $opts ) {
+               list( $label, $input ) = Xml::inputLabelSep( $this->msg( 
'pageslist-basepage' )->text(),
+                               'basepage', 'mw-basepage', false, 
$opts['basepage'] );
+
+               return array( $label, $input );
+       }
+
+       /**
+        * Get a FormOptions object containing the default options
+        *
+        * @return FormOptions
+        */
+       public static function getDefaultOptions() {
+               $opts = new FormOptions();
+
+               $opts->add( 'namespace', '', FormOptions::INTNULL );
+               $opts->add( 'invert', false );
+               $opts->add( 'associated', false );
+
+               $opts->add( 'categories', '' );
+               $opts->add( 'basepage', '' );
+
+               return $opts;
+       }
+}
diff --git a/specials/SpecialPagesList.php b/specials/SpecialPagesList.php
new file mode 100644
index 0000000..774055c
--- /dev/null
+++ b/specials/SpecialPagesList.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * SpecialPage for PagesList extension
+ *
+ * @file
+ * @ingroup Extensions
+ */
+class SpecialPagesList extends IncludableSpecialPage {
+       /**
+        *
+        * @var PagesList
+        */
+       private $pagesList;
+
+       /**
+        *
+        * @var PagesListOptions
+        */
+       private $pagesListOptions;
+
+       public function __construct() {
+               parent::__construct( 'PagesList' );
+
+               $opts = $this->fetchOptionsFromRequest( 
PagesListOptions::getDefaultOptions() );
+               $categoryTitle = Title::makeTitleSafe( NS_CATEGORY, 
$opts['categories'] );
+               $basePageTitle = Title::newFromText( $opts['basepage'] );
+               $this->pagesList = new PagesList( wfGetDB( DB_SLAVE ), 
$opts['namespace'], $opts['invert'],
+                       $opts['associated'], $categoryTitle, $basePageTitle );
+               $this->pagesListOptions = new PagesListOptions(
+                       $this->getPageTitle(), $opts, $this->getContext() );
+       }
+
+       /**
+        * Shows the page to the user.
+        * @param string $sub Unused
+        */
+       public function execute( $sub ) {
+               global $wgPagesListShowLastUser, 
$wgPagesListShowLastModification, $wgPagesListDataTablesOptions;
+
+               $out = $this->getOutput();
+               $out->setPageTitle( $this->msg( 'pageslist' ) );
+               $out->addHTML( $this->pagesListOptions->getPageHeader() );
+               /** @todo modify to check if DataTables submodule exists */
+               $out->addHTML( $this->pagesList->getList( 'datatable', 
$wgPagesListShowLastUser,
+                               $wgPagesListShowLastModification, 
$wgPagesListDataTablesOptions, $out ) );
+       }
+
+       /**
+        * Fetch values for a FormOptions object from the WebRequest associated 
with this instance.
+        *
+        * Intended for subclassing, e.g. to add a backwards-compatibility 
layer.
+        *
+        * @param FormOptions $opts
+        * @return FormOptions
+        */
+       protected function fetchOptionsFromRequest( $opts ) {
+               $opts->fetchValuesFromRequest( $this->getRequest() );
+
+               return $opts;
+       }
+
+       protected function getGroupName() {
+               return 'pages';
+       }
+}
diff --git a/specials/SpecialPagesListQueryPage.php 
b/specials/SpecialPagesListQueryPage.php
new file mode 100644
index 0000000..7353ada
--- /dev/null
+++ b/specials/SpecialPagesListQueryPage.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * SpecialPage for PagesList extension
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+class SpecialPagesListQueryPage extends QueryPage {
+       /**
+        *
+        * @var PagesList
+        */
+       private $pagesList;
+
+       /**
+        *
+        * @var PagesListOptions
+        */
+       private $pagesListOptions;
+
+       public function __construct(  ) {
+               parent::__construct( 'PagesListQueryPage' );
+
+               $opts = $this->fetchOptionsFromRequest( 
PagesListOptions::getDefaultOptions() );
+               $categoryTitle = Title::makeTitleSafe( NS_CATEGORY, 
$opts['categories'] );
+               $basePageTitle = Title::newFromText( $opts['basepage'] );
+               $this->pagesList = new PagesList( wfGetDB( DB_SLAVE ), 
$opts['namespace'], $opts['invert'],
+                       $opts['associated'], $categoryTitle, $basePageTitle );
+               $this->pagesListOptions = new PagesListOptions(
+                       $this->getPageTitle(), $opts, $this->getContext() );
+       }
+
+       /**
+        * Fetch values for a FormOptions object from the WebRequest associated 
with this instance.
+        *
+        * Intended for subclassing, e.g. to add a backwards-compatibility 
layer.
+        *
+        * @param FormOptions $opts
+        * @return FormOptions
+        */
+       protected function fetchOptionsFromRequest( $opts ) {
+               $opts->fetchValuesFromRequest( $this->getRequest() );
+
+               return $opts;
+       }
+
+       function isExpensive() {
+               return true;
+       }
+
+       function getQueryInfo() {
+               return $this->pagesList->getQueryInfo();
+       }
+
+       function usesTimestamps() {
+               return true;
+       }
+
+       function getOrderFields() {
+               return $this->pagesList->getOrderFields();
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       protected function getGroupName() {
+               return 'pages';
+       }
+
+       /**
+        * Borrowed from AncientPagesPage
+        *
+        * @global Language $wgContLang
+        * @global boolean $wgPagesListShowLastModification
+        * @param Skin $skin Unused
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               global $wgContLang, $wgPagesListShowLastModification;
+
+               if ( $wgPagesListShowLastModification ) {
+                       $d = $this->getLanguage()->userDate( $result->value, 
$this->getUser() );
+               } else {
+                       $d = null;
+               }
+               $title = Title::makeTitle( $result->namespace, $result->title );
+               $link = Linker::linkKnown(
+                               $title, htmlspecialchars( $wgContLang->convert( 
$title->getPrefixedText() ) )
+               );
+
+               return $this->getLanguage()->specialList( $link, 
htmlspecialchars( $d ) );
+       }
+
+       public function getPageHeader() {
+               return $this->pagesListOptions->getPageHeader();
+       }
+       public function isIncludable() {
+               return true;
+       }
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/177675
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Id26042493c12f9f31495bb8be86ced53625afbee
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/PagesList
Gerrit-Branch: master
Gerrit-Owner: tosfos <[email protected]>
Gerrit-Reviewer: Siebrand <[email protected]>
Gerrit-Reviewer: tosfos <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to