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

Версия 1.1 от Андрей Ганьков на 2020/03/30 19:01

Скрыть последних авторов
Андрей Ганьков 1.1 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 },
488 'a_attr': {
489 'href': $attachment.document.getAttachmentURL($attachment.filename)
490 }
491 }))
492 #end
493
494 #set ($fileIconByMediaType = {
495 'text': ['text/', 'application/xml', 'application/javascript', 'application/ecmascript', 'application/json', 'application/x-sh', '+xml'],
496 'image': ['image/'],
497 'audio': ['audio/'],
498 'video': ['video/'],
499 'pdf': ['application/pdf', 'application/postscript'],
500 'word': ['application/msword', 'application/vnd.ms-word.', 'application/vnd.oasis.opendocument.text', 'application/vnd.openxmlformats-officedocument.word'],
501 'powerpoint': ['application/vnd.ms-powerpoint', 'application/vnd.oasis.opendocument.presentation', 'application/vnd.openxmlformats-officedocument.presentation'],
502 'excel': ['application/vnd.ms-excel', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.openxmlformats-officedocument.spreadsheet'],
503 'archive': ['application/zip', 'application/x-gzip', 'application/x-bzip', 'application/x-tar', 'application/x-gtar', 'application/vnd.xara', '-archive', '-compressed', '-package', '+zip']
504 })
505
506 #macro (getAttachmentIcon $attachment $return)
507 #set ($mediaType = $attachment.mimeType)
508 #set ($icon = $NULL)
509 #foreach ($entry in $fileIconByMediaType.entrySet())
510 #foreach ($pattern in $entry.value)
511 #if ($mediaType.startsWith($pattern) || $mediaType.endsWith($pattern))
512 #set ($icon = $entry.key)
513 #break
514 #end
515 #end
516 #if ($icon)
517 #break
518 #end
519 #end
520 #set ($suffix = $stringtool.substringAfterLast($attachment.filename, '.'))
521 #set ($codeSuffixes = ['html', 'css', 'js', 'java', 'c', 'cpp', 'c++', 'cs', 'h', 'sql', 'php', 'ruby'])
522 #if (!$icon)
523 #set ($icon = 'fa fa-paperclip')
524 #elseif ($icon == 'text' && $codeSuffixes.contains($suffix))
525 #set ($icon = 'fa fa-file-code-o')
526 #else
527 #set ($icon = "fa fa-file-${icon}-o")
528 #end
529 #set ($return = $NULL)
530 #setVariable("$return" $icon)
531 #end
532
533 #macro (maybeAddAddAttachmentNode $documentId $siblings)
534 #set ($documentReference = $services.model.resolveDocument($documentId))
535 #if ($services.security.authorization.hasAccess('edit', $documentReference))
536 #addAddAttachmentNode($documentReference $siblings)
537 #end
538 #end
539
540 #macro (addAddAttachmentNode $documentReference $siblings)
541 #set ($discard = $siblings.add({
542 'id': "addAttachment:$documentReference",
543 'text': 'Upload file...',
544 'icon': 'fa fa-plus-circle',
545 'children': false,
546 'data': {
547 'type': 'addAttachment',
548 'validChildren': []
549 },
550 'a_attr': {
551 'href': $xwiki.getURL($documentReference, 'view', 'viewer=attachments')
552 }
553 }))
554 #end
555
556 ##
557 ## Class Property Nodes
558 ##
559
560 #macro (maybeAddClassPropertiesNode $documentId $siblings)
561 #set ($documentReference = $services.model.resolveDocument($documentId))
562 #if ($services.security.authorization.hasAccess('view', $documentReference))
563 #addClassPropertiesNode($documentReference $siblings)
564 #end
565 #end
566
567 #macro (addClassPropertiesNode $documentReference $siblings)
568 #set ($discard = $children.add({
569 'id': "classProperties:${documentReference}",
570 'text': 'Class Properties',
571 'icon': 'fa fa-gears',
572 'children': true,
573 'data': {
574 'type': 'classProperties',
575 'validChildren': ['classProperty'],
576 'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
577 }
578 }))
579 #end
580
581 #set ($iconByPropertyType = {
582 'Boolean': 'check-square-o',
583 'Date': 'calendar-o',
584 'DBList': 'database',
585 'Groups': 'group',
586 'Password': 'asterisk',
587 'Levels': 'lock',
588 'StaticList': 'list',
589 'TextArea': 'paragraph',
590 'DBTreeList': 'sitemap',
591 'Users': 'user'
592 })
593
594 #macro (maybeAddClassPropertyNode $classPropertyId $siblings)
595 #set ($classPropertyReference = $services.model.resolveClassProperty($classPropertyId))
596 #if ($services.security.authorization.hasAccess('view', $classPropertyReference.parent))
597 #addClassPropertyNode($classPropertyReference $siblings)
598 #end
599 #end
600
601 #macro (addClassPropertyNode $classPropertyReference $siblings)
602 #set ($classPropertyId = $services.model.serialize($classPropertyReference, 'default'))
603 #set ($xclass = $xwiki.getDocument($classPropertyReference).getxWikiClass())
604 #set ($property = $xclass.get($classPropertyReference.name))
605 #set ($icon = $iconByPropertyType.get($property.classType))
606 #if (!$icon)
607 #set ($icon = 'gear')
608 #end
609 #set ($discard = $siblings.add({
610 'id': "classProperty:$classPropertyId",
611 'text': $property.name,
612 'icon': "fa fa-$icon",
613 'children': false,
614 'data': {
615 'id': $classPropertyId,
616 'type': 'classProperty',
617 'validChildren': []
618 }
619 }))
620 #end
621
622 ##
623 ## Object Nodes
624 ##
625
626 #macro (maybeAddObjectsNode $documentId $siblings)
627 #set ($documentReference = $services.model.resolveDocument($documentId))
628 #if ($services.security.authorization.hasAccess('view', $documentReference))
629 #addObjectsNode($documentReference $siblings)
630 #end
631 #end
632
633 #macro (addObjectsNode $documentReference $siblings)
634 #set ($discard = $children.add({
635 'id': "objects:${documentReference}",
636 'text': 'Objects',
637 'icon': 'fa fa-cubes',
638 'children': true,
639 'data': {
640 'type': 'objects',
641 'validChildren': ['objectsOfType'],
642 'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
643 }
644 }))
645 #end
646
647 #macro (maybeAddObjectsOfTypeNode $nodeReference $siblings)
648 #set ($parts = $nodeReference.split('/', 2))
649 #if ($parts && $parts.size() == 2)
650 #set ($documentReference = $services.model.resolveDocument($parts.get(0)))
651 #set ($classReference = $services.model.resolveDocument($parts.get(1)))
652 #if ($services.security.authorization.hasAccess('view', $documentReference))
653 #set ($discard = $children.add({
654 'id': "objectsOfType:$documentReference/$classReference",
655 'text': $services.model.serialize($classReference, 'local'),
656 'icon': 'fa fa-cubes',
657 'children': true,
658 'data': {
659 'type': 'objectsOfType',
660 'validChildren': ['object', 'pagination'],
661 'canDelete': $services.security.authorization.hasAccess('edit', $documentReference)
662 }
663 }))
664 #end
665 #end
666 #end
667
668 #macro (maybeAddObjectNode $objectId $siblings)
669 #set ($objectReference = $services.model.resolveObject($objectId))
670 #getXObject($objectReference)
671 #if ($object)
672 #addObjectNode($object $objectReference $siblings)
673 #end
674 #end
675
676 #macro (getXObject $objectReference)
677 ## Object name is: Space.Class[index]
678 #set ($separatorIndex = $objectReference.name.lastIndexOf('['))
679 #set ($classId = $objectReference.name.substring(0, $separatorIndex))
680 #set ($objectNumber = $numbertool.toNumber($objectReference.name.substring($mathtool.add($separatorIndex, 1),
681 $mathtool.sub($objectReference.name.length(), 1))).intValue())
682 #set ($document = $xwiki.getDocument($objectReference))
683 #set ($object = $document.getObject($classId, $objectNumber))
684 #end
685
686 #macro (addObjectNode $object $objectReference $siblings)
687 #set ($objectId = $services.model.serialize($objectReference, 'default'))
688 #set ($discard = $children.add({
689 'id': "object:$objectId",
690 'text': "[$object.number]",
691 'icon': 'fa fa-cube',
692 'children': true,
693 'data': {
694 'id': $objectId,
695 'type': 'object',
696 'validChildren': ['objectProperty'],
697 'canDelete': $services.security.authorization.hasAccess('edit', $objectReference.parent)
698 }
699 }))
700 #end
701
702 #macro (maybeAddObjectPropertyNode $objectPropertyId $siblings)
703 #set ($objectPropertyReference = $services.model.resolveObjectProperty($objectPropertyId))
704 #set ($objectReference = $objectPropertyReference.parent)
705 #getXObject($objectReference)
706 #set ($property = $object.getProperty($objectPropertyReference.name))
707 #if ($property)
708 #addObjectPropertyNode($property $objectReference $siblings)
709 #end
710 #end
711
712 #macro (addObjectPropertyNode $property $objRef $siblings)
713 #set ($classId = $stringtool.substringBeforeLast($objRef.name, '['))
714 #set ($classRef = $services.model.resolveDocument($classId, 'explicit', $objRef))
715 #set ($xclass = $xwiki.getDocument($classRef).getxWikiClass())
716 #set ($icon = $iconByPropertyType.get($xclass.get($property.name).classType))
717 #if (!$icon)
718 #set ($icon = 'gear')
719 #end
720 #set ($objectPropertyReference = $services.model.createEntityReference($property.name, 'OBJECT_PROPERTY', $objRef))
721 #set ($objectPropertyId = $services.model.serialize($objectPropertyReference, 'default'))
722 #set ($discard = $siblings.add({
723 'id': "objectProperty:$objectPropertyId",
724 'text': $property.name,
725 'icon': "fa fa-$icon",
726 'children': false,
727 'data': {
728 'id': $objectPropertyId,
729 'type': 'objectProperty',
730 'validChildren': []
731 }
732 }))
733 #end
734
735 ##
736 ## Pagination Nodes
737 ##
738
739 #macro (addPaginationNode $parentId $offset $totalCount $siblings)
740 #set ($discard = $siblings.add({
741 'id': "pagination:$parentId",
742 'text': $services.localization.render('index.documentTree.more', $!mathtool.sub($totalCount, $offset)),
743 'icon': 'fa fa-eye',
744 'children': false,
745 'data': {
746 'type': 'pagination',
747 'validChildren': [],
748 'canDelete': true,
749 'offset': $offset
750 }
751 }))
752 #end
753
754 ##
755 ## Empty Tree Node
756 ##
757
758 #macro (addEmptyTreeNode $siblings)
759 #set ($discard = $siblings.add({
760 'id': "empty",
761 'text': $services.localization.render('index.documentTree.empty'),
762 'icon': 'fa fa-info-circle',
763 'children': false,
764 'data': {
765 'type': 'empty',
766 'validChildren': []
767 }
768 }))
769 #end
770
771 ##------------------------------------------------------------
772 ## Path
773 ##------------------------------------------------------------
774
775 #macro (getPath $nodeId $return)
776 #set ($path = [])
777 #if ($docTreeConfig.showRoot)
778 #maybeAddNode($docTreeConfig.root $path {})
779 #end
780 #foreach ($pathElement in $tree.getPath($nodeId))
781 #maybeAddNode($pathElement $path {})
782 #end
783 #set ($return = $NULL)
784 #setVariable("$return" $path)
785 #end
786
787 ##------------------------------------------------------------
788 ## Context Menu
789 ##------------------------------------------------------------
790
791 #macro (getContextMenu $return)
792 #set ($contextMenuByNodeType = {})
793 #if ($docTreeConfig.showSpaces)
794 #addSpaceContextMenu($contextMenuByNodeType)
795 #end
796 #addDocumentContextMenu($contextMenuByNodeType)
797 #if ($docTreeConfig.showAttachments)
798 #addAttachmentsContextMenu($contextMenuByNodeType)
799 #addAttachmentContextMenu($contextMenuByNodeType)
800 #end
801 #set ($return = $NULL)
802 #setVariable("$return" $contextMenuByNodeType)
803 #end
804
805 #macro (addSpaceContextMenu $contextMenuByNodeType)
806 #set ($contextMenuByNodeType.space = {
807 'createDocument': {
808 'label': 'New Page',
809 'icon': 'fa fa-file-o',
810 'action': 'openLink',
811 'parameters': {
812 'urlProperty': 'createDocumentURL'
813 }
814 },
815 'openLink': {
816 'separator_before': true,
817 'label': 'Go to Space',
818 'icon': 'fa fa-external-link'
819 },
820 'refresh': {
821 'label': 'Refresh',
822 'icon': 'fa fa-refresh'
823 },
824 'paste': {
825 'separator_before': true,
826 'label': 'Paste Into Space',
827 'icon': 'fa fa-clipboard'
828 },
829 'rename': {
830 'label': 'Rename...',
831 'icon': 'fa fa-pencil-square-o'
832 },
833 'remove': {
834 'label': 'Delete',
835 'icon': 'fa fa-trash-o',
836 'parameters': {
837 '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.'
838 }
839 }
840 })
841 #end
842
843 #macro (addDocumentContextMenu $contextMenuByNodeType)
844 #set ($contextMenuByNodeType.document = {
845 'createDocument': {
846 'label': 'New Page',
847 'icon': 'fa fa-file-o',
848 'action': 'openLink',
849 'parameters': {
850 'urlProperty': 'createDocumentURL'
851 }
852 },
853 'openLink': {
854 'separator_before': true,
855 'label': 'Go to Page',
856 'icon': 'fa fa-external-link'
857 },
858 'refresh': {
859 'label': 'Refresh',
860 'icon': 'fa fa-refresh'
861 },
862 'cut': {
863 'separator_before': true,
864 'label': 'Cut',
865 'icon': 'fa fa-scissors'
866 },
867 'copy': {
868 'label': 'Copy',
869 'icon': 'fa fa-files-o'
870 },
871 'paste': {
872 'label': 'Paste',
873 'icon': 'fa fa-clipboard'
874 },
875 'remove': {
876 'separator_before': true,
877 'label': 'Delete',
878 'icon': 'fa fa-trash-o',
879 'parameters': {
880 'confirmationMessage': 'Are you sure you want to move this document to the recycle bin? All child documents will become orphan as a result.'
881 }
882 }
883 })
884 #end
885
886 #macro (addAttachmentsContextMenu $contextMenuByNodeType)
887 #set ($contextMenuByNodeType.attachments = {
888 'openLink': {
889 'label': 'Go to Attachments',
890 'icon': 'fa fa-external-link'
891 },
892 'refresh': {
893 'label': 'Refresh',
894 'icon': 'fa fa-refresh'
895 },
896 'paste': {
897 'separator_before': true,
898 'label': 'Paste',
899 'icon': 'fa fa-clipboard'
900 },
901 'remove': {
902 'label': 'Delete All',
903 'icon': 'fa fa-trash-o',
904 'parameters': {
905 'confirmationMessage': 'Are you sure you want to delete all the attachments of this page?'
906 }
907 }
908 })
909 #end
910
911 #macro (addAttachmentContextMenu $contextMenuByNodeType)
912 #set ($contextMenuByNodeType.attachment = {
913 'openLink': {
914 'label': 'Go to Attachment',
915 'icon': 'fa fa-external-link'
916 },
917 'cut': {
918 'separator_before': true,
919 'label': 'Cut',
920 'icon': 'fa fa-scissors'
921 },
922 'copy': {
923 'label': 'Copy',
924 'icon': 'fa fa-files-o'
925 },
926 'rename': {
927 'separator_before': true,
928 'label': 'Rename...',
929 'icon': 'fa fa-pencil-square-o'
930 },
931 'remove': {
932 'label': 'Delete',
933 'icon': 'fa fa-trash-o',
934 'parameters': {
935 'confirmationMessage': 'Are you sure you want to delete this attachment?'
936 }
937 }
938 })
939 #end
940
941 ##------------------------------------------------------------
942 ## Finder Suggestions
943 ##------------------------------------------------------------
944
945 #macro (getSuggestions $return)
946 #set ($limit = 6)
947 #set ($text = "$!request.query")
948 #set ($lists = [])
949 #getRootReference
950 #set ($ancestorsOf = {
951 'space': ['farm', 'wiki', 'space'],
952 'document': ['farm', 'wiki', 'space', 'document'],
953 'attachment': ['farm', 'wiki', 'space', 'document', 'attachments']
954 })
955 #if ((!$docTreeConfig.showSpaces || $docTreeConfig.showTerminalDocuments)
956 && $ancestorsOf.document.contains($rootType))
957 #addDocumentSuggestions($text $limit $lists)
958 #end
959 #if ($docTreeConfig.showAttachments && $ancestorsOf.attachment.contains($rootType))
960 #addAttachmentSuggestions($text $limit $lists)
961 #end
962 #if ($docTreeConfig.showSpaces && $ancestorsOf.space.contains($rootType))
963 #addSpaceSuggestions($text $limit $lists)
964 #end
965 #limitTotalCount($lists $limit)
966 #set ($output = [])
967 #foreach ($list in $lists)
968 #foreach ($node in $list)
969 ## Use the node path as suggestion info.
970 #getPath($node.id $path)
971 ## The path is empty when the node is not found in the tree. This happens if the tree finder doesn't restrict the
972 ## search to the nodes that are available in the tree.
973 #if ($path.size() > 0)
974 #displayPath($path)
975 #set ($node.data.info = $stringtool.join($path.subList(0, $mathtool.sub($path.size(), 1)), ' / '))
976 #set ($discard = $output.add($node))
977 #end
978 #end
979 #end
980 #set ($return = $NULL)
981 #setVariable("$return" $output)
982 #end
983
984 #macro (getRootReference)
985 #set ($parts = $docTreeConfig.root.split(':', 2))
986 #if ($parts.size() == 2)
987 #set ($rootType = $parts[0])
988 #set ($rootReference = $parts[1])
989 #if ($rootType == 'wiki')
990 #set ($rootReference = $services.model.createWikiReference($parts[1]))
991 #elseif ($rootType == 'space')
992 #set ($rootReference = $services.model.resolveSpace($parts[1]))
993 #elseif ($rootType == 'document' || $rootType == 'attachments')
994 #set ($rootReference = $services.model.resolveDocument($parts[1]))
995 #end
996 #else
997 #set ($rootType = 'unknown')
998 #set ($rootReference = $parts[0])
999 #end
1000 #end
1001
1002 #macro (addSpaceSuggestions $text $limit $suggestions)
1003 #searchSpaces($text $limit $spaceReferences)
1004 #set ($spaceSuggestions = [])
1005 #foreach ($spaceReference in $spaceReferences)
1006 #maybeAddSpaceNode($spaceReference $spaceSuggestions)
1007 #end
1008 #set ($discard = $suggestions.add($spaceSuggestions))
1009 #end
1010
1011 #macro (searchSpaces $text $limit $return)
1012 #set ($constraints = ["upper(space.name) like upper(:spaceNamePattern) escape '!'"])
1013 #set ($params = {'spaceNamePattern': "%$!text.replaceAll('([%_!])', '!$1')%"})
1014 #addSpaceLocationDatabaseConstraint($rootReference $constraints $params 'space.reference')
1015 #set ($statement = "select space.reference from XWikiSpace space where $stringtool.join($constraints, ' and ') "
1016 + "order by lower(space.reference), space.reference")
1017 #set ($query = $services.query.hql($statement).setLimit($limit))
1018 #addWikiLocationDatabaseConstraint($rootReference $query)
1019 #if ($docTreeConfig.filterHiddenDocuments)
1020 #set ($query = $query.addFilter('hidden/space'))
1021 #end
1022 #foreach ($entry in $params.entrySet())
1023 #set ($query = $query.bindValue($entry.key, $entry.value))
1024 #end
1025 #set ($spaceReferences = [])
1026 #foreach ($localSpaceRef in $query.execute())
1027 #set ($discard = $spaceReferences.add($services.model.resolveSpace($localSpaceRef)))
1028 #end
1029 #set ($return = $NULL)
1030 #setVariable("$return" $spaceReferences)
1031 #end
1032
1033 #macro (addDocumentSuggestions $text $limit $suggestions)
1034 #searchDocuments($text $limit $documentReferences)
1035 #set ($docSuggestions = [])
1036 #foreach ($documentReference in $documentReferences)
1037 #maybeAddDocumentNode($documentReference $docSuggestions)
1038 #end
1039 #set ($discard = $suggestions.add($docSuggestions))
1040 #end
1041
1042 #macro (searchDocuments $text $limit $return)
1043 #if ($xwiki.exists('XWiki.SuggestSolrMacros'))
1044 #searchDocumentsSolr($text $limit $return)
1045 #else
1046 #searchDocumentsDatabase($text $limit $return)
1047 #end
1048 #end
1049
1050 #macro (searchDocumentsSolr $text $limit $return)
1051 #set ($params = [
1052 'fq=type:DOCUMENT',
1053 'fq=doclocale:""',
1054 'qf=title^6 name^4 doccontent^2 doccontentraw',
1055 'fl=wiki spaces name'
1056 ])
1057 #addCommonDocTreeSolrParams($params)
1058 #set ($params = $stringtool.join($params, $util.newline))
1059 #createSearchSuggestQuery($params $text $query)
1060 #set ($discard = $query.setLimit($limit))
1061 #set ($documentReferences = [])
1062 #foreach ($result in $query.execute()[0].results)
1063 #set ($discard = $documentReferences.add($services.solr.resolveDocument($result)))
1064 #end
1065 #set ($return = $NULL)
1066 #setVariable("$return" $documentReferences)
1067 #end
1068
1069 #macro (searchDocumentsDatabase $text $limit $return)
1070 #set ($constraints = [
1071 'doc.translation = 0',
1072 'doc.space = space.reference'
1073 ])
1074 #set ($defaultDocumentName = $services.model.getEntityReference('DOCUMENT', 'default').name)
1075 #set ($matchDocTitle = "upper(doc.title) like upper(:text) escape '!'")
1076 #set ($params = {'text': "%$!text.replaceAll('([%_!])', '!$1')%"})
1077 #if ($docTreeConfig.showTerminalDocuments)
1078 #set ($matchDocName = "(doc.name <> '$defaultDocumentName' and upper(doc.name) like upper(:text) escape '!')")
1079 #set ($matchSpaceName = "(doc.name = '$defaultDocumentName' and upper(space.name) like upper(:text) escape '!')")
1080 #set ($discard = $constraints.add("($matchDocTitle or $matchDocName or $matchSpaceName)"))
1081 #else
1082 #set ($matchSpaceName = "upper(space.name) like upper(:text) escape '!'")
1083 #set ($discard = $constraints.addAll([
1084 "doc.name = '$defaultDocumentName'",
1085 "($matchDocTitle or $matchSpaceName)"
1086 ]))
1087 #end
1088 #addDocumentLocationDatabaseConstraint($rootReference $constraints $params)
1089 #set ($constraints = $stringtool.join($constraints, ' and '))
1090 #set ($statement = "select doc.fullName from XWikiDocument doc, XWikiSpace space where $constraints")
1091 #set ($query = $services.query.hql($statement).setLimit($limit))
1092 #foreach ($entry in $params.entrySet())
1093 #set ($query = $query.bindValue($entry.key, $entry.value))
1094 #end
1095 #addWikiLocationDatabaseConstraint($rootReference $query)
1096 #if ($docTreeConfig.filterHiddenDocuments)
1097 #set ($query = $query.addFilter('hidden/document'))
1098 #end
1099 #set ($documentReferences = [])
1100 #foreach ($docFullName in $query.execute())
1101 #set ($discard = $documentReferences.add($services.model.resolveDocument($docFullName)))
1102 #end
1103 #set ($return = $NULL)
1104 #setVariable("$return" $documentReferences)
1105 #end
1106
1107 #macro (addAttachmentSuggestions $text $limit $suggestions)
1108 #searchAttachments($text $limit $attachmentReferences)
1109 #set ($attachmentSuggestions = [])
1110 #foreach ($attachmentReference in $attachmentReferences)
1111 #set ($attachment = $xwiki.getDocument($attachmentReference.parent).getAttachment($attachmentReference.name))
1112 #addAttachmentNode($attachment $attachmentSuggestions)
1113 #end
1114 #set ($discard = $suggestions.add($attachmentSuggestions))
1115 #end
1116
1117 #macro (searchAttachments $text $limit $return)
1118 #if ($xwiki.exists('XWiki.SuggestSolrMacros'))
1119 #searchAttachmentsSolr($text $limit $return)
1120 #else
1121 #searchAttachmentsDatabase($text $limit $return)
1122 #end
1123 #end
1124
1125 #macro (searchAttachmentsSolr $text $limit $return)
1126 #set ($params = [
1127 'fq=type:ATTACHMENT',
1128 'qf=filename^4 attcontent',
1129 'fl=type wiki spaces name filename'
1130 ])
1131 #addCommonDocTreeSolrParams($params)
1132 #set ($params = $stringtool.join($params, $util.newline))
1133 #createSearchSuggestQuery($params $text $query)
1134 #set ($discard = $query.setLimit($limit))
1135 #set ($attachmentReferences = [])
1136 #foreach ($result in $query.execute()[0].results)
1137 #set ($discard = $attachmentReferences.add($services.solr.resolve($result)))
1138 #end
1139 #set ($return = $NULL)
1140 #setVariable("$return" $attachmentReferences)
1141 #end
1142
1143 #macro (searchAttachmentsDatabase $text $limit $return)
1144 #set ($constraints = ["upper(attach.filename) like upper(:text) escape'!'"])
1145 #set ($params = {'text': "%$!text.replaceAll('([%_!])', '!$1')%"})
1146 #if ($docTreeConfig.filterHiddenDocuments && "$!xwiki.getUserPreference('displayHiddenDocuments')" != '1')
1147 #set ($discard = $constraints.add("(doc.hidden <> true or doc.hidden is null)"))
1148 #end
1149 #set ($exactMatch = $rootType == 'attachments')
1150 #addDocumentLocationDatabaseConstraint($rootReference $constraints $params $exactMatch)
1151 #set ($statement = "where $stringtool.join($constraints, ' and ')")
1152 ##
1153 ## Convert named parameters to positional parameters.
1154 #set ($paramList = [])
1155 #foreach ($item in $regextool.findAll($statement, ':(\w+)'))
1156 #set ($paramName = $item.get(1).getGroup())
1157 #set ($discard = $paramList.add($params.get($paramName)))
1158 #end
1159 #set ($statement = $statement.replaceAll(':\w+', '\?'))
1160 ##
1161 ## TODO: Search in the wiki that corresponds to the root node.
1162 #set ($attachments = $xwiki.searchAttachments($statement, $limit, 0, $paramList))
1163 #set ($attachmentReferences = [])
1164 #foreach ($attachment in $attachments)
1165 #set ($discard = $attachmentReferences.add($services.model.createAttachmentReference(
1166 $attachment.document.documentReference, $attachment.filename)))
1167 #end
1168 #set ($return = $NULL)
1169 #setVariable("$return" $attachmentReferences)
1170 #end
1171
1172 #macro (addCommonDocTreeSolrParams $params)
1173 #if ($rootType == 'wiki')
1174 ## Limit the search to the specified wiki.
1175 #addWikiLocationSolrParams($rootReference $params)
1176 #elseif ($rootType == 'space')
1177 ## Limit the search to the specified space.
1178 #addSpaceLocationSolrParams($rootReference $params)
1179 #elseif ($rootType == 'document')
1180 ## Limit the search to the specified document.
1181 #addDocumentLocationSolrParams($rootReference $params)
1182 #elseif ($rootType == 'attachments')
1183 ## Limit the search to the attachments of the specified document.
1184 #addDocumentLocationSolrParams($rootReference $params true)
1185 #end
1186 #if (!$docTreeConfig.showTerminalDocuments)
1187 #set ($defaultDocumentName = $services.model.getEntityReference('DOCUMENT', 'default').name)
1188 #set ($discard = $params.add("fq=name:$defaultDocumentName"))
1189 #end
1190 #if (!$docTreeConfig.filterHiddenDocuments)
1191 ## Force the inclusion of the hidden documents.
1192 #set ($discard = $params.add("fq=hidden:*"))
1193 #end
1194 #end
1195
1196 #macro (addWikiLocationSolrParams $rootReference $params)
1197 #set ($wikiReference = $rootReference.extractReference('WIKI'))
1198 #if ($wikiReference)
1199 #set ($discard = $params.add("fq=wiki:$wikiReference.name"))
1200 #end
1201 #end
1202
1203 #macro (addWikiLocationDatabaseConstraint $rootReference $query)
1204 #set ($wikiReference = $rootReference.extractReference('WIKI'))
1205 #if ($wikiReference)
1206 #set ($query = $query.setWiki($wikiReference.name))
1207 #end
1208 #end
1209
1210 #macro (addSpaceLocationSolrParams $rootReference $params $exactMatch)
1211 #addWikiLocationSolrParams($rootReference $params)
1212 #set ($spaceReference = $rootReference.extractReference('SPACE'))
1213 #if ($spaceReference && ($docTreeConfig.showSpaces || $docTreeConfig.hierarchyMode == 'reference'))
1214 #set ($localSpaceReference = $services.model.serialize($spaceReference, 'local'))
1215 #set ($spaceField = 'space_prefix')
1216 #if ($exactMatch)
1217 #set ($spaceField = 'space_exact')
1218 #end
1219 #set ($discard = $params.add("fq=$spaceField:""$localSpaceReference"""))
1220 #end
1221 #end
1222
1223 #macro (addSpaceLocationDatabaseConstraint $rootReference $constraints $params $field)
1224 #set ($spaceReference = $rootReference.extractReference('SPACE'))
1225 #if ($spaceReference && ($docTreeConfig.showSpaces || $docTreeConfig.hierarchyMode == 'reference'))
1226 #set ($discard = $constraints.add("($field = :localSpaceReference or $field like :spaceReferencePattern escape '!')"))
1227 #set ($localSpaceReference = $services.model.serialize($spaceReference, 'local'))
1228 #set ($discard = $params.put('localSpaceReference', $localSpaceReference))
1229 #set ($spaceReferencePattern = $services.model.createEntityReference('x', 'SPACE', $spaceReference))
1230 #set ($spaceReferencePattern = $services.model.serialize($spaceReferencePattern, 'local'))
1231 #set ($spaceReferencePattern = $stringtool.removeEnd($spaceReferencePattern, 'x').replaceAll('([%_!])', '!$1'))
1232 #set ($discard = $params.put('spaceReferencePattern', "$spaceReferencePattern%"))
1233 #end
1234 #end
1235
1236 #macro (addDocumentLocationSolrParams $rootReference $params $exactMatch)
1237 #set ($documentReference = $rootReference.extractReference('DOCUMENT'))
1238 #set ($defaultDocumentName = $services.model.getEntityReference('DOCUMENT', 'default').name)
1239 #set ($macro.exactMatch = $exactMatch || ($docTreeConfig.hierarchyMode == 'reference'
1240 && $documentReference && $documentReference.name != $defaultDocumentName))
1241 #addSpaceLocationSolrParams($rootReference $params $macro.exactMatch)
1242 #if ($documentReference && $macro.exactMatch)
1243 #set ($discard = $params.add("fq=name_exact:""$documentReference.name"""))
1244 #end
1245 #end
1246
1247 #macro (addDocumentLocationDatabaseConstraint $rootReference $constraints $params $exactMatch)
1248 #set ($documentReference = $rootReference.extractReference('DOCUMENT'))
1249 #set ($defaultDocumentName = $services.model.getEntityReference('DOCUMENT', 'default').name)
1250 #set ($macro.exactMatch = $exactMatch || ($docTreeConfig.hierarchyMode == 'reference'
1251 && $documentReference && $documentReference.name != $defaultDocumentName))
1252 #if ($documentReference && $macro.exactMatch)
1253 #set ($localDocumentReference = $services.model.serialize($documentReference, 'local'))
1254 #set ($discard = $constraints.add('doc.fullName = :localDocumentReference'))
1255 #set ($discard = $params.put('localDocumentReference', $localDocumentReference))
1256 #elseif (!$macro.exactMatch)
1257 #addSpaceLocationDatabaseConstraint($rootReference $constraints $params 'doc.space')
1258 #end
1259 #end
1260
1261 #macro (displayPath $path)
1262 #foreach ($node in $path)
1263 #set ($discard = $path.set($foreach.index, $node.text))
1264 #end
1265 #end
1266
1267 #macro (limitTotalCount $lists $limit)
1268 ## Prepare the input.
1269 #set ($input = [])
1270 #foreach ($list in $lists)
1271 ## We use queues to be able to easily remove items from the start.
1272 #set ($queue = $collectiontool.queue)
1273 #set ($discard = $queue.addAll($list))
1274 #set ($discard = $input.add($queue))
1275 ## We will add (part of) the items back later.
1276 #set ($discard = $list.clear())
1277 #end
1278 ## Limit the total item count.
1279 #set ($index = -1)
1280 #foreach ($count in [1..$limit])
1281 #foreach ($i in [1..$input.size()])
1282 #set ($newIndex = ($index + $i) % $input.size())
1283 #if ($input.get($newIndex).size() > 0)
1284 #set ($index = $newIndex)
1285 #break
1286 #end
1287 #end
1288 #if ($index < 0 || $input.get($index).isEmpty())
1289 #break
1290 #else
1291 #set ($discard = $lists.get($index).add($input.get($index).poll()))
1292 #end
1293 #end
1294 #end
1295 {{/velocity}}