mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Add support for 3D/CAD file formats preview (#34794)
Fix #34775 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		
							
								
								
									
										76
									
								
								web_src/js/features/file-view.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								web_src/js/features/file-view.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| import type {FileRenderPlugin} from '../render/plugin.ts'; | ||||
| import {newRenderPlugin3DViewer} from '../render/plugins/3d-viewer.ts'; | ||||
| import {newRenderPluginPdfViewer} from '../render/plugins/pdf-viewer.ts'; | ||||
| import {registerGlobalInitFunc} from '../modules/observer.ts'; | ||||
| import {createElementFromHTML, showElem, toggleClass} from '../utils/dom.ts'; | ||||
| import {htmlEscape} from 'escape-goat'; | ||||
| import {basename} from '../utils.ts'; | ||||
|  | ||||
| const plugins: FileRenderPlugin[] = []; | ||||
|  | ||||
| function initPluginsOnce(): void { | ||||
|   if (plugins.length) return; | ||||
|   plugins.push(newRenderPlugin3DViewer(), newRenderPluginPdfViewer()); | ||||
| } | ||||
|  | ||||
| function findFileRenderPlugin(filename: string, mimeType: string): FileRenderPlugin | null { | ||||
|   return plugins.find((plugin) => plugin.canHandle(filename, mimeType)) || null; | ||||
| } | ||||
|  | ||||
| function showRenderRawFileButton(elFileView: HTMLElement, renderContainer: HTMLElement | null): void { | ||||
|   const toggleButtons = elFileView.querySelector('.file-view-toggle-buttons'); | ||||
|   showElem(toggleButtons); | ||||
|   const displayingRendered = Boolean(renderContainer); | ||||
|   toggleClass(toggleButtons.querySelectorAll('.file-view-toggle-source'), 'active', !displayingRendered); // it may not exist | ||||
|   toggleClass(toggleButtons.querySelector('.file-view-toggle-rendered'), 'active', displayingRendered); | ||||
|   // TODO: if there is only one button, hide it? | ||||
| } | ||||
|  | ||||
| async function renderRawFileToContainer(container: HTMLElement, rawFileLink: string, mimeType: string) { | ||||
|   const elViewRawPrompt = container.querySelector('.file-view-raw-prompt'); | ||||
|   if (!rawFileLink || !elViewRawPrompt) throw new Error('unexpected file view container'); | ||||
|  | ||||
|   let rendered = false, errorMsg = ''; | ||||
|   try { | ||||
|     const plugin = findFileRenderPlugin(basename(rawFileLink), mimeType); | ||||
|     if (plugin) { | ||||
|       container.classList.add('is-loading'); | ||||
|       container.setAttribute('data-render-name', plugin.name); // not used yet | ||||
|       await plugin.render(container, rawFileLink); | ||||
|       rendered = true; | ||||
|     } | ||||
|   } catch (e) { | ||||
|     errorMsg = `${e}`; | ||||
|   } finally { | ||||
|     container.classList.remove('is-loading'); | ||||
|   } | ||||
|  | ||||
|   if (rendered) { | ||||
|     elViewRawPrompt.remove(); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // remove all children from the container, and only show the raw file link | ||||
|   container.replaceChildren(elViewRawPrompt); | ||||
|  | ||||
|   if (errorMsg) { | ||||
|     const elErrorMessage = createElementFromHTML(htmlEscape`<div class="ui error message">${errorMsg}</div>`); | ||||
|     elViewRawPrompt.insertAdjacentElement('afterbegin', elErrorMessage); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export function initRepoFileView(): void { | ||||
|   registerGlobalInitFunc('initRepoFileView', async (elFileView: HTMLElement) => { | ||||
|     initPluginsOnce(); | ||||
|     const rawFileLink = elFileView.getAttribute('data-raw-file-link'); | ||||
|     const mimeType = elFileView.getAttribute('data-mime-type') || ''; // not used yet | ||||
|     // TODO: we should also provide the prefetched file head bytes to let the plugin decide whether to render or not | ||||
|     const plugin = findFileRenderPlugin(basename(rawFileLink), mimeType); | ||||
|     if (!plugin) return; | ||||
|  | ||||
|     const renderContainer = elFileView.querySelector<HTMLElement>('.file-view-render-container'); | ||||
|     showRenderRawFileButton(elFileView, renderContainer); | ||||
|     // maybe in the future multiple plugins can render the same file, so we should not assume only one plugin will render it | ||||
|     if (renderContainer) await renderRawFileToContainer(renderContainer, rawFileLink, mimeType); | ||||
|   }); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Kerwin Bryant
					Kerwin Bryant