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