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 e9dae2c65832ffb5a04dda48703ef4bd593b3500 Author: Hugo PIGEON <hpigeon@codelutin.com> Date: Mon Jun 1 16:29:52 2015 +0200 Add the ability to open image files --- .../org/nuiton/scmwebeditor/git/GitConnection.java | 9 + .../org/nuiton/scmwebeditor/git/GitProvider.java | 5 + .../org/nuiton/scmwebeditor/api/ScmConnection.java | 9 + .../org/nuiton/scmwebeditor/api/ScmProvider.java | 6 + .../org/nuiton/scmwebeditor/svn/SvnConnection.java | 5 + .../org/nuiton/scmwebeditor/svn/SvnProvider.java | 5 + .../scmwebeditor/uiweb/ImageBytesResult.java | 43 +++ .../scmwebeditor/uiweb/actions/BrowseAction.java | 16 +- .../scmwebeditor/uiweb/actions/GetImageAction.java | 102 +++++++ .../uiweb/actions/ViewImageAction.java | 244 ++++++++++++++++ .../i18n/scmwebeditor-ui-web_en_GB.properties | 3 +- .../i18n/scmwebeditor-ui-web_fr_FR.properties | 3 +- swe-ui-web/src/main/resources/struts.xml | 13 + .../src/main/webapp/WEB-INF/content/browse.jsp | 12 +- .../main/webapp/WEB-INF/content/imageViewer.jsp | 312 +++++++++++++++++++++ .../webapp/WEB-INF/content/modificationViewer.jsp | 12 +- swe-ui-web/src/main/webapp/css/main.css | 5 + swe-ui-web/src/main/webapp/js/editor.js | 4 +- 18 files changed, 792 insertions(+), 16 deletions(-) diff --git a/swe-git/src/main/java/org/nuiton/scmwebeditor/git/GitConnection.java b/swe-git/src/main/java/org/nuiton/scmwebeditor/git/GitConnection.java index 384c5e9..92a5e3a 100644 --- a/swe-git/src/main/java/org/nuiton/scmwebeditor/git/GitConnection.java +++ b/swe-git/src/main/java/org/nuiton/scmwebeditor/git/GitConnection.java @@ -1273,6 +1273,15 @@ public class GitConnection implements ScmConnection { return fileName; } + @Override + public String getImagePath(String address, String repositoryRoot) { + + String path = localDirectory.getAbsolutePath() + address.replace(repositoryRoot, ""); + path.replaceAll("/", File.separator); + + return path; + } + /** * Changing for another branch diff --git a/swe-git/src/main/java/org/nuiton/scmwebeditor/git/GitProvider.java b/swe-git/src/main/java/org/nuiton/scmwebeditor/git/GitProvider.java index 95ea4f0..fefa5fc 100644 --- a/swe-git/src/main/java/org/nuiton/scmwebeditor/git/GitProvider.java +++ b/swe-git/src/main/java/org/nuiton/scmwebeditor/git/GitProvider.java @@ -251,6 +251,11 @@ public class GitProvider implements ScmProvider { } @Override + public boolean filesDirectlyAccessible() { + return false; + } + + @Override public ScmConnection getConnection(String address, String pathToLocalRepos) { GitConnection gitConn = null; diff --git a/swe-scm-api/src/main/java/org/nuiton/scmwebeditor/api/ScmConnection.java b/swe-scm-api/src/main/java/org/nuiton/scmwebeditor/api/ScmConnection.java index 65010ec..542f256 100644 --- a/swe-scm-api/src/main/java/org/nuiton/scmwebeditor/api/ScmConnection.java +++ b/swe-scm-api/src/main/java/org/nuiton/scmwebeditor/api/ScmConnection.java @@ -122,4 +122,13 @@ public interface ScmConnection { * @return the name of the edited file */ String getFileName(); + + + /** + * Gives the path to use to display an image on a web page + * @param address the full address of the image on the repository + * @param repositoryRoot the address of the repository's root + * @return the path to use to display an image on a web page + */ + String getImagePath(String address, String repositoryRoot); } diff --git a/swe-scm-api/src/main/java/org/nuiton/scmwebeditor/api/ScmProvider.java b/swe-scm-api/src/main/java/org/nuiton/scmwebeditor/api/ScmProvider.java index 46bbc63..08976e6 100644 --- a/swe-scm-api/src/main/java/org/nuiton/scmwebeditor/api/ScmProvider.java +++ b/swe-scm-api/src/main/java/org/nuiton/scmwebeditor/api/ScmProvider.java @@ -77,6 +77,12 @@ public interface ScmProvider { boolean supportsPush(); /** + * Tells whether the repositories' files are directly accessible by their address + * @return true if the files are directly accessible + */ + boolean filesDirectlyAccessible(); + + /** * Gives the connection to the SCM * @param address the repository's address * @param pathToLocalRepos the folder which will be used to store one client's repositories 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 d8808bc..b4da898 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 @@ -997,6 +997,11 @@ public class SvnConnection implements ScmConnection { return fileName; } + @Override + public String getImagePath(String address, String repositoryRoot) { + return address; + } + public String getSvnRoot(String username, String password) { String repositoryRoot; diff --git a/swe-svn/src/main/java/org/nuiton/scmwebeditor/svn/SvnProvider.java b/swe-svn/src/main/java/org/nuiton/scmwebeditor/svn/SvnProvider.java index 6b3fdf4..52e73f3 100644 --- a/swe-svn/src/main/java/org/nuiton/scmwebeditor/svn/SvnProvider.java +++ b/swe-svn/src/main/java/org/nuiton/scmwebeditor/svn/SvnProvider.java @@ -81,6 +81,11 @@ public class SvnProvider implements ScmProvider { } @Override + public boolean filesDirectlyAccessible() { + return true; + } + + @Override public ScmConnection getConnection(String address, String pathToLocalRepos) { SvnConnection svnConn = null; diff --git a/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/ImageBytesResult.java b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/ImageBytesResult.java new file mode 100644 index 0000000..25ea9e5 --- /dev/null +++ b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/ImageBytesResult.java @@ -0,0 +1,43 @@ +/* + * #%L + * ScmWebEditor + * %% + * Copyright (C) 2009 - 2015 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.scmwebeditor.uiweb; + +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.Result; +import org.apache.struts2.ServletActionContext; +import org.nuiton.scmwebeditor.uiweb.actions.GetImageAction; + +import javax.servlet.http.HttpServletResponse; + +public class ImageBytesResult implements Result { + + public void execute(ActionInvocation invocation) throws Exception { + + GetImageAction action = (GetImageAction) invocation.getAction(); + HttpServletResponse response = ServletActionContext.getResponse(); + + response.setContentType(action.getCustomContentType()); + response.getOutputStream().write(action.getCustomImageInBytes()); + response.getOutputStream().flush(); + + } +} 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 87eccb2..70cab1d 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 @@ -198,21 +198,21 @@ public class BrowseAction extends AbstractScmWebEditorAction implements ServletR node.setTitle(file.substring(file.lastIndexOf("/") + 1)); node.setState(TreeNode.NODE_STATE_LEAF); - if (file.endsWith((".js"))) { + if (file.toLowerCase().endsWith((".js"))) { node.setIcon("ui-icon-js"); - } else if (file.endsWith(".html") || file.endsWith(".htm")) { + } else if (file.toLowerCase().endsWith(".html") || file.toLowerCase().endsWith(".htm")) { node.setIcon("ui-icon-html"); - } else if (file.endsWith(".xml")) { + } else if (file.toLowerCase().endsWith(".xml")) { node.setIcon("ui-icon-xml"); - } else if (file.endsWith(".java")) { + } else if (file.toLowerCase().endsWith(".java")) { node.setIcon("ui-icon-java"); - } else if (file.endsWith(".css")) { + } else if (file.toLowerCase().endsWith(".css")) { node.setIcon("ui-icon-css"); - } else if (file.endsWith(".rst")) { + } else if (file.toLowerCase().endsWith(".rst")) { node.setIcon("ui-icon-rst"); - } else if (file.endsWith(".tex")) { + } else if (file.toLowerCase().endsWith(".tex")) { node.setIcon("ui-icon-tex"); - } else if (file.endsWith(".txt")) { + } else if (file.toLowerCase().endsWith(".txt")) { node.setIcon("ui-icon-txt"); } 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 new file mode 100644 index 0000000..65537d4 --- /dev/null +++ b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/GetImageAction.java @@ -0,0 +1,102 @@ +/* + * #%L + * ScmWebEditor + * %% + * Copyright (C) 2009 - 2015 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.scmwebeditor.uiweb.actions; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts2.interceptor.ServletRequestAware; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletRequest; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; + +/** + * Gets the image at the given path + */ +public class GetImageAction extends ScmWebEditorMainAction implements ServletRequestAware { + + private static final Log log = LogFactory.getLog(GetImageAction.class); + + protected byte[] imageInByte = null; + + protected String imagePath; + + protected HttpServletRequest servletRequest; + + + public byte[] getImageInByte() { return imageInByte; } + + public void setImageInByte(byte[] imageInByte) { this.imageInByte = imageInByte; } + + public String getImagePath() { return imagePath; } + + public void setImagePath(String imagePath) { this.imagePath = imagePath; } + + + public String execute() { + return SUCCESS; + } + + public byte[] getCustomImageInBytes() { + + BufferedImage originalImage; + + try { + File fileImage = new File(imagePath); + originalImage = ImageIO.read(fileImage); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(originalImage, imagePath.substring(imagePath.length() - 3), baos); + baos.flush(); + imageInByte = baos.toByteArray(); + baos.close(); + } catch (IOException e) { + if (log.isErrorEnabled()) { + log.error("Can not get image file at " + imagePath, e); + } + } + + return imageInByte; + } + + public String getCustomContentType() { + + String type = "image/jpeg"; + String path = imagePath.toLowerCase(); + + if (path.endsWith(".png")) { + type = "image/png"; + } else if(path.endsWith(".gif")) { + type = "image/gif"; + } + + return type; + } + + @Override + public void setServletRequest(HttpServletRequest request) { + servletRequest = request; + } +} 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 new file mode 100644 index 0000000..a6ea51f --- /dev/null +++ b/swe-ui-web/src/main/java/org/nuiton/scmwebeditor/uiweb/actions/ViewImageAction.java @@ -0,0 +1,244 @@ +/* + * #%L + * ScmWebEditor + * %% + * Copyright (C) 2009 - 2015 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.scmwebeditor.uiweb.actions; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.shiro.codec.Base64; +import org.apache.shiro.crypto.BlowfishCipherService; +import org.nuiton.scmwebeditor.api.OperationNotSupportedException; +import org.nuiton.scmwebeditor.api.ScmConnection; +import org.nuiton.scmwebeditor.api.ScmProvider; +import org.nuiton.scmwebeditor.api.dto.result.AbstractResultDto; +import org.nuiton.scmwebeditor.uiweb.ScmWebEditorConfig; + +import javax.naming.AuthenticationException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpSession; +import java.io.File; +import java.text.Normalizer; + +/** + * Allows to view an image + */ +public class ViewImageAction extends ScmWebEditorMainAction { + + private static final Log log = LogFactory.getLog(ViewImageAction.class); + + protected final String VIEW_IMAGE = "viewImage"; + + /** the name of the selected branch */ + protected String selectedBranch; + + /** equals true if the SCM is able to use branches */ + protected boolean scmSupportsBranches; + + /** the full path to the root of the repository */ + protected String repositoryRoot; + + /** the path to use to get the image displayed in a web page */ + protected String imagePath; + + /** equals true if the repository's files are directly accessible using their address */ + protected boolean filesDirectlyAccessible; + + + public String getSelectedBranch() { return selectedBranch; } + + public void setSelectedBranch(String selectedBranch) { this.selectedBranch = selectedBranch; } + + public boolean isScmSupportsBranches() { return scmSupportsBranches; } + + public void setScmSupportsBranches(boolean scmSupportsBranches) { this.scmSupportsBranches = scmSupportsBranches; } + + public String getRepositoryRoot() { return repositoryRoot; } + + public void setRepositoryRoot(String repositoryRoot) { this.repositoryRoot = repositoryRoot; } + + public String getImagePath() { return imagePath; } + + public void setImagePath(String imagePath) { this.imagePath = imagePath; } + + public boolean isFilesDirectlyAccessible() { return filesDirectlyAccessible; } + + public void setFilesDirectlyAccessible( + boolean filesDirectlyAccessible) { this.filesDirectlyAccessible = filesDirectlyAccessible; } + + /** + * Execution of the view image action + * @return a code interpreted in the file struts.xml + */ + public String execute() { + + HttpSession session = request.getSession(); + String sessionId = session.getId(); + + String pathToLocalRepos = ScmWebEditorConfig.getLocalRepositoriesPath() + File.separator + sessionId; + + ScmProvider provider = ScmWebEditorConfig.getProvider(scmType); + ScmConnection scmConn = provider.getConnection(address, pathToLocalRepos); + + scmSupportsBranches = provider.supportsBranches(); + filesDirectlyAccessible = provider.filesDirectlyAccessible(); + + // if the repository is not protected, we get its UUID + String repositoryUUID = scmConn.getRepositoryId(); + if (repositoryUUID == null) { + repositoryUUID = address.replace(' ', '_'); + repositoryUUID = Normalizer.normalize(repositoryUUID, Normalizer.Form.NFD).replaceAll("[\u0300-\u036F]", ""); + } + + if (repositoryRoot == null) { + repositoryRoot = address.substring(0, address.lastIndexOf('/')); + } else if (repositoryRoot.equals("")) { + repositoryRoot = address.substring(0, address.lastIndexOf('/')); + } + + if (log.isDebugEnabled()) { + log.debug("Login : " + username); + } + + + /* + * Reading the cookie + */ + + + String usernamepwCookie = null; + // read the cookies + + BlowfishCipherService bf = new BlowfishCipherService(); + + byte[] privateKey = Base64.decode(ScmWebEditorConfig.getKey()); + + if (request.getCookies() != null) { + for (Cookie c : request.getCookies()) { + if (c.getName().equals(repositoryUUID)) { + usernamepwCookie = c.getValue(); + } + } + } + + if (usernamepwCookie != null) { + + String usernameDecode = new String(bf.decrypt(Base64.decode(usernamepwCookie), privateKey).getBytes()); + + String[] resCookie = usernameDecode.split(","); + if (resCookie.length == 2) { + username = resCookie[0]; + pw = resCookie[1]; + } + } + + if (saveCookie) { + if (username != null && pw != null) { + + if (!username.equals("") && !pw.equals("")) { + Cookie authCookie = new Cookie(repositoryUUID, bf.encrypt((username + "," + pw).getBytes(), privateKey).toBase64()); + authCookie.setMaxAge(60 * 60 * 24 * 365); + response.addCookie(authCookie); + } + } + + } + + // authentication + String[] usernamePw = getUsernamePwFromSession(repositoryUUID, username, pw); + username = usernamePw[0]; + pw = usernamePw[1]; + + String name = username; + String password = pw; + + if (name == null) { + name = "anonymous"; + } + if (password == null) { + password = "anonymous"; + } + + String changeBranchError = null; + + if (scmSupportsBranches) { + try { + changeBranchError = provider.changeBranch(selectedBranch, pathToLocalRepos, username, pw); + } catch (OperationNotSupportedException e) { + if (log.isErrorEnabled()) { + log.error("Can not change branch with SCM '" + scmType + "'"); + } + } + } + + if (changeBranchError != null) { + if (changeBranchError.equals(AbstractResultDto.AUTH_ERROR)) { + return LOGIN; + } else { + return ERROR_PATH; + } + } + + + /* + * Getting the file's revision + */ + + try { + numRevision = scmConn.getHeadRevisionNumber(address, name, password); + } catch (AuthenticationException e) { + request.setAttribute(PARAMETER_ADDRESS, address); + + // if scm authentication failed user is redirected on login page + if (log.isDebugEnabled()) { + log.debug("Auth Fail ", e); + } + + // deleting the cookies for this repository + for (Cookie c : request.getCookies()) { + if (c.getName().equals(repositoryUUID)) { + c.setMaxAge(0);//On supprime le cookie + response.addCookie(c); + if (log.isDebugEnabled()) { + log.debug("Cookie supprimé"); + } + } + } + + getScmSession().delScmUser(repositoryUUID); + //redirect to a login page + return LOGIN; + } catch (IllegalArgumentException e) { + if (log.isErrorEnabled()) { + log.error("The file does not exist", e); + } + return ERROR_PATH; + } + + imagePath = scmConn.getImagePath(address, repositoryRoot); + + + if (log.isInfoEnabled()) { + log.info("IP client : " + request.getRemoteAddr() + " , get file : " + address + ". File's mimetype : " + mimeType); + } + + return VIEW_IMAGE; + } +} 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 384ebf8..1ebc305 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 @@ -21,6 +21,7 @@ scm.createDirectorySuccess=Directory created successfully scm.createDirectoryTitle=Create a new directory on the repository scm.destinationDirectory=Destination directory\: scm.directoryToRemove=Directory to remove\: +scm.displayedImage=Displayed image\: scm.exit=Exit scm.exitJavascript=Exit ScmWebEditor? scm.exitJavascriptChanges=Exit ScmWebEditor without saving? All modification will be lost. @@ -40,7 +41,7 @@ scm.logoutWait=Logout... scm.modificationViewer.betterUseJavascript=For a better use of SCMWebEditor please activate JavaScript. scm.modificationViewer.branch=Working on branch\: scm.modificationViewer.commitOnly=Make a commit only (no push) -scm.modificationViewer.noJavascript=Javascript is not activated. You can't only use Save and Quit or upload button. +scm.modificationViewer.noJavascript=Javascript is not activated. You can only use save and quit, quit, upload a file, remove a file, Create a directory, remove a directory or move a file. scm.modificationViewer.previewPosition=Preview's position\: scm.modificationViewer.previewPosition.below=Below scm.modificationViewer.previewPosition.none=No preview 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 59bf203..ff4cf2f 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 @@ -21,6 +21,7 @@ scm.createDirectorySuccess=Répertoire créé avec succès scm.createDirectoryTitle=Créer un nouveau répertoire sur le dépôt scm.destinationDirectory=Répertoire de destination \: scm.directoryToRemove=Répertoire à supprimer \: +scm.displayedImage=Image affichée \: scm.exit=Quitter scm.exitJavascript=Quitter ScmWebEditor ? scm.exitJavascriptChanges=Quitter ScmWebEditor sans sauvegarder ? Toutes les modifications seront perdues. @@ -40,7 +41,7 @@ scm.logoutWait=Déconnexion... scm.modificationViewer.betterUseJavascript=Activer Javascript pour accéder à toutes les fonctionnalités. scm.modificationViewer.branch=Vous travaillez sur la branche \: scm.modificationViewer.commitOnly=Faire un commit seulement (pas de push) -scm.modificationViewer.noJavascript=Javascript est désactivé. Vous pouvez seulement utiliser les boutons sauvegarder et quitter, quitter ou ajouter un fichier. +scm.modificationViewer.noJavascript=Javascript est désactivé. Vous pouvez seulement utiliser les boutons sauvegarder et quitter, quitter, ajouter un fichier, supprimer un fichier, créer un répertoire, supprimer un répertoire ou déplacer un fichier. scm.modificationViewer.previewPosition=Position de l'aperçu \: scm.modificationViewer.previewPosition.below=En dessous scm.modificationViewer.previewPosition.none=Pas d'aperçu diff --git a/swe-ui-web/src/main/resources/struts.xml b/swe-ui-web/src/main/resources/struts.xml index e7034d4..ec640c5 100644 --- a/swe-ui-web/src/main/resources/struts.xml +++ b/swe-ui-web/src/main/resources/struts.xml @@ -41,6 +41,7 @@ <result-types> <result-type name="json" class="org.apache.struts2.json.JSONResult"/> + <result-type name="imageResult" class="org.nuiton.scmwebeditor.uiweb.ImageBytesResult"/> </result-types> <interceptors> @@ -75,6 +76,18 @@ <result name="errorPath" >/WEB-INF/content/badFileRedirect.jsp</result> <result name="editPage" >/WEB-INF/content/modificationViewer.jsp</result> </action> + + <action name="viewImage" class="org.nuiton.scmwebeditor.uiweb.actions.ViewImageAction"> + <result name="noParameter" >/WEB-INF/content/outConnection.jsp</result> + <result name="login" >/WEB-INF/content/privateScmRedirect.jsp</result> + <result name="errorPath" >/WEB-INF/content/badFileRedirect.jsp</result> + <result name="viewImage" >/WEB-INF/content/imageViewer.jsp</result> + </action> + + <action name="getImage" class="org.nuiton.scmwebeditor.uiweb.actions.GetImageAction"> + <result name="success" type="imageResult"> + </result> + </action> <action name="commit" class="org.nuiton.scmwebeditor.uiweb.actions.ScmWebEditorCommitAction"> <result name="success" >/WEB-INF/content/redirect.jsp</result> 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 804aaaa..0c62a7d 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 @@ -42,9 +42,17 @@ 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"; - document.location.href = ("edit.action?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); } } 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 new file mode 100644 index 0000000..445f6da --- /dev/null +++ b/swe-ui-web/src/main/webapp/WEB-INF/content/imageViewer.jsp @@ -0,0 +1,312 @@ +<%-- + #%L + ScmWebEditor + %% + Copyright (C) 2009 - 2015 CodeLutin + %% + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Lesser Public License for more details. + + You should have received a copy of the GNU General Lesser Public + License along with this program. If not, see + <http://www.gnu.org/licenses/lgpl-3.0.html>. + #L% + --%> + +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@ taglib prefix="s" uri="/struts-tags" %> +<%@ taglib prefix="sj" uri="/struts-jquery-tags" %> +<%@ taglib prefix="sjt" uri="/struts-jquery-tree-tags" %> +<sj:head jquerytheme="default"/> + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" +"http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <title><s:text name="scm.titles.swe"/></title> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <script type="text/javascript" src="js/selectLanguage.js"></script> + + <script src="js/cancelRedirect.js" type="text/javascript"></script> + <script src="js/popup.js" type="text/javascript"></script> + + <link rel="icon" href="img/machine-a-ecrire_little.png" type="image/png"> + <link rel="stylesheet" type="text/css" href="css/main.css"> + + <script type="text/javascript" src="js/editor.js"></script> + + <script type="text/javascript"> + // Opens the selected file in the tree + $.subscribe('treeClicked', function(event, data) { + var item = event.originalEvent.data.rslt.obj; + + if (item.length == 1) { + var classAttr = item[0].getAttribute("class"); + + if (classAttr.contains("jstree-leaf")) { + 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 (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"/>'); + } + } + + }); + </script> + +</head> +<body> + +<div id="wrapper"> + + +<s:hidden name="scmType" id="scmType" value="%{scmType}"/> + +<div id="head"> + + +<div id="flagEdit"> + + <ul class="flags"> + <li> + <s:if + test="%{#session['WW_TRANS_I18N_LOCALE'] != null && #session['WW_TRANS_I18N_LOCALE'].language == 'en'}"> + <img src="img/flag-i18n-uk.png"/> + </s:if> + <s:else> + <s:a action="edit.action" namespace="/"> + <s:param name="address"><s:property value="address"/></s:param> + <s:param name="scmType"><s:property value="scmType"/></s:param> + <s:param name="selectedBranch"><s:property value="selectedBranch"/></s:param> + <s:param name="repositoryRoot"><s:property value="repositoryRoot"/></s:param> + <s:param name="request_locale">en_GB</s:param> + <img src="img/flag-i18n-uk.png"/> + </s:a> + </s:else> + </li> + <li> + <s:if + test="%{#session['WW_TRANS_I18N_LOCALE'] == null || #session['WW_TRANS_I18N_LOCALE'].language == 'fr'}"> + <img src="img/flag-i18n-fr.png"/> + </s:if> + <s:else> + <s:a action="edit.action" namespace="/"> + <s:param name="address"><s:property value="address"/></s:param> + <s:param name="scmType"><s:property value="scmType"/></s:param> + <s:param name="selectedBranch"><s:property value="selectedBranch"/></s:param> + <s:param name="repositoryRoot"><s:property value="repositoryRoot"/></s:param> + <s:param name="request_locale">fr_FR</s:param> + <img src="img/flag-i18n-fr.png"/> + </s:a> + </s:else> + </li> + + </ul> + +</div> + + +<!-- <a title="ScmWebEditor Project Website" target="_blank" href="http://maven-site.nuiton.org/scmwebeditor/"><img width="200" height="160" src="img/editor/machine-a-ecrire.png" alt="ScmWebEditor logo"/></a> --> + +<h1 id="editorTitle">SCMWebEditor</h1> + +<s:set id="openAnotherFile"> + <s:text name="scm.openAnotherFile"/> +</s:set> + +<s:submit id="openAnotherFile" value="%{openAnotherFile}" onclick="openPopin('openFilePopin'); return false;"/> + + <div id="buttonList"> + + <!-- BEGIN exit --> + + <s:if test="projectUrl != null"> + <s:hidden key="projectUrl" label=''/> + </s:if> + <s:else> + <s:hidden id="projectUrl" value="checkout.action"/> + </s:else> + + + <s:set id="scm.exitTitle"> + <s:text name="scm.exitTitle"/> + </s:set> + <s:set id="scm.exitJavascript"> + <s:text name="scm.exitJavascript"/> + </s:set> + + <s:a + href="checkout.action" + title="%{scm.exitTitle}" + value="%{scm.exit}" + name="Cancel"> + <div id="exitButton"></div> + </s:a> + + <!-- END exit --> + + </div> + + <!-- Buttons for the actions on the repository --> + + <s:set id="scm.upload"> + <s:text name="scm.upload"/> + </s:set> + <s:set id="scm.uploadTitle"> + <s:text name="scm.uploadTitle"/> + </s:set> + + <s:set id="scm.removeFile"> + <s:text name="scm.removeFile"/> + </s:set> + <s:set id="scm.removeFileTitle"> + <s:text name="scm.removeFileTitle"/> + </s:set> + + <s:set id="scm.createDirectory"> + <s:text name="scm.createDirectory"/> + </s:set> + <s:set id="scm.createDirectoryTitle"> + <s:text name="scm.createDirectoryTitle"/> + </s:set> + + <s:set id="scm.removeDirectory"> + <s:text name="scm.removeDirectory"/> + </s:set> + <s:set id="scm.removeDirectoryTitle"> + <s:text name="scm.removeDirectoryTitle"/> + </s:set> + + <s:set id="scm.moveFile"> + <s:text name="scm.moveFile"/> + </s:set> + <s:set id="scm.moveFileTitle"> + <s:text name="scm.moveFileTitle"/> + </s:set> + + <s:set name="address"> + <s:property value="address"/> + </s:set> + + <ul id="repositoryButtons"> + <li> + <s:submit name="uploadButton" value="%{scm.upload}" title="%{scm.uploadTitle}" + onClick="javascript:open_popup('doUploadFile.action', 'upload', getElementById('address').value, '%{scmType}'); return false;"/> + </li> + <li> + <s:submit name="removeButton" value="%{scm.removeFile}" title="%{scm.removeFileTitle}" + onClick="javascript:open_popup('doRemoveFile.action', 'remove', getElementById('address').value, '%{scmType}'); return false;"/> + </li> + <li> + <s:submit name="createDirectoryButton" value="%{scm.createDirectory}" title="%{scm.createDirectoryTitle}" + onClick="javascript:open_popup('doCreateDirectory.action', 'create directory',getElementById('address').value,'%{scmType}'); return false;"/> + </li> + <li> + <s:submit name="removeDirectoryButton" value="%{scm.removeDirectory}" title="%{scm.removeDirectoryTitle}" + onClick="javascript:open_popup('doRemoveDirectory.action', 'remove directory',getElementById('address').value,'%{scmType}'); return false;"/> + </li> + <li> + <s:submit name="moveFileButton" value="%{scm.moveFile}" title="%{scm.moveFileTitle}" + onClick="javascript:open_popup('doMoveFile.action', 'move file',getElementById('address').value,'%{scmType}'); return false;"/> + </li> + </ul> + +</div> + +<div id="editBody"> + + <p> + <s:text name="scm.displayedImage"/> <s:property value="address"/> + <s:text name="scm.atRevision"/> <span id="numrevisionDiv"><s:property + value="numRevision"/></span> + + <s:if test="scmSupportsBranches"> + <br/> + <s:text name="scm.modificationViewer.branch"/> <s:property value="selectedBranch"></s:property> + </s:if> + </p> + + <s:if test="filesDirectlyAccessible"> + + <img src="<s:property value="imagePath"/>" id="displayedImage"/> + + </s:if> + <s:else> + + <s:set id="imagePath"> + <s:property value="imagePath"/> + </s:set> + <img src="<s:url action='getImage.action?imagePath=%{imagePath}'/>" id="displayedImage"/> + + </s:else> + + <noscript><h4><s:text name="scm.modificationViewer.noJavascript"/></h4> + </noscript> + <noscript><h4><s:text name="scm.modificationViewer.betterUseJavascript"/></h4> + </noscript> + + <div id="form"> + + <p> + + <s:hidden key="address" label=''/> + <s:hidden key="origText" label=''/> + <s:hidden key="scmEditorUrl" label=''/> + <s:hidden key="selectedBranch" label=''/> + <s:hidden key="repositoryRoot" label=''/> + + <div id="scmButton"></div> + + </div> +</div> + + <div id="targetContentUpload"></div> + + </div> + <p align="right">©2004-2015 CodeLutin</p> + +</div> + +<!-- popin to open another file --> +<div class="popin" id="openFilePopin"> + <span class="closePopin" onclick="closePopin('openFilePopin')"> + X + </span> + + <h1><s:text name="scm.openAnotherFile"/></h1> + + <div id="searchTree"> + + <s:url id="searchTreeUrl" + action="browse?address=%{repositoryRoot}&username=%{username}&pw=%{pw}&selectedBranch=%{selectedBranch}&scmType=%{scmType}"/> + <sjt:tree id="scmTree" + htmlTitles="true" + jstreetheme="classic" + href="%{searchTreeUrl}" + onClickTopics="treeClicked" + onSuccessTopics="treeChanged" + /> + + </div> + +</div> + +<div id="popinBackground"></div> + +</body> +</html> 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 957734a..3fc4c5e 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 @@ -108,14 +108,24 @@ if (classAttr.contains("jstree-leaf")) { var scmType = document.getElementById("scmType").value; + var fileExtension = item.attr("id").substr(item.attr("id").lastIndexOf(".") + 1); + var actionFile = "edit.action"; - document.location.href = ("edit.action?address=" + item.attr("id") + "&scmType=" + scmType + 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"/>'); } } }); + window.onbeforeunload = confirmExitOnUnload; + </script> <script type="text/javascript" src="js/editor.js"></script> diff --git a/swe-ui-web/src/main/webapp/css/main.css b/swe-ui-web/src/main/webapp/css/main.css index 3497678..5ae4a10 100644 --- a/swe-ui-web/src/main/webapp/css/main.css +++ b/swe-ui-web/src/main/webapp/css/main.css @@ -476,4 +476,9 @@ ul#repositoryButtons li { .jstree { background: #FFF none repeat scroll 0% 0%; +} + +#displayedImage { + display: block; + margin: auto; } \ No newline at end of file diff --git a/swe-ui-web/src/main/webapp/js/editor.js b/swe-ui-web/src/main/webapp/js/editor.js index f1e05b1..2d9db58 100644 --- a/swe-ui-web/src/main/webapp/js/editor.js +++ b/swe-ui-web/src/main/webapp/js/editor.js @@ -39,6 +39,4 @@ $.subscribe('treeChanged', function(event, data) { children.item('ins').click(); } } -}); - -window.onbeforeunload = confirmExitOnUnload; \ No newline at end of file +}); \ No newline at end of file -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.