adminFooter.ftl

 1   <#--
 2   Macro: adminFooter
 3   
 4   Description: Generates the footer section, including documentation and source code links, a Lutece logo, and a version number.
 5   
 6   Parameters:
 7   - version : The version number
 8   -->
 9   <#macro adminFooter closeMain=true >
 10   <!-- footer menu -->
 11   <footer class="lutece-main-footer footer footer-transparent d-print-none">
 12   	<div class="container-fluid">
 13   		<div class="row text-center align-items-center flex-row-reverse">
 14   			<div class="col-lg-auto ms-lg-auto">
 15   				<ul class="list-inline mb-0">
 16   					<li class="list-inline-item nav-item "><a href="https://lutece.paris.fr/support/jsp/site/Portal.jsp?page=wiki" class="nav-link">Documentation</a></li>
 17   					<li class="list-inline-item nav-item "><a href="https://github.com/lutece-platform/" target="_blank" class="nav-link" rel="noopener">Source code</a></li>
 18   				</ul>
 19   			</div>
 20   			<div class="col-12 col-lg-auto mt-3 mt-lg-0">
 21   				<ul class="nav list-inline mb-0">
 22   					<li class="list-inline-item nav-item">
 23   						<a class="nav-link d-flex align-items-center" href="https://lutece.paris.fr" target="lutece" title="#i18n{portal.site.portal_footer.labelPortal}">
 24   							<span class="me-2">${site_name}</span>
 25   							<img src="themes/admin/shared/images/poweredby.svg" style="height:15px" class="img-fluid theme-invert" alt="#i18n{portal.site.portal_footer.labelMadeBy}">
 26   							<span class="visually-hidden">LUTECE</span>
 27   							<span class="text-muted ms-2" rel="noopener">version ${version}</span>
 28   						</a>
 29   					</li>
 30   				</ul>
 31   			</div>
 32   		</div>
 33   	</div>
 34   </footer>
 35   <!-- Included JS Files 												-->
 36   <!-- Le javascript 													-->
 37   <!-- ============================================================== -->
 38   <!-- Placed at the end of the document so the pages load faster 	-->
 39   <@coreAdminJSLinks />
 40   ${javascript_files}
 41   </div><!-- Close wrapper -->
 42   </#macro>
 43   <#--
 44   Macro: adminSiteFooter
 45   
 46   Description: Footer for site Admin
 47   Parameters:
 48   - 
 49   -->
 50   <#macro adminSiteFooter >
 51   <#assign siteFooter = .get_optional_template('../../../../../skin/site/portal_footer.html')>
 52   <#if siteFooter.exists><@siteFooter.include /></#if>
 53   <!-- A modal dialog containing a form -->
 54   <dialog id="addPortletDialog" class="lutece-dialog" aria-labelledby="portletModalLabel" aria-hidden="true" tabindex="-1">
 55       <div class="lutece-dialog lutece-dialog-fullscreen">
 56           <div class="lutece-dialog-content">
 57               <div class="lutece-dialog-header">
 58                   <h2 class="lutece-dialog-title h4 text-dark" id="portletModalLabel">#i18n{portal.site.portletType.labelCreate}</h2>
 59                   <button type="button" class="btn btn-link btn-close text-dark" aria-label="#i18n{portal.util.labelCancel}"><i class="ti ti-x"></i></button>
 60               </div>
 61               <div class="lutece-dialog-body">
 62                       <form action="jsp/admin/DoCreatePortlet.jsp" type="get">
 63                       <div class="container">
 64                           <div id='portlet_type_id' class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4"></div>
 65                       </div>
 66                       <div class="d-flex justify-content-center">
 67                           <button type="button" class="btn btn-secondary btn-close" value="cancel" >#i18n{portal.util.labelCancel}</button>
 68                       </div>
 69                       </form>
 70                   </div>
 71               <div>
 72           </div>
 73       </div>
 74   </div>
 75   </dialog>
 76   <script type="module">
 77   document.addEventListener( "DOMContentLoaded", function(){
 78       const parentPortletTypeNodes = window.parent.document.querySelectorAll( '#offcanvas-body-portlet-type-wrapper ul li' );
 79       const dialogPortletTypes = document.getElementById( 'portlet_type_id' );
 80       const portletDialog = document.querySelector( '#addPortletDialog' );
 81   
 82       parentPortletTypeNodes.forEach( ( item ) => {
 83           const divType = document.createElement('div')
 84           divType.classList.add('col')
 85           const aType = document.createElement('a')
 86           aType.classList.add('btn', 'btn-outline-primary', 'btn-lg','btn-block', 'btn-new-portlet', 'py-5', 'px-0' , 'my-3', 'd-flex', 'align-items-center' )
 87           aType.setAttribute( 'href', item.dataset.portletTypeHref )
 88           const spanType = document.createElement('span')
 89           spanType.classList.add( 'px-2', 'text-left' )
 90           spanType.innerText = item.dataset.portletTypeName
 91           const iconType = document.createElement('i')
 92           iconType.classList.add('ti', <#noparse>`ti-${item.dataset.portletTypeIcon}`</#noparse> ,'fs-0','d-block','me-4','mr-4','ps-2','pl-2')
 93           aType.appendChild( iconType );
 94           aType.appendChild( spanType );
 95           divType.appendChild( aType );
 96           dialogPortletTypes.appendChild( divType );
 97       })
 98   
 99       // 
 100       const columnList = document.querySelectorAll( '.lutece-admin-column' );
 101       columnList.forEach( ( col ) => {
 102           const colOutList = col.querySelectorAll( '.lutece-admin-column-outline' );
 103           colOutList.forEach( ( colOut ) => { 
 104               if( colOut.textContent.trim() === '' ){
 105                   colOut.textContent= '';
 106               }
 107           })
 108       })
 109   
 110       // "Show the dialog" button opens the <dialog> modally
 111       const btnPortletList = document.querySelectorAll( '[data-bs-toggle="modal"]' );
 112       btnPortletList.forEach( ( btnPortlet ) => {
 113           btnPortlet.addEventListener( 'click', ( event ) => {
 114               const portlet = event.currentTarget
 115               const portletColumn = portlet.dataset.portletColumn
 116               let portletOrder = portlet.dataset.portletOrder
 117               if( portletOrder === '' ){
 118                   const lastPortlet = document.querySelector(<#noparse>`#lutece-column-${portletColumn} .lutece-admin-column-outline .lutece-admin-portlet:last-child .lutece-admin-toolbar</#noparse>`)
 119                   if( lastPortlet != null ){
 120                       portletOrder = parseInt( document.querySelector(<#noparse>`#lutece-column-${portletColumn} .lutece-admin-column-outline .lutece-admin-portlet:last-child .lutece-admin-toolbar</#noparse>`).dataset.portletOrder ) + 1
 121                   } else {
 122                       portletOrder = 1
 123                   }
 124               }
 125               dialogPortletTypes.childNodes.forEach( ( item ) => {
 126                   let itemLnk = item.firstElementChild;
 127                   let itemHref = itemLnk.getAttribute('href');
 128                   <#noparse>itemLnk.setAttribute('href',`${itemHref}&portlet_column=${portletColumn}&portlet_order=${portletOrder}`)</#noparse>
 129               })  
 130               portletDialog.showModal()
 131           })
 132       })
 133   
 134       const btnCloseDialogList = document.querySelectorAll( '.btn-close' );
 135       btnCloseDialogList.forEach( ( btnCloseDialog ) => {
 136           btnCloseDialog.addEventListener( 'click', ( event ) => {
 137               portletDialog.close()
 138           })
 139       })
 140   
 141   }); 
 142   
 143   import {
 144       LuteceDraggable
 145   } from './themes/shared/modules/luteceDraggable.js';
 146   
 147   const root = document.querySelector(":root");
 148   root.style.setProperty("--column-empty-text", `"#i18n{portal.site.portletType.labelCreateColumn}"`);
 149   
 150   const containers = document.querySelectorAll('#main .lutece-admin-column-outline');
 151   const draggables = Array.from(containers).flatMap(container => [...container.children]);
 152   const AdminHomeDraggable = new LuteceDraggable( draggables, containers);
 153   
 154   async function updatePortlet( portletId, col, order ){
 155   <#noparse>const response = await fetch( `jsp/admin/site/DoModifyPortletPosition.jsp?portlet_id=${portletId}&column=${col}&order=${order}` );</#noparse>
 156   }
 157    
 158   AdminHomeDraggable.on('dragstart', (event) => {
 159      root.style.setProperty( "--column-empty-text", `"Drop moi ici !"` );
 160   });
 161    
 162   AdminHomeDraggable.on('dragover', (event) => {
 163       //event.currentTarget.style.setProperty( "opacity", ".5" );
 164   });
 165    
 166   AdminHomeDraggable.on( 'dragend', (event) => {
 167       root.style.setProperty("--column-empty-text", `"#i18n{portal.site.portletType.labelCreateColumn}"`);
 168       const dragContainer = event.target.closest( '.lutece-draggable-container' );
 169       const newCol = dragContainer.dataset.portletColumn;
 170       const portletId = event.currentTarget.firstElementChild.dataset.portletId
 171       let newOrder= 1
 172   	if ( event.currentTarget.nextSibling != null ){
 173   		newOrder = parseInt( event.currentTarget.nextSibling.firstElementChild.dataset.portletOrder )
 174   		if( newOrder > 1 ){ newOrder-- }
 175   	} else if ( event.currentTarget.previousSibling != null ){
 176   		newOrder = parseInt( event.currentTarget.previousSibling.previousSibling.firstElementChild.dataset.portletOrder )
 177   		newOrder++
 178       }
 179   
 180   	event.currentTarget.firstElementChild.firstElementChild.textContent = newOrder
 181   	event.currentTarget.firstElementChild.firstElementChild.dataset.portletOrder = newOrder
 182   	event.currentTarget.firstElementChild.firstElementChild.dataset.portletColumn = newCol
 183   
 184       if( dragContainer.textContent.trim() === '' ){ dragContainer.textContent = '' }
 185   
 186   	updatePortlet( portletId, newCol, newOrder )
 187   }); 
 188   </script> 
 189   </#macro>