Wiki source code of Administration
Last modified by Leon Poon on 2025/05/12 14:26
Show last authors
| author | version | line-number | content |
|---|---|---|---|
| 1 | {{include reference="XWiki.ConfigurableClassMacros" /}} | ||
| 2 | |||
| 3 | {{velocity output="false"}} | ||
| 4 | #if ($request.xaction == 'switchContext') | ||
| 5 | $response.sendRedirect($request.target) | ||
| 6 | #stop | ||
| 7 | #end | ||
| 8 | |||
| 9 | #set ($adminAction = 'admin') | ||
| 10 | #set ($crtCategoryId = "$!{request.category}") | ||
| 11 | #if ($crtCategoryId != '') | ||
| 12 | #set ($crtCategoryId = $numbertool.toNumber($crtCategoryId).intValue()) | ||
| 13 | #end | ||
| 14 | #set ($crtSectionId = "$!{request.section}") | ||
| 15 | |||
| 16 | ## | ||
| 17 | ## Admin menu map | ||
| 18 | ## | ||
| 19 | ## displayInSection: menu.name | sectionOrder: 200 | page: Menu.MenuConfigurationSection | ||
| 20 | ## displayInSection: panels.applications | sectionOrder: 400 | page: PanelsCode.ApplicationsPanelConfigurable | ||
| 21 | ## displayInSection: panels.navigation | sectionOrder: 500 | page: PanelsCode.NavigationConfigurationSection | ||
| 22 | #set($adminMenu = [ | ||
| 23 | { | ||
| 24 | 'id' : 'lf', | ||
| 25 | 'icon': 'columns', | ||
| 26 | 'displayBeforeCategory': 'content', | ||
| 27 | 'children': [ | ||
| 28 | {'id' : 'Themes', 'perSpace' : true, 'order' : 100}, | ||
| 29 | {'id' : 'Panels.PanelWizard', 'perSpace' : true, 'order' : 300}, | ||
| 30 | {'id' : 'Presentation', 'perSpace' : true, 'order' : 600} | ||
| 31 | ] | ||
| 32 | }, | ||
| 33 | { | ||
| 34 | 'id' : 'usersgroups', | ||
| 35 | 'icon': 'group', | ||
| 36 | 'displayBeforeCategory': 'extensionmanager', | ||
| 37 | 'children': [ | ||
| 38 | {'id' : 'Users', 'order' : 100}, | ||
| 39 | {'id' : 'Groups', 'order' : 200}, | ||
| 40 | {'id' : 'Rights', 'perSpace' : false, 'order' : 300}, | ||
| 41 | {'id' : 'PageAndChildrenRights', 'perSpace' : true, 'order' : 300, 'global': false}, | ||
| 42 | {'id' : 'PageRights', 'perSpace' : true, 'order' : 350, 'global': false}, | ||
| 43 | {'id' : 'UserProfile', 'order' : 400}, | ||
| 44 | {'id' : 'Registration', 'order' : 500} | ||
| 45 | ] | ||
| 46 | }, | ||
| 47 | { | ||
| 48 | 'id' : 'other', | ||
| 49 | 'icon': 'wrench', | ||
| 50 | 'children' : [] | ||
| 51 | } | ||
| 52 | ]) | ||
| 53 | |||
| 54 | ## | ||
| 55 | ## Fill in the list of custom applications to configure | ||
| 56 | ## | ||
| 57 | #findCustomSectionsToConfigure($adminMenu) | ||
| 58 | ## | ||
| 59 | ## Filter only the sections that are valid in the context | ||
| 60 | ## | ||
| 61 | #set ($categoriesToRemove = []) | ||
| 62 | #foreach ($category in $adminMenu) | ||
| 63 | #set ($sectionsToRemove = []) | ||
| 64 | #foreach ($section in $category.children) | ||
| 65 | #if ($editor == 'spaceadmin' && !$section.perSpace) | ||
| 66 | #set ($discard = $sectionsToRemove.add($section)) | ||
| 67 | #elseif ($editor == 'globaladmin' && "$!section.global" == "false") | ||
| 68 | ## For retro-compatibility, all sections are global unless the 'global' field is explicitly marked as false | ||
| 69 | #set ($discard = $sectionsToRemove.add($section)) | ||
| 70 | #end | ||
| 71 | #end | ||
| 72 | #set ($discard = $category.children.removeAll($sectionsToRemove)) | ||
| 73 | #if ($category.children.size() == 0) | ||
| 74 | #set ($discard = $categoriesToRemove.add($category)) | ||
| 75 | #end | ||
| 76 | #end | ||
| 77 | #set ($discard = $adminMenu.removeAll($categoriesToRemove)) | ||
| 78 | #if ("$!crtCategoryId" != '' && $crtCategoryId >= $adminMenu.size()) | ||
| 79 | #set ($crtCategoryId = '') | ||
| 80 | #end | ||
| 81 | |||
| 82 | ## | ||
| 83 | ## Prepare the Admin menu map for processing | ||
| 84 | ## | ||
| 85 | #set ($filteredAdminMenu = []) | ||
| 86 | #set ($crtSection = $NULL) | ||
| 87 | #set ($crtCategory = $NULL) | ||
| 88 | #foreach ($category in $adminMenu) | ||
| 89 | ## "Standard" URLs and icons for categories | ||
| 90 | #set ($category.url = $xwiki.getURL($currentDoc, $adminAction, "category=${mathtool.sub($foreach.count, 1)}")) | ||
| 91 | #if ($xwiki.getDocument('XWiki.AdminSheet').getAttachment("${category.id}.png")) | ||
| 92 | #set ($category.iconReference = "XWiki.AdminSheet@${category.id}.png") | ||
| 93 | #else | ||
| 94 | #set ($category.iconReference = "XWiki.ConfigurableClass@DefaultAdminSectionIcon.png") | ||
| 95 | #end | ||
| 96 | #set ($category.description = $services.localization.render("admin.${category.id}.description").trim()) | ||
| 97 | #set ($category.cssClass = "${category.id}Icon") | ||
| 98 | #set ($category.name = $services.localization.render("admin.${category.id}").trim()) | ||
| 99 | #if ("$!{crtCategoryId}" != '' && $foreach.count == $mathtool.add($crtCategoryId, 1)) | ||
| 100 | #set ($crtCategory = $category) | ||
| 101 | #end | ||
| 102 | ## | ||
| 103 | ## Process each admin section | ||
| 104 | #set ($filteredCategoryChildren = []) | ||
| 105 | #foreach ($section in $category.children) | ||
| 106 | #if ($xwiki.exists($section.id) || $xwiki.exists("XWiki.Admin${section.id}Sheet")) | ||
| 107 | #if ($crtSectionId == $section.id) | ||
| 108 | #set ($crtSection = $section) | ||
| 109 | #set ($crtCategory = $category) | ||
| 110 | #end | ||
| 111 | #set ($section.iconReference = '') | ||
| 112 | #if ($section.id.indexOf('.') > 0) | ||
| 113 | #set ($sectionDoc = $xwiki.getDocument($section.id)) | ||
| 114 | #set ($section.name = $sectionDoc.getDisplayTitle()) | ||
| 115 | #if ($sectionDoc.getAttachment('icon.png')) | ||
| 116 | #set ($section.iconReference = "${sectionDoc}@icon.png") | ||
| 117 | #else | ||
| 118 | #set ($section.iconReference = 'XWiki.ConfigurableClass@DefaultAdminSectionIcon.png') | ||
| 119 | #end | ||
| 120 | #else | ||
| 121 | #set ($sectionDoc = $xwiki.getDocument('XWiki.AdminSheet')) | ||
| 122 | #set ($section.name = $services.localization.render("admin.${section.id.toLowerCase()}")) | ||
| 123 | #set ($iconName = "${section.id.toLowerCase()}.png") | ||
| 124 | #if ($sectionDoc.getAttachment($iconName)) | ||
| 125 | #set ($section.iconReference = "${sectionDoc}@${iconName}") | ||
| 126 | #else | ||
| 127 | #set ($section.iconReference = 'XWiki.ConfigurableClass@DefaultAdminSectionIcon.png') | ||
| 128 | #end | ||
| 129 | #end | ||
| 130 | #set ($query = "editor=$escapetool.url(${editor})§ion=$escapetool.url(${section.id})") | ||
| 131 | #if ($editor != 'globaladmin') | ||
| 132 | #set ($query = $query + "&space=$escapetool.url(${currentSpace})") | ||
| 133 | #end | ||
| 134 | #set ($action = "$!{section.action}") | ||
| 135 | #if ($action == '') | ||
| 136 | #set ($action = $adminAction) | ||
| 137 | #end | ||
| 138 | #set ($section.url = $xwiki.getURL($currentDoc, $action, $query)) | ||
| 139 | #set ($key = "admin.${section.id.toLowerCase()}.description") | ||
| 140 | #if ($services.localization.get($key)) | ||
| 141 | #set ($section.description = $services.localization.render($key)) | ||
| 142 | #end | ||
| 143 | #set ($discard = $filteredCategoryChildren.add($section)) | ||
| 144 | #elseif ($section.configurable) | ||
| 145 | #if ($section.readOnly) | ||
| 146 | #set ($section.cssClass = 'readOnly') | ||
| 147 | #end | ||
| 148 | #if ($crtSectionId == $section.id) | ||
| 149 | #set ($crtSection = $section) | ||
| 150 | #set ($crtCategory = $category) | ||
| 151 | #end | ||
| 152 | #set ($discard = $filteredCategoryChildren.add($section)) | ||
| 153 | #end | ||
| 154 | #end | ||
| 155 | #set ($category.children = $filteredCategoryChildren) | ||
| 156 | #if ($filteredCategoryChildren.size() > 0) | ||
| 157 | #set ($discard = $filteredAdminMenu.add($category)) | ||
| 158 | #end | ||
| 159 | #end | ||
| 160 | #set ($adminMenu = $filteredAdminMenu) | ||
| 161 | |||
| 162 | ## Mark the active category/section. We use this flag when displaying the menu. | ||
| 163 | #if ($crtCategory) | ||
| 164 | #set ($crtCategory.active = true) | ||
| 165 | #if ($crtSection) | ||
| 166 | #set ($crtSection.active = true) | ||
| 167 | #else | ||
| 168 | #set ($crtSectionId = $NULL) | ||
| 169 | #end | ||
| 170 | #else | ||
| 171 | #set ($crtCategoryId = $NULL) | ||
| 172 | #end | ||
| 173 | |||
| 174 | #** | ||
| 175 | * Displays the sections from an administration category | ||
| 176 | * | ||
| 177 | * Expected format: | ||
| 178 | * sections = vector of items | ||
| 179 | * item = map with the following fields: | ||
| 180 | * 'id' : mandatory | ||
| 181 | * 'name' : the text displayed for the corresponding menu item; | ||
| 182 | * optional, defaults to | ||
| 183 | * $services.localization.render("$!{translationPrefix}${item.id}") | ||
| 184 | * 'description' : the description displayed for the corresponding section; | ||
| 185 | * optional | ||
| 186 | * 'link' : the "action" of the menu item; mandatory | ||
| 187 | * 'cssClass' : a specific css class for the menu item for custom | ||
| 188 | * styling; optional, defaults to '' | ||
| 189 | * | ||
| 190 | * @param $sections the sections list, in the format described above | ||
| 191 | * @param $translationPrefix the translation prefix added to the id of each | ||
| 192 | * item, in order to generate the name and description; ignored when | ||
| 193 | * name or description are specified | ||
| 194 | *# | ||
| 195 | #macro(admin_displayCategory $sections $translationPrefix) | ||
| 196 | (% class="admin-category" %) | ||
| 197 | #set ($sortedSections = []) | ||
| 198 | #sortCollectionOfMapsByField($sections, 'order', 9999, 'asc', $sortedSections) | ||
| 199 | #foreach ($section in $sortedSections) | ||
| 200 | * [[[[image:${section.iconReference}]] **${section.name}**>>path:${section.url}]] (% class="description" %)$!{section.description} | ||
| 201 | #end | ||
| 202 | #end | ||
| 203 | |||
| 204 | |||
| 205 | #** | ||
| 206 | * Displays the administration categories | ||
| 207 | * | ||
| 208 | * Expected format: | ||
| 209 | * sections = vector of items | ||
| 210 | * item = map with the following fields: | ||
| 211 | * 'id' : mandatory | ||
| 212 | * 'name' : the text displayed for the corresponding menu item; | ||
| 213 | * optional, defaults to | ||
| 214 | * $services.localization.render("$!{translationPrefix}${item.id}") | ||
| 215 | * 'description' : the description displayed for the corresponding section; | ||
| 216 | * optional | ||
| 217 | * 'link' : the "action" of the menu item; mandatory | ||
| 218 | * 'cssClass' : a specific css class for the menu item for custom | ||
| 219 | * styling; optional, defaults to '' | ||
| 220 | * | ||
| 221 | * @param $sections the sections list, in the format described above | ||
| 222 | * @param $translationPrefix the translation prefix added to the id of each | ||
| 223 | * item, in order to generate the name and description; ignored when | ||
| 224 | * name or description are specified | ||
| 225 | *# | ||
| 226 | #macro(admin_displayCategories $adminMenu $translationPrefix) | ||
| 227 | (% class="admin-category" %) | ||
| 228 | #foreach ($category in $adminMenu) | ||
| 229 | * [[[[image:${category.iconReference}]] **${category.name}**>>path:${category.url}]] (% class="description" %)$!{category.description} | ||
| 230 | #end | ||
| 231 | #end | ||
| 232 | |||
| 233 | #macro (verticalNavigation $menu $options) | ||
| 234 | {{html clean="false"}} | ||
| 235 | <nav id="$!options.id" class="panel-group $!options.cssClass" | ||
| 236 | aria-label="$escapetool.xml($services.localization.render('administration.menu.label'))"> | ||
| 237 | <div class="panel xform"> | ||
| 238 | <label for="adminsearchmenu" class="hidden">$services.localization.render('search')</label> | ||
| 239 | <input type="text" class="form-control panel-group-filter" autocomplete="off" id="adminsearchmenu" | ||
| 240 | placeholder="$escapetool.xml($services.localization.render('administration.menu.search.hint'))" | ||
| 241 | ## Disable the search input initially until the JavaScript code that handles the search is ready. | ||
| 242 | disabled="disabled" /> | ||
| 243 | </div> | ||
| 244 | #foreach ($item in $menu) | ||
| 245 | #verticalNavigationItem($item $options) | ||
| 246 | #end | ||
| 247 | <div class="panel panel-default noitems hidden"> | ||
| 248 | <div class="panel-heading collapsed"> | ||
| 249 | $escapetool.xml($services.localization.render('administration.menu.search.noResults')) | ||
| 250 | </div> | ||
| 251 | </div> | ||
| 252 | </nav> | ||
| 253 | {{/html}} | ||
| 254 | #end | ||
| 255 | |||
| 256 | #macro (verticalNavigationItem $item $options) | ||
| 257 | #set ($escapedId = $escapetool.xml($item.id)) | ||
| 258 | #set ($name = "$!item.name") | ||
| 259 | #if ($name == '') | ||
| 260 | #set ($name = $services.localization.render("$!options.translationPrefix$item.id")) | ||
| 261 | #end | ||
| 262 | #set ($isActive = $item.active == true) | ||
| 263 | #set ($hasChildren = $item.children && $item.children.size() > 0) | ||
| 264 | #if ($hasChildren) | ||
| 265 | #set ($children = []) | ||
| 266 | #sortCollectionOfMapsByField($item.children, 'order', 99999, 'asc', $children) | ||
| 267 | <div class="panel panel-default"> | ||
| 268 | <a class="panel-heading#if (!$isActive) collapsed#end" id="panel-heading-$escapedId" | ||
| 269 | href="$!item.url" data-toggle="collapse"#if ("$!options.id" != '') data-parent="#$options.id" #end | ||
| 270 | data-target="#panel-body-$escapedId" aria-expanded="$isActive" aria-controls="panel-body-$escapedId" | ||
| 271 | title="$!escapetool.xml($item.description)"> | ||
| 272 | <span>$!services.icon.renderHTML($item.icon)$escapetool.xml($name)</span> | ||
| 273 | <div>$services.icon.renderHTML('caret-down')</div> | ||
| 274 | </a> | ||
| 275 | <section class="panel-collapse collapse#if ($isActive) in#end" id="panel-body-$escapedId" | ||
| 276 | aria-labelledby="panel-heading-$escapedId"> | ||
| 277 | <div class="list-group"> | ||
| 278 | #foreach ($child in $children) | ||
| 279 | #verticalNavigationItem($child $options) | ||
| 280 | #end | ||
| 281 | </div> | ||
| 282 | </section> | ||
| 283 | </div> | ||
| 284 | #else | ||
| 285 | <a class="list-group-item#if ($isActive) active#end" data-id="$escapedId" | ||
| 286 | href="$!item.url" title="$!escapetool.xml($item.description)" | ||
| 287 | >$!services.icon.renderHTML($item.icon)$escapetool.xml($name)</a> | ||
| 288 | #end | ||
| 289 | #end | ||
| 290 | {{/velocity}} | ||
| 291 | |||
| 292 | {{velocity}} | ||
| 293 | ##************************************************************************************************** | ||
| 294 | ## Administration Sheet, used to display a common UI for some wiki features (presentation, users, | ||
| 295 | ## groups, rights etc.) at global / space level and also for several applications. | ||
| 296 | ##************************************************************************************************** | ||
| 297 | #if($xcontext.action == 'view' && "$!request.viewer" == '') | ||
| 298 | $response.sendRedirect($xwiki.getURL($doc.getFullName(), 'admin', $request.getQueryString()))## | ||
| 299 | #else | ||
| 300 | $xwiki.jsx.use('XWiki.AdminSheet')## | ||
| 301 | ## Construct the SSX parameter map. | ||
| 302 | #set ($parameterMap = {}) | ||
| 303 | #if ($themeDoc) | ||
| 304 | #set ($discard = $parameterMap.put('colorTheme', $themeDocFullName)) | ||
| 305 | #end | ||
| 306 | $xwiki.ssx.use('XWiki.AdminSheet', $parameterMap)## | ||
| 307 | #if ("$!crtSectionId" != '' && $crtSectionId.indexOf('.') > 0 && $xwiki.exists($crtSectionId)) | ||
| 308 | #set ($sectionName = $xwiki.getDocument($crtSectionId).getDisplayTitle()) | ||
| 309 | #elseif ($crtSectionId != '' && $services.localization.get("admin.${crtSectionId.toLowerCase()}")) | ||
| 310 | #set ($sectionName = $services.localization.render("admin.${crtSectionId.toLowerCase()}")) | ||
| 311 | #elseif ("$!crtSectionId" != '') | ||
| 312 | #set ($sectionName = $crtSectionId) | ||
| 313 | #elseif ("$!crtCategoryId" != '') | ||
| 314 | #set ($sectionName = $services.localization.render("admin.$crtCategory.id")) | ||
| 315 | #elseif ($editor == 'globaladmin') | ||
| 316 | #set ($sectionName = $services.wiki.getById($xcontext.database).prettyName) | ||
| 317 | #if ("$!sectionName" == '') | ||
| 318 | #set ($sectionName = $xcontext.database) | ||
| 319 | #end | ||
| 320 | #else | ||
| 321 | #set ($sectionName = $currentSpace) | ||
| 322 | #end | ||
| 323 | |||
| 324 | {{html}} | ||
| 325 | #template('hierarchy.vm') | ||
| 326 | {{/html}} | ||
| 327 | |||
| 328 | ## Determine the administration level. | ||
| 329 | #set ($level = '') | ||
| 330 | #if ($doc.documentReference.name == 'WebPreferences') | ||
| 331 | #set ($level = '.page') | ||
| 332 | #elseif ($doc.fullName == 'XWiki.XWikiPreferences') | ||
| 333 | #if ($xcontext.isMainWiki()) | ||
| 334 | #set ($level = '.global') | ||
| 335 | #else | ||
| 336 | #set ($level = '.wiki') | ||
| 337 | #end | ||
| 338 | #end | ||
| 339 | (% id="document-title" %)((( | ||
| 340 | = $services.localization.render("administration.sectionTitle$level", 'xwiki/2.1', [$sectionName]) = | ||
| 341 | ## Display the category/section description below the title. | ||
| 342 | #set ($categoryOrSectionId = $crtCategory.id) | ||
| 343 | #if ("$!crtSection.id" != '') | ||
| 344 | #set ($categoryOrSectionId = $crtSection.id) | ||
| 345 | #end | ||
| 346 | #set ($descriptionTranslationKey = "admin.$!{categoryOrSectionId.toLowerCase()}.description") | ||
| 347 | #if ($services.localization.get($descriptionTranslationKey)) | ||
| 348 | (% class = "noitems" %)((( | ||
| 349 | $services.localization.render($descriptionTranslationKey) | ||
| 350 | ))) | ||
| 351 | #end | ||
| 352 | |||
| 353 | ---- | ||
| 354 | ))) | ||
| 355 | |||
| 356 | #verticalNavigation($adminMenu { | ||
| 357 | 'id': 'administration-menu', | ||
| 358 | 'translationPrefix': 'admin.', | ||
| 359 | 'cssClass': 'admin-menu' | ||
| 360 | }) | ||
| 361 | |||
| 362 | ##----------------------------------------- | ||
| 363 | ## admin-page display | ||
| 364 | ##----------------------------------------- | ||
| 365 | #if(!$crtSection && !$crtCategory) | ||
| 366 | #admin_displayCategories($adminMenu) | ||
| 367 | #elseif (!$crtSection) | ||
| 368 | #admin_displayCategory($crtCategory.children) | ||
| 369 | #else | ||
| 370 | (% id="admin-page-content" %)((( | ||
| 371 | ##------------------------------------------------------------------------------------------------------------ | ||
| 372 | ## The Administration allows editing other pages from different applications inside the admin context (UI) | ||
| 373 | ##------------------------------------------------------------------------------------------------------------ | ||
| 374 | #if ($xwiki.exists("XWiki.Admin${section}Sheet")) | ||
| 375 | ## Handle known XWiki administration sections | ||
| 376 | {{include reference="XWiki.Admin${section}Sheet" /}} | ||
| 377 | #elseif ($xwiki.exists($section)) | ||
| 378 | {{html clean="false"}}#includeForm($section){{/html}} | ||
| 379 | #end | ||
| 380 | #if ($crtSection.configurable) | ||
| 381 | |||
| 382 | {{include reference="XWiki.ConfigurableClass" /}} | ||
| 383 | #end | ||
| 384 | ))) ## admin-page-content | ||
| 385 | #end | ||
| 386 | #end | ||
| 387 | {{/velocity}} |