From 2c4b91e835030d30c5a6b285bd20e36b8f5925f9 Mon Sep 17 00:00:00 2001 From: "francesco.mangiacrapa" Date: Mon, 20 Jul 2020 16:39:13 +0200 Subject: [PATCH] #19695#note-1 integrated with Google Docs Viewer as first version --- CHANGELOG.md | 4 + .../workspace/client/resources/Icons.java | 5 +- .../workspace/client/resources/Resources.java | 33 +- .../resources/icons/preview-not-available.png | Bin 0 -> 4396 bytes .../view/windows/DialogGetInfoBootstrap.java | 145 ++++++++- .../user/workspace/public/js/pdfobject.js | 286 ++++++++++++++++++ 6 files changed, 455 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/gcube/portlets/user/workspace/client/resources/icons/preview-not-available.png create mode 100644 src/main/java/org/gcube/portlets/user/workspace/public/js/pdfobject.js diff --git a/CHANGELOG.md b/CHANGELOG.md index f2196c1..20f9ffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm [#19600] revisit the "Get Info" Dialog in a modern view +#### New Features + +[#19695] Show the file preview via Google Docs Viewer + ## [v6.30.1] [r4.24.0] - 2020-06-25 diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/resources/Icons.java b/src/main/java/org/gcube/portlets/user/workspace/client/resources/Icons.java index de6ec65..7e211ca 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/resources/Icons.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/resources/Icons.java @@ -417,8 +417,9 @@ public interface Icons extends ClientBundle { @Source("icons/sync-icon-synched.png") ImageResource syncIconSynched(); - - + + @Source("icons/preview-not-available.png") + ImageResource previewNotAvailable(); } diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/resources/Resources.java b/src/main/java/org/gcube/portlets/user/workspace/client/resources/Resources.java index 930e967..b506b1d 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/resources/Resources.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/resources/Resources.java @@ -7,6 +7,7 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.ui.AbstractImagePrototype; +// TODO: Auto-generated Javadoc /** * The Class Resources. * @@ -1248,15 +1249,30 @@ public class Resources { } + /** + * Gets the icon sync to. + * + * @return the icon sync to + */ public static AbstractImagePrototype getIconSyncTo() { return AbstractImagePrototype.create(ICONS.syncIconTo()); } + /** + * Gets the icon sync from. + * + * @return the icon sync from + */ public static AbstractImagePrototype getIconSyncFrom() { return AbstractImagePrototype.create(ICONS.syncIconFrom()); } + /** + * Gets the icon synched. + * + * @return the icon synched + */ public static AbstractImagePrototype getIconSynched() { return AbstractImagePrototype.create(ICONS.syncIconSynched()); } @@ -1344,6 +1360,17 @@ public class Resources { public static ImageResource getImageAttachs() { return ICONS.attach(); } + + + /** + * Gets the preview not available. + * + * @return the preview not available + */ + public static ImageResource getPreviewNotAvailable() { + return ICONS.previewNotAvailable(); + } + /** * Gets the icon by media type name. @@ -1503,10 +1530,4 @@ public class Resources { return null; } - - - - - - } diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/resources/icons/preview-not-available.png b/src/main/java/org/gcube/portlets/user/workspace/client/resources/icons/preview-not-available.png new file mode 100644 index 0000000000000000000000000000000000000000..fe85c9e38af7f585d2307921277d8f2e6e8bfb88 GIT binary patch literal 4396 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 literal 0 HcmV?d00001 diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.java b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.java index f5a254d..ff4926d 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.java @@ -12,6 +12,8 @@ import org.gcube.portlets.user.workspace.client.event.FileDownloadEvent.Download import org.gcube.portlets.user.workspace.client.interfaces.GXTFolderItemTypeEnum; import org.gcube.portlets.user.workspace.client.model.FileGridModel; import org.gcube.portlets.user.workspace.client.model.FileModel; +import org.gcube.portlets.user.workspace.client.resources.Icons; +import org.gcube.portlets.user.workspace.client.resources.Resources; import org.gcube.portlets.user.workspace.client.workspace.GWTWorkspaceItem; import org.gcube.portlets.user.workspace.client.workspace.folder.item.GWTExternalImage; import org.gcube.portlets.user.workspace.client.workspace.folder.item.gcube.GWTImageDocument; @@ -29,21 +31,26 @@ import com.github.gwtbootstrap.client.ui.constants.LabelType; import com.github.gwtbootstrap.client.ui.constants.ResizeType; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Float; +import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.LoadEvent; +import com.google.gwt.event.dom.client.LoadHandler; import com.google.gwt.http.client.URL; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.NumberFormat; -import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Frame; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.NamedFrame; import com.google.gwt.user.client.ui.Widget; // TODO: Auto-generated Javadoc @@ -177,6 +184,10 @@ public class DialogGetInfoBootstrap extends Composite { // private Button buttonShareableLink = new Button(); private DateTimeFormat dateFormatter = DateTimeFormat.getFormat("dd MMM yyyy, hh:mm aaa"); + + private boolean iFrameGoogleDocViewerLoaded = false; + + private Long fileSize = null; /** * Instantiates a new dialog get info bootstrap. @@ -297,6 +308,7 @@ public class DialogGetInfoBootstrap extends Composite { //last update htmlSetValue(txtLastMofication, dateFormatter.format(fileGridModel.getLastModification())); //size + fileSize = fileGridModel.getSize(); htmlSetValue(txtSize, getFormattedSize(fileGridModel.getSize())); }else { loadLastModificationDate(fileModel.getIdentifier()); @@ -327,9 +339,88 @@ public class DialogGetInfoBootstrap extends Composite { } - if(typeEnum.equals(GXTFolderItemTypeEnum.EXTERNAL_PDF_FILE) || - typeEnum.equals(GXTFolderItemTypeEnum.PDF_DOCUMENT) || - typeEnum.equals(GXTFolderItemTypeEnum.EXTERNAL_FILE)) { + // SOLUTION BASED ON GOOGLE DOC VIEWER + if (typeEnum.equals(GXTFolderItemTypeEnum.EXTERNAL_PDF_FILE) || + + typeEnum.equals(GXTFolderItemTypeEnum.PDF_DOCUMENT) + || typeEnum.equals(GXTFolderItemTypeEnum.EXTERNAL_FILE)) { + + AppControllerExplorer.rpcWorkspaceService.getPublicLinkForFileItemId(fileModel.getIdentifier(), false, + new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + } + + @Override + public void onSuccess(PublicLink result) { + + GWT.log("The PublicLink link is: " + result); + + if (result != null) { + + //if file size is null or greater than 25MB + long byteTo25MB = 1024*1024*25; + GWT.log("The file size is: "+fileSize); + if(fileSize==null || fileSize>byteTo25MB) { + GWT.log("The file size is null or greater than "+byteTo25MB+", returning"); + //htmlPanelFilePreview.add(new Image(Resources.getPreviewNotAvailable())); + return; + } + +// String pdfPreview = ""; + + String googleDocViewerURL = "https://docs.google.com/viewer?url=" + + URL.encode(result.getCompleteURL()) + "&embedded=true"; + + final HTML loadingPreviewHTML = new HTML(); + setPlaceholder(loadingPreviewHTML, "loading preview..."); + + final Frame frame = instanceFrame(googleDocViewerURL, loadingPreviewHTML); + + final long startTime = new Date().getTime(); + Timer timer = new Timer() { + + @Override + public void run() { + GWT.log("Checking if the iFrameGoogleDocViewer is ready"); + if(iFrameGoogleDocViewerLoaded) { + removePlaceHolder(loadingPreviewHTML); + GWT.log("iFrameGoogleDocViewer currently loaded, cancelling timer"); + cancel(); + return; + } + long checkTime = new Date().getTime(); + long diff = checkTime - startTime; + if(diff>5000) {//is greater than 5 sec + try { + GWT.log("iFrameGoogleDocViewer not loaded within 5 sec, cancelling timer, removing iframe"); + cancel(); + removePlaceHolder(loadingPreviewHTML); + htmlPanelFilePreview.add(new Image(Resources.getPreviewNotAvailable())); + frame.setVisible(false); + htmlPanelFilePreview.remove(frame); + }catch (Exception e) { + //Silent + } + } + } + }; + timer.scheduleRepeating(200); + + htmlPanelFilePreview.add(loadingPreviewHTML); + htmlPanelFilePreview.add(frame); + htmlPanelFilePreview.setVisible(true); + } + } + }); + } + + //SOLUTION BASED ON PDFOBEJCT + /*if(typeEnum.equals(GXTFolderItemTypeEnum.EXTERNAL_PDF_FILE) || + typeEnum.equals(GXTFolderItemTypeEnum.PDF_DOCUMENT)) { GWT.log("The file is a PDF"); @@ -338,7 +429,7 @@ public class DialogGetInfoBootstrap extends Composite { @Override public void onFailure(Throwable caught) { } - + @Override public void onSuccess(PublicLink result) { @@ -346,20 +437,45 @@ public class DialogGetInfoBootstrap extends Composite { if(result!=null) { - String pdfPreview = ""; - + String pdfPreview = "
"; htmlPanelFilePreview.add(new HTML(pdfPreview)); + showPDFPreview(result.getCompleteURL(), "pdfPrewiewDiv"); htmlPanelFilePreview.setVisible(true); } } }); - } + }*/ } addHandlers(); } + + public Frame instanceFrame(String fileURL, final HTML thePreviewPlaceholder) { + //addLoading(); + String urlEncoded = URL.encode(fileURL); + GWT.log("Encoded url for instanciating frame is " + urlEncoded); + + iFrameGoogleDocViewerLoaded = false; + + final NamedFrame frame = new NamedFrame("iFrameGoogleDocViewer"); + frame.setUrl(urlEncoded); + frame.setVisible(false); + frame.getElement().setId("iFrameGoogleDocViewer"); + frame.getElement().getStyle().setBorderWidth(0, Unit.PX); + frame.addLoadHandler(new LoadHandler() { + + @Override + public void onLoad(LoadEvent arg0) { + GWT.log("iFrameGoogleDocViewer loaded"); + iFrameGoogleDocViewerLoaded = true; + removePlaceHolder(thePreviewPlaceholder); + frame.getElement().addClassName("my-preview-doc"); + frame.setVisible(true); + + } + }); + return frame; + } /** * Adds the handlers. @@ -526,10 +642,12 @@ public class DialogGetInfoBootstrap extends Composite { private void loadSize(final String itemId) { GWT.log("Load size"); setPlaceholder(txtSize, "loading..."); + fileSize = new Long(-1); //means is loading AppControllerExplorer.rpcWorkspaceService.loadSizeByItemId(itemId, new AsyncCallback() { @Override public void onFailure(Throwable caught) { + fileSize = null; GWT.log("an error occured in load creation date by Id " + itemId + " " + caught.getMessage()); removePlaceHolder(txtSize); @@ -538,6 +656,7 @@ public class DialogGetInfoBootstrap extends Composite { @Override public void onSuccess(Long result) { GWT.log("Loaded size=" + result); + fileSize = result; removePlaceHolder(txtSize); if(result!=null) htmlSetValue(txtSize, getFormattedSize(result)); @@ -758,5 +877,11 @@ public class DialogGetInfoBootstrap extends Composite { html.setHTML(""); html.getElement().removeClassName("placeholder-loading"); } + + + public static native String showPDFPreview(String pdfURL, String divId)/*-{ + var theDivContainer = "#"+divId; + $wnd.PDFObject.embed(pdfURL, theDivContainer); + }-*/; } diff --git a/src/main/java/org/gcube/portlets/user/workspace/public/js/pdfobject.js b/src/main/java/org/gcube/portlets/user/workspace/public/js/pdfobject.js new file mode 100644 index 0000000..b1e3ec5 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/workspace/public/js/pdfobject.js @@ -0,0 +1,286 @@ +/*global ActiveXObject, window, console, define, module, jQuery */ +//jshint unused:false, strict: false + +/* + PDFObject v2.1.1 + https://github.com/pipwerks/PDFObject + Copyright (c) 2008-2018 Philip Hutchison + MIT-style license: http://pipwerks.mit-license.org/ + UMD module pattern from https://github.com/umdjs/umd/blob/master/templates/returnExports.js +*/ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + // Browser globals (root is window) + root.PDFObject = factory(); + } +}(this, function () { + + "use strict"; + //jshint unused:true + + //PDFObject is designed for client-side (browsers), not server-side (node) + //Will choke on undefined navigator and window vars when run on server + //Return boolean false and exit function when running server-side + + if(typeof window === "undefined" || typeof navigator === "undefined"){ return false; } + + var pdfobjectversion = "2.1.1", + ua = window.navigator.userAgent, + + //declare booleans + supportsPDFs, + isIE, + supportsPdfMimeType = (typeof navigator.mimeTypes['application/pdf'] !== "undefined"), + supportsPdfActiveX, + isModernBrowser = (function (){ return (typeof window.Promise !== "undefined"); })(), + isFirefox = (function (){ return (ua.indexOf("irefox") !== -1); } )(), + isFirefoxWithPDFJS = (function (){ + //Firefox started shipping PDF.js in Firefox 19. + //If this is Firefox 19 or greater, assume PDF.js is available + if(!isFirefox){ return false; } + //parse userAgent string to get release version ("rv") + //ex: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:57.0) Gecko/20100101 Firefox/57.0 + return (parseInt(ua.split("rv:")[1].split(".")[0], 10) > 18); + })(), + isIOS = (function (){ return (/iphone|ipad|ipod/i.test(ua.toLowerCase())); })(), + + //declare functions + createAXO, + buildFragmentString, + log, + embedError, + embed, + getTargetElement, + generatePDFJSiframe, + generateEmbedElement; + + + /* ---------------------------------------------------- + Supporting functions + ---------------------------------------------------- */ + + createAXO = function (type){ + var ax; + try { + ax = new ActiveXObject(type); + } catch (e) { + ax = null; //ensure ax remains null + } + return ax; + }; + + //IE11 still uses ActiveX for Adobe Reader, but IE 11 doesn't expose + //window.ActiveXObject the same way previous versions of IE did + //window.ActiveXObject will evaluate to false in IE 11, but "ActiveXObject" in window evaluates to true + //so check the first one for older IE, and the second for IE11 + //FWIW, MS Edge (replacing IE11) does not support ActiveX at all, both will evaluate false + //Constructed as a method (not a prop) to avoid unneccesarry overhead -- will only be evaluated if needed + isIE = function (){ return !!(window.ActiveXObject || "ActiveXObject" in window); }; + + //If either ActiveX support for "AcroPDF.PDF" or "PDF.PdfCtrl" are found, return true + //Constructed as a method (not a prop) to avoid unneccesarry overhead -- will only be evaluated if needed + supportsPdfActiveX = function (){ return !!(createAXO("AcroPDF.PDF") || createAXO("PDF.PdfCtrl")); }; + + //Determines whether PDF support is available + supportsPDFs = ( + //as of iOS 12, inline PDF rendering is still not supported in Safari or native webview + //3rd-party browsers (eg Chrome, Firefox) use Apple's webview for rendering, and thus the same result as Safari + //Therefore if iOS, we shall assume that PDF support is not available + !isIOS && ( + //Modern versions of Firefox come bundled with PDFJS + isFirefoxWithPDFJS || + //Browsers that still support the original MIME type check + supportsPdfMimeType || ( + //Pity the poor souls still using IE + isIE() && supportsPdfActiveX() + ) + ) + ); + + //Create a fragment identifier for using PDF Open parameters when embedding PDF + buildFragmentString = function(pdfParams){ + + var string = "", + prop; + + if(pdfParams){ + + for (prop in pdfParams) { + if (pdfParams.hasOwnProperty(prop)) { + string += encodeURIComponent(prop) + "=" + encodeURIComponent(pdfParams[prop]) + "&"; + } + } + + //The string will be empty if no PDF Params found + if(string){ + + string = "#" + string; + + //Remove last ampersand + string = string.slice(0, string.length - 1); + + } + + } + + return string; + + }; + + log = function (msg){ + if(typeof console !== "undefined" && console.log){ + console.log("[PDFObject] " + msg); + } + }; + + embedError = function (msg){ + log(msg); + return false; + }; + + getTargetElement = function (targetSelector){ + + //Default to body for full-browser PDF + var targetNode = document.body; + + //If a targetSelector is specified, check to see whether + //it's passing a selector, jQuery object, or an HTML element + + if(typeof targetSelector === "string"){ + + //Is CSS selector + targetNode = document.querySelector(targetSelector); + + } else if (typeof jQuery !== "undefined" && targetSelector instanceof jQuery && targetSelector.length) { + + //Is jQuery element. Extract HTML node + targetNode = targetSelector.get(0); + + } else if (typeof targetSelector.nodeType !== "undefined" && targetSelector.nodeType === 1){ + + //Is HTML element + targetNode = targetSelector; + + } + + return targetNode; + + }; + + generatePDFJSiframe = function (targetNode, url, pdfOpenFragment, PDFJS_URL, id){ + + var fullURL = PDFJS_URL + "?file=" + encodeURIComponent(url) + pdfOpenFragment; + var scrollfix = (isIOS) ? "-webkit-overflow-scrolling: touch; overflow-y: scroll; " : "overflow: hidden; "; + var iframe = "
"; + targetNode.className += " pdfobject-container"; + targetNode.style.position = "relative"; + targetNode.style.overflow = "auto"; + targetNode.innerHTML = iframe; + return targetNode.getElementsByTagName("iframe")[0]; + + }; + + generateEmbedElement = function (targetNode, targetSelector, url, pdfOpenFragment, width, height, id){ + + var style = ""; + + if(targetSelector && targetSelector !== document.body){ + style = "width: " + width + "; height: " + height + ";"; + } else { + style = "position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%;"; + } + + targetNode.className += " pdfobject-container"; + targetNode.innerHTML = ""; + + return targetNode.getElementsByTagName("embed")[0]; + + }; + + embed = function(url, targetSelector, options){ + + //Ensure URL is available. If not, exit now. + if(typeof url !== "string"){ return embedError("URL is not valid"); } + + //If targetSelector is not defined, convert to boolean + targetSelector = (typeof targetSelector !== "undefined") ? targetSelector : false; + + //Ensure options object is not undefined -- enables easier error checking below + options = (typeof options !== "undefined") ? options : {}; + + //Get passed options, or set reasonable defaults + var id = (options.id && typeof options.id === "string") ? "id='" + options.id + "'" : "", + page = (options.page) ? options.page : false, + pdfOpenParams = (options.pdfOpenParams) ? options.pdfOpenParams : {}, + fallbackLink = (typeof options.fallbackLink !== "undefined") ? options.fallbackLink : true, + width = (options.width) ? options.width : "100%", + height = (options.height) ? options.height : "100%", + assumptionMode = (typeof options.assumptionMode === "boolean") ? options.assumptionMode : true, + forcePDFJS = (typeof options.forcePDFJS === "boolean") ? options.forcePDFJS : false, + PDFJS_URL = (options.PDFJS_URL) ? options.PDFJS_URL : false, + targetNode = getTargetElement(targetSelector), + fallbackHTML = "", + pdfOpenFragment = "", + fallbackHTML_default = "

This browser does not support inline PDFs. Please download the PDF to view it: Download PDF

"; + + //If target element is specified but is not valid, exit without doing anything + if(!targetNode){ return embedError("Target element cannot be determined"); } + + + //page option overrides pdfOpenParams, if found + if(page){ + pdfOpenParams.page = page; + } + + //Stringify optional Adobe params for opening document (as fragment identifier) + pdfOpenFragment = buildFragmentString(pdfOpenParams); + + //Do the dance + + //If the forcePDFJS option is invoked, skip everything else and embed as directed + if(forcePDFJS && PDFJS_URL){ + + return generatePDFJSiframe(targetNode, url, pdfOpenFragment, PDFJS_URL, id); + + //If traditional support is provided, or if this is a modern browser and not iOS (see comment for supportsPDFs declaration) + } else if(supportsPDFs || (assumptionMode && isModernBrowser && !isIOS)){ + + return generateEmbedElement(targetNode, targetSelector, url, pdfOpenFragment, width, height, id); + + //If everything else has failed and a PDFJS fallback is provided, try to use it + } else if(PDFJS_URL){ + + return generatePDFJSiframe(targetNode, url, pdfOpenFragment, PDFJS_URL, id); + + } else { + + //Display the fallback link if available + if(fallbackLink){ + + fallbackHTML = (typeof fallbackLink === "string") ? fallbackLink : fallbackHTML_default; + targetNode.innerHTML = fallbackHTML.replace(/\[url\]/g, url); + + } + + return embedError("This browser does not support embedded PDFs"); + + } + + }; + + return { + embed: function (a,b,c){ return embed(a,b,c); }, + pdfobjectversion: (function () { return pdfobjectversion; })(), + supportsPDFs: (function (){ return supportsPDFs; })() + }; + +})); \ No newline at end of file