Wiki-Quellcode von $services.localization.render('xe.admin.configurable.macros.title')
Verstecke letzte Bearbeiter
| author | version | line-number | content |
|---|---|---|---|
| |
1.1 | 1 | {{velocity output="false"}} |
| 2 | ## Constants: | ||
| 3 | #set($redirectParameter = 'xredirect') | ||
| 4 | #set($nameOfThisDocument = 'XWiki.ConfigurableClass') | ||
| 5 | |||
| 6 | |||
| 7 | #* | ||
| 8 | * Try to determine whether a document was edited by a user who has edit right on this page. This is tricky because | ||
| 9 | * documents are imported with the name XWiki.XWikiGuest who has no access to anything after import. | ||
| 10 | * | ||
| 11 | * @param theDoc - Document who's editor should be checked for edit access on this document. | ||
| 12 | *### | ||
| 13 | #macro(checkDocumentSavedByAuthorizedUser, $docToCheck, $currentDoc, $hasAccess) | ||
| 14 | ## The system is started and the only user is XWikiGuest who has admin right but gives it up when he imports the default | ||
| 15 | ## documents, we are checking to see if this looks like the guest imported the document with the first import. | ||
| 16 | #if($docToCheck.getWiki() == $xcontext.getMainWikiName() | ||
| 17 | && $docToCheck.getVersion() == '1.1' | ||
| 18 | && $docToCheck.getCreator() != $docToCheck.getContentAuthor() | ||
| 19 | && $docToCheck.getContentAuthor() == 'XWiki.XWikiGuest') | ||
| 20 | ## | ||
| 21 | #set($userToCheck = $docToCheck.getCreator()) | ||
| 22 | #else | ||
| 23 | #set($userToCheck = $docToCheck.getAuthor()) | ||
| 24 | #end | ||
| 25 | #set ($hasAccess = $NULL) | ||
| 26 | #setVariable ("$hasAccess" $xwiki.hasAccessLevel('edit', $userToCheck, $currentDoc)) | ||
| 27 | #end | ||
| 28 | |||
| 29 | |||
| 30 | #* | ||
| 31 | * Find names of documents which contain objects of the class 'XWiki.ConfigurableClass' | ||
| 32 | * | ||
| 33 | * @param $section - String - Look for apps which specify that they should be configured in this section, | ||
| 34 | * if null or "" then returns them for all sections. | ||
| 35 | * | ||
| 36 | * @param $globaladmin - boolean - If true then we will look for applications which should be configured globally. | ||
| 37 | * | ||
| 38 | * @param $space - String - If not looking for apps which are configured globally, then this is the space where we | ||
| 39 | * will look for apps in. If null or "" or if $globaladmin is true, then all spaces will be | ||
| 40 | * searched. | ||
| 41 | * | ||
| 42 | * @param $outputList - List - The returns from this macro will be put in this list, passing the list as a parameter | ||
| 43 | * a safety measure because macros can't return values. | ||
| 44 | *### | ||
| 45 | #macro(findNamesOfAppsToConfigure, $section, $globaladmin, $space, $outputList) | ||
| 46 | ## We keep looking in the old configureGlobally property since we do not provide a migration for it: | ||
| 47 | ## this choice has been made to avoid any problem during the upgrade of old wikis. | ||
| 48 | ## And we are doing this look in a separate query for performance reason: adding a or statement is very bad | ||
| 49 | ## in terms of performance. This all should be improved in the future with proper caching. | ||
| 50 | ## | ||
| 51 | #set ($fromClauseWithoutGlobal = [ | ||
| 52 | 'BaseObject as obj', | ||
| 53 | 'StringProperty as category', | ||
| 54 | 'IntegerProperty as sectionOrder' | ||
| 55 | ]) | ||
| 56 | ## | ||
| 57 | #set ($fromClause = []) | ||
| 58 | #set ($discard = $fromClause.addAll($fromClauseWithoutGlobal)) | ||
| 59 | #set ($discard = $fromClause.add('StringProperty as global')) | ||
| 60 | ## | ||
| 61 | #set ($fromClauseDeprecated = []) | ||
| 62 | #set ($discard = $fromClauseDeprecated.addAll($fromClauseWithoutGlobal)) | ||
| 63 | #set ($discard = $fromClauseDeprecated.add('IntegerProperty as deprecatedGlobal')) | ||
| 64 | ## | ||
| 65 | #set ($whereClauseWithoutGlobal = [ | ||
| 66 | "obj.name = doc.fullName and obj.className = :className", | ||
| 67 | "category.id = obj.id and category.name = 'displayInCategory'", | ||
| 68 | "sectionOrder.id = obj.id and sectionOrder.name = 'sectionOrder'" | ||
| 69 | ]) | ||
| 70 | ## | ||
| 71 | #set ($whereClause = []) | ||
| 72 | #set ($discard = $whereClause.addAll($whereClauseWithoutGlobal)) | ||
| 73 | #set ($discard = $whereClause.add("global.id = obj.id and global.name = 'scope' and global.value in (:global)")) | ||
| 74 | ## | ||
| 75 | #set ($whereClauseDeprecated = []) | ||
| 76 | #set ($discard = $whereClauseDeprecated.addAll($whereClauseWithoutGlobal)) | ||
| 77 | #set ($discard = $whereClauseDeprecated.add("deprecatedGlobal.id = obj.id and deprecatedGlobal.name = 'configureGlobally' and deprecatedGlobal.value = :deprecatedGlobal")) | ||
| 78 | ## | ||
| 79 | #set ($params = {'className' : $nameOfThisDocument}) | ||
| 80 | ## Order by category and section priority, leaving empty/null category at the end, because we want to read the | ||
| 81 | ## category meta data from the first (most important) section in each category. | ||
| 82 | #set ($orderByClause = [ | ||
| 83 | "case when category.value is null or category.value = '' then 1 else 0 end", | ||
| 84 | 'category.value', | ||
| 85 | 'sectionOrder.value' | ||
| 86 | ]) | ||
| 87 | #if ($globaladmin == true) | ||
| 88 | #set ($discard = $params.put('deprecatedGlobal', 1)) | ||
| 89 | #set ($discard = $params.put('global', ['WIKI','WIKI+ALL_SPACES'])) | ||
| 90 | #else | ||
| 91 | #set ($discard = $params.put('deprecatedGlobal', 0)) | ||
| 92 | #if ("$!space" != '') | ||
| 93 | #set ($discard = $params.put('global', ['SPACE'])) | ||
| 94 | #set ($discard = $whereClause.add('doc.space = :space')) | ||
| 95 | #set ($discard = $params.put('space', $space)) | ||
| 96 | #else | ||
| 97 | #set ($discard = $params.put('global', ['ALL_SPACES','WIKI+ALL_SPACES'])) | ||
| 98 | #end | ||
| 99 | #end | ||
| 100 | #if ("$!section" != '') | ||
| 101 | #set ($discard = $fromClause.add('StringProperty as section')) | ||
| 102 | #set ($discard = $fromClauseDeprecated.add('StringProperty as section')) | ||
| 103 | #set ($discard = $whereClause.add("section.id = obj.id and section.name = 'displayInSection' and section.value = :section")) | ||
| 104 | #set ($discard = $whereClauseDeprecated.add("section.id = obj.id and section.name = 'displayInSection' and section.value = :section")) | ||
| 105 | #set ($discard = $params.put('section', $section)) | ||
| 106 | #end | ||
| 107 | #set ($statement = ', ' + $stringtool.join($fromClause, ', ') + | ||
| 108 | ' where ' + $stringtool.join($whereClause, ' and ') + | ||
| 109 | ' order by ' + $stringtool.join($orderByClause, ', ')) | ||
| 110 | #set ($statementDeprecated = ', ' + $stringtool.join($fromClauseDeprecated, ', ') + | ||
| 111 | ' where ' + $stringtool.join($whereClauseDeprecated, ' and ') + | ||
| 112 | ' order by ' + $stringtool.join($orderByClause, ', ')) | ||
| 113 | ## | ||
| 114 | #set ($deprecatedParams = {}) | ||
| 115 | #set ($discard = $deprecatedParams.putAll($params)) | ||
| 116 | #set ($discard = $deprecatedParams.remove('global')) | ||
| 117 | #set ($discard = $deprecatedParams.remove('space')) | ||
| 118 | #set ($discard = $params.remove('deprecatedGlobal')) | ||
| 119 | ## | ||
| 120 | ## We can't remove duplicates using the unique filter because the select clause will be extended with the information | ||
| 121 | ## needed by the order by clause. Thus we remove the duplicates after we get the results. | ||
| 122 | #set ($orderedSetOfAppNames = $collectiontool.orderedSet) | ||
| 123 | #set ($discard = $orderedSetOfAppNames.addAll($services.query.hql($statement).bindValues($params).execute())) | ||
| 124 | #set ($discard = $orderedSetOfAppNames.addAll($services.query.hql($statementDeprecated).bindValues($deprecatedParams).execute())) | ||
| 125 | #set ($discard = $outputList.addAll($orderedSetOfAppNames)) | ||
| 126 | #if ($globaladmin == false && "$!space" != '') | ||
| 127 | ## If we are looking for the apps of a specific space, we should also get the one configured for all spaces. | ||
| 128 | ## Note that we're doing that call at the end to avoid polluting the different velocity variables during the | ||
| 129 | ## execution. | ||
| 130 | #findNamesOfAppsToConfigure($section, false, '', $outputList) | ||
| 131 | #end | ||
| 132 | #end | ||
| 133 | |||
| 134 | #* | ||
| 135 | * Augment the $adminMenu variable with all $nameOfThisDocument (i.e. XWiki.ConfigurableClass) xobjects found on this wiki. | ||
| 136 | *### | ||
| 137 | #macro(findCustomSectionsToConfigure $adminMenu) | ||
| 138 | #set ($outputList = []) | ||
| 139 | #set ($global = ($editor == 'globaladmin')) | ||
| 140 | #findNamesOfAppsToConfigure('', $global, $currentSpace, $outputList) | ||
| 141 | #set ($sectionsByName = {}) | ||
| 142 | #set ($categoriesByName = {}) | ||
| 143 | #foreach ($category in $adminMenu) | ||
| 144 | #set ($discard = $categoriesByName.put($category.id, $category)) | ||
| 145 | #foreach ($section in $category.children) | ||
| 146 | #set ($discard = $sectionsByName.put($section.id, $section)) | ||
| 147 | #end | ||
| 148 | #end | ||
| 149 | ## | ||
| 150 | #set ($query = "editor=$escapetool.url(${editor})") | ||
| 151 | #if ($editor != 'globaladmin') | ||
| 152 | #set ($query = $query + "&space=$escapetool.url(${currentSpace})") | ||
| 153 | #end | ||
| 154 | #foreach ($appName in $outputList) | ||
| 155 | ## | ||
| 156 | ## Get the configurable application | ||
| 157 | #set ($app = $xwiki.getDocument($appName)) | ||
| 158 | ## | ||
| 159 | ## If getDocument returns null, then warn the user that they don't have view access to that application. | ||
| 160 | #if (!$app) | ||
| 161 | #set ($discard = $appsUserCannotView.add($appName)) | ||
| 162 | #end | ||
| 163 | ## | ||
| 164 | #foreach ($configurableObject in $app.getObjects($nameOfThisDocument)) | ||
| 165 | #set ($displayInCategory = $app.getValue('displayInCategory', $configurableObject)) | ||
| 166 | ## It's OK to not specify a category, in which case the app will be added to a default one (i.e. "other"). | ||
| 167 | #if ("$!displayInCategory" != '') | ||
| 168 | #if ($categoriesByName.containsKey($displayInCategory)) | ||
| 169 | ## Add a new section in this category. | ||
| 170 | #set ($appCategory = $categoriesByName.get($displayInCategory)) | ||
| 171 | #else | ||
| 172 | ## Add a new category. | ||
| 173 | #set ($key = "admin.$displayInCategory.toLowerCase()") | ||
| 174 | #set ($name = $displayInCategory) | ||
| 175 | #if ($services.localization.get($key)) | ||
| 176 | #set ($name = $services.localization.render($key)) | ||
| 177 | #end | ||
| 178 | #set ($appCategory= { | ||
| 179 | 'id': $displayInCategory, | ||
| 180 | 'name': $name, | ||
| 181 | 'children': [] | ||
| 182 | }) | ||
| 183 | #set ($discard = $categoriesByName.put($displayInCategory, $appCategory)) | ||
| 184 | ## Insert the category at the end for now. We'll sort the categories after we add all of them. | ||
| 185 | #set ($discard = $adminMenu.add($appCategory)) | ||
| 186 | #end | ||
| 187 | #set ($categoryIcon = $app.getValue('categoryIcon', $configurableObject)) | ||
| 188 | #if ("$!categoryIcon" != '') | ||
| 189 | #set ($appCategory.icon = $categoryIcon) | ||
| 190 | #end | ||
| 191 | #set ($displayBeforeCategory = $app.getValue('displayBeforeCategory', $configurableObject)) | ||
| 192 | #if ("$!displayBeforeCategory" != '') | ||
| 193 | #set ($appCategory.displayBeforeCategory = $displayBeforeCategory) | ||
| 194 | #end | ||
| 195 | #else | ||
| 196 | #set ($appCategory = $categoriesByName.get('other')) | ||
| 197 | #end | ||
| 198 | ## | ||
| 199 | #set ($displayInSection = $app.getValue('displayInSection', $configurableObject)) | ||
| 200 | ## | ||
| 201 | ## If there is no section specified in the object, just skip it | ||
| 202 | #if ("$!displayInSection" == '') | ||
| 203 | ## Skip, bad object | ||
| 204 | ## If there is no section for this configurable or if the section cannot be edited, then check if the | ||
| 205 | ## application can be edited by the current user, if so then we display the icon from the current app and | ||
| 206 | ## don't display any message to tell the user they can't edit that section. | ||
| 207 | #elseif ($sectionsByName.containsKey($displayInSection)) | ||
| 208 | #set ($appSection = $sectionsByName.get($displayInSection)) | ||
| 209 | #set ($appSection.configurable = true) | ||
| 210 | #set ($newSection = false) | ||
| 211 | #else | ||
| 212 | ## | ||
| 213 | ## If there is no section for this configurable, then we will have to add one. | ||
| 214 | #set ($key = "admin.$displayInSection.toLowerCase()") | ||
| 215 | #set ($name = $displayInSection) | ||
| 216 | #if ($services.localization.get($key)) | ||
| 217 | #set ($name = $services.localization.render($key)) | ||
| 218 | #end | ||
| 219 | #set ($appSection = { | ||
| 220 | 'id': $displayInSection, | ||
| 221 | 'name': $name, | ||
| 222 | 'url': $xwiki.getURL($currentDoc, $adminAction, "${query}§ion=$escapetool.url($displayInSection)"), | ||
| 223 | 'configurable': true, | ||
| 224 | 'order': $configurableObject.getValue('sectionOrder') | ||
| 225 | }) | ||
| 226 | #if ($app.getValue('configureGlobally', $configurableObject) != 1) | ||
| 227 | #set ($appSection.perSpace = true) | ||
| 228 | #end | ||
| 229 | #set ($key = "admin.${displayInSection.toLowerCase()}.description") | ||
| 230 | #if ($services.localization.get($key)) | ||
| 231 | #set ($appSection.description = $services.localization.render($key)) | ||
| 232 | #end | ||
| 233 | #set ($discard = $sectionsByName.put($displayInSection, $appSection)) | ||
| 234 | #set ($discard = $appCategory.children.add($appSection)) | ||
| 235 | #set ($newSection = true) | ||
| 236 | #end | ||
| 237 | ## | ||
| 238 | ## If an attachment by the filename iconAttachment exists and is an image | ||
| 239 | #set ($attachment = $app.getAttachment("$!app.getValue('iconAttachment', $configurableObject)")) | ||
| 240 | #if ($attachment && $attachment.isImage()) | ||
| 241 | ## Set the icon for this section as the attachment URL. | ||
| 242 | #set ($appSection.iconReference = "${appName}@$attachment.getFilename()") | ||
| 243 | #elseif (!$appSection.iconReference) | ||
| 244 | #set ($appSection.iconReference = 'XWiki.ConfigurableClass@DefaultAdminSectionIcon.png') | ||
| 245 | #end | ||
| 246 | ## | ||
| 247 | ## If the user doesn't have edit access to the application, we want to show a message on the icon | ||
| 248 | #if (!$xcontext.hasAccessLevel('edit', $app.getFullName()) && $newSection) | ||
| 249 | #set ($appSection.readOnly = true) | ||
| 250 | #elseif ($xcontext.hasAccessLevel('edit', $app.getFullName()) && $appSection.readOnly) | ||
| 251 | #set ($appSection.readOnly = false) | ||
| 252 | #end | ||
| 253 | #end## Foreach configurable object in this app. | ||
| 254 | #end## Foreach application which is configurable. | ||
| 255 | ## | ||
| 256 | ## Sort the categories | ||
| 257 | ## | ||
| 258 | #foreach ($category in $adminMenu) | ||
| 259 | #set ($category.score = 0) | ||
| 260 | #end | ||
| 261 | #foreach ($round in [1..$adminMenu.size()]) | ||
| 262 | #set ($scoreChanged = false) | ||
| 263 | #foreach ($category in $adminMenu) | ||
| 264 | #if ($category.displayBeforeCategory) | ||
| 265 | #set ($newScore = $categoriesByName.get($category.displayBeforeCategory).score + 1) | ||
| 266 | #if ($newScore && $newScore > $category.score) | ||
| 267 | #set ($category.score = $newScore) | ||
| 268 | #set ($scoreChanged = true) | ||
| 269 | #end | ||
| 270 | #end | ||
| 271 | #end | ||
| 272 | #if (!$scoreChanged) | ||
| 273 | #break | ||
| 274 | #end | ||
| 275 | #end | ||
| 276 | #set ($adminMenu = $collectiontool.sort($adminMenu, 'score:desc')) | ||
| 277 | #end | ||
| 278 | |||
| 279 | |||
| 280 | #* | ||
| 281 | * Show the heading for configuration for a given application. | ||
| 282 | * | ||
| 283 | * $appName (String) Name of the application to show configuration heading for. | ||
| 284 | * | ||
| 285 | * $headingAlreadyShowing (boolean) If true then we don't make another heading. Otherwise it is set to true. | ||
| 286 | *### | ||
| 287 | #macro(showHeading, $appName, $headingAlreadyShowing) | ||
| 288 | #if(!$headingAlreadyShowing) | ||
| 289 | #set($headingAlreadyShowing = true) | ||
| 290 | #set($escapedAppName = $services.rendering.escape($appName, 'xwiki/2.1')) | ||
| 291 | #set($doubleEscapedAppName = $services.rendering.escape($escapedAppName, 'xwiki/2.1')) | ||
| 292 | |||
| 293 | == {{translation key="admin.customize"/}} [[$doubleEscapedAppName>>$escapedAppName]]: == | ||
| 294 | #end | ||
| 295 | #end | ||
| 296 | |||
| 297 | #define($formHtml) | ||
| 298 | #if ($objClass.getPropertyNames().size() > 0) | ||
| 299 | <dl> | ||
| 300 | #foreach($propName in $objClass.getPropertyNames()) | ||
| 301 | #if($propertiesToShow.size() > 0 && !$propertiesToShow.contains($propName)) | ||
| 302 | ## Silently skip over this property. | ||
| 303 | #else | ||
| 304 | #set($hintKey = "${obj.xWikiClass.name}_${propName}.hint") | ||
| 305 | #set($hint = $services.localization.render($hintKey)) | ||
| 306 | #if($hint == $hintKey) | ||
| 307 | #set($hint = $NULL) | ||
| 308 | #end | ||
| 309 | ## | ||
| 310 | ## Further processing of the field display HTML is needed. | ||
| 311 | ## Step 1: Strip <pre> tags which $obj.display inserts, this won't affect content because it's escaped. | ||
| 312 | #set($out = $obj.display($propName, 'edit').replaceAll('<[/]?+pre>', '')) | ||
| 313 | ## Step 2: Select only content between first < and last > because $obj.display inserts html macros. | ||
| 314 | ## Careful not to remove html macros from the content because they are not escaped! | ||
| 315 | #set ($out = $out.substring($out.indexOf('<'), $mathtool.add(1, $out.lastIndexOf('>')))) | ||
| 316 | ## Step 3: Prepend app name to all ID and FOR attributes to prevent id collision with multiple apps on one page. | ||
| 317 | #set ($oldId = "$objClass.getName()_$obj.getNumber()_$propName") | ||
| 318 | #set ($newId = "${escapedAppName}_$oldId") | ||
| 319 | #set ($out = $out.replaceAll(" (id|for)=('|"")$regextool.quote($oldId)", | ||
| 320 | " ${escapetool.d}1=${escapetool.d}2$regextool.quoteReplacement($newId)")) | ||
| 321 | ## App Name is prepended to for= to make label work with id which is modified to prevent collisions. | ||
| 322 | <dt><label#if ($out.matches("(?s).*id=['""]${newId}['""].*")) for="${newId}"#end>## | ||
| 323 | #if ($out.indexOf('type=''checkbox''') != -1 && $out.indexOf('class="xwiki-form-listclass"') == -1) | ||
| 324 | $out ## | ||
| 325 | #set ($out = '') | ||
| 326 | #end | ||
| 327 | $escapetool.xml($app.displayPrettyName($propName, $obj)) | ||
| 328 | </label> | ||
| 329 | #if($linkPrefix != '') | ||
| 330 | <a href="$escapetool.xml($linkPrefix + $propName)" class="xHelp" title="$services.localization.render('admin.documentation')">$services.localization.render('admin.documentation')</a> | ||
| 331 | #end | ||
| 332 | #if ($hint) | ||
| 333 | <span class="xHint">$hint</span> | ||
| 334 | #end | ||
| 335 | </dt> | ||
| 336 | #if ($out != '') | ||
| 337 | <dd>$out</dd> | ||
| 338 | #else | ||
| 339 | ## We always display a dd element to avoid having a last dt element alone, which would lead to an invalid html. | ||
| 340 | <dd class="hidden">$out</dd> | ||
| 341 | #end | ||
| 342 | #end## If property is in propertiesToShow | ||
| 343 | #end## Foreach property in this class | ||
| 344 | </dl> | ||
| 345 | #end | ||
| 346 | #end## define $formHtml | ||
| 347 | {{/velocity}} |