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

Версия 1.1 от Admin xWiKi на 15.10.2019, 13:19

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