Yaron Koren has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/107883


Change subject: Added new input type, "tree" - "category" and "categories" are 
now deprecated.
......................................................................

Added new input type, "tree" - "category" and "categories" are now deprecated.

...and are wrappers for "tree". "tree" is currently essentially a combination
of "category", "categories" and the "menuselect" input type from the
Semantic Forms Inputs extension.

Change-Id: If4ba1af81205591303eb5883e21b1299005248ce
---
M SemanticForms.php
M includes/SF_FormPrinter.php
M includes/forminputs/SF_CategoriesInput.php
M includes/forminputs/SF_CategoryInput.php
A includes/forminputs/SF_TreeInput.php
M languages/SF_Messages.php
M libs/ext.dynatree.js
7 files changed, 393 insertions(+), 274 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/SemanticForms 
refs/changes/83/107883/1

diff --git a/SemanticForms.php b/SemanticForms.php
index 7a553a7..1fcb67b 100644
--- a/SemanticForms.php
+++ b/SemanticForms.php
@@ -40,7 +40,7 @@
        die( "ERROR: <a href=\"http://semantic-mediawiki.org\";>Semantic 
MediaWiki</a> must be installed for Semantic Forms to run!" );
 }
 
-define( 'SF_VERSION', '2.6.1' );
+define( 'SF_VERSION', '2.6.2-alpha' );
 
 $wgExtensionCredits[defined( 'SEMANTIC_EXTENSION_TYPE' ) ? 'semantic' : 
'specialpage'][] = array(
        'path' => __FILE__,
@@ -178,6 +178,7 @@
 $wgAutoloadClasses['SFDateInput'] = $sfgIP . 
'/includes/forminputs/SF_DateInput.php';
 $wgAutoloadClasses['SFDateTimeInput'] = $sfgIP . 
'/includes/forminputs/SF_DateTimeInput.php';
 $wgAutoloadClasses['SFYearInput'] = $sfgIP . 
'/includes/forminputs/SF_YearInput.php';
+$wgAutoloadClasses['SFTreeInput'] = $sfgIP . 
'/includes/forminputs/SF_TreeInput.php';
 $wgAutoloadClasses['SFCategoryInput'] = $sfgIP . 
'/includes/forminputs/SF_CategoryInput.php';
 $wgAutoloadClasses['SFCategoriesInput'] = $sfgIP . 
'/includes/forminputs/SF_CategoriesInput.php';
 
diff --git a/includes/SF_FormPrinter.php b/includes/SF_FormPrinter.php
index 3847d9c..469f5e6 100644
--- a/includes/SF_FormPrinter.php
+++ b/includes/SF_FormPrinter.php
@@ -45,6 +45,7 @@
                $this->registerInputType( 'SFCheckboxesInput' );
                $this->registerInputType( 'SFListBoxInput' );
                $this->registerInputType( 'SFComboBoxInput' );
+               $this->registerInputType( 'SFTreeInput' );
                $this->registerInputType( 'SFCategoryInput' );
                $this->registerInputType( 'SFCategoriesInput' );
 
diff --git a/includes/forminputs/SF_CategoriesInput.php 
b/includes/forminputs/SF_CategoriesInput.php
index 3f8dc20..c3fbdd7 100644
--- a/includes/forminputs/SF_CategoriesInput.php
+++ b/includes/forminputs/SF_CategoriesInput.php
@@ -2,6 +2,9 @@
 /**
  * File holding the SFCategoriesInput class
  *
+ * This input type is deprecated - in SF 2.6.2, it was replaced with, and
+ * became a wrapper for, the "tree" input type.
+ *
  * @file
  * @ingroup SF
  */
@@ -11,7 +14,7 @@
  *
  * @ingroup SFFormInput
  */
-class SFCategoriesInput extends SFCategoryInput {
+class SFCategoriesInput extends SFTreeInput {
        public static function getName() {
                return 'categories';
        }
@@ -19,6 +22,4 @@
        public static function getOtherPropTypeListsHandled() {
                return array( '_wpg' );
        }
-
-
 }
diff --git a/includes/forminputs/SF_CategoryInput.php 
b/includes/forminputs/SF_CategoryInput.php
index cb921c5..b48121b 100644
--- a/includes/forminputs/SF_CategoryInput.php
+++ b/includes/forminputs/SF_CategoryInput.php
@@ -2,6 +2,9 @@
 /**
  * File holding the SFCategoryInput class
  *
+ * This input type is deprecated - in SF 2.6.2, it was replaced with, and
+ * became a wrapper for, the "tree" input type.
+ *
  * @file
  * @ingroup SF
  */
@@ -11,10 +14,7 @@
  *
  * @ingroup SFFormInput
  */
-class SFCategoryInput extends SFFormInput {
-
-       private static $multipleSelect = false;
-
+class SFCategoryInput extends SFTreeInput {
        public static function getName() {
                return 'category';
        }
@@ -22,268 +22,4 @@
        public static function getOtherPropTypesHandled() {
                return array( '_wpg' );
        }
-
-       public static function getHTML( $cur_value, $input_name, $is_mandatory, 
$is_disabled, $other_args ) {
-               if ( array_key_exists( 'top category', $other_args ) ) {
-                       $top_category = $other_args['top category'];
-               } else {
-                       // escape - we can't do anything
-                       return null;
-               }
-
-               if ( $other_args['input type'] == 'category' ) {
-                       $inputType = "radio";
-                       self::$multipleSelect = false;
-               } else {
-                       $inputType = "checkbox";
-                       self::$multipleSelect = true;
-               }
-
-               // get list delimiter - default is comma
-               if ( array_key_exists( 'delimiter', $other_args ) ) {
-                       $delimiter = $other_args['delimiter'];
-               } else {
-                       $delimiter = ',';
-               }
-
-               $cur_values = SFUtils::getValuesArray( $cur_value, $delimiter );
-
-               $cats = self::getCategoryHierarchy( $top_category );
-
-               $hideroot = array_key_exists( 'hideroot', $other_args );
-               if ( array_key_exists( 'depth', $other_args ) ) {
-                       $depth = $other_args['depth'];
-               } else {
-                       $depth = '10';
-               }
-               if ( array_key_exists( 'height', $other_args ) ) {
-                       $height = $other_args['height'];
-               } else {
-                       $height = '100';
-               }
-               if ( array_key_exists( 'width', $other_args ) ) {
-                       $width = $other_args['width'];
-               } else {
-                       $width = '500';
-               }
-
-               $dummy_str = "REPLACE THIS TEXT";
-               $text = '<div id="' . $input_name . 'categoryinput" 
style="height: ' . $height . 'px; width: ' . $width . 'px;">';
-               $catText = self::encode_categories($cats, $input_name, 
$cur_values, $hideroot, $depth, $inputType);
-
-               // replace values one at a time, by an incrementing index -
-               // inspired by http://bugs.php.net/bug.php?id=11457
-               $i = 0;
-               while ( ( $a = strpos( $catText, $dummy_str ) ) > 0 ) {
-                       $catText = substr( $catText, 0, $a ) . $i++ . substr( 
$catText, $a + strlen( $dummy_str ) );
-               }
-               $text .= $catText;
-               $text .= '</div>';
-
-               return $text;
-       }
-
-       private static function encode_categories( $categories, $input_name, 
$current_selection, $hideprefix, $depth, $inputType ) {
-               $key_prefix = $input_name . "key";
-               $text = '';
-               if ( !$hideprefix ) {
-                       $text .= "<ul>\n";
-               }
-               $text .= self::encode_node( $categories, $key_prefix, 
$input_name, $current_selection, $hideprefix, $depth, $inputType );
-               if ( !$hideprefix ) {
-                       $text .= "</ul>\n";
-               }
-               if ( self::$multipleSelect ) {
-                       $text .= Html::hidden( $input_name . '[is_list]', 1 );
-               }
-               return $text;
-       }
-
-       private static function encode_node( $categories, $key_prefix, 
$input_name, $current_selection, $hidenode, $depth, $inputType, $index = 1 ) {
-               global $sfgTabIndex, $sfgFieldNum;
-
-               $input_id = "input_$sfgFieldNum";
-               $key_id = "$key_prefix$index";
-               $dataItems = array();
-               $li_data = "";
-               $input_data = "";
-               if ( in_array($categories['title'], $current_selection) ) {
-                       $li_data .= 'class="selected" ';
-                       $input_data .= 'checked="checked"';
-               }
-
-               if ( $depth > 0 ) {
-                       $dataItems[] = "'expand': true";
-               }
-
-               if ( $dataItems ) {
-                       $li_data .= "data=\"" . implode(",", $dataItems) . "\" 
";
-               }
-
-               $text = '';
-               if ( !$hidenode ) {
-                       $dummy_str = "REPLACE THIS TEXT";
-                       $text .= "<li id=\"$key_id\" $li_data>";
-                       if ( self::$multipleSelect) {
-                               $inputName = $input_name . "[" . $dummy_str . 
"]";
-                       } else {
-                               $inputName = $input_name;
-                       }
-                       $text .= "<input type=\"$inputType\" 
tabindex=\"$sfgTabIndex\" name=\"" . $inputName .
-                               "\" value=\"" . $categories['title'] . "\" 
id=\"chb-$key_id\" $input_data class=\"hidden\" />";
-                       $text .= $categories['title'] . "\n";
-               }
-               if ( array_key_exists('children', $categories) ) {
-                       $text .= "<ul>\n";
-                       $i = 1;
-                       foreach ( $categories['children'] as $cat ) {
-                               $text .= self::encode_node( $cat, $key_id, 
$input_name, $current_selection, false, $depth - 1, $inputType, $i++ );
-                       }
-                       $text .= "</ul>\n";
-               }
-               return $text;
-       }
-
-       public static function getParameters() {
-               $params = parent::getParameters();
-               $params[] = array(
-                       'name' => 'top category',
-                       'type' => 'string',
-                       'description' => wfMessage( 'sf_forminputs_topcategory' 
)->text()
-               );
-               $params[] = array(
-                       'name' => 'hideroot',
-                       'type' => 'boolean',
-                       'description' => wfMessage( 'sf_forminputs_hideroot' 
)->text()
-               );
-               $params[] = array(
-                       'name' => 'depth',
-                       'type' => 'int',
-                       'description' => wfMessage( 'sf_forminputs_depth' 
)->text()
-               );
-               $params[] = array(
-                       'name' => 'height',
-                       'type' => 'int',
-                       'description' => wfMessage( 'sf_forminputs_height' 
)->text()
-               );
-               $params[] = array(
-                       'name' => 'width',
-                       'type' => 'int',
-                       'description' => wfMessage( 'sf_forminputs_width' 
)->text()
-               );
-               return $params;
-       }
-
-       /**
-        * Returns the HTML code to be included in the output page for this 
input.
-        */
-       public function getHtmlText() {
-               return self::getHTML(
-                       $this->mCurrentValue,
-                       $this->mInputName,
-                       $this->mIsMandatory,
-                       $this->mIsDisabled,
-                       $this->mOtherArgs
-               );
-       }
-
-       /**
-        * Creates a Title object from a user provided (and thus unsafe) string
-        * @param $title string
-        * @return null|Title
-        */
-       static function makeTitle( $title ) {
-               $title = trim( $title );
-
-               if ( strval( $title ) === '' ) {
-                       return null;
-               }
-
-               # The title must be in the category namespace
-               # Ignore a leading Category: if there is one
-               $t = Title::newFromText( $title, NS_CATEGORY );
-               if ( !$t || $t->getNamespace() != NS_CATEGORY || 
$t->getInterWiki() != '' ) {
-                       // If we were given something like "Wikipedia:Foo" or 
"Template:",
-                       // try it again but forced.
-                       $title = "Category:$title";
-                       $t = Title::newFromText( $title );
-               }
-               return $t;
-       }
-
-       /**
-        * @param $top_category String
-        * @return mixed
-        */
-       private static function getCategoryHierarchy( $top_category ) {
-               $title = self::makeTitle( $top_category );
-               if ( $title->getNamespace() != NS_CATEGORY ) {
-                       return null;
-               }
-
-               $nodes = array();
-
-               $defaultDepth = 20;
-               $res = self::getNode( $title, $defaultDepth, $nodes );
-               return $res;
-       }
-
-       /**
-        * @param Title $title
-        * @param int $depth
-        * @param array $nodes
-        * @return array
-        */
-       private static function getNode ( $title, $depth, &$nodes ) {
-               $res = array( 'title' => $title->getText() );
-               if ( !in_array( $title, $nodes ) ) {
-                       $nodes[] = $title;
-                       if ( $depth != 0 ) {
-                               $children = self::getChildren( $title, $depth - 
1, $nodes );
-                               if ( !empty($children) ) {
-                                       $res['children'] = $children;
-                               }
-                       }
-               }
-               return $res;
-       }
-
-
-       /**
-        * @param Title $title
-        * @param int $depth
-        * @return array
-        */
-       private static function getChildren( $title, $depth, &$nodes ) {
-               $dbr = wfGetDb( DB_SLAVE );
-
-               $tables = array( 'page', 'categorylinks' );
-               $fields = array( 'page_id', 'page_namespace', 'page_title',
-                       'page_is_redirect', 'page_len', 'page_latest', 'cl_to',
-                       'cl_from' );
-               $where = array();
-               $joins = array();
-               $options = array( 'ORDER BY' => 'cl_type, cl_sortkey' );
-
-               $joins['categorylinks'] = array( 'JOIN', 'cl_from = page_id' );
-               $where['cl_to'] = $title->getDBkey();
-               $options['USE INDEX']['categorylinks'] = 'cl_sortkey';
-
-               $tables = array_merge( $tables, array( 'category' ) );
-               $fields = array_merge( $fields, array( 'cat_id', 'cat_title', 
'cat_subcats', 'cat_pages', 'cat_files' ) );
-               $joins['category'] = array( 'LEFT JOIN', array( 'cat_title = 
page_title', 'page_namespace' => NS_CATEGORY ) );
-
-               $res = $dbr->select( $tables, $fields, $where, __METHOD__, 
$options, $joins );
-               $children = array();
-
-               foreach ( $res as $row ) {
-                       $t = Title::newFromRow( $row );
-                       if ( $t->getNamespace() == NS_CATEGORY ) {
-                               $children[] = self::getNode( $t, $depth, $nodes 
);
-                       }
-               }
-               return $children;
-       }
-
-
 }
diff --git a/includes/forminputs/SF_TreeInput.php 
b/includes/forminputs/SF_TreeInput.php
new file mode 100644
index 0000000..54453ff
--- /dev/null
+++ b/includes/forminputs/SF_TreeInput.php
@@ -0,0 +1,373 @@
+<?php
+/**
+ * File holding the SFTreeInput class
+ *
+ * @file
+ * @ingroup SF
+ *
+ * @author Yaron Koren
+ * @author Mathias Lidal
+ */
+
+/**
+ * The SFTreeInput class.
+ *
+ * @ingroup SFFormInput
+ */
+class SFTreeInput extends SFFormInput {
+
+       private static $multipleSelect = false;
+
+       public static function getName() {
+               return 'tree';
+       }
+
+       public static function getOtherPropTypesHandled() {
+               if ( defined( 'SMWDataItem::TYPE_STRING' ) ) {
+                       // SMW < 1.9
+                       return array( '_str', '_wpg' );
+               } else {
+                       return array( '_txt', '_wpg' );
+               }
+       }
+
+       public static function getOtherPropTypeListsHandled() {
+               if ( defined( 'SMWDataItem::TYPE_STRING' ) ) {
+                       // SMW < 1.9
+                       return array( '_str', '_wpg' );
+               } else {
+                       return array( '_txt', '_wpg' );
+               }
+       }
+
+       public static function getHTML( $cur_value, $input_name, $is_mandatory, 
$is_disabled, $other_args ) {
+               // Handle the now-deprecated 'category' and 'categories'
+               // input types.
+               if ( $other_args['input type'] == 'category' ) {
+                       $inputType = "radio";
+                       self::$multipleSelect = false;
+               } elseif ( $other_args['input type'] == 'categories' ) {
+                       $inputType = "checkbox";
+                       self::$multipleSelect = true;
+               } else {
+                       $is_list = ( array_key_exists( 'is_list', $other_args ) 
&& $other_args['is_list'] == true );
+                       if ( $is_list ) {
+                               $inputType = "checkbox";
+                               self::$multipleSelect = true;
+                       } else {
+                               $inputType = "radio";
+                               self::$multipleSelect = false;
+                       }
+               }
+
+               // get list delimiter - default is comma
+               if ( array_key_exists( 'delimiter', $other_args ) ) {
+                       $delimiter = $other_args['delimiter'];
+               } else {
+                       $delimiter = ',';
+               }
+
+               $cur_values = SFUtils::getValuesArray( $cur_value, $delimiter );
+               if ( array_key_exists( 'height', $other_args ) ) {
+                       $height = $other_args['height'];
+               } else {
+                       $height = '100';
+               }
+               if ( array_key_exists( 'width', $other_args ) ) {
+                       $width = $other_args['width'];
+               } else {
+                       $width = '500';
+               }
+
+               $dummy_str = "REPLACE THIS TEXT";
+               $text = '<div id="' . $input_name . 'treeinput" style="height: 
' . $height . 'px; width: ' . $width . 'px;">';
+
+               if ( array_key_exists( 'depth', $other_args ) ) {
+                       $depth = $other_args['depth'];
+               } else {
+                       $depth = '10';
+               }
+
+               if ( array_key_exists( 'top category', $other_args ) ) {
+                       $top_category = $other_args['top category'];
+
+                       $title = self::makeTitle( $top_category );
+                       if ( $title->getNamespace() != NS_CATEGORY ) {
+                               return null;
+                       }
+
+                       $tree = SFTree::newFromTopCategory( $top_category );
+                       $hideroot = array_key_exists( 'hideroot', $other_args );
+               } elseif ( array_key_exists( 'structure', $other_args ) ) {
+                       $structure = $other_args['structure'];
+                       $tree = SFTree::newFromWikiText( $structure );
+                       $hideroot = true;
+               } else {
+                       // Escape - we can't do anything.
+                       return null;
+               }
+
+               $inputText = self::treeToHTML( $tree, $input_name, $cur_values, 
$hideroot, $depth, $inputType );
+
+               // Replace values one at a time, by an incrementing index -
+               // inspired by http://bugs.php.net/bug.php?id=11457
+               $i = 0;
+               while ( ( $a = strpos( $inputText, $dummy_str ) ) > 0 ) {
+                       $inputText = substr( $inputText, 0, $a ) . $i++ . 
substr( $inputText, $a + strlen( $dummy_str ) );
+               }
+               $text .= $inputText;
+
+               $text .= '</div>';
+
+               return $text;
+       }
+
+       // Perhaps treeToHTML() and nodeToHTML() should be moved to the
+       // SFTree class? Currently SFTree doesn't know about HTML stuff, but
+       // maybe it should.
+       private static function treeToHTML( $fullTree, $input_name, 
$current_selection, $hideprefix, $depth, $inputType ) {
+               $key_prefix = $input_name . "key";
+               $text = '';
+               if ( !$hideprefix ) {
+                       $text .= "<ul>\n";
+               }
+               $text .= self::nodeToHTML( $fullTree, $key_prefix, $input_name, 
$current_selection, $hideprefix, $depth, $inputType );
+               if ( !$hideprefix ) {
+                       $text .= "</ul>\n";
+               }
+               if ( self::$multipleSelect ) {
+                       $text .= Html::hidden( $input_name . '[is_list]', 1 );
+               }
+               return $text;
+       }
+
+       private static function nodeToHTML( $node, $key_prefix, $input_name, 
$current_selection, $hidenode, $depth, $inputType, $index = 1 ) {
+               global $sfgTabIndex, $sfgFieldNum;
+
+               $input_id = "input_$sfgFieldNum";
+               $key_id = "$key_prefix$index";
+               $dataItems = array();
+               $li_data = "";
+               $input_data = "";
+               if ( in_array( $node->title, $current_selection ) ) {
+                       $li_data .= 'class="selected" ';
+                       $input_data .= 'checked="checked"';
+               }
+
+               if ( $depth > 0 ) {
+                       $dataItems[] = "'expand': true";
+               }
+
+               if ( $dataItems ) {
+                       $li_data .= "data=\"" . implode(",", $dataItems) . "\" 
";
+               }
+
+               $text = '';
+               if ( !$hidenode ) {
+                       $dummy_str = "REPLACE THIS TEXT";
+                       $text .= "<li id=\"$key_id\" $li_data>";
+                       if ( self::$multipleSelect) {
+                               $inputName = $input_name . "[" . $dummy_str . 
"]";
+                       } else {
+                               $inputName = $input_name;
+                       }
+                       $text .= "<input type=\"$inputType\" 
tabindex=\"$sfgTabIndex\" name=\"" . $inputName .
+                               "\" value=\"" . $node->title . "\" 
id=\"chb-$key_id\" $input_data class=\"hidden\" />";
+                       $text .= $node->title . "\n";
+               }
+               if ( array_key_exists( 'children', $node ) ) {
+                       $text .= "<ul>\n";
+                       $i = 1;
+                       foreach ( $node->children as $cat ) {
+                               $text .= self::nodeToHTML( $cat, $key_id, 
$input_name, $current_selection, false, $depth - 1, $inputType, $i++ );
+                       }
+                       $text .= "</ul>\n";
+               }
+               return $text;
+       }
+
+       public static function getParameters() {
+               $params = parent::getParameters();
+               $params[] = array(
+                       'name' => 'top category',
+                       'type' => 'string',
+                       'description' => wfMessage( 'sf_forminputs_topcategory' 
)->text()
+               );
+               $params[] = array(
+                       'name' => 'structure',
+                       'type' => 'text',
+                       'description' => wfMessage( 'sf_forminputs_structure' 
)->text()
+               );
+               $params[] = array(
+                       'name' => 'hideroot',
+                       'type' => 'boolean',
+                       'description' => wfMessage( 'sf_forminputs_hideroot' 
)->text()
+               );
+               $params[] = array(
+                       'name' => 'depth',
+                       'type' => 'int',
+                       'description' => wfMessage( 'sf_forminputs_depth' 
)->text()
+               );
+               $params[] = array(
+                       'name' => 'height',
+                       'type' => 'int',
+                       'description' => wfMessage( 'sf_forminputs_height' 
)->text()
+               );
+               $params[] = array(
+                       'name' => 'width',
+                       'type' => 'int',
+                       'description' => wfMessage( 'sf_forminputs_width' 
)->text()
+               );
+               return $params;
+       }
+
+       /**
+        * Returns the HTML code to be included in the output page for this 
input.
+        */
+       public function getHtmlText() {
+               return self::getHTML(
+                       $this->mCurrentValue,
+                       $this->mInputName,
+                       $this->mIsMandatory,
+                       $this->mIsDisabled,
+                       $this->mOtherArgs
+               );
+       }
+
+       /**
+        * Creates a Title object from a user provided (and thus unsafe) string
+        * @param $title string
+        * @return null|Title
+        */
+       static function makeTitle( $title ) {
+               $title = trim( $title );
+
+               if ( strval( $title ) === '' ) {
+                       return null;
+               }
+
+               # The title must be in the category namespace
+               # Ignore a leading Category: if there is one
+               $t = Title::newFromText( $title, NS_CATEGORY );
+               if ( !$t || $t->getNamespace() != NS_CATEGORY || 
$t->getInterWiki() != '' ) {
+                       // If we were given something like "Wikipedia:Foo" or 
"Template:",
+                       // try it again but forced.
+                       $title = "Category:$title";
+                       $t = Title::newFromText( $title );
+               }
+               return $t;
+       }
+
+}
+
+/**
+ * A class that defines a tree - and can populate it based on either
+ * wikitext or a category structure.
+ *
+ * @author Yaron Koren
+ */
+class SFTree {
+       var $title, $children;
+
+       function __construct( $curTitle ) {
+               $this->title = $curTitle;
+               $this->children = array();
+       }
+
+       /**
+        * Turn a manually-created "structure", defined as a bulleted list
+        * in wikitext, into a tree. This is based on the concept originated
+        * by the "menuselect" input type in the Semantic Forms Inputs
+        * extension - the difference here is that the text is manually
+        * parsed, instead of being run through the MediaWiki parser.
+        */
+       public static function newFromWikiText( $wikitext ) {
+               // The top "leaf", called "Top" will be ignored, because
+               // we'll set "hideroot" to true.
+               $fullTree = new SFTree( 'Top' );
+               $lines = explode( "\n", $wikitext );
+               foreach ( $lines as $line ) {
+                       $numBullets = 0;
+                       for ( $i = 0; $i < strlen( $line ) && $line[$i] == '*'; 
$i++ ) {
+                               $numBullets++;
+                       }
+                       if ( $numBullets == 0 ) continue;
+                       $lineText = trim( substr( $line, $numBullets ) );
+                       $curParentNode = $fullTree->getLastNodeForLevel( 
$numBullets );
+                       $curParentNode->children[] = new SFTree( $lineText );
+               }
+               return $fullTree;
+       }
+
+       function getLastNodeForLevel( $level ) {
+               if ( $level <= 1 || count( $this->children ) == 0 ) {
+                       return $this;
+               }
+               $lastNodeOnCurLevel = end( $this->children );
+               return $lastNodeOnCurLevel->getLastNodeForLevel( $level - 1 );
+       }
+
+       /**
+        * @param $top_category String
+        * @return mixed
+        */
+       static function newFromTopCategory( $top_category ) {
+               $sfTree = new SFTree( $top_category );
+               $defaultDepth = 20;
+               $sfTree->populateChildren( $defaultDepth );
+               return $sfTree;
+       }
+
+       /**
+        * Recuresive function to populate a tree based on category information.
+        */
+       private function populateChildren( $depth ) {
+               if ( $depth == 0 ) return;
+               $subcats = self::getSubcategories( $this->title );
+               foreach( $subcats as $subcat ) {
+                       $childTree = new SFTree( $subcat );
+                       $childTree->populateChildren( $depth - 1 );
+                       $this->children[] = $childTree;
+               }
+       }
+
+       /**
+        * Gets all the subcategories of the passed-in category.
+        *
+        * @TODO This might not belong in this class.
+        *
+        * @param Title $title
+        * @return array
+        */
+       private static function getSubcategories( $categoryName ) {
+               $dbr = wfGetDb( DB_SLAVE );
+
+               $tables = array( 'page', 'categorylinks' );
+               $fields = array( 'page_id', 'page_namespace', 'page_title',
+                       'page_is_redirect', 'page_len', 'page_latest', 'cl_to',
+                       'cl_from' );
+               $where = array();
+               $joins = array();
+               $options = array( 'ORDER BY' => 'cl_type, cl_sortkey' );
+
+               $joins['categorylinks'] = array( 'JOIN', 'cl_from = page_id' );
+               $where['cl_to'] = str_replace( ' ', '_', $categoryName );
+               $options['USE INDEX']['categorylinks'] = 'cl_sortkey';
+
+               $tables = array_merge( $tables, array( 'category' ) );
+               $fields = array_merge( $fields, array( 'cat_id', 'cat_title', 
'cat_subcats', 'cat_pages', 'cat_files' ) );
+               $joins['category'] = array( 'LEFT JOIN', array( 'cat_title = 
page_title', 'page_namespace' => NS_CATEGORY ) );
+
+               $res = $dbr->select( $tables, $fields, $where, __METHOD__, 
$options, $joins );
+               $subcats = array();
+
+               foreach ( $res as $row ) {
+                       $t = Title::newFromRow( $row );
+                       if ( $t->getNamespace() == NS_CATEGORY ) {
+                               $subcats[] = $t->getText();
+                       }
+               }
+               return $subcats;
+       }
+
+}
diff --git a/languages/SF_Messages.php b/languages/SF_Messages.php
index c2ff82a..fa9062b 100644
--- a/languages/SF_Messages.php
+++ b/languages/SF_Messages.php
@@ -76,7 +76,8 @@
        'sf_forminputs_showonselect'         => 'Page elements to display only 
if certain values are selected (example: "value1=>div1;value2=>div2")',
        'sf_forminputs_listboxsize'          => 'The height of this listbox, in 
rows',
        'sf_forminputs_includetimezone'      => 'Include an input for the time 
zone',
-       'sf_forminputs_topcategory'          => 'The parent category of this 
set of categories (required)',
+       'sf_forminputs_topcategory'          => 'The parent category of a set 
of categories',
+       'sf_forminputs_structure'            => 'A manual list of values, done 
as an unordered list of values in wikitext',
        'sf_forminputs_hideroot'             => 'Hide the parent category',
        'sf_forminputs_depth'                => 'The number of levels of 
categories to show initially',
        'sf_forminputs_height'               => 'The height of this input, in 
pixels',
@@ -300,6 +301,12 @@
 * {{msg-mw|Sf createform hiddensection}}',
        'sf_forminputs_uploadable' => 'This is a message describing a checkbox. 
The message included within this message is: {{msg-mw|upload}}',
        'sf_forminputs_listboxsize' => 'See [[wikipedia:list box|listbox]] for 
an listbox example',
+       'sf_forminputs_structure' => 'This describes one parameter to the 
"tree" form input, that takes in wikitext and sets the structure. The wikitext 
that should be entered for this parameter should look something like:
+* A
+** B
+** C
+*** D
+* E',
        'createform' => '{{doc-special|CreateForm}}
 Title below, create link. If you enter, include ".".',
        'sf-createform-with-name' => 'Used as page title. Parameters:
diff --git a/libs/ext.dynatree.js b/libs/ext.dynatree.js
index 8ffc821..f53acb9 100644
--- a/libs/ext.dynatree.js
+++ b/libs/ext.dynatree.js
@@ -1,7 +1,7 @@
 $(function () {
        // Attach the dynatree widget to an existing <div id="tree"> element
        // and pass the tree options as an argument to the dynatree() function:
-       var nodeSelection = $("div[id*=categoryinput]");
+       var nodeSelection = $("div[id*=treeinput]");
     nodeSelection.each (function (index) {
         var node = nodeSelection.eq(index);
         var selectMode = 2;

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: If4ba1af81205591303eb5883e21b1299005248ce
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/SemanticForms
Gerrit-Branch: master
Gerrit-Owner: Yaron Koren <yaro...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to