Index: trunk/extensions/CategoryTree/CategoryTree.js |
— | — | @@ -34,7 +34,7 @@ |
35 | 35 | lnk.title= categoryTreeCollapseMsg; |
36 | 36 | lnk.onclick= function() { categoryTreeCollapseNode(cat, options, lnk) } |
37 | 37 | |
38 | | - if (lnk.className != "CategoryTreeLoaded") { |
| 38 | + if (!lnk.className.match(/(^| )CategoryTreeLoaded($| )/)) { |
39 | 39 | categoryTreeLoadNode(cat, options, lnk, div); |
40 | 40 | } |
41 | 41 | } |
— | — | @@ -58,40 +58,52 @@ |
59 | 59 | categoryTreeLoadChildren(cat, options, div) |
60 | 60 | } |
61 | 61 | |
62 | | - function categoryTreeEncodeOptions(options) { |
63 | | - var opt = ""; |
| 62 | + function categoryTreeEncodeValue(value) { |
| 63 | + switch (typeof value) { |
| 64 | + case 'function': |
| 65 | + throw new Error("categoryTreeEncodeValue encountered a function"); |
| 66 | + break; |
64 | 67 | |
65 | | - for (k in options) { |
66 | | - v = options[k]; |
67 | | - |
68 | | - switch (typeof v) { |
69 | 68 | case 'string': |
70 | | - v = '"' + v.replace(/([\\"'])/g, "\\$1") + '"'; |
| 69 | + s = '"' + value.replace(/([\\"'])/g, "\\$1") + '"'; |
71 | 70 | break; |
72 | 71 | |
73 | 72 | case 'number': |
74 | 73 | case 'boolean': |
75 | 74 | case 'null': |
76 | | - v = String(v); |
| 75 | + s = String(value); |
77 | 76 | break; |
78 | 77 | |
79 | 78 | case 'object': |
80 | | - if ( !v ) v = 'null'; |
81 | | - else throw new Error("categoryTreeLoadChildren can not encode complex types"); |
| 79 | + if ( !value ) { |
| 80 | + s = 'null'; |
| 81 | + } |
| 82 | + else if (typeof value.length === 'number' && !(value.propertyIsEnumerable('length'))) { |
| 83 | + s = ''; |
| 84 | + for (i = 0; i<value.length; i++) { |
| 85 | + v = value[i]; |
| 86 | + if ( s!='' ) s += ', '; |
| 87 | + s += categoryTreeEncodeValue( v ); |
| 88 | + } |
| 89 | + s = '[' + s + ']'; |
| 90 | + } |
| 91 | + else { |
| 92 | + s = ''; |
| 93 | + for (k in value) { |
| 94 | + v = value[k]; |
| 95 | + if ( s!='' ) s += ', '; |
| 96 | + s += categoryTreeEncodeValue( k ); |
| 97 | + s += ': '; |
| 98 | + s += categoryTreeEncodeValue( v ); |
| 99 | + } |
| 100 | + s = '{' + s + '}'; |
| 101 | + } |
82 | 102 | break; |
83 | | - |
84 | 103 | default: |
85 | | - throw new Error("categoryTreeLoadChildren encountered strange variable type " + (typeof v)); |
| 104 | + throw new Error("categoryTreeEncodeValue encountered strange variable type " + (typeof value)); |
86 | 105 | } |
87 | 106 | |
88 | | - if ( opt != "" ) opt += ", "; |
89 | | - opt += k; |
90 | | - opt += ":"; |
91 | | - opt += v; |
92 | | - } |
93 | | - |
94 | | - opt = "{"+opt+"}"; |
95 | | - return opt; |
| 107 | + return s; |
96 | 108 | } |
97 | 109 | |
98 | 110 | function categoryTreeLoadChildren(cat, options, div) { |
— | — | @@ -130,6 +142,6 @@ |
131 | 143 | div.innerHTML= result; |
132 | 144 | } |
133 | 145 | |
134 | | - var opt = categoryTreeEncodeOptions(options); |
| 146 | + var opt = categoryTreeEncodeValue(options); |
135 | 147 | sajax_do_call( "efCategoryTreeAjaxWrapper", [cat, opt, 'json'] , f ); |
136 | 148 | } |
Index: trunk/extensions/CategoryTree/CategoryTreeFunctions.php |
— | — | @@ -33,12 +33,60 @@ |
34 | 34 | $this->mOptions['mode'] = self::decodeMode( $this->mOptions['mode'] ); |
35 | 35 | $this->mOptions['hideprefix'] = self::decodeHidePrefix( $this->mOptions['hideprefix'] ); |
36 | 36 | $this->mOptions['showcount'] = self::decodeBoolean( $this->mOptions['showcount'] ); |
| 37 | + $this->mOptions['namespaces'] = self::decodeNamespaces( $this->mOptions['namespaces'] ); |
| 38 | + |
| 39 | + if ( $this->mOptions['namespaces'] ) { |
| 40 | + # automatically adjust mode to match namespace filter |
| 41 | + if ( sizeof( $this->mOptions['namespaces'] ) === 1 |
| 42 | + && $this->mOptions['namespaces'][0] == NS_CATEGORY ) { |
| 43 | + $this->mOptions['mode'] = CT_MODE_CATEGORIES; |
| 44 | + } else if ( !in_array( NS_IMAGE, $this->mOptions['namespaces'] ) ) { |
| 45 | + $this->mOptions['mode'] = CT_MODE_PAGES; |
| 46 | + } else { |
| 47 | + $this->mOptions['mode'] = CT_MODE_ALL; |
| 48 | + } |
| 49 | + } |
37 | 50 | } |
38 | 51 | |
39 | 52 | function getOption( $name ) { |
40 | 53 | return $this->mOptions[$name]; |
41 | 54 | } |
42 | 55 | |
| 56 | + static function decodeNamespaces( $nn ) { |
| 57 | + global $wgContLang; |
| 58 | + |
| 59 | + if ( !$nn ) |
| 60 | + return false; |
| 61 | + |
| 62 | + if ( !is_array($nn) ) |
| 63 | + $nn = preg_split( '![\s#:|]+!', $nn ); |
| 64 | + |
| 65 | + $namespaces = array(); |
| 66 | + |
| 67 | + foreach ( $nn as $n ) { |
| 68 | + if ( is_int( $n ) ) { |
| 69 | + $ns = $n; |
| 70 | + } |
| 71 | + else { |
| 72 | + $n = trim( $n ); |
| 73 | + if ( $n === '' ) continue; |
| 74 | + |
| 75 | + $lower = strtolower( $n ); |
| 76 | + |
| 77 | + if ( is_numeric($n) ) $ns = (int)$n; |
| 78 | + elseif ( $n == '-' || $n == '_' || $n == '*' || $lower == 'main' ) $ns = NS_MAIN; |
| 79 | + else $ns = $wgContLang->getNsIndex( $n ); |
| 80 | + } |
| 81 | + |
| 82 | + if ( is_int( $ns ) ) { |
| 83 | + $namespaces[] = $ns; |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + sort( $namespaces ); # get elements into canonical order |
| 88 | + return $namespaces; |
| 89 | + } |
| 90 | + |
43 | 91 | static function decodeMode( $mode ) { |
44 | 92 | global $wgCategoryTreeDefaultOptions; |
45 | 93 | |
— | — | @@ -199,6 +247,7 @@ |
200 | 248 | $key = ""; |
201 | 249 | |
202 | 250 | foreach ( $this->mOptions as $k => $v ) { |
| 251 | + if ( is_array( $v ) ) $v = implode( '|', $v ); |
203 | 252 | $key .= $k . ':' . $v . ';'; |
204 | 253 | } |
205 | 254 | |
— | — | @@ -341,11 +390,19 @@ |
342 | 391 | |
343 | 392 | |
344 | 393 | $mode = $this->getOption('mode'); |
| 394 | + $namespaces = $this->getOption('namespaces'); |
345 | 395 | |
346 | | - #namespace filter. Should be configurable |
347 | | - if ( $mode == CT_MODE_ALL ) $nsmatch = ''; |
348 | | - else if ( $mode == CT_MODE_PAGES ) $nsmatch = ' AND cat.page_namespace != ' . NS_IMAGE; |
349 | | - else $nsmatch = ' AND cat.page_namespace = ' . NS_CATEGORY; |
| 396 | + #namespace filter. |
| 397 | + if ( $namespaces ) { |
| 398 | + #NOTE: we assume that the $namespaces array contains only integers! |
| 399 | + if ( sizeof( $namespaces ) === 1 ) $nsmatch = ' AND cat.page_namespace = ' . $namespaces[0] . ' '; |
| 400 | + else $nsmatch = ' AND cat.page_namespace IN ( ' . implode( ', ', $namespaces ) . ') '; |
| 401 | + } |
| 402 | + else { |
| 403 | + if ( $mode == CT_MODE_ALL ) $nsmatch = ''; |
| 404 | + else if ( $mode == CT_MODE_PAGES ) $nsmatch = ' AND cat.page_namespace != ' . NS_IMAGE; |
| 405 | + else $nsmatch = ' AND cat.page_namespace = ' . NS_CATEGORY; |
| 406 | + } |
350 | 407 | |
351 | 408 | #additional stuff to be used if "transaltion" by interwiki-links is desired |
352 | 409 | $transFields = ''; |
— | — | @@ -551,13 +608,15 @@ |
552 | 609 | |
553 | 610 | $linkattr[ 'class' ] = "CategoryTreeToggle"; |
554 | 611 | |
555 | | - if ( $count === 0 ) { |
| 612 | + /*if ( $count === 0 ) { |
556 | 613 | $tag = 'span'; |
557 | 614 | $txt = wfMsgNoTrans( 'categorytree-empty-bullet' ); |
558 | 615 | } |
559 | | - else if ( $children == 0 || $loadchildren ) { |
| 616 | + else*/ |
| 617 | + if ( $children == 0 || $loadchildren ) { |
560 | 618 | $tag = 'a'; |
561 | | - $txt = wfMsgNoTrans( 'categorytree-expand-bullet' ); |
| 619 | + if ( $count === 0 ) $txt = wfMsgNoTrans( 'categorytree-empty-bullet' ); |
| 620 | + else $txt = wfMsgNoTrans( 'categorytree-expand-bullet' ); |
562 | 621 | $linkattr[ 'onclick' ] = "this.href='javascript:void(0)'; categoryTreeExpandNode('".Xml::escapeJsString($key)."',".$this->getOptionsAsJsStructure().",this);"; |
563 | 622 | # Don't load this message for ajax requests, so that we don't have to initialise $wgLang |
564 | 623 | $linkattr[ 'title' ] = $this->mIsAjaxRequest ? '##LOAD##' : wfMsgNoTrans('categorytree-expand'); |
— | — | @@ -593,7 +652,19 @@ |
594 | 653 | $s .= "\n\t\t"; |
595 | 654 | $s .= Xml::openElement( 'div', array( 'class' => 'CategoryTreeChildren', 'style' => $children > 0 ? "display:block" : "display:none" ) ); |
596 | 655 | |
597 | | - if ( $children > 0 && !$loadchildren) $s .= $this->renderChildren( $title, $children ); |
| 656 | + if ( $ns == NS_CATEGORY && $children > 0 && !$loadchildren) { |
| 657 | + $children = $this->renderChildren( $title, $children ); |
| 658 | + if ( $children == '' ) { |
| 659 | + $s .= Xml::openElement( 'i', array( 'class' => 'CategoryTreeNotice' ) ); |
| 660 | + if ( $mode == CT_MODE_CATEGORIES ) $s .= wfMsgExt( 'categorytree-no-subcategories', 'parsemag'); |
| 661 | + else if ( $mode == CT_MODE_PAGES ) $s .= wfMsgExt( 'categorytree-no-pages', 'parsemag'); |
| 662 | + else $s .= wfMsgExt( 'categorytree-nothing-found', 'parsemag'); |
| 663 | + $s .= Xml::closeElement( 'i' ); |
| 664 | + } else { |
| 665 | + $s .= $children; |
| 666 | + } |
| 667 | + } |
| 668 | + |
598 | 669 | $s .= Xml::closeElement( 'div' ); |
599 | 670 | $s .= Xml::closeElement( 'div' ); |
600 | 671 | |
Index: trunk/extensions/CategoryTree/CategoryTree.php |
— | — | @@ -67,7 +67,7 @@ |
68 | 68 | $wgCategoryTreeDefaultOptions['mode'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk |
69 | 69 | $wgCategoryTreeDefaultOptions['hideprefix'] = NULL; # will be set to $wgCategoryTreeDefaultMode in efCategoryTree(); compatibility quirk |
70 | 70 | $wgCategoryTreeDefaultOptions['showcount'] = false; |
71 | | -#TODO: hideprefix: always, never, catonly, catonly_if_onlycat |
| 71 | +$wgCategoryTreeDefaultOptions['namespaces'] = false; # false means "no filter" |
72 | 72 | |
73 | 73 | $wgCategoryTreeCategoryPageMode = CT_MODE_CATEGORIES; |
74 | 74 | $wgCategoryTreeCategoryPageOptions = array(); #Options to be used for category pages |
— | — | @@ -115,7 +115,6 @@ |
116 | 116 | $wgHooks['ArticleFromTitle'][] = 'efCategoryTreeArticleFromTitle'; |
117 | 117 | $wgHooks['LanguageGetMagic'][] = 'efCategoryTreeGetMagic'; |
118 | 118 | |
119 | | - |
120 | 119 | /** |
121 | 120 | * register Ajax function |
122 | 121 | */ |