Исходный код вики Document Tree Macros

Версия 2.1 от Андрей Ганьков на 2022/08/01 10:37

Последние авторы
1 {{include reference="XWiki.SuggestSolrMacros" /}}
2
3 {{template name="documentTree_macros.vm" /}}
4
5 {{velocity output="false"}}
6 #macro (updateDocTreeConfigFromRequest)
7 #foreach ($entry in $docTreeConfig.entrySet())
8 #set ($valueFromRequest = $request.getParameter($entry.key))
9 #if ("$!valueFromRequest" != '')
10 #if ($entry.value.getClass().getName() == 'java.lang.Boolean')
11 #set ($entry.value = $valueFromRequest == 'true')
12 #elseif ($entry.value.iterator())
13 #set ($valuesFromRequest = $request.getParameterValues($entry.key))
14 #set ($discard = $entry.value.clear())
15 ## We need to convert the String[] to List<String> before calling addAll (which expects a collection).
16 #set ($discard = $entry.value.addAll($valuesFromRequest.subList(0, $valuesFromRequest.size())))
17 #else
18 #set ($entry.value = $valueFromRequest)
19 #end
20 #end
21 #end
22 ## Show the wikis only for global users.
23 #set ($docTreeConfig.showWikis = $docTreeConfig.showWikis &&
24 $xcontext.userReference.wikiReference.name == $xcontext.mainWikiName)
25 #if ("$!docTreeConfig.root" == '')
26 #if ($docTreeConfig.showWikis)
27 #set ($docTreeConfig.root = 'farm:*')
28 #else
29 #set ($docTreeConfig.root = "wiki:$xcontext.database")
30 #end
31 #end
32 ## Handle relative references
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')
37 #end
38 ## Determine which hierarchy needs to be used.
39 #if ($docTreeConfig.showSpaces)
40 #if ($docTreeConfig.hierarchyMode == 'parentchild')
41 #set ($tree = $services.tree.parentChildOnNestedSpaces)
42 #else
43 #set ($tree = $services.tree.nestedSpaces)
44 #end
45 #elseif ($docTreeConfig.hierarchyMode == 'parentchild')
46 #set ($tree = $services.tree.parentChild)
47 #else
48 #set ($tree = $services.tree.nestedPages)
49 #end
50 #set ($discard = $tree.properties.putAll($docTreeConfig))
51 #end
52
53 #set ($documentPseudoNodeTypes = ['translations', 'attachments', 'classProperties', 'objects', 'addDocument',
54 'addAttachment'])
55 #macro (makeNodeReferencesAbsolute $map $keys)
56 #foreach ($key in $keys)
57 #set ($nodeId = $map.get($key))
58 #set ($parts = $nodeId.split(':', 2))
59 #if ($parts && $parts.size() == 2)
60 #set ($nodeType = $parts[0].toLowerCase())
61 #set ($nodeReference = $parts[1])
62 #set ($entityType = $nodeType)
63 #if ($documentPseudoNodeTypes.contains($nodeType))
64 #set ($entityType = 'document')
65 #end
66 #set ($discard = "#evaluate(""${escapetool.h}set (${escapetool.d}entityReference =
67 ${escapetool.d}services.model.resolve$stringtool.capitalize($entityType)(${escapetool.d}nodeReference))"")")
68 #if ($entityReference)
69 #set ($nodeReference = $services.model.serialize($entityReference, 'default'))
70 #end
71 #set ($discard = $map.put($key, "$nodeType:$nodeReference"))
72 #end
73 #end
74 #end
75
76 #macro (handleDocumentTreeRequest)
77 #if ($request.action)
78 #if ($services.csrf.isTokenValid($request.form_token))
79 $response.sendError(400, 'The specified action is not supported.')
80 #elseif ($isAjaxRequest)
81 $response.sendError(403, 'The CSRF token is missing.')
82 #else
83 $response.sendRedirect($services.csrf.getResubmissionURL())
84 #end
85 #else
86 #set ($data = $NULL)
87 #if ($request.data == 'children')
88 #getChildren($request.id $data)
89 #elseif ($request.data == 'path')
90 #getPath($request.id $data)
91 #elseif ($request.data == 'contextMenu')
92 #getContextMenu($data)
93 #elseif ($request.data == 'suggestions')
94 #getSuggestions($data)
95 #end
96 #if ($data)
97 #postProcessDocumentTreeData($data)
98 #jsonResponse($data)
99 #else
100 $response.sendError(404)
101 #end
102 #end
103 #end
104
105 #macro (postProcessDocumentTreeData $data)
106 ## This is just a hook to allow post processing the document tree data.
107 #end
108
109 ##------------------------------------------------------------
110 ## Children
111 ##------------------------------------------------------------
112
113 #macro (getChildren $nodeId $return)
114 #set ($children = [])
115 #if ($nodeId == '#')
116 ## Return the top level nodes.
117 #set ($actualNodeId = $docTreeConfig.root)
118 #else
119 ## Return the children of the specified node.
120 #set ($actualNodeId = $nodeId)
121 #end
122 #set ($offset = $mathtool.max($numbertool.toNumber($request.offset).intValue(), 0))
123 #if ("$!offset" == '')
124 #set ($offset = 0)
125 #end
126 #set ($limit = $mathtool.max($numbertool.toNumber($request.limit).intValue(), 1))
127 #if ("$!limit" == '')
128 #set ($limit = 15)
129 #end
130 #if ($nodeId == '#' && $docTreeConfig.showRoot)
131 #maybeAddNode($actualNodeId $children)
132 #else
133 #addChildNodes($actualNodeId $offset $limit $children)
134 #end
135 #if ($children.isEmpty() && $nodeId == '#')
136 ## Inform the user that the tree is empty.
137 #addEmptyTreeNode($children)
138 #end
139 #set ($return = $NULL)
140 #setVariable("$return" $children)
141 #end
142
143 #macro (maybeAddNode $nodeId $siblings $placeholder)
144 #set ($parts = $nodeId.split(':', 2))
145 #if ($parts && $parts.size() == 2)
146 #set ($nodeType = $parts[0])
147 #set ($nodeReference = $parts[1])
148 #set ($discard = "#evaluate(""${escapetool.h}maybeAdd$stringtool.capitalize($nodeType)Node(
149 ${escapetool.d}nodeReference ${escapetool.d}siblings ${escapetool.d}placeholder)"")")
150 #end
151 #end
152
153 #macro (addChildNodes $nodeId $offset $limit $children)
154 ## Avoid pages with only one node when paginating the child nodes.
155 #set ($actualLimit = $limit + 1)
156 #set ($childNodeIds = $tree.getChildren($nodeId, $offset, $actualLimit))
157 #set ($hasMoreChildNodes = false)
158 #if ($childNodeIds.size() >= $actualLimit)
159 #set ($totalCount = $tree.getChildCount($nodeId))
160 #set ($newOffset = $offset + $actualLimit)
161 #if ($newOffset < $totalCount)
162 ## There are at least 2 more child nodes.
163 #set ($hasMoreChildNodes = true)
164 #set ($newOffset = $newOffset - 1)
165 #set ($childNodeIds = $childNodeIds.subList(0, $limit))
166 #end
167 #end
168 #foreach ($childNodeId in $childNodeIds)
169 #maybeAddNode($childNodeId $children)
170 #end
171 #if ($hasMoreChildNodes)
172 #addPaginationNode($nodeId $newOffset $totalCount $children)
173 #end
174 #end
175
176 ##
177 ## Farm Node
178 ##
179
180 #macro (maybeAddFarmNode $nodeReference $siblings)
181 #set ($farmHomeReference = $services.model.resolveDocument('', 'default'))
182 #set ($discard = $siblings.add({
183 'id': 'farm:*',
184 'text': 'Farm',
185 'icon': 'fa fa-home',
186 'children': true,
187 'data': {
188 'type': 'farm',
189 'validChildren': ['wiki', 'pagination']
190 },
191 'a_attr': {
192 'href': $xwiki.getURL($farmHomeReference)
193 }
194 }))
195 #end
196
197 ##
198 ## Wiki Nodes
199 ##
200
201 #macro (maybeAddWikiNode $wikiId $siblings $placeholder)
202 #set ($wiki = $services.wiki.getById($wikiId))
203 #if ($wiki && (!$docTreeConfig.showOnlyViewable || $services.security.authorization.hasAccess('view', $wiki.reference)))
204 #addWikiNode($wiki $siblings)
205 #elseif ($placeholder)
206 #set ($discard = $siblings.add($placeholder))
207 #end
208 #end
209
210 #macro (addWikiNode $wiki $siblings)
211 ## The main wiki cannot be deleted. For the rest we need special rights.
212 #set ($canDeleteWiki = $wiki.id != $services.wiki.mainWikiId
213 && $services.wiki.canDeleteWiki($xcontext.user, $wiki.id))
214 #if ($docTreeConfig.showWikiPrettyName)
215 #set ($label = $wiki.prettyName)
216 #else
217 #set ($label = $wiki.id)
218 #end
219 #set ($discard = $siblings.add({
220 'id': "wiki:$wiki.id",
221 'text': $label,
222 'icon': 'fa fa-hdd-o',
223 'children': true,
224 'data': {
225 'id': $wiki.id,
226 'type': 'wiki',
227 'validChildren': ['space', 'document', 'pagination'],
228 'canDelete': $canDeleteWiki
229 },
230 'a_attr': {
231 'href': $xwiki.getURL($wiki.mainPageReference)
232 }
233 }))
234 #end
235
236 ##
237 ## Space Nodes
238 ##
239
240 #macro (maybeAddSpaceNode $spaceIdOrReference $siblings $placeholder)
241 #if ($spaceIdOrReference.type)
242 #set ($spaceReference = $spaceIdOrReference)
243 #else
244 #set ($spaceReference = $services.model.resolveSpace($spaceIdOrReference))
245 #end
246 #if (!$docTreeConfig.showOnlyViewable || $services.security.authorization.hasAccess('view', $spaceReference))
247 #addSpaceNode($spaceReference $siblings)
248 #elseif ($placeholder)
249 #set ($discard = $siblings.add($placeholder))
250 #end
251 #end
252
253 #macro (addSpaceNode $spaceReference $siblings)
254 #set ($spaceId = $services.model.serialize($spaceReference, 'default'))
255 #set ($hasSpaceAdmin = $services.security.authorization.hasAccess('admin', $spaceReference))
256 #set ($canViewSpace = $services.security.authorization.hasAccess('view', $spaceReference))
257 #if ($docTreeConfig.showTerminalDocuments)
258 ## Each space has at least one document or one sub-space. There's no such thing as "empty space" in the model.
259 #set ($hasChildren = true)
260 #else
261 ## We display only the nested spaces. This space might contain only documents.
262 #set ($hasChildren = $tree.getChildCount("space:$spaceId") > 0)
263 #end
264 #set ($discard = $siblings.add({
265 'id': "space:$spaceId",
266 'text': $spaceReference.name,
267 'icon': 'fa fa-folder-o',
268 'iconOpened': 'fa fa-folder-open-o',
269 'children': $hasChildren,
270 'data': {
271 'id': $spaceId,
272 'type': 'space',
273 'validChildren': ['addDocument', 'space', 'document', 'pagination'],
274 'hasContextMenu': true,
275 'draggable': $canViewSpace,
276 'canMove': $hasSpaceAdmin,
277 'canCopy': $canViewSpace,
278 'canRename': $hasSpaceAdmin,
279 'canDelete': $hasSpaceAdmin,
280 'createDocumentURL': $xwiki.getURL($spaceReference, 'create', $NULL),
281 'deleteURL': $xwiki.getURL($spaceReference, 'deletespace', $NULL)
282 },
283 'a_attr': {
284 'href': $xwiki.getURL($spaceReference)
285 }
286 }))
287 #end
288
289 ##
290 ## Document Nodes
291 ##
292
293 #macro (maybeAddDocumentNode $documentIdOrReference $siblings $placeholder)
294 #if ($documentIdOrReference.type)
295 #set ($documentReference = $documentIdOrReference)
296 #else
297 #set ($documentReference = $services.model.resolveDocument($documentIdOrReference))
298 #end
299 #if (!$docTreeConfig.showOnlyViewable || $services.security.authorization.hasAccess('view', $documentReference))
300 #addDocumentNode($documentReference $siblings)
301 #elseif ($placeholder)
302 #set ($discard = $siblings.add($placeholder))
303 #end
304 #end
305
306 #macro (addDocumentNode $documentReference $siblings)
307 #set ($documentId = $services.model.serialize($documentReference, 'default'))
308 #set ($label = $documentReference.name)
309 #if (!$docTreeConfig.showSpaces &&
310 $documentReference.name == $services.model.getEntityReference('DOCUMENT', 'default').name)
311 ## Use the space name as default value for the node label (in case the document is not viewable).
312 #set ($label = $documentReference.parent.name)
313 #end
314 #set ($canViewDoc = $services.security.authorization.hasAccess('view', $documentReference))
315 #set ($canDeleteDoc = $services.security.authorization.hasAccess('delete', $documentReference))
316 #if ($canViewDoc && $docTreeConfig.showDocumentTitle)
317 ## Display the translated title.
318 #set ($translatedDocument = $xwiki.getDocument($documentReference).translatedDocument)
319 ## Make sure the displayed title is not affected by the sheet request parameter (e.g. when $translatedDocument is
320 ## the current document). By setting the title (even if we don't change it) the internal document instance is cloned
321 ## so it's going to be different than the current document instance (which is the target of the sheet parameter).
322 #set ($discard = $translatedDocument.setTitle($translatedDocument.title))
323 #set ($plainTitle = $translatedDocument.plainTitle)
324 #if (!$stringtool.isBlank($plainTitle))
325 #set ($label = $plainTitle)
326 #end
327 #end
328 #set ($hasChildren = $tree.getChildCount("document:$documentId") > 0)
329 #set ($discard = $siblings.add({
330 'id': "document:$documentId",
331 'text': $label,
332 'icon': 'fa fa-file-o',
333 'children': $hasChildren,
334 'data': {
335 'id': $services.model.serialize($documentReference, 'default'),
336 'type': 'document',
337 'validChildren': ['translations', 'attachments', 'attachment', 'classProperties', 'objects', 'document', 'pagination'],
338 'hasContextMenu': true,
339 'draggable': $canViewDoc,
340 'canDelete': $canDeleteDoc,
341 'canMove': $canDeleteDoc,
342 'canCopy': $canViewDoc,
343 'createDocumentURL': $xwiki.getURL($documentReference, 'create', $NULL)
344 },
345 'a_attr': {
346 'href': $xwiki.getURL($documentReference)
347 }
348 }))
349 #end
350
351 #macro (maybeAddAddDocumentNode $documentId $siblings)
352 #set ($documentReference = $services.model.resolveDocument($documentId))
353 #if ($services.security.authorization.hasAccess('edit', $documentReference.parent))
354 #addAddDocumentNode($documentReference $siblings)
355 #end
356 #end
357
358 #macro (addAddDocumentNode $documentReference $siblings)
359 #set ($discard = $siblings.add({
360 'id': "addDocument:$services.model.serialize($documentReference, 'default')",
361 'text': 'New page...',
362 'icon': 'fa fa-plus-circle',
363 'children': false,
364 'data': {
365 'type': 'addDocument',
366 'validChildren': []
367 },
368 'a_attr': {
369 'href': $xwiki.getURL($documentReference, 'create')
370 }
371 }))
372 #end
373
374 ##
375 ## Translation Nodes
376 ##
377
378 #macro (maybeAddTranslationsNode $documentId $siblings)
379 #set ($documentReference = $services.model.resolveDocument($documentId))
380 #if ($services.security.authorization.hasAccess('view', $documentReference))
381 #addTranslationsNode($documentReference $siblings)
382 #end
383 #end
384
385 #macro (addTranslationsNode $documentReference $siblings)
386 #set ($discard = $children.add({
387 'id': "translations:${documentReference}",
388 'text': 'Translations',
389 'icon': 'fa fa-language',
390 'children': true,
391 'data': {
392 'type': 'translations',
393 'validChildren': ['translation'],
394 'canDelete': $services.security.authorization.hasAccess('delete', $documentReference)
395 }
396 }))
397 #end
398
399 #macro (maybeAddTranslationNode $nodeReference $siblings)
400 #set ($documentId = $stringtool.substringBeforeLast($nodeReference, '/'))
401 #set ($locale = $services.localization.toLocale($stringtool.substringAfterLast($nodeReference, '/')))
402 #set ($documentReference = $services.model.resolveDocument($documentId))
403 #set ($translationReference = $services.model.createDocumentReference($documentReference, $locale))
404 #if ($services.security.authorization.hasAccess('view', $documentReference))
405 #addTranslationNode($translationReference $siblings)
406 #end
407 #end
408
409 #macro (addTranslationNode $translationReference $siblings)
410 #set ($currentLocale = $services.localization.currentLocale)
411 #set ($discard = $siblings.add({
412 'id': "translation:$services.model.serialize($translationReference, 'default')_$translationReference.locale",
413 'text': $translationReference.locale.getDisplayName($currentLocale),
414 'icon': 'fa fa-file-text-o',
415 'children': false,
416 'data': {
417 'type': 'translation',
418 'validChildren': [],
419 'canDelete': $services.security.authorization.hasAccess('delete', $translationReference)
420 },
421 'a_attr': {
422 'href': $xwiki.getURL($translationReference)
423 }
424 }))
425 #end
426
427 ##
428 ## Attachment Nodes
429 ##
430
431 #macro (maybeAddAttachmentsNode $documentId $siblings)
432 #set ($documentReference = $services.model.resolveDocument($documentId))
433 #if ($services.security.authorization.hasAccess('view', $documentReference))
434 #addAttachmentsNode($documentReference $siblings)
435 #end
436 #end
437
438 #macro (addAttachmentsNode $documentReference $siblings)
439 #set ($discard = $siblings.add({
440 'id': "attachments:${documentReference}",
441 'text': 'Attachments',
442 'icon': 'fa fa-paperclip',
443 'children': true,
444 'data': {
445 'type': 'attachments',
446 'validChildren': ['addAttachment', 'attachment', 'pagination'],
447 'hasContextMenu': true,
448 'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
449 },
450 'a_attr': {
451 'href': $xwiki.getURL($documentReference, 'view', 'viewer=attachments')
452 }
453 }))
454 #end
455
456 #macro (maybeAddAttachmentNode $attachmentId $siblings))
457 #set ($attachmentReference = $services.model.resolveAttachment($attachmentId))
458 #set ($document = $xwiki.getDocument($attachmentReference))
459 #set ($attachment = $document.getAttachment($attachmentReference.name))
460 #if ($attachment)
461 #addAttachmentNode($attachment $siblings)
462 #end
463 #end
464
465 #macro (addAttachmentNode $attachment $siblings)
466 #set ($attachmentReference = $services.model.createAttachmentReference($attachment.document.documentReference,
467 $attachment.filename))
468 #set ($attachmentId = $services.model.serialize($attachmentReference, 'default'))
469 #set ($canEditDoc = $services.security.authorization.hasAccess('edit', $attachmentReference.parent))
470 #getAttachmentIcon($attachment $icon)
471 #set ($discard = $siblings.add({
472 'id': "attachment:$attachmentId",
473 'text': $attachment.filename,
474 'icon': $icon,
475 'children': false,
476 'data': {
477 'id': $attachmentId,
478 'type': 'attachment',
479 'validChildren': [],
480 'hasContextMenu': true,
481 'draggable': true,
482 'canRename': $canEditDoc,
483 'canDelete': $canEditDoc,
484 'canMove': $canEditDoc,
485 'canCopy': true,
486 'deleteURL': $attachment.document.getAttachmentURL($attachment.filename, 'delattachment'),
487 'mimetype': $attachment.mimeType
488 },
489 'a_attr': {
490 'href': $attachment.document.getAttachmentURL($attachment.filename)
491 }
492 }))
493 #end
494
495 #set ($fileIconByMediaType = {
496 'text': ['text/', 'application/xml', 'application/javascript', 'application/ecmascript', 'application/json', 'application/x-sh', '+xml'],
497 'image': ['image/'],
498 'audio': ['audio/'],
499 'video': ['video/'],
500 'pdf': ['application/pdf', 'application/postscript'],
501 'word': ['application/msword', 'application/vnd.ms-word.', 'application/vnd.oasis.opendocument.text', 'application/vnd.openxmlformats-officedocument.word'],
502 'powerpoint': ['application/vnd.ms-powerpoint', 'application/vnd.oasis.opendocument.presentation', 'application/vnd.openxmlformats-officedocument.presentation'],
503 'excel': ['application/vnd.ms-excel', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.openxmlformats-officedocument.spreadsheet'],
504 'archive': ['application/zip', 'application/x-gzip', 'application/x-bzip', 'application/x-tar', 'application/x-gtar', 'application/vnd.xara', '-archive', '-compressed', '-package', '+zip']
505 })
506
507 #macro (getAttachmentIcon $attachment $return)
508 #set ($mediaType = $attachment.mimeType)
509 #set ($icon = $NULL)
510 #foreach ($entry in $fileIconByMediaType.entrySet())
511 #foreach ($pattern in $entry.value)
512 #if ($mediaType.startsWith($pattern) || $mediaType.endsWith($pattern))
513 #set ($icon = $entry.key)
514 #break
515 #end
516 #end
517 #if ($icon)
518 #break
519 #end
520 #end
521 #set ($suffix = $stringtool.substringAfterLast($attachment.filename, '.'))
522 #set ($codeSuffixes = ['html', 'css', 'js', 'java', 'c', 'cpp', 'c++', 'cs', 'h', 'sql', 'php', 'ruby'])
523 #if (!$icon)
524 #set ($icon = 'fa fa-paperclip')
525 #elseif ($icon == 'text' && $codeSuffixes.contains($suffix))
526 #set ($icon = 'fa fa-file-code-o')
527 #else
528 #set ($icon = "fa fa-file-${icon}-o")
529 #end
530 #set ($return = $NULL)
531 #setVariable("$return" $icon)
532 #end
533
534 #macro (maybeAddAddAttachmentNode $documentId $siblings)
535 #set ($documentReference = $services.model.resolveDocument($documentId))
536 #if ($services.security.authorization.hasAccess('edit', $documentReference))
537 #addAddAttachmentNode($documentReference $siblings)
538 #end
539 #end
540
541 #macro (addAddAttachmentNode $documentReference $siblings)
542 #set ($discard = $siblings.add({
543 'id': "addAttachment:$documentReference",
544 'text': 'Upload file...',
545 'icon': 'fa fa-plus-circle',
546 'children': false,
547 'data': {
548 'type': 'addAttachment',
549 'validChildren': []
550 },
551 'a_attr': {
552 'href': $xwiki.getURL($documentReference, 'view', 'viewer=attachments')
553 }
554 }))
555 #end
556
557 ##
558 ## Class Property Nodes
559 ##
560
561 #macro (maybeAddClassPropertiesNode $documentId $siblings)
562 #set ($documentReference = $services.model.resolveDocument($documentId))
563 #if ($services.security.authorization.hasAccess('view', $documentReference))
564 #addClassPropertiesNode($documentReference $siblings)
565 #end
566 #end
567
568 #macro (addClassPropertiesNode $documentReference $siblings)
569 #set ($discard = $children.add({
570 'id': "classProperties:${documentReference}",
571 'text': 'Class Properties',
572 'icon': 'fa fa-gears',
573 'children': true,
574 'data': {
575 'type': 'classProperties',
576 'validChildren': ['classProperty'],
577 'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
578 }
579 }))
580 #end
581
582 #set ($iconByPropertyType = {
583 'Boolean': 'check-square-o',
584 'Date': 'calendar-o',
585 'DBList': 'database',
586 'Groups': 'group',
587 'Password': 'asterisk',
588 'Levels': 'lock',
589 'StaticList': 'list',
590 'TextArea': 'paragraph',
591 'DBTreeList': 'sitemap',
592 'Users': 'user'
593 })
594
595 #macro (maybeAddClassPropertyNode $classPropertyId $siblings)
596 #set ($classPropertyReference = $services.model.resolveClassProperty($classPropertyId))
597 #if ($services.security.authorization.hasAccess('view', $classPropertyReference.parent))
598 #addClassPropertyNode($classPropertyReference $siblings)
599 #end
600 #end
601
602 #macro (addClassPropertyNode $classPropertyReference $siblings)
603 #set ($classPropertyId = $services.model.serialize($classPropertyReference, 'default'))
604 #set ($xclass = $xwiki.getDocument($classPropertyReference).getxWikiClass())
605 #set ($property = $xclass.get($classPropertyReference.name))
606 #set ($icon = $iconByPropertyType.get($property.classType))
607 #if (!$icon)
608 #set ($icon = 'gear')
609 #end
610 #set ($discard = $siblings.add({
611 'id': "classProperty:$classPropertyId",
612 'text': $property.name,
613 'icon': "fa fa-$icon",
614 'children': false,
615 'data': {
616 'id': $classPropertyId,
617 'type': 'classProperty',
618 'validChildren': []
619 }
620 }))
621 #end
622
623 ##
624 ## Object Nodes
625 ##
626
627 #macro (maybeAddObjectsNode $documentId $siblings)
628 #set ($documentReference = $services.model.resolveDocument($documentId))
629 #if ($services.security.authorization.hasAccess('view', $documentReference))
630 #addObjectsNode($documentReference $siblings)
631 #end
632 #end
633
634 #macro (addObjectsNode $documentReference $siblings)
635 #set ($discard = $children.add({
636 'id': "objects:${documentReference}",
637 'text': 'Objects',
638 'icon': 'fa fa-cubes',
639 'children': true,
640 'data': {
641 'type': 'objects',
642 'validChildren': ['objectsOfType'],
643 'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
644 }
645 }))
646 #end
647
648 #macro (maybeAddObjectsOfTypeNode $nodeReference $siblings)
649 #set ($parts = $nodeReference.split('/', 2))
650 #if ($parts && $parts.size() == 2)
651 #set ($documentReference = $services.model.resolveDocument($parts.get(0)))
652 #set ($classReference = $services.model.resolveDocument($parts.get(1)))
653 #if ($services.security.authorization.hasAccess('view', $documentReference))
654 #set ($discard = $children.add({
655 'id': "objectsOfType:$documentReference/$classReference",
656 'text': $services.model.serialize($classReference, 'local'),
657 'icon': 'fa fa-cubes',
658 'children': true,
659 'data': {
660 'type': 'objectsOfType',
661 'validChildren': ['object', 'pagination'],
662 'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
663 }
664 }))
665 #end
666 #end
667 #end
668
669 #macro (maybeAddObjectNode $objectId $siblings)
670 #set ($objectReference = $services.model.resolveObject($objectId))
671 #getXObject($objectReference)
672 #if ($object)
673 #addObjectNode($object $objectReference $siblings)
674 #end
675 #end
676
677 #macro (getXObject $objectReference)
678 ## Object name is: Space.Class[index]
679 #set ($separatorIndex = $objectReference.name.lastIndexOf('['))
680 #set ($classId = $objectReference.name.substring(0, $separatorIndex))
681 #set ($objectNumber = $numbertool.toNumber($objectReference.name.substring($mathtool.add($separatorIndex, 1),
682 $mathtool.sub($objectReference.name.length(), 1))).intValue())
683 #set ($document = $xwiki.getDocument($objectReference))
684 #set ($object = $document.getObject($classId, $objectNumber))
685 #end
686
687 #macro (addObjectNode $object $objectReference $siblings)
688 #set ($objectId = $services.model.serialize($objectReference, 'default'))
689 #set ($discard = $children.add({
690 'id': "object:$objectId",
691 'text': "[$object.number]",
692 'icon': 'fa fa-cube',
693 'children': true,
694 'data': {
695 'id': $objectId,
696 'type': 'object',
697 'validChildren': ['objectProperty'],
698 'canDelete': $services.security.authorization.hasAccess('edit', $objectReference.parent)
699 }
700 }))
701 #end
702
703 #macro (maybeAddObjectPropertyNode $objectPropertyId $siblings)
704 #set ($objectPropertyReference = $services.model.resolveObjectProperty($objectPropertyId))
705 #set ($objectReference = $objectPropertyReference.parent)
706 #getXObject($objectReference)
707 #set ($property = $object.getProperty($objectPropertyReference.name))
708 #if ($property)
709 #addObjectPropertyNode($property $objectReference $siblings)
710 #end
711 #end
712
713 #macro (addObjectPropertyNode $property $objRef $siblings)
714 #set ($classId = $stringtool.substringBeforeLast($objRef.name, '['))
715 #set ($classRef = $services.model.resolveDocument($classId, 'explicit', $objRef))
716 #set ($xclass = $xwiki.getDocument($classRef).getxWikiClass())
717 #set ($icon = $iconByPropertyType.get($xclass.get($property.name).classType))
718 #if (!$icon)
719 #set ($icon = 'gear')
720 #end
721 #set ($objectPropertyReference = $services.model.createEntityReference($property.name, 'OBJECT_PROPERTY', $objRef))
722 #set ($objectPropertyId = $services.model.serialize($objectPropertyReference, 'default'))
723 #set ($discard = $siblings.add({
724 'id': "objectProperty:$objectPropertyId",
725 'text': $property.name,
726 'icon': "fa fa-$icon",
727 'children': false,
728 'data': {
729 'id': $objectPropertyId,
730 'type': 'objectProperty',
731 'validChildren': []
732 }
733 }))
734 #end
735
736 ##
737 ## Pagination Nodes
738 ##
739
740 #macro (addPaginationNode $parentId $offset $totalCount $siblings)
741 #set ($discard = $siblings.add({
742 'id': "pagination:$parentId",
743 'text': $services.localization.render('index.documentTree.more', $!mathtool.sub($totalCount, $offset)),
744 'icon': 'fa fa-eye',
745 'children': false,
746 'data': {
747 'type': 'pagination',
748 'validChildren': [],
749 'canDelete': true,
750 'offset': $offset
751 }
752 }))
753 #end
754
755 ##
756 ## Empty Tree Node
757 ##
758
759 #macro (addEmptyTreeNode $siblings)
760 #set ($discard = $siblings.add({
761 'id': "empty",
762 'text': $services.localization.render('index.documentTree.empty'),
763 'icon': 'fa fa-info-circle',
764 'children': false,
765 'data': {
766 'type': 'empty',
767 'validChildren': []
768 }
769 }))
770 #end
771
772 ##------------------------------------------------------------
773 ## Path
774 ##------------------------------------------------------------
775
776 #macro (getPath $nodeId $return)
777 #set ($path = [])
778 #if ($docTreeConfig.showRoot)
779 #maybeAddNode($docTreeConfig.root $path {})
780 #end
781 #foreach ($pathElement in $tree.getPath($nodeId))
782 #maybeAddNode($pathElement $path {})
783 #end
784 #set ($return = $NULL)
785 #setVariable("$return" $path)
786 #end
787
788 ##------------------------------------------------------------
789 ## Context Menu
790 ##------------------------------------------------------------
791
792 #macro (getContextMenu $return)
793 #set ($contextMenuByNodeType = {})
794 #if ($docTreeConfig.showSpaces)
795 #addSpaceContextMenu($contextMenuByNodeType)
796 #end
797 #addDocumentContextMenu($contextMenuByNodeType)
798 #if ($docTreeConfig.showAttachments)
799 #addAttachmentsContextMenu($contextMenuByNodeType)
800 #addAttachmentContextMenu($contextMenuByNodeType)
801 #end
802 #set ($return = $NULL)
803 #setVariable("$return" $contextMenuByNodeType)
804 #end
805
806 #macro (addSpaceContextMenu $contextMenuByNodeType)
807 #set ($contextMenuByNodeType.space = {
808 'createDocument': {
809 'label': 'New Page',
810 'icon': 'fa fa-file-o',
811 'action': 'openLink',
812 'parameters': {
813 'urlProperty': 'createDocumentURL'
814 }
815 },
816 'openLink': {
817 'separator_before': true,
818 'label': 'Go to Space',
819 'icon': 'fa fa-external-link'
820 },
821 'refresh': {
822 'label': 'Refresh',
823 'icon': 'fa fa-refresh'
824 },
825 'paste': {
826 'separator_before': true,
827 'label': 'Paste Into Space',
828 'icon': 'fa fa-clipboard'
829 },
830 'rename': {
831 'label': 'Rename...',
832 'icon': 'fa fa-pencil-square-o'
833 },
834 'remove': {
835 'label': 'Delete',
836 'icon': 'fa fa-trash-o',
837 'parameters': {
838 'confirmationMessage': 'Are you sure you want to move ALL the documents from this space to the recycle bin? If there are hidden documents in this space they will also be deleted.'
839 }
840 }
841 })
842 #end
843
844 #macro (addDocumentContextMenu $contextMenuByNodeType)
845 #set ($contextMenuByNodeType.document = {
846 'createDocument': {
847 'label': 'New Page',
848 'icon': 'fa fa-file-o',
849 'action': 'openLink',
850 'parameters': {
851 'urlProperty': 'createDocumentURL'
852 }
853 },
854 'openLink': {
855 'separator_before': true,
856 'label': 'Go to Page',
857 'icon': 'fa fa-external-link'
858 },
859 'refresh': {
860 'label': 'Refresh',
861 'icon': 'fa fa-refresh'
862 },
863 'cut': {
864 'separator_before': true,
865 'label': 'Cut',
866 'icon': 'fa fa-scissors'
867 },
868 'copy': {
869 'label': 'Copy',
870 'icon': 'fa fa-files-o'
871 },
872 'paste': {
873 'label': 'Paste',
874 'icon': 'fa fa-clipboard'
875 },
876 'remove': {
877 'separator_before': true,
878 'label': 'Delete',
879 'icon': 'fa fa-trash-o',
880 'parameters': {
881 'confirmationMessage': 'Are you sure you want to move this document to the recycle bin? All child documents will become orphan as a result.'
882 }
883 }
884 })
885 #end
886
887 #macro (addAttachmentsContextMenu $contextMenuByNodeType)
888 #set ($contextMenuByNodeType.attachments = {
889 'openLink': {
890 'label': 'Go to Attachments',
891 'icon': 'fa fa-external-link'
892 },
893 'refresh': {
894 'label': 'Refresh',
895 'icon': 'fa fa-refresh'
896 },
897 'paste': {
898 'separator_before': true,
899 'label': 'Paste',
900 'icon': 'fa fa-clipboard'
901 },
902 'remove': {
903 'label': 'Delete All',
904 'icon': 'fa fa-trash-o',
905 'parameters': {
906 'confirmationMessage': 'Are you sure you want to delete all the attachments of this page?'
907 }
908 }
909 })
910 #end
911
912 #macro (addAttachmentContextMenu $contextMenuByNodeType)
913 #set ($contextMenuByNodeType.attachment = {
914 'openLink': {
915 'label': 'Go to Attachment',
916 'icon': 'fa fa-external-link'
917 },
918 'cut': {
919 'separator_before': true,
920 'label': 'Cut',
921 'icon': 'fa fa-scissors'
922 },
923 'copy': {
924 'label': 'Copy',
925 'icon': 'fa fa-files-o'
926 },
927 'rename': {
928 'separator_before': true,
929 'label': 'Rename...',
930 'icon': 'fa fa-pencil-square-o'
931 },
932 'remove': {
933 'label': 'Delete',
934 'icon': 'fa fa-trash-o',
935 'parameters': {
936 'confirmationMessage': 'Are you sure you want to delete this attachment?'
937 }
938 }
939 })
940 #end
941
942 ##------------------------------------------------------------
943 ## Finder Suggestions
944 ##------------------------------------------------------------
945
946 #macro (getSuggestions $return)
947 #set ($limit = 6)
948 #set ($text = "$!request.query")
949 #set ($lists = [])
950 #getRootReference
951 #set ($ancestorsOf = {
952 'space': ['farm', 'wiki', 'space'],
953 'document': ['farm', 'wiki', 'space', 'document'],
954 'attachment': ['farm', 'wiki', 'space', 'document', 'attachments']
955 })
956 #if ((!$docTreeConfig.showSpaces || $docTreeConfig.showTerminalDocuments)
957 && $ancestorsOf.document.contains($rootType))
958 #addDocumentSuggestions($text $limit $lists)
959 #end
960 #if ($docTreeConfig.showAttachments && $ancestorsOf.attachment.contains($rootType))
961 #addAttachmentSuggestions($text $limit $lists)
962 #end
963 #if ($docTreeConfig.showSpaces && $ancestorsOf.space.contains($rootType))
964 #addSpaceSuggestions($text $limit $lists)
965 #end
966 #limitTotalCount($lists $limit)
967 #set ($output = [])
968 #foreach ($list in $lists)
969 #foreach ($node in $list)
970 ## Use the node path as suggestion info.
971 #getPath($node.id $path)
972 ## The path is empty when the node is not found in the tree. This happens if the tree finder doesn't restrict the
973 ## search to the nodes that are available in the tree.
974 #if ($path.size() > 0)
975 #displayPath($path)
976 #set ($node.data.info = $stringtool.join($path.subList(0, $mathtool.sub($path.size(), 1)), ' / '))
977 #set ($discard = $output.add($node))
978 #end
979 #end
980 #end
981 #set ($return = $NULL)
982 #setVariable("$return" $output)
983 #end
984
985 #macro (getRootReference)
986 #set ($parts = $docTreeConfig.root.split(':', 2))
987 #if ($parts.size() == 2)
988 #set ($rootType = $parts[0])
989 #set ($rootReference = $parts[1])
990 #if ($rootType == 'wiki')
991 #set ($rootReference = $services.model.createWikiReference($parts[1]))
992 #elseif ($rootType == 'space')
993 #set ($rootReference = $services.model.resolveSpace($parts[1]))
994 #elseif ($rootType == 'document' || $rootType == 'attachments')
995 #set ($rootReference = $services.model.resolveDocument($parts[1]))
996 #end
997 #else
998 #set ($rootType = 'unknown')
999 #set ($rootReference = $parts[0])
1000 #end
1001 #end
1002
1003 #macro (addSpaceSuggestions $text $limit $suggestions)
1004 #searchSpaces($text $limit $spaceReferences)
1005 #set ($spaceSuggestions = [])
1006 #foreach ($spaceReference in $spaceReferences)
1007 #maybeAddSpaceNode($spaceReference $spaceSuggestions)
1008 #end
1009 #set ($discard = $suggestions.add($spaceSuggestions))
1010 #end
1011
1012 #macro (searchSpaces $text $limit $return)
1013 #set ($constraints = ["upper(space.name) like upper(:spaceNamePattern) escape '!'"])
1014 #set ($params = {'spaceNamePattern': "%$!text.replaceAll('([%_!])', '!$1')%"})
1015 #addSpaceLocationDatabaseConstraint($rootReference $constraints $params 'space.reference')
1016 #set ($statement = "select space.reference from XWikiSpace space where $stringtool.join($constraints, ' and ') "
1017 + "order by lower(space.reference), space.reference")
1018 #set ($query = $services.query.hql($statement).setLimit($limit))
1019 #addWikiLocationDatabaseConstraint($rootReference $query)
1020 #if ($docTreeConfig.filterHiddenDocuments)
1021 #set ($query = $query.addFilter('hidden/space'))
1022 #end
1023 #foreach ($entry in $params.entrySet())
1024 #set ($query = $query.bindValue($entry.key, $entry.value))
1025 #end
1026 #set ($spaceReferences = [])
1027 #foreach ($localSpaceRef in $query.execute())
1028 #set ($discard = $spaceReferences.add($services.model.resolveSpace($localSpaceRef)))
1029 #end
1030 #set ($return = $NULL)
1031 #setVariable("$return" $spaceReferences)
1032 #end
1033
1034 #macro (addDocumentSuggestions $text $limit $suggestions)
1035 #searchDocuments($text $limit $documentReferences)
1036 #set ($docSuggestions = [])
1037 #foreach ($documentReference in $documentReferences)
1038 #maybeAddDocumentNode($documentReference $docSuggestions)
1039 #end
1040 #set ($discard = $suggestions.add($docSuggestions))
1041 #end
1042
1043 #macro (searchDocuments $text $limit $return)
1044 #if ($xwiki.exists('XWiki.SuggestSolrMacros'))
1045 #searchDocumentsSolr($text $limit $return)
1046 #else
1047 #searchDocumentsDatabase($text $limit $return)
1048 #end
1049 #end
1050
1051 #macro (searchDocumentsSolr $text $limit $return)
1052 #set ($params = [
1053 'fq=type:DOCUMENT',
1054 'fq=doclocale:""',
1055 'qf=title^6 name^4 doccontent^2 doccontentraw',
1056 'fl=wiki spaces name'
1057 ])
1058 #addCommonDocTreeSolrParams($params)
1059 #set ($params = $stringtool.join($params, $util.newline))
1060 #createSearchSuggestQuery($params $text $query)
1061 #set ($discard = $query.setLimit($limit))
1062 #set ($documentReferences = [])
1063 #foreach ($result in $query.execute()[0].results)
1064 #set ($discard = $documentReferences.add($services.solr.resolveDocument($result)))
1065 #end
1066 #set ($return = $NULL)
1067 #setVariable("$return" $documentReferences)
1068 #end
1069
1070 #macro (searchDocumentsDatabase $text $limit $return)
1071 #set ($constraints = [
1072 'doc.translation = 0',
1073 'doc.space = space.reference'
1074 ])
1075 #set ($defaultDocumentName = $services.model.getEntityReference('DOCUMENT', 'default').name)
1076 #set ($matchDocTitle = "upper(doc.title) like upper(:text) escape '!'")
1077 #set ($params = {'text': "%$!text.replaceAll('([%_!])', '!$1')%"})
1078 #if ($docTreeConfig.showTerminalDocuments)
1079 #set ($matchDocName = "(doc.name <> '$defaultDocumentName' and upper(doc.name) like upper(:text) escape '!')")
1080 #set ($matchSpaceName = "(doc.name = '$defaultDocumentName' and upper(space.name) like upper(:text) escape '!')")
1081 #set ($discard = $constraints.add("($matchDocTitle or $matchDocName or $matchSpaceName)"))
1082 #else
1083 #set ($matchSpaceName = "upper(space.name) like upper(:text) escape '!'")
1084 #set ($discard = $constraints.addAll([
1085 "doc.name = '$defaultDocumentName'",
1086 "($matchDocTitle or $matchSpaceName)"
1087 ]))
1088 #end
1089 #addDocumentLocationDatabaseConstraint($rootReference $constraints $params)
1090 #set ($constraints = $stringtool.join($constraints, ' and '))
1091 #set ($statement = "select doc.fullName from XWikiDocument doc, XWikiSpace space where $constraints")
1092 #set ($query = $services.query.hql($statement).setLimit($limit))
1093 #foreach ($entry in $params.entrySet())
1094 #set ($query = $query.bindValue($entry.key, $entry.value))
1095 #end
1096 #addWikiLocationDatabaseConstraint($rootReference $query)
1097 #if ($docTreeConfig.filterHiddenDocuments)
1098 #set ($query = $query.addFilter('hidden/document'))
1099 #end
1100 #set ($documentReferences = [])
1101 #foreach ($docFullName in $query.execute())
1102 #set ($discard = $documentReferences.add($services.model.resolveDocument($docFullName)))
1103 #end
1104 #set ($return = $NULL)
1105 #setVariable("$return" $documentReferences)
1106 #end
1107
1108 #macro (addAttachmentSuggestions $text $limit $suggestions)
1109 #searchAttachments($text $limit $attachmentReferences)
1110 #set ($attachmentSuggestions = [])
1111 #foreach ($attachmentReference in $attachmentReferences)
1112 #set ($attachment = $xwiki.getDocument($attachmentReference.parent).getAttachment($attachmentReference.name))
1113 #addAttachmentNode($attachment $attachmentSuggestions)
1114 #end
1115 #set ($discard = $suggestions.add($attachmentSuggestions))
1116 #end
1117
1118 #macro (searchAttachments $text $limit $return)
1119 #if ($xwiki.exists('XWiki.SuggestSolrMacros'))
1120 #searchAttachmentsSolr($text $limit $return)
1121 #else
1122 #searchAttachmentsDatabase($text $limit $return)
1123 #end
1124 #end
1125
1126 #macro (searchAttachmentsSolr $text $limit $return)
1127 #set ($params = [
1128 'fq=type:ATTACHMENT',
1129 'qf=filename^4 attcontent',
1130 'fl=type wiki spaces name filename'
1131 ])
1132 #addCommonDocTreeSolrParams($params)
1133 #set ($params = $stringtool.join($params, $util.newline))
1134 #createSearchSuggestQuery($params $text $query)
1135 #set ($discard = $query.setLimit($limit))
1136 #set ($attachmentReferences = [])
1137 #foreach ($result in $query.execute()[0].results)
1138 #set ($discard = $attachmentReferences.add($services.solr.resolve($result)))
1139 #end
1140 #set ($return = $NULL)
1141 #setVariable("$return" $attachmentReferences)
1142 #end
1143
1144 #macro (searchAttachmentsDatabase $text $limit $return)
1145 #set ($constraints = ["upper(attach.filename) like upper(:text) escape'!'"])
1146 #set ($params = {'text': "%$!text.replaceAll('([%_!])', '!$1')%"})
1147 #if ($docTreeConfig.filterHiddenDocuments && "$!xwiki.getUserPreference('displayHiddenDocuments')" != '1')
1148 #set ($discard = $constraints.add("(doc.hidden <> true or doc.hidden is null)"))
1149 #end
1150 #set ($exactMatch = $rootType == 'attachments')
1151 #addDocumentLocationDatabaseConstraint($rootReference $constraints $params $exactMatch)
1152 #set ($statement = "where $stringtool.join($constraints, ' and ')")
1153 ##
1154 ## Convert named parameters to positional parameters.
1155 #set ($paramList = [])
1156 #foreach ($item in $regextool.findAll($statement, ':(\w+)'))
1157 #set ($paramName = $item.get(1).getGroup())
1158 #set ($discard = $paramList.add($params.get($paramName)))
1159 #end
1160 #set ($statement = $statement.replaceAll(':\w+', '\?'))
1161 ##
1162 ## TODO: Search in the wiki that corresponds to the root node.
1163 #set ($attachments = $xwiki.searchAttachments($statement, $limit, 0, $paramList))
1164 #set ($attachmentReferences = [])
1165 #foreach ($attachment in $attachments)
1166 #set ($discard = $attachmentReferences.add($services.model.createAttachmentReference(
1167 $attachment.document.documentReference, $attachment.filename)))
1168 #end
1169 #set ($return = $NULL)
1170 #setVariable("$return" $attachmentReferences)
1171 #end
1172
1173 #macro (addCommonDocTreeSolrParams $params)
1174 #if ($rootType == 'wiki')
1175 ## Limit the search to the specified wiki.
1176 #addWikiLocationSolrParams($rootReference $params)
1177 #elseif ($rootType == 'space')
1178 ## Limit the search to the specified space.
1179 #addSpaceLocationSolrParams($rootReference $params)
1180 #elseif ($rootType == 'document')
1181 ## Limit the search to the specified document.
1182 #addDocumentLocationSolrParams($rootReference $params)
1183 #elseif ($rootType == 'attachments')
1184 ## Limit the search to the attachments of the specified document.
1185 #addDocumentLocationSolrParams($rootReference $params true)
1186 #end
1187 #if (!$docTreeConfig.showTerminalDocuments)
1188 #set ($defaultDocumentName = $services.model.getEntityReference('DOCUMENT', 'default').name)
1189 #set ($discard = $params.add("fq=name:$defaultDocumentName"))
1190 #end
1191 #if (!$docTreeConfig.filterHiddenDocuments)
1192 ## Force the inclusion of the hidden documents.
1193 #set ($discard = $params.add("fq=hidden:*"))
1194 #end
1195 #end
1196
1197 #macro (addWikiLocationSolrParams $rootReference $params)
1198 #set ($wikiReference = $rootReference.extractReference('WIKI'))
1199 #if ($wikiReference)
1200 #set ($discard = $params.add("fq=wiki:$wikiReference.name"))
1201 #end
1202 #end
1203
1204 #macro (addWikiLocationDatabaseConstraint $rootReference $query)
1205 #set ($wikiReference = $rootReference.extractReference('WIKI'))
1206 #if ($wikiReference)
1207 #set ($query = $query.setWiki($wikiReference.name))
1208 #end
1209 #end
1210
1211 #macro (addSpaceLocationSolrParams $rootReference $params $exactMatch)
1212 #addWikiLocationSolrParams($rootReference $params)
1213 #set ($spaceReference = $rootReference.extractReference('SPACE'))
1214 #if ($spaceReference && ($docTreeConfig.showSpaces || $docTreeConfig.hierarchyMode == 'reference'))
1215 #set ($localSpaceReference = $services.model.serialize($spaceReference, 'local'))
1216 #set ($spaceField = 'space_prefix')
1217 #if ($exactMatch)
1218 #set ($spaceField = 'space_exact')
1219 #end
1220 #set ($discard = $params.add("fq=$spaceField:""$localSpaceReference"""))
1221 #end
1222 #end
1223
1224 #macro (addSpaceLocationDatabaseConstraint $rootReference $constraints $params $field)
1225 #set ($spaceReference = $rootReference.extractReference('SPACE'))
1226 #if ($spaceReference && ($docTreeConfig.showSpaces || $docTreeConfig.hierarchyMode == 'reference'))
1227 #set ($discard = $constraints.add("($field = :localSpaceReference or $field like :spaceReferencePattern escape '!')"))
1228 #set ($localSpaceReference = $services.model.serialize($spaceReference, 'local'))
1229 #set ($discard = $params.put('localSpaceReference', $localSpaceReference))
1230 #set ($spaceReferencePattern = $services.model.createEntityReference('x', 'SPACE', $spaceReference))
1231 #set ($spaceReferencePattern = $services.model.serialize($spaceReferencePattern, 'local'))
1232 #set ($spaceReferencePattern = $stringtool.removeEnd($spaceReferencePattern, 'x').replaceAll('([%_!])', '!$1'))
1233 #set ($discard = $params.put('spaceReferencePattern', "$spaceReferencePattern%"))
1234 #end
1235 #end
1236
1237 #macro (addDocumentLocationSolrParams $rootReference $params $exactMatch)
1238 #set ($documentReference = $rootReference.extractReference('DOCUMENT'))
1239 #set ($defaultDocumentName = $services.model.getEntityReference('DOCUMENT', 'default').name)
1240 #set ($macro.exactMatch = $exactMatch || ($docTreeConfig.hierarchyMode == 'reference'
1241 && $documentReference && $documentReference.name != $defaultDocumentName))
1242 #addSpaceLocationSolrParams($rootReference $params $macro.exactMatch)
1243 #if ($documentReference && $macro.exactMatch)
1244 #set ($discard = $params.add("fq=name_exact:""$documentReference.name"""))
1245 #end
1246 #end
1247
1248 #macro (addDocumentLocationDatabaseConstraint $rootReference $constraints $params $exactMatch)
1249 #set ($documentReference = $rootReference.extractReference('DOCUMENT'))
1250 #set ($defaultDocumentName = $services.model.getEntityReference('DOCUMENT', 'default').name)
1251 #set ($macro.exactMatch = $exactMatch || ($docTreeConfig.hierarchyMode == 'reference'
1252 && $documentReference && $documentReference.name != $defaultDocumentName))
1253 #if ($documentReference && $macro.exactMatch)
1254 #set ($localDocumentReference = $services.model.serialize($documentReference, 'local'))
1255 #set ($discard = $constraints.add('doc.fullName = :localDocumentReference'))
1256 #set ($discard = $params.put('localDocumentReference', $localDocumentReference))
1257 #elseif (!$macro.exactMatch)
1258 #addSpaceLocationDatabaseConstraint($rootReference $constraints $params 'doc.space')
1259 #end
1260 #end
1261
1262 #macro (displayPath $path)
1263 #foreach ($node in $path)
1264 #set ($discard = $path.set($foreach.index, $node.text))
1265 #end
1266 #end
1267
1268 #macro (limitTotalCount $lists $limit)
1269 ## Prepare the input.
1270 #set ($input = [])
1271 #foreach ($list in $lists)
1272 ## We use queues to be able to easily remove items from the start.
1273 #set ($queue = $collectiontool.queue)
1274 #set ($discard = $queue.addAll($list))
1275 #set ($discard = $input.add($queue))
1276 ## We will add (part of) the items back later.
1277 #set ($discard = $list.clear())
1278 #end
1279 ## Limit the total item count.
1280 #set ($index = -1)
1281 #foreach ($count in [1..$limit])
1282 #foreach ($i in [1..$input.size()])
1283 #set ($newIndex = ($index + $i) % $input.size())
1284 #if ($input.get($newIndex).size() > 0)
1285 #set ($index = $newIndex)
1286 #break
1287 #end
1288 #end
1289 #if ($index < 0 || $input.get($index).isEmpty())
1290 #break
1291 #else
1292 #set ($discard = $lists.get($index).add($input.get($index).poll()))
1293 #end
1294 #end
1295 #end
1296 {{/velocity}}