Skip to content

Commit 8b230ca

Browse files
committed
LUT-25955 : Create anchors inside a page
1 parent b0b7560 commit 8b230ca

File tree

4 files changed

+157
-1
lines changed

4 files changed

+157
-1
lines changed

src/java/fr/paris/lutece/plugins/wiki/web/WikiDynamicInputs.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535

3636

3737
import com.fasterxml.jackson.databind.ObjectMapper;
38+
import com.google.gson.Gson;
39+
import com.google.gson.GsonBuilder;
3840
import fr.paris.lutece.plugins.wiki.business.*;
3941
import fr.paris.lutece.plugins.wiki.service.ContentDeserializer;
4042
import fr.paris.lutece.plugins.wiki.service.RoleService;
@@ -45,12 +47,17 @@
4547
import fr.paris.lutece.portal.service.security.UserNotSignedException;
4648
import fr.paris.lutece.portal.service.util.AppLogService;
4749
import fr.paris.lutece.plugins.wiki.service.parser.LuteceHtmlParser;
50+
import org.jsoup.Jsoup;
51+
import org.jsoup.nodes.Document;
52+
import org.jsoup.nodes.Element;
4853

4954
import javax.servlet.http.HttpServletRequest;
5055
import javax.servlet.http.HttpServletResponse;
5156
import java.io.BufferedReader;
5257
import java.io.IOException;
58+
import java.util.ArrayList;
5359
import java.util.HashMap;
60+
import java.util.List;
5461

5562
/**
5663
* Upload application
@@ -142,4 +149,47 @@ public static HttpServletResponse modifyPage( HttpServletRequest request, HttpSe
142149

143150
return response;
144151
}
152+
153+
public static HttpServletResponse getPageHeadings( HttpServletRequest resquest, HttpServletResponse response ) throws IOException, UserNotSignedException
154+
{
155+
String pageName = resquest.getParameter( "pageName" );
156+
String locale = resquest.getParameter( "locale" );
157+
Topic topic = TopicHome.findByPageName( pageName );
158+
159+
160+
List<HashMap<String, String>> headings = new ArrayList<HashMap<String, String>>( );
161+
try
162+
{
163+
if ( RoleService.hasEditRole( resquest, topic ) )
164+
{
165+
// if you merge this after LUT-25169, change findLastVersion to getPublishedVersion
166+
TopicVersion topicVersion = TopicVersionHome.findLastVersion( topic.getIdTopic( ) );
167+
WikiContent wikiContent = topicVersion.getWikiContent( locale );
168+
String htmlContent = SpecialChar.renderWiki( wikiContent.getHtmlWikiContent( ) );
169+
Document htmlDocument = Jsoup.parse( htmlContent );
170+
Element docBody = htmlDocument.body( );
171+
for ( Element element : docBody.select( "h1, h2, h3, h4, h5, h6" ) )
172+
{
173+
HashMap<String, String> heading = new HashMap<String, String>( );
174+
heading.put( "header_id", element.id( ) );
175+
heading.put( "header_text", element.text( ) );
176+
headings.add( heading );
177+
}
178+
}
179+
else
180+
{
181+
throw new UserNotSignedException( );
182+
}
183+
}
184+
catch( Exception e )
185+
{
186+
AppLogService.error( "Error saving last user opening modify topic page", e );
187+
188+
}
189+
ObjectMapper mapper = new ObjectMapper();
190+
String res = mapper.writeValueAsString(headings);
191+
192+
response.getWriter( ).write( res );
193+
return response;
194+
}
145195
}

webapp/WEB-INF/templates/skin/plugins/wiki/custom_input_editor.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,35 @@
136136
</div>
137137
</div>
138138

139+
<!------------ modal to select a link to the same plugin ----------------->
140+
<div id="selectInnerLinkModal" class="toastui-editor-popup" style="display: none;" >
141+
<div style="position: absolute; top: 50%; left: 50%; z-index: -1;"></div>
142+
<button class="btn btn-default" type="button" style="position: absolute; right: 0;" onclick="closeToastUiModal()">
143+
<span class="fa fa-times"></span>
144+
</button>
145+
<div class="toastui-editor-popup-header">
146+
<div class="toastui-editor-popup-header-title">Select a link to this wiki site</div>
147+
</div>
148+
<div class="toastui-editor-popup-body">
149+
<div class="toastui-editor-popup-content-body">
150+
<select id="selectInnerLinkPage" name="parent_page_name" class="form-control" onchange="loadInnerLinksHeadings(this.value)">
151+
<option disabled selected>select a published page</option>
152+
<option value="${topic.pageName}" >${topic.pageName}</option>
153+
<#list topicNameList as topicName>
154+
<#if topicName != "">
155+
<option value="${topicName}" >${topicName}</option>
156+
</#if>
157+
</#list>
158+
</select>
159+
</div>
160+
</div>
161+
<div id="pageIsSelected" style="display: none">
162+
<div class="toastui-editor-popup-content-body" style="margin: 25px;">
163+
<label for="selectPageHeadingLink">Icon Size :</label>
164+
<select id="selectPageHeadingLink" class="form-control" onchange="insertInnerLink(this.value)">
165+
</select>
166+
</div>
167+
</div>
168+
</div>
169+
139170
<!------------------- END OF CUSTOM INPUTS -------------------------->

webapp/js/plugins/wiki/wiki_pages/modify_page.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ editor.insertToolbarItem({ groupIndex: 0, itemIndex: 6 }, {
116116
className: 'fa fa-video editor',
117117
style: { backgroundImage: 'none' },
118118
});
119+
editor.insertToolbarItem({ groupIndex: 0, itemIndex: 8 }, {
120+
name: 'InternalLink',
121+
tooltip: 'Internal Link',
122+
text: 'IL',
123+
className: 'fa fa-link editor',
124+
style: { backgroundImage: 'none' },
125+
});
119126
editor.insertToolbarItem({ groupIndex: 0, itemIndex: 9 }, {
120127
name: 'Image',
121128
tooltip: 'Image',
@@ -301,6 +308,71 @@ function selectJumbotron(jumbotronValue) {
301308
closeToastUiModal();
302309
}
303310

311+
/* -------------- INTERNAL LINK -------------- */
312+
const addInternalLinkButton = document.getElementsByClassName("fa fa-link editor")[0];
313+
addInternalLinkButton.addEventListener('click', function() {
314+
document.getElementById("selectInnerLinkModal").style.display = "block";
315+
});
316+
let pageValueInnerLink = "";
317+
function loadInnerLinksHeadings(pageValue){
318+
pageValueInnerLink = pageValue;
319+
const queryParam = "?actionName=getPageHeadings&pageName=" + pageValue + "&locale=" + localeJs;
320+
const urlHeadings = 'jsp/site/plugins/wiki/WikiDynamicInputs.jsp' + queryParam;
321+
fetch( urlHeadings, {
322+
method: 'GET',
323+
headers: {
324+
'Accept': 'application/json',
325+
'Content-Type': 'application/json',
326+
credentials: "same-origin",
327+
}
328+
})
329+
.then(response => response.json())
330+
.then(data => {
331+
if(data.length === 0){
332+
alert("No headings found in this page");
333+
return;
334+
} else {
335+
let selectHeadingLink = document.getElementById("selectPageHeadingLink");
336+
selectHeadingLink.innerHTML = "";
337+
let opt1 = document.createElement('option');
338+
opt1.value = "";
339+
opt1.innerText = "Select a heading";
340+
opt1.selected = true;
341+
opt1.disabled = true;
342+
selectHeadingLink.appendChild(opt1);
343+
for (let i = 0; i < data.length; i++) {
344+
let opt = document.createElement('option');
345+
opt.value = JSON.stringify(data[i]);
346+
opt.innerText = data[i].header_text;
347+
document.getElementById("selectPageHeadingLink").appendChild(opt);
348+
}
349+
document.getElementById("pageIsSelected").style.display = "block";
350+
}
351+
})
352+
.catch((error) => {
353+
console.error('Error:', error);
354+
});
355+
356+
}
357+
358+
function insertInnerLink (linkValue){
359+
let linkValueJson = JSON.parse(linkValue);
360+
let pageDestinationUrl = window.location.href;
361+
362+
// replace all char after &view= parameter from url
363+
pageDestinationUrl = pageDestinationUrl.replace("view=modifyPage", "view=page");
364+
pageDestinationUrl = pageDestinationUrl.replace(/&version=[0-9]*/g, "");
365+
pageDestinationUrl = pageDestinationUrl.replace(/&page_name=[a-z]*/g, "");
366+
pageDestinationUrl += "&";
367+
pageDestinationUrl += "page_name="
368+
pageDestinationUrl += pageValueInnerLink;
369+
pageDestinationUrl += "#" + linkValueJson.header_id;
370+
editor.insertText("[" + linkValueJson.header_text + "](" + pageDestinationUrl + ")");
371+
document.getElementById("pageIsSelected").style.display = "none";
372+
closeToastUiModal();
373+
}
374+
375+
304376
/* -------------- DARK MODE -------------- */
305377
const darkModeButton = document.getElementsByClassName("fa fa-moon editor")[0];
306378
darkModeButton.addEventListener('click', function() {

webapp/jsp/site/plugins/wiki/WikiDynamicInputs.jsp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
<jsp:useBean id="AutoSaveWiki" scope="request" class="fr.paris.lutece.plugins.wiki.web.WikiDynamicInputs" />
44

55
<%
6-
if("modifyPage".equals(request.getParameter("actionName")))
6+
if("modifyPage".equals(request.getParameter("actionName")))
77
{
88
WikiDynamicInputs.modifyPage( request, response );
9+
} else if("getPageHeadings".equals(request.getParameter("actionName")))
10+
{
11+
WikiDynamicInputs.getPageHeadings( request, response );
912
}
1013
%>

0 commit comments

Comments
 (0)