This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository scmwebeditor. See http://git.nuiton.org/scmwebeditor.git commit 0afabfbd2184c8c0d089e2b441144a3170370eee Author: Hugo PIGEON <hpigeon@codelutin.com> Date: Mon Jun 15 17:04:05 2015 +0200 Add the support of SVG files: when opening one, SCMWebEditor asks the user if he wants to edit the code or view the image --- .../org/nuiton/scmwebeditor/svn/SvnConnection.java | 24 ++++++- .../scmwebeditor/uiweb/actions/BrowseAction.java | 2 +- .../scmwebeditor/uiweb/actions/GetImageAction.java | 57 ++++++++++++---- .../uiweb/actions/ViewImageAction.java | 6 +- .../i18n/scmwebeditor-ui-web_en_GB.properties | 4 ++ .../i18n/scmwebeditor-ui-web_fr_FR.properties | 4 ++ .../src/main/webapp/WEB-INF/content/browse.jsp | 62 +++++++++++++++--- .../main/webapp/WEB-INF/content/imageViewer.jsp | 75 ++++++++++++++++++---- .../webapp/WEB-INF/content/modificationViewer.jsp | 57 +++++++++++++--- .../main/webapp/WEB-INF/content/outConnection.jsp | 1 + swe-ui-web/src/main/webapp/css/main.css | 36 ++++++++--- 11 files changed, 268 insertions(+), 60 deletions(-) diff --git a/swe-svn/src/main/java/org/nuiton/scmwebeditor/svn/SvnConnection.java b/swe-svn/src/main/java/org/nuiton/scmwebeditor/svn/SvnConnection.java index bec40e6..4ef9e19 100644 --- a/swe-svn/src/main/java/org/nuiton/scmwebeditor/svn/SvnConnection.java +++ b/swe-svn/src/main/java/org/nuiton/scmwebeditor/svn/SvnConnection.java @@ -80,7 +80,7 @@ public class SvnConnection implements ScmConnection { /** svn default option */ protected DefaultSVNOptions svnOption; - /** the id of the HTTP session */ + /** the path to the local repositories */ protected String pathToLocalRepos; /** the manager which allows authentication */ @@ -506,7 +506,27 @@ public class SvnConnection implements ScmConnection { @Override public String getFilePath(String address, String repositoryRoot, String username, String password) { - return address; + + String path = address; + + if (address.toLowerCase().endsWith(".svg")) { + + File svgFile = null; + + try { + svgFile = getFileContent(address, username, password); + } catch (AuthenticationException e) { + if (log.isErrorEnabled()) { + log.error("Can not get file content for address " + address); + } + } + + if (svgFile != null) { + path = svgFile.getAbsolutePath(); + } + } + + return path; } @Override diff --git a/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/BrowseAction.java b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/BrowseAction.java index 7cffa65..f074b51 100644 --- a/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/BrowseAction.java +++ b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/BrowseAction.java @@ -218,7 +218,7 @@ public class BrowseAction extends AbstractScmWebEditorAction implements ServletR } else if (fileName.endsWith(".txt")) { node.setIcon("ui-icon-txt"); } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".png") - || fileName.endsWith(".gif")) { + || fileName.endsWith(".gif") || fileName.endsWith(".svg")) { node.setIcon("ui-icon-image"); } else { node.setIcon("ui-icon-document"); diff --git a/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/GetImageAction.java b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/GetImageAction.java index 8eb49b9..8891888 100644 --- a/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/GetImageAction.java +++ b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/GetImageAction.java @@ -23,13 +23,18 @@ package org.nuiton.scmwebeditor.uiweb.actions; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.nuiton.scmwebeditor.uiweb.ScmWebEditorConfig; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; /** @@ -71,20 +76,42 @@ public class GetImageAction extends ScmWebEditorMainAction { public byte[] getCustomImageInBytes() { - BufferedImage originalImage; - try { - File fileImage = new File(imagePath); - originalImage = ImageIO.read(fileImage); + HttpSession session = servletRequest.getSession(); + String sessionId = session.getId(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageIO.write(originalImage, imagePath.substring(imagePath.lastIndexOf('.') + 1), baos); - baos.flush(); - imageInByte = baos.toByteArray(); - baos.close(); - } catch (IOException e) { - if (log.isErrorEnabled()) { - log.error("Can not get image file at " + imagePath, e); + String pathToLocalRepos = ScmWebEditorConfig.getLocalRepositoriesPath() + File.separator + sessionId; + + if (imagePath.startsWith(pathToLocalRepos)) { + + BufferedImage originalImage; + + try { + File fileImage = new File(imagePath); + String fileFormat = imagePath.substring(imagePath.lastIndexOf('.') + 1); + + if (fileFormat.toLowerCase().equals("svg")) { + + Path path = Paths.get(imagePath); + imageInByte = Files.readAllBytes(path); + + } else { + + originalImage = ImageIO.read(fileImage); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + ImageIO.write(originalImage, fileFormat, baos); + + baos.flush(); + + imageInByte = baos.toByteArray(); + + baos.close(); + } + } catch (IOException e) { + if (log.isErrorEnabled()) { + log.error("Can not get image file at " + imagePath, e); + } } } @@ -94,7 +121,7 @@ public class GetImageAction extends ScmWebEditorMainAction { imageInByteCopy = Arrays.copyOf(imageInByte, imageInByte.length); } - return imageInByte; + return imageInByteCopy; } public String getCustomContentType() { @@ -104,8 +131,10 @@ public class GetImageAction extends ScmWebEditorMainAction { if (path.endsWith(".png")) { type = "image/png"; - } else if(path.endsWith(".gif")) { + } else if (path.endsWith(".gif")) { type = "image/gif"; + } else if (path.endsWith(".svg")) { + type = "image/svg+xml"; } return type; diff --git a/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/ViewImageAction.java b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/ViewImageAction.java index d341de1..35961d8 100644 --- a/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/ViewImageAction.java +++ b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/ViewImageAction.java @@ -49,7 +49,7 @@ public class ViewImageAction extends ScmWebEditorMainAction { protected static final String VIEW_IMAGE = "viewImage"; - protected static final List<String> SUPPORTED_IMAGE_FORMATS = Arrays.asList("jpg", "jpeg", "png", "gif"); + protected static final List<String> SUPPORTED_IMAGE_FORMATS = Arrays.asList("jpg", "jpeg", "png", "gif", "svg"); /** the name of the selected branch */ protected String selectedBranch; @@ -94,9 +94,9 @@ public class ViewImageAction extends ScmWebEditorMainAction { */ public String execute() { - String imageFormat = address.substring(address.lastIndexOf('.') + 1).toLowerCase(); + format = address.substring(address.lastIndexOf('.') + 1).toLowerCase(); - if (!SUPPORTED_IMAGE_FORMATS.contains(imageFormat)) { + if (!SUPPORTED_IMAGE_FORMATS.contains(format)) { return ERROR_PATH; } diff --git a/swe-ui-web/src/main/resources/i18n/scmwebeditor-ui-web_en_GB.properties b/swe-ui-web/src/main/resources/i18n/scmwebeditor-ui-web_en_GB.properties index df0755c..f7cc41f 100644 --- a/swe-ui-web/src/main/resources/i18n/scmwebeditor-ui-web_en_GB.properties +++ b/swe-ui-web/src/main/resources/i18n/scmwebeditor-ui-web_en_GB.properties @@ -75,6 +75,9 @@ scm.newDirectoryName=Name of the new directory\: scm.no=No scm.notEditable=is not editable. scm.openAnotherFile=Open another file +scm.openSvgEdit=Edit the SVG file's code +scm.openSvgFile=SVG files are images created from XML code. Do you want to edit the XML code or to see the resulting image? +scm.openSvgView=View the image scm.outConnection.branches=List of branches scm.outConnection.enterRepo=Please enter your repository address. scm.outConnection.headBranch=Current branch\: @@ -117,6 +120,7 @@ scm.shortcuts=Shortcuts scm.showDiff=Show differences scm.stayLogin=Keep me logged scm.submit=Submit +scm.svgFile=SVG file scm.text=Text scm.thankUsing=Thank you using SCMWebEditor scm.titles.badRstFile=RST not valid diff --git a/swe-ui-web/src/main/resources/i18n/scmwebeditor-ui-web_fr_FR.properties b/swe-ui-web/src/main/resources/i18n/scmwebeditor-ui-web_fr_FR.properties index af0120a..093757e 100644 --- a/swe-ui-web/src/main/resources/i18n/scmwebeditor-ui-web_fr_FR.properties +++ b/swe-ui-web/src/main/resources/i18n/scmwebeditor-ui-web_fr_FR.properties @@ -75,6 +75,9 @@ scm.newDirectoryName=Nom du nouveau répertoire \: scm.no=Non scm.notEditable=n'est pas éditable. scm.openAnotherFile=Ouvrir un autre fichier +scm.openSvgEdit=Éditer le code du fichier SVG +scm.openSvgFile=Les fichiers SVG sont des images créées à partir de code XML. Souhaitez-vous éditer le code XML ou voir l'image qui en résulte ? +scm.openSvgView=Voir l'image scm.outConnection.branches=Liste des branches scm.outConnection.enterRepo=Entrez l'adresse de votre dépôt. scm.outConnection.headBranch=Branche courante \: @@ -117,6 +120,7 @@ scm.shortcuts=Raccourcis scm.showDiff=Voir les differences scm.stayLogin=Rester connecté scm.submit=Envoyer +scm.svgFile=Fichier SVG scm.text=Texte scm.thankUsing=merci d'avoir utilisé SCMWebEditor scm.titles.badRstFile=RST non valide diff --git a/swe-ui-web/src/main/webapp/WEB-INF/content/browse.jsp b/swe-ui-web/src/main/webapp/WEB-INF/content/browse.jsp index 189b066..8fd164a 100644 --- a/swe-ui-web/src/main/webapp/WEB-INF/content/browse.jsp +++ b/swe-ui-web/src/main/webapp/WEB-INF/content/browse.jsp @@ -30,8 +30,18 @@ <sj:head debug="true" jquerytheme="default"/> <script> + var svgAddress; document.getElementById('loadingIndicator').style.display = 'none'; + function openSvg(action) { + var scmType = document.getElementById("scmType").value; + var selectedBranch = $("#selectedBranchDisplay").text().trim(); + var repositoryRoot = document.getElementById("addressInput").value; + + document.location.href = (action + "?address=" + svgAddress + "&scmType=" + scmType + + "&selectedBranch=" + selectedBranch + "&repositoryRoot=" + repositoryRoot); + } + $.subscribe('treeClicked', function(event, data) { var item = event.originalEvent.data.rslt.obj; @@ -39,20 +49,27 @@ var classAttr = item[0].getAttribute("class"); if (classAttr.indexOf("jstree-leaf") != -1) { - var scmType = document.getElementById("scmType").value; - var selectedBranch = $("#selectedBranchDisplay").text().trim(); - var repositoryRoot = document.getElementById("addressInput").value; var fileExtension = item.attr("id").substr(item.attr("id").lastIndexOf(".") + 1); - var actionFile = "edit.action"; - var supportedImages = ["jpg", "jpeg", "png", "gif"]; + if (fileExtension.toLowerCase() === "svg") { + svgAddress = item.attr("id"); + openPopin("svgPopin"); + } else { - if (supportedImages.indexOf(fileExtension.toLowerCase()) != -1) { - actionFile = "viewImage.action"; - } + var scmType = document.getElementById("scmType").value; + var selectedBranch = $("#selectedBranchDisplay").text().trim(); + var repositoryRoot = document.getElementById("addressInput").value; + var actionFile = "edit.action"; - document.location.href = (actionFile + "?address=" + item.attr("id") + "&scmType=" + scmType - + "&selectedBranch=" + selectedBranch + "&repositoryRoot=" + repositoryRoot); + var supportedImages = ["jpg", "jpeg", "png", "gif"]; + + if (supportedImages.indexOf(fileExtension.toLowerCase()) != -1) { + actionFile = "viewImage.action"; + } + + document.location.href = (actionFile + "?address=" + item.attr("id") + "&scmType=" + scmType + + "&selectedBranch=" + selectedBranch + "&repositoryRoot=" + repositoryRoot); + } } } @@ -332,5 +349,30 @@ </ul> + <!-- popin to choose how to open the SVG file --> + <div id="svgPopin" class="popin"> + <span class="closePopin" onclick="closePopin('svgPopin')"> + X + </span> + + <s:set id="scm.openSvgEdit"> + <s:text name="scm.openSvgEdit"/> + </s:set> + + <s:set id="scm.openSvgView"> + <s:text name="scm.openSvgView"/> + </s:set> + + <h4><s:text name="scm.svgFile"/></h4> + <p> + <s:text name="scm.openSvgFile"/> + </p> + <s:submit id="openSvgEdit" value="%{scm.openSvgEdit}" onclick="openSvg('edit.action');"/> + <s:submit id="openSvgView" value="%{scm.openSvgView}" onclick="openSvg('viewImage.action');"/> + </div> + + + <div id="popinBackground"></div> + </s:else> diff --git a/swe-ui-web/src/main/webapp/WEB-INF/content/imageViewer.jsp b/swe-ui-web/src/main/webapp/WEB-INF/content/imageViewer.jsp index 6c96988..a45d49d 100644 --- a/swe-ui-web/src/main/webapp/WEB-INF/content/imageViewer.jsp +++ b/swe-ui-web/src/main/webapp/WEB-INF/content/imageViewer.jsp @@ -42,9 +42,10 @@ <link rel="stylesheet" type="text/css" href="css/main.css"> <script type="text/javascript" src="js/popin.js"></script> - <script type="text/javascript" src="js/editor.js"></script> <script type="text/javascript"> + var svgAddress; + // Opens the selected file in the tree $.subscribe('treeClicked', function(event, data) { var item = event.originalEvent.data.rslt.obj; @@ -53,26 +54,56 @@ var classAttr = item[0].getAttribute("class"); if (classAttr.indexOf("jstree-leaf") != -1) { - var scmType = document.getElementById("scmType").value; var fileExtension = item.attr("id").substr(item.attr("id").lastIndexOf(".") + 1); - var actionFile = "edit.action"; - var supportedImages = ["jpg", "jpeg", "png", "gif"]; + if (fileExtension.toLowerCase() === "svg") { + svgAddress = item.attr("id"); + openPopin("svgPopin"); + } else { - if (supportedImages.indexOf(fileExtension.toLowerCase()) != -1) { - actionFile = "viewImage.action"; - } + var scmType = document.getElementById("scmType").value; + var actionFile = "edit.action"; + + var supportedImages = ["jpg", "jpeg", "png", "gif"]; - document.location.href = (actionFile + "?address=" + item.attr("id") + "&scmType=" + scmType - + '&selectedBranch=<s:property value="selectedBranch"/>&repositoryRoot=<s:property value="repositoryRoot"/>'); + if (supportedImages.indexOf(fileExtension.toLowerCase()) != -1) { + actionFile = "viewImage.action"; + } + + document.location.href = (actionFile + "?address=" + item.attr("id") + "&scmType=" + scmType + + '&selectedBranch=<s:property value="selectedBranch"/>&repositoryRoot=<s:property value="repositoryRoot"/>'); + } } } + }); + // automatically expand the directory when there is no other file + $.subscribe('treeChanged', function(event, data) { + + var json = event.originalEvent.data.responseJSON; + + if (json.length == 1) { + var object = json[0]; + + if (object.state === "closed") { + var htmlObject = document.getElementById(object.id); + var children = htmlObject.children; + children.item('ins').click(); + } + } }); + + /* Allows to open a SVG file in the selected mode */ + function openSvg(action) { + var scmType = document.getElementById("scmType").value; + + document.location.href = (action + "?address=" + svgAddress + "&scmType=" + scmType + + '&selectedBranch=<s:property value="selectedBranch"/>&repositoryRoot=<s:property value="repositoryRoot"/>'); + } </script> </head> -<body> +<body id="viewImageBody"> <div id="wrapper"> @@ -364,7 +395,7 @@ </ul> <!-- END menu --> - <s:if test="filesDirectlyAccessible"> + <s:if test="filesDirectlyAccessible && format != 'svg'"> <img src="<s:property value="imagePath"/>" id="displayedImage"/> @@ -426,6 +457,28 @@ </div> +<!-- popin to choose how to open the SVG file --> +<div id="svgPopin" class="popin"> + <span class="closePopin" onclick="closePopin('svgPopin')"> + X + </span> + + <s:set id="scm.openSvgEdit"> + <s:text name="scm.openSvgEdit"/> + </s:set> + + <s:set id="scm.openSvgView"> + <s:text name="scm.openSvgView"/> + </s:set> + + <h4><s:text name="scm.svgFile"/></h4> + <p> + <s:text name="scm.openSvgFile"/> + </p> + <s:submit id="openSvgEdit" value="%{scm.openSvgEdit}" onclick="openSvg('edit.action');"/> + <s:submit id="openSvgView" value="%{scm.openSvgView}" onclick="openSvg('viewImage.action');"/> +</div> + <div id="popinBackground"></div> </body> diff --git a/swe-ui-web/src/main/webapp/WEB-INF/content/modificationViewer.jsp b/swe-ui-web/src/main/webapp/WEB-INF/content/modificationViewer.jsp index 0c7526a..a54dfb3 100644 --- a/swe-ui-web/src/main/webapp/WEB-INF/content/modificationViewer.jsp +++ b/swe-ui-web/src/main/webapp/WEB-INF/content/modificationViewer.jsp @@ -88,6 +88,8 @@ <script type="text/javascript"> + var svgAddress; + // Opens the selected file in the tree $.subscribe('treeClicked', function(event, data) { var item = event.originalEvent.data.rslt.obj; @@ -96,23 +98,38 @@ var classAttr = item[0].getAttribute("class"); if (classAttr.indexOf("jstree-leaf") != -1) { - var scmType = document.getElementById("scmType").value; + var fileExtension = item.attr("id").substr(item.attr("id").lastIndexOf(".") + 1); - var actionFile = "edit.action"; - var supportedImages = ["jpg", "jpeg", "png", "gif"]; + if (fileExtension.toLowerCase() === "svg") { + svgAddress = item.attr("id"); + openPopin("svgPopin"); + } else { - if (supportedImages.indexOf(fileExtension.toLowerCase()) != -1) { - actionFile = "viewImage.action"; - } + var scmType = document.getElementById("scmType").value; + var actionFile = "edit.action"; - document.location.href = (actionFile + "?address=" + item.attr("id") + "&scmType=" + scmType - + '&selectedBranch=<s:property value="selectedBranch"/>&repositoryRoot=<s:property value="repositoryRoot"/>'); + var supportedImages = ["jpg", "jpeg", "png", "gif"]; + + if (supportedImages.indexOf(fileExtension.toLowerCase()) != -1) { + actionFile = "viewImage.action"; + } + + document.location.href = (actionFile + "?address=" + item.attr("id") + "&scmType=" + scmType + + '&selectedBranch=<s:property value="selectedBranch"/>&repositoryRoot=<s:property value="repositoryRoot"/>'); + } } } - }); + /* Allows to open a SVG file in the selected mode */ + function openSvg(action) { + var scmType = document.getElementById("scmType").value; + + document.location.href = (action + "?address=" + svgAddress + "&scmType=" + scmType + + '&selectedBranch=<s:property value="selectedBranch"/>&repositoryRoot=<s:property value="repositoryRoot"/>'); + } + window.onbeforeunload = confirmExitOnUnload; </script> @@ -864,6 +881,28 @@ </div> </s:elseif> +<!-- popin to choose how to open the SVG file --> +<div id="svgPopin" class="popin"> + <span class="closePopin" onclick="closePopin('svgPopin')"> + X + </span> + + <s:set id="scm.openSvgEdit"> + <s:text name="scm.openSvgEdit"/> + </s:set> + + <s:set id="scm.openSvgView"> + <s:text name="scm.openSvgView"/> + </s:set> + + <h4><s:text name="scm.svgFile"/></h4> + <p> + <s:text name="scm.openSvgFile"/> + </p> + <s:submit id="openSvgEdit" value="%{scm.openSvgEdit}" onclick="openSvg('edit.action');"/> + <s:submit id="openSvgView" value="%{scm.openSvgView}" onclick="openSvg('viewImage.action');"/> +</div> + <div id="popinBackground"></div> diff --git a/swe-ui-web/src/main/webapp/WEB-INF/content/outConnection.jsp b/swe-ui-web/src/main/webapp/WEB-INF/content/outConnection.jsp index 50227c1..b37d7f4 100644 --- a/swe-ui-web/src/main/webapp/WEB-INF/content/outConnection.jsp +++ b/swe-ui-web/src/main/webapp/WEB-INF/content/outConnection.jsp @@ -39,6 +39,7 @@ <script type="text/javascript" src="js/branches.js"></script> <script type="text/javascript" src="js/scmDetector.js"></script> + <script type="text/javascript" src="js/popin.js"></script> <script type="text/javascript"> diff --git a/swe-ui-web/src/main/webapp/css/main.css b/swe-ui-web/src/main/webapp/css/main.css index 11ae4de..b829e4d 100644 --- a/swe-ui-web/src/main/webapp/css/main.css +++ b/swe-ui-web/src/main/webapp/css/main.css @@ -27,7 +27,7 @@ body { margin:auto; } -#editBody { +#editBody, #viewImageBody { width: 100%; } @@ -139,6 +139,29 @@ ul.flags li { display:inline; } +#wwctrl_submitPrivateScm { + display: inline; +} + +#wwctrl_viewHistoryButton { + display: inline; +} + +#wwctrl_openSvgEdit, #wwctrl_openSvgView { + position: relative; + top: 50px; +} + +#wwctrl_openSvgEdit { + float: left; + left: 50px; +} + +#wwctrl_openSvgView { + float: right; + right: 50px; +} + #repositoryButtonsBrowse { display: table; border-spacing: 10px; @@ -279,10 +302,6 @@ ul.flags li { font-family: Verdana, Arial, Helvetica, sans-serif; } -#wwctrl_submitPrivateScm { - display: inline; -} - .popin { position: fixed; width: 50%; @@ -314,7 +333,7 @@ ul.flags li { width: 90%; } -#rstInfoPopin, #mdInfoPopin { +#rstInfoPopin, #mdInfoPopin, #svgPopin { height: 50%; top: 25%; left: 25%; @@ -438,6 +457,7 @@ ul.buttonsGroup li { #displayedImage { display: block; margin: auto; + max-width: 100%; } #historyContent { @@ -446,10 +466,6 @@ ul.buttonsGroup li { padding: 5px; } -#wwctrl_viewHistoryButton { - display: inline; -} - #viewHistoryButton { margin-top: 10px; } -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.