Исходный код вики Template Switch attachment
Версия 1.1 от Alexey Semenihin на 27.05.2025 06:20
Скрыть последних авторов
| author | version | line-number | content |
|---|---|---|---|
| |
1.1 | 1 | {{velocity}} |
| 2 | ## Макрос для отображения подстраниц с отображаемыми именами в алфавитном порядке | ||
| 3 | #macro(displayDirectChildrenClean) | ||
| 4 | #set ($currentPage = $doc.fullName) | ||
| 5 | #set ($children = $xwiki.getDocument($currentPage).getChildren()) | ||
| 6 | #if ($children.size() > 0) | ||
| 7 | ## Создаем список для хранения пар (отображаемое имя, полное имя) | ||
| 8 | #set ($childList = []) | ||
| 9 | #foreach ($child in $children) | ||
| 10 | #set ($childDoc = $xwiki.getDocument($child)) | ||
| 11 | ## Получаем отображаемое имя (title), если оно не пустое, иначе используем имя документа | ||
| 12 | #set ($displayName = $childDoc.getPlainTitle()) | ||
| 13 | #if ($displayName == '') | ||
| 14 | #set ($displayName = $childDoc.getName()) | ||
| 15 | #end | ||
| 16 | ## Добавляем пару в список | ||
| 17 | #set ($discard = $childList.add({"displayName": $displayName, "fullName": $child})) | ||
| 18 | #end | ||
| 19 | ## Сортируем список по displayName | ||
| 20 | #set ($sortedChildren = $sorttool.sort($childList, "displayName:asc")) | ||
| 21 | ## Выводим отсортированный список | ||
| 22 | #foreach ($item in $sortedChildren) | ||
| 23 | [[$item.displayName>>$item.fullName]] | ||
| 24 | #end | ||
| 25 | #end | ||
| 26 | #end | ||
| 27 | ## Выводим список | ||
| 28 | #displayDirectChildrenClean() | ||
| 29 | {{/velocity}} | ||
| 30 | |||
| 31 | {{velocity}} | ||
| 32 | ## Подключаем необходимые JS/CSS для работы вкладок | ||
| 33 | $xwiki.jsfx.use('uicomponents/widgets/tabView.js', {'forceSkinAction': true, 'language': 'xwiki/2.1'}) | ||
| 34 | $xwiki.ssfx.use('uicomponents/widgets/tabView.css', true) | ||
| 35 | {{html}} | ||
| 36 | <script> | ||
| 37 | // Ждём загрузки DOM | ||
| 38 | document.observe("dom:loaded", function() { | ||
| 39 | // Находим ссылку на вкладку "Вложения" (по ID или тексту) | ||
| 40 | var attachmentsTab = $('Attachmentslink'); | ||
| 41 | |||
| 42 | // Если вкладка найдена, имитируем клик | ||
| 43 | if (attachmentsTab) { | ||
| 44 | attachmentsTab.click(); | ||
| 45 | } | ||
| 46 | // Альтернативный вариант (если не сработал ID): | ||
| 47 | else { | ||
| 48 | var tabs = $$('.tab-menu a').find(function(tab) { | ||
| 49 | return tab.textContent.trim().includes('Вложения'); | ||
| 50 | }); | ||
| 51 | if (tabs && tabs.length > 0) tabs[0].click(); | ||
| 52 | } | ||
| 53 | }); | ||
| 54 | </script> | ||
| 55 | {{/html}} | ||
| 56 | {{/velocity}} | ||
| 57 | |||
| 58 | {{velocity}} | ||
| 59 | ## Подключаем необходимые JS/CSS для работы вкладок | ||
| 60 | $xwiki.jsfx.use('uicomponents/widgets/tabView.js', {'forceSkinAction': true, 'language': 'xwiki/2.1'}) | ||
| 61 | $xwiki.ssfx.use('uicomponents/widgets/tabView.css', true) | ||
| 62 | {{html}} | ||
| 63 | <script> | ||
| 64 | // Ждём загрузки DOM | ||
| 65 | document.observe("dom:loaded", function() { | ||
| 66 | // Находим ссылку на вкладку "Вложения" (по ID или тексту) | ||
| 67 | var attachmentsTab = $('Attachmentslink'); | ||
| 68 | |||
| 69 | // Если вкладка найдена, имитируем клик | ||
| 70 | if (attachmentsTab) { | ||
| 71 | attachmentsTab.click(); | ||
| 72 | } | ||
| 73 | // Альтернативный вариант (если не сработал ID): | ||
| 74 | else { | ||
| 75 | var tabs = $$('.tab-menu a').find(function(tab) { | ||
| 76 | return tab.textContent.trim().includes('Вложения'); | ||
| 77 | }); | ||
| 78 | if (tabs && tabs.length > 0) tabs[0].click(); | ||
| 79 | } | ||
| 80 | }); | ||
| 81 | </script> | ||
| 82 | {{/html}} | ||
| 83 | {{/velocity}} | ||
| 84 | |||
| 85 | {{html}} | ||
| 86 | <script> | ||
| 87 | // Ждём загрузки DOM | ||
| 88 | document.observe("dom:loaded", function() { | ||
| 89 | // Находим ссылку на вкладку "Вложения" (по ID или тексту) | ||
| 90 | var attachmentsTab = $('Attachmentslink'); | ||
| 91 | |||
| 92 | // Если вкладка найдена, имитируем клик | ||
| 93 | if (attachmentsTab) { | ||
| 94 | attachmentsTab.click(); | ||
| 95 | } | ||
| 96 | // Альтернативный вариант (если не сработал ID): | ||
| 97 | else { | ||
| 98 | var tabs = $$('.tab-menu a').find(function(tab) { | ||
| 99 | return tab.textContent.trim().includes('Вложения'); | ||
| 100 | }); | ||
| 101 | if (tabs && tabs.length > 0) tabs[0].click(); | ||
| 102 | } | ||
| 103 | }); | ||
| 104 | </script> | ||
| 105 | {{/html}} | ||
| 106 | |||
| 107 | {{velocity}} | ||
| 108 | === Прикрепите вложения и используйте кнопки для навигации === | ||
| 109 | #set($spaceRef = $doc.documentReference.lastSpaceReference.name) | ||
| 110 | #set($pageName = $doc.documentReference.name) | ||
| 111 | #set($docFullName = "${spaceRef}.${pageName}") | ||
| 112 | #set($attachments = $doc.getAttachmentList()) | ||
| 113 | #set($itemsPerPage = 1) | ||
| 114 | #set($totalPages = ($attachments.size() + $itemsPerPage - 1) / $itemsPerPage) | ||
| 115 | #set($currentPage = 1) | ||
| 116 | #if("$!request.page" != "") | ||
| 117 | #set($currentPage = $mathtool.toInteger($request.page)) | ||
| 118 | #end | ||
| 119 | #set($startIndex = ($currentPage - 1) * $itemsPerPage) | ||
| 120 | #set($endIndex = $startIndex + $itemsPerPage - 1) | ||
| 121 | #if($endIndex >= $attachments.size()) | ||
| 122 | #set($endIndex = $attachments.size() - 1) | ||
| 123 | #end | ||
| 124 | |||
| 125 | {{html}} | ||
| 126 | <div class="navigation-controls"> | ||
| 127 | #if($attachments && !$attachments.isEmpty()) | ||
| 128 | <!-- Выпадающий список для выбора вложения --> | ||
| 129 | <div class="attachment-selector"> | ||
| 130 | <label for="attachment-select">Выберите вложение:</label> | ||
| 131 | <select id="attachment-select"> | ||
| 132 | #foreach($attachment in $attachments) | ||
| 133 | <option value="$attachment.filename" #if($velocityCount == $currentPage)selected#end> | ||
| 134 | $attachment.filename | ||
| 135 | </option> | ||
| 136 | #end | ||
| 137 | </select> | ||
| 138 | </div> | ||
| 139 | |||
| 140 | <!-- Пагинация --> | ||
| 141 | <div class="pagination-controls"> | ||
| 142 | #if($currentPage > 1) | ||
| 143 | #set($prevPage = $currentPage - 1) | ||
| 144 | <a href="$doc.getURL('view', "page=${prevPage}")" class="btn btn-primary">Назад</a> | ||
| 145 | #else | ||
| 146 | <span class="btn btn-disabled">Назад</span> | ||
| 147 | #end | ||
| 148 | |||
| 149 | <span class="page-info">Страница $currentPage из $totalPages</span> | ||
| 150 | |||
| 151 | #if($currentPage < $totalPages) | ||
| 152 | #set($nextPage = $currentPage + 1) | ||
| 153 | <a href="$doc.getURL('view', "page=${nextPage}")" class="btn btn-primary">Далее</a> | ||
| 154 | #else | ||
| 155 | <span class="btn btn-disabled">Далее</span> | ||
| 156 | #end | ||
| 157 | </div> | ||
| 158 | #else | ||
| 159 | <div class="no-attachments-message"> | ||
| 160 | Нет прикрепленных вложений. Пожалуйста, добавьте файлы для просмотра. | ||
| 161 | </div> | ||
| 162 | #end | ||
| 163 | </div> | ||
| 164 | {{/html}} | ||
| 165 | |||
| 166 | #if($attachments && !$attachments.isEmpty()) | ||
| 167 | #foreach($i in [$startIndex..$endIndex]) | ||
| 168 | #set($attachment = $attachments.get($i)) | ||
| 169 | #set($filename = $attachment.filename) | ||
| 170 | #set($fileurl = $doc.getAttachmentURL($filename, "download")) | ||
| 171 | #set($fileExtension = $filename.substring($filename.lastIndexOf('.') + 1).toLowerCase()) | ||
| 172 | |||
| 173 | === Документ: $filename === | ||
| 174 | |||
| 175 | {{html}} | ||
| 176 | <div class="document-viewer-container" id="document-viewer"> | ||
| 177 | #if($fileExtension == 'pdf') | ||
| 178 | <!-- PDF Viewer --> | ||
| 179 | <iframe | ||
| 180 | id="document-frame" | ||
| 181 | src="/resources/pdfjs/web/viewer.html?file=${escapetool.url($fileurl)}" | ||
| 182 | width="100%" | ||
| 183 | height="600px"> | ||
| 184 | </iframe> | ||
| 185 | #elseif($fileExtension == 'doc' || $fileExtension == 'docx' || $fileExtension == 'ppt' || $fileExtension == 'pptx' || $fileExtension == 'xls' || $fileExtension == 'xlsx') | ||
| 186 | <!-- Office Viewer --> | ||
| 187 | #set($officeViewerUrl = "${doc.getURL('view')}?xpage=office&attachment=${escapetool.url($filename)}") | ||
| 188 | <iframe | ||
| 189 | id="document-frame" | ||
| 190 | src="$officeViewerUrl" | ||
| 191 | width="100%" | ||
| 192 | height="600px"> | ||
| 193 | </iframe> | ||
| 194 | #else | ||
| 195 | <div class="unsupported-format"> | ||
| 196 | Формат файла (${fileExtension}) не поддерживается для просмотра. | ||
| 197 | <a href="${fileurl}">Скачать файл</a> | ||
| 198 | </div> | ||
| 199 | #end | ||
| 200 | </div> | ||
| 201 | {{/html}} | ||
| 202 | #end | ||
| 203 | #else | ||
| 204 | {{html}} | ||
| 205 | <div class="no-attachments-message"> | ||
| 206 | Нет доступных вложений для отображения. | ||
| 207 | </div> | ||
| 208 | {{/html}} | ||
| 209 | #end | ||
| 210 | |||
| 211 | {{html}} | ||
| 212 | <style> | ||
| 213 | .navigation-controls { | ||
| 214 | display: flex; | ||
| 215 | flex-direction: column; | ||
| 216 | gap: 15px; | ||
| 217 | margin-bottom: 20px; | ||
| 218 | } | ||
| 219 | .attachment-selector { | ||
| 220 | display: flex; | ||
| 221 | align-items: center; | ||
| 222 | gap: 10px; | ||
| 223 | } | ||
| 224 | .attachment-selector select { | ||
| 225 | padding: 8px; | ||
| 226 | border-radius: 4px; | ||
| 227 | min-width: 300px; | ||
| 228 | } | ||
| 229 | .document-viewer-container { | ||
| 230 | margin: 20px 0; | ||
| 231 | border: 1px solid #eee; | ||
| 232 | padding: 10px; | ||
| 233 | background: #f9f9f9; | ||
| 234 | } | ||
| 235 | .pagination-controls { | ||
| 236 | margin: 20px 0; | ||
| 237 | display: flex; | ||
| 238 | justify-content: center; | ||
| 239 | align-items: center; | ||
| 240 | gap: 20px; | ||
| 241 | } | ||
| 242 | .btn { | ||
| 243 | padding: 8px 16px; | ||
| 244 | border-radius: 4px; | ||
| 245 | text-decoration: none; | ||
| 246 | } | ||
| 247 | .btn-primary { | ||
| 248 | background-color: #3366cc; | ||
| 249 | color: white; | ||
| 250 | } | ||
| 251 | .btn-disabled { | ||
| 252 | background-color: #eee; | ||
| 253 | color: #999; | ||
| 254 | cursor: not-allowed; | ||
| 255 | } | ||
| 256 | .page-info { | ||
| 257 | font-weight: bold; | ||
| 258 | } | ||
| 259 | .unsupported-format { | ||
| 260 | padding: 20px; | ||
| 261 | text-align: center; | ||
| 262 | color: #666; | ||
| 263 | } | ||
| 264 | .no-attachments-message { | ||
| 265 | padding: 20px; | ||
| 266 | text-align: center; | ||
| 267 | color: #666; | ||
| 268 | font-style: italic; | ||
| 269 | border: 1px dashed #ccc; | ||
| 270 | background-color: #f5f5f5; | ||
| 271 | } | ||
| 272 | </style> | ||
| 273 | |||
| 274 | <script> | ||
| 275 | //<![CDATA[ | ||
| 276 | document.addEventListener('DOMContentLoaded', function() { | ||
| 277 | const select = document.getElementById('attachment-select'); | ||
| 278 | const viewerContainer = document.getElementById('document-viewer'); | ||
| 279 | |||
| 280 | if (select && viewerContainer) { | ||
| 281 | select.addEventListener('change', function() { | ||
| 282 | const filename = this.value; | ||
| 283 | const fileExtension = filename.split('.').pop().toLowerCase(); | ||
| 284 | const fileurl = "${doc.getURL('download')}" + "/" + encodeURIComponent(filename); | ||
| 285 | const pdfViewerUrl = "/resources/pdfjs/web/viewer.html?file=" + encodeURIComponent(fileurl); | ||
| 286 | const baseUrl = "${doc.getURL('view')}"; | ||
| 287 | |||
| 288 | let viewerHtml = ''; | ||
| 289 | |||
| 290 | if (fileExtension === 'pdf') { | ||
| 291 | viewerHtml = '<iframe id="document-frame" ' + | ||
| 292 | 'src="' + pdfViewerUrl + '" ' + | ||
| 293 | 'width="100%" height="600px"></iframe>'; | ||
| 294 | } else if (['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx'].indexOf(fileExtension) >= 0) { | ||
| 295 | viewerHtml = '<iframe id="document-frame" ' + | ||
| 296 | 'src="' + baseUrl + '?xpage=office&attachment=' + encodeURIComponent(filename) + '" ' + | ||
| 297 | 'width="100%" height="600px"></iframe>'; | ||
| 298 | } else { | ||
| 299 | viewerHtml = '<div class="unsupported-format">' + | ||
| 300 | 'Формат файла (' + fileExtension + ') не поддерживается для просмотра. ' + | ||
| 301 | '<a href="' + fileurl + '">Скачать файл</a></div>'; | ||
| 302 | } | ||
| 303 | |||
| 304 | viewerContainer.innerHTML = viewerHtml; | ||
| 305 | |||
| 306 | // Обновляем заголовок документа | ||
| 307 | const titleElement = viewerContainer.previousElementSibling; | ||
| 308 | if (titleElement && titleElement.tagName === 'H3') { | ||
| 309 | titleElement.textContent = 'Документ: ' + filename; | ||
| 310 | } | ||
| 311 | }); | ||
| 312 | } | ||
| 313 | }); | ||
| 314 | //]]> | ||
| 315 | </script> | ||
| 316 | {{/html}} | ||
| 317 | {{/velocity}} |