Изменения документа Document Tree Macros

Редактировал(а) Андрей Ганьков 2026/01/23 10:50

От версии 4.1
отредактировано Давид Гавриков
на 2024/07/22 16:03
Изменить комментарий: Install extension [org.xwiki.platform:xwiki-platform-index-tree-macro/16.5.0]
К версии 8.1
отредактировано Андрей Ганьков
на 2026/01/23 10:50
Изменить комментарий: Install extension [org.xwiki.platform:xwiki-platform-index-tree-macro/17.10.2]

Сводка

Подробности

Свойства страницы
Автор документа
... ... @@ -1,1 +1,1 @@
1 -xwiki:XWiki.gavrikof
1 +xwiki:XWiki.gav
Содержимое
... ... @@ -31,9 +31,15 @@
31 31   #end
32 32   ## Handle relative references
33 33   #makeNodeReferencesAbsolute($docTreeConfig ['root', 'openTo'])
34 - ## Sort the child documents by (raw) title when the node label is the document title.
35 - #if ($docTreeConfig.showDocumentTitle)
36 - #set ($docTreeConfig.orderBy = 'title')
34 + ## FIXME: The 'orderBy' property of the tree API is shared by all tree node types, which means we can't indicate a
35 + ## different sort field per tree node type (e.g. sort wiki nodes by name and document nodes by last modification
36 + ## date). At the same time, this property is currently taken into account only for sorting document tree nodes, so for
37 + ## now we set its value to the specified document sort. In the future we may want to convert this into a map, where
38 + ## the key is the node type.
39 + #set ($docTreeConfig.orderBy = $docTreeConfig.sortDocumentsBy)
40 + ## Sort the child documents by (raw) title when the node label is the document title and there's no sort specified.
41 + #if ($docTreeConfig.showDocumentTitle && "$!docTreeConfig.orderBy" == '')
42 + #set ($docTreeConfig.orderBy = 'title:asc')
37 37   #end
38 38   ## Determine which hierarchy needs to be used.
39 39   #if ($docTreeConfig.showSpaces)
... ... @@ -76,7 +76,11 @@
76 76  #macro (handleDocumentTreeRequest)
77 77   #if ($request.action)
78 78   #if ($services.csrf.isTokenValid($request.form_token))
79 - $response.sendError(400, 'The specified action is not supported.')
85 + #if ($request.action == 'create' && $request.type == 'addDocument')
86 + #handleNewNodeCreationRequest()
87 + #else
88 + $response.sendError(400, 'The specified action is not supported.')
89 + #end
80 80   #elseif ($isAjaxRequest)
81 81   $response.sendError(403, 'The CSRF token is missing.')
82 82   #else
... ... @@ -102,6 +102,22 @@
102 102   #end
103 103  #end
104 104  
115 +#macro (handleNewNodeCreationRequest)
116 + #set ($cleanId = $stringtool.substring($request.id, $stringtool.length('document:')))
117 + #set ($parentReference = $services.model.resolveDocument($cleanId))
118 + #set ($requestedName = $request.name)
119 + #set ($transformedName = $services.modelvalidation.transformName($requestedName))
120 + #set ($spaceReference = $services.model.createSpaceReference($transformedName, $parentReference.lastSpaceReference))
121 + #set ($documentReference = $services.model.createDocumentReference('WebHome', $spaceReference))
122 + #set ($data = [])
123 + #addDocumentNode($documentReference, $data)
124 + ## We want to allow opening the node to add another hierarchy.
125 + #set ($data[0].children = true)
126 + ## We want to display the actual requested name as node name.
127 + #set ($data[0].text = $requestedName)
128 + #jsonResponse($data)
129 +#end
130 +
105 105  #macro (postProcessDocumentTreeData $data)
106 106   ## This is just a hook to allow post processing the document tree data.
107 107  #end
... ... @@ -126,6 +126,8 @@
126 126   #set ($limit = $mathtool.max($numbertool.toNumber($request.limit).intValue(), 1))
127 127   #if ("$!limit" == '')
128 128   #set ($limit = 15)
155 + #else
156 + #validateQueryLimit($limit)
129 129   #end
130 130   #if ($nodeId == '#' && $docTreeConfig.showRoot)
131 131   #maybeAddNode($actualNodeId $children)
... ... @@ -179,6 +179,7 @@
179 179  
180 180  #macro (maybeAddFarmNode $nodeReference $siblings)
181 181   #set ($farmHomeReference = $services.model.resolveDocument('', 'default'))
210 + #set ($isOpened = $docTreeConfig.expandToLevel > 0)
182 182   #set ($discard = $siblings.add({
183 183   'id': 'farm:*',
184 184   'text': 'Farm',
... ... @@ -188,6 +188,9 @@
188 188   'type': 'farm',
189 189   'validChildren': ['wiki', 'pagination']
190 190   },
220 + 'state': {
221 + 'opened': $isOpened
222 + },
191 191   'a_attr': {
192 192   'href': $xwiki.getURL($farmHomeReference)
193 193   }
... ... @@ -216,6 +216,7 @@
216 216   #else
217 217   #set ($label = $wiki.id)
218 218   #end
251 + #set ($isOpened = $docTreeConfig.expandToLevel > 0)
219 219   #set ($discard = $siblings.add({
220 220   'id': "wiki:$wiki.id",
221 221   'text': $label,
... ... @@ -227,6 +227,9 @@
227 227   'validChildren': ['space', 'document', 'pagination'],
228 228   'canDelete': $canDeleteWiki
229 229   },
263 + 'state': {
264 + 'opened': $isOpened
265 + },
230 230   'a_attr': {
231 231   'href': $xwiki.getURL($wiki.mainPageReference)
232 232   }
... ... @@ -252,6 +252,7 @@
252 252  
253 253  #macro (addSpaceNode $spaceReference $siblings)
254 254   #set ($spaceId = $services.model.serialize($spaceReference, 'default'))
291 + #set ($spaceNodeId = "space:$spaceId")
255 255   #set ($hasSpaceAdmin = $services.security.authorization.hasAccess('admin', $spaceReference))
256 256   #set ($canViewSpace = $services.security.authorization.hasAccess('view', $spaceReference))
257 257   #if ($docTreeConfig.showTerminalDocuments)
... ... @@ -259,10 +259,21 @@
259 259   #set ($hasChildren = true)
260 260   #else
261 261   ## We display only the nested spaces. This space might contain only documents.
262 - #set ($hasChildren = $tree.getChildCount("space:$spaceId") > 0)
299 + #set ($hasChildren = $tree.getChildCount($spaceNodeId) > 0)
263 263   #end
301 + #set ($isOpened = false)
302 + #if ("$!docTreeConfig.expandToLevel" != '')
303 + #set ($rootNode = "wiki:$services.wiki.currentWikiId")
304 + #if ("$!docTreeConfig.root" != '')
305 + #set ($rootNode = "wiki:$services.wiki.currentWikiId")
306 + #else
307 + #set ($rootNode = $docTreeConfig.root)
308 + #end
309 + #set ($rootDistance = $tree.getPath($spaceNodeId).size())
310 + #set ($isOpened = ($rootDistance != -1 && $docTreeConfig.expandToLevel >= $rootDistance))
311 + #end
264 264   #set ($discard = $siblings.add({
265 - 'id': "space:$spaceId",
313 + 'id': $spaceNodeId,
266 266   'text': $spaceReference.name,
267 267   'icon': 'fa fa-folder-o',
268 268   'iconOpened': 'fa fa-folder-open-o',
... ... @@ -280,6 +280,9 @@
280 280   'createDocumentURL': $xwiki.getURL($spaceReference, 'create', $NULL),
281 281   'deleteURL': $xwiki.getURL($spaceReference, 'deletespace', $NULL)
282 282   },
331 + 'state': {
332 + 'opened': $isOpened
333 + },
283 283   'a_attr': {
284 284   'href': $xwiki.getURL($spaceReference)
285 285   }
... ... @@ -305,6 +305,7 @@
305 305  
306 306  #macro (addDocumentNode $documentReference $siblings)
307 307   #set ($documentId = $services.model.serialize($documentReference, 'default'))
359 + #set ($docNodeId = "document:$documentId")
308 308   #set ($label = $documentReference.name)
309 309   #if (!$docTreeConfig.showSpaces &&
310 310   $documentReference.name == $services.model.getEntityReference('DOCUMENT', 'default').name)
... ... @@ -321,9 +321,11 @@
321 321   #set ($label = $plainTitle)
322 322   #end
323 323   #end
324 - #set ($hasChildren = $tree.getChildCount("document:$documentId") > 0)
376 + #set ($hasChildren = $tree.getChildCount($docNodeId) > 0)
377 + #set ($isOpened = false)
378 + #computeIsOpened($docNodeId $isOpened)
325 325   #set ($discard = $siblings.add({
326 - 'id': "document:$documentId",
380 + 'id': $docNodeId,
327 327   'text': $label,
328 328   'icon': 'fa fa-file-o',
329 329   'children': $hasChildren,
... ... @@ -338,6 +338,9 @@
338 338   'canCopy': $canViewDoc,
339 339   'createDocumentURL': $xwiki.getURL($documentReference, 'create', $NULL)
340 340   },
395 + 'state': {
396 + 'opened': $isOpened
397 + },
341 341   'a_attr': {
342 342   'href': $xwiki.getURL($documentReference)
343 343   }
... ... @@ -352,14 +352,18 @@
352 352  #end
353 353  
354 354  #macro (addAddDocumentNode $documentReference $siblings)
412 + ## FIXME: This URL is wrong, it should use the $documentReference as the parent for creation of the node:
413 + ## the reference is already an existing doc, so it shouldn't be the one used for creation.
355 355   #set ($discard = $siblings.add({
356 356   'id': "addDocument:$services.model.serialize($documentReference, 'default')",
357 - 'text': 'New page...',
416 + 'text': $services.localization.render('index.documentTree.addDocument'),
358 358   'icon': 'fa fa-plus-circle',
359 359   'children': false,
360 360   'data': {
361 361   'type': 'addDocument',
362 - 'validChildren': []
421 + 'validChildren': [],
422 + 'hasContextMenu': true,
423 + 'canRename': true
363 363   },
364 364   'a_attr': {
365 365   'href': $xwiki.getURL($documentReference, 'create')
... ... @@ -378,9 +378,27 @@
378 378   #end
379 379  #end
380 380  
442 +#macro (computeIsOpened $docNodeId $result)
443 + #set ($isOpened = false)
444 + #if ("$!docTreeConfig.expandToLevel" != '')
445 + #set ($rootNode = "wiki:$services.wiki.currentWikiId")
446 + #if ("$!docTreeConfig.root" != '')
447 + #set ($rootNode = "wiki:$services.wiki.currentWikiId")
448 + #else
449 + #set ($rootNode = $docTreeConfig.root)
450 + #end
451 + #set ($rootDistance = $tree.getPath($docNodeId).size())
452 + #set ($isOpened = ($rootDistance != -1 && $docTreeConfig.expandToLevel >= $rootDistance))
453 + #end
454 + #setVariable("$result" $isOpened)
455 +#end
456 +
381 381  #macro (addTranslationsNode $documentReference $siblings)
382 - #set ($discard = $children.add({
383 - 'id': "translations:${documentReference}",
458 + #set ($isOpened = false)
459 + #set ($docNodeId = "translations:${documentReference}")
460 + #computeIsOpened($docNodeId $isOpened)
461 + #set ($discard = $siblings.add({
462 + 'id': $docNodeId,
384 384   'text': 'Translations',
385 385   'icon': 'fa fa-language',
386 386   'children': true,
... ... @@ -388,6 +388,9 @@
388 388   'type': 'translations',
389 389   'validChildren': ['translation'],
390 390   'canDelete': $services.security.authorization.hasAccess('delete', $documentReference)
470 + },
471 + 'state': {
472 + 'opened': $isOpened
391 391   }
392 392   }))
393 393  #end
... ... @@ -404,8 +404,11 @@
404 404  
405 405  #macro (addTranslationNode $translationReference $siblings)
406 406   #set ($currentLocale = $services.localization.currentLocale)
489 + #set ($isOpened = false)
490 + #set ($docNodeId = "translation:$services.model.serialize($translationReference, 'default')_$translationReference.locale")
491 + #computeIsOpened($docNodeId $isOpened)
407 407   #set ($discard = $siblings.add({
408 - 'id': "translation:$services.model.serialize($translationReference, 'default')_$translationReference.locale",
493 + 'id': $docNodeId,
409 409   'text': $translationReference.locale.getDisplayName($currentLocale),
410 410   'icon': 'fa fa-file-text-o',
411 411   'children': false,
... ... @@ -416,6 +416,9 @@
416 416   },
417 417   'a_attr': {
418 418   'href': $xwiki.getURL($translationReference)
504 + },
505 + 'state': {
506 + 'opened': $isOpened
419 419   }
420 420   }))
421 421  #end
... ... @@ -432,8 +432,11 @@
432 432  #end
433 433  
434 434  #macro (addAttachmentsNode $documentReference $siblings)
523 + #set ($isOpened = false)
524 + #set ($docNodeId = "attachments:${documentReference}")
525 + #computeIsOpened($docNodeId $isOpened)
435 435   #set ($discard = $siblings.add({
436 - 'id': "attachments:${documentReference}",
527 + 'id': $docNodeId,
437 437   'text': 'Attachments',
438 438   'icon': 'fa fa-paperclip',
439 439   'children': true,
... ... @@ -445,6 +445,9 @@
445 445   },
446 446   'a_attr': {
447 447   'href': $xwiki.getURL($documentReference, 'view', 'viewer=attachments')
539 + },
540 + 'state': {
541 + 'opened': $isOpened
448 448   }
449 449   }))
450 450  #end
... ... @@ -464,8 +464,11 @@
464 464   #set ($attachmentId = $services.model.serialize($attachmentReference, 'default'))
465 465   #set ($canEditDoc = $services.security.authorization.hasAccess('edit', $attachmentReference.parent))
466 466   #getAttachmentIcon($attachment $icon)
561 + #set ($isOpened = false)
562 + #set ($docNodeId = "attachment:$attachmentId")
563 + #computeIsOpened($docNodeId $isOpened)
467 467   #set ($discard = $siblings.add({
468 - 'id': "attachment:$attachmentId",
565 + 'id': $docNodeId,
469 469   'text': $attachment.filename,
470 470   'icon': $icon,
471 471   'children': false,
... ... @@ -484,6 +484,9 @@
484 484   },
485 485   'a_attr': {
486 486   'href': $attachment.document.getAttachmentURL($attachment.filename)
584 + },
585 + 'state': {
586 + 'opened': $isOpened
487 487   }
488 488   }))
489 489  #end
... ... @@ -562,8 +562,11 @@
562 562  #end
563 563  
564 564  #macro (addClassPropertiesNode $documentReference $siblings)
565 - #set ($discard = $children.add({
566 - 'id': "classProperties:${documentReference}",
665 + #set ($isOpened = false)
666 + #set ($docNodeId = "classProperties:${documentReference}")
667 + #computeIsOpened($docNodeId $isOpened)
668 + #set ($discard = $siblings.add({
669 + 'id': $docNodeId,
567 567   'text': 'Class Properties',
568 568   'icon': 'fa fa-gears',
569 569   'children': true,
... ... @@ -571,6 +571,9 @@
571 571   'type': 'classProperties',
572 572   'validChildren': ['classProperty'],
573 573   'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
677 + },
678 + 'state': {
679 + 'opened': $isOpened
574 574   }
575 575   }))
576 576  #end
... ... @@ -603,8 +603,11 @@
603 603   #if (!$icon)
604 604   #set ($icon = 'gear')
605 605   #end
712 + #set ($isOpened = false)
713 + #set ($docNodeId = "classProperty:$classPropertyId")
714 + #computeIsOpened($docNodeId $isOpened)
606 606   #set ($discard = $siblings.add({
607 - 'id': "classProperty:$classPropertyId",
716 + 'id': $docNodeId,
608 608   'text': $property.name,
609 609   'icon': "fa fa-$icon",
610 610   'children': false,
... ... @@ -612,6 +612,9 @@
612 612   'id': $classPropertyId,
613 613   'type': 'classProperty',
614 614   'validChildren': []
724 + },
725 + 'state': {
726 + 'opened': $isOpened
615 615   }
616 616   }))
617 617  #end
... ... @@ -628,8 +628,11 @@
628 628  #end
629 629  
630 630  #macro (addObjectsNode $documentReference $siblings)
631 - #set ($discard = $children.add({
632 - 'id': "objects:${documentReference}",
743 + #set ($isOpened = false)
744 + #set ($docNodeId = "objects:${documentReference}")
745 + #computeIsOpened($docNodeId $isOpened)
746 + #set ($discard = $siblings.add({
747 + 'id': $docNodeId,
633 633   'text': 'Objects',
634 634   'icon': 'fa fa-cubes',
635 635   'children': true,
... ... @@ -637,6 +637,9 @@
637 637   'type': 'objects',
638 638   'validChildren': ['objectsOfType'],
639 639   'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
755 + },
756 + 'state': {
757 + 'opened': $isOpened
640 640   }
641 641   }))
642 642  #end
... ... @@ -647,8 +647,11 @@
647 647   #set ($documentReference = $services.model.resolveDocument($parts.get(0)))
648 648   #set ($classReference = $services.model.resolveDocument($parts.get(1)))
649 649   #if ($services.security.authorization.hasAccess('view', $documentReference))
650 - #set ($discard = $children.add({
651 - 'id': "objectsOfType:$documentReference/$classReference",
768 + #set ($isOpened = false)
769 + #set ($docNodeId = "objectsOfType:$documentReference/$classReference")
770 + #computeIsOpened($docNodeId $isOpened)
771 + #set ($discard = $siblings.add({
772 + 'id': $docNodeId,
652 652   'text': $services.model.serialize($classReference, 'local'),
653 653   'icon': 'fa fa-cubes',
654 654   'children': true,
... ... @@ -656,6 +656,9 @@
656 656   'type': 'objectsOfType',
657 657   'validChildren': ['object', 'pagination'],
658 658   'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
780 + },
781 + 'state': {
782 + 'opened': $isOpened
659 659   }
660 660   }))
661 661   #end
... ... @@ -682,8 +682,11 @@
682 682  
683 683  #macro (addObjectNode $object $objectReference $siblings)
684 684   #set ($objectId = $services.model.serialize($objectReference, 'default'))
685 - #set ($discard = $children.add({
686 - 'id': "object:$objectId",
809 + #set ($isOpened = false)
810 + #set ($docNodeId = "object:$objectId")
811 + #computeIsOpened($docNodeId $isOpened)
812 + #set ($discard = $siblings.add({
813 + 'id': $docNodeId,
687 687   'text': "[$object.number]",
688 688   'icon': 'fa fa-cube',
689 689   'children': true,
... ... @@ -692,6 +692,9 @@
692 692   'type': 'object',
693 693   'validChildren': ['objectProperty'],
694 694   'canDelete': $services.security.authorization.hasAccess('edit', $objectReference.parent)
822 + },
823 + 'state': {
824 + 'opened': $isOpened
695 695   }
696 696   }))
697 697  #end
... ... @@ -716,8 +716,11 @@
716 716   #end
717 717   #set ($objectPropertyReference = $services.model.createEntityReference($property.name, 'OBJECT_PROPERTY', $objRef))
718 718   #set ($objectPropertyId = $services.model.serialize($objectPropertyReference, 'default'))
849 + #set ($isOpened = false)
850 + #set ($docNodeId = "objectProperty:$objectPropertyId")
851 + #computeIsOpened($docNodeId $isOpened)
719 719   #set ($discard = $siblings.add({
720 - 'id': "objectProperty:$objectPropertyId",
853 + 'id': $docNodeId,
721 721   'text': $property.name,
722 722   'icon': "fa fa-$icon",
723 723   'children': false,
... ... @@ -725,6 +725,9 @@
725 725   'id': $objectPropertyId,
726 726   'type': 'objectProperty',
727 727   'validChildren': []
861 + },
862 + 'state': {
863 + 'opened': $isOpened
728 728   }
729 729   }))
730 730  #end