From 999a148b32f864ca9ef93909455a168d0ed747a6 Mon Sep 17 00:00:00 2001 From: Mario Russo Date: Thu, 6 Nov 2014 23:40:25 +0100 Subject: [PATCH] ui: added 'View original' link to sidebar Notes: -this patch also introduces the sidebar to the contents listing aspect (when viewing members of a set) -the link will only appear for a _single_ selected item https://code.google.com/p/camlistore/issues/detail?id=541 https://code.google.com/p/camlistore/issues/detail?id=546 Change-Id: Icc93eaa2478f40f3fe272520b1f6ede41f0731dc --- pkg/server/download.go | 7 ++- server/camlistored/ui/index.html | 1 + server/camlistored/ui/index.js | 74 +++++++++++++++++++++++--------- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/pkg/server/download.go b/pkg/server/download.go index 6b8c0cca2..6a3c18409 100644 --- a/pkg/server/download.go +++ b/pkg/server/download.go @@ -70,12 +70,17 @@ func (dh *DownloadHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, mimeType = "application/octet-stream" } h.Set("Content-Type", mimeType) + if mimeType == "application/octet-stream" { // Chrome seems to silently do nothing on // application/octet-stream unless this is set. // Maybe it's confused by lack of URL it recognizes // along with lack of mime type? - rw.Header().Set("Content-Disposition", "attachment; filename=file-"+file.String()+".dat") + fileName := fr.FileName() + if fileName == "" { + fileName = "file-" + file.String() + ".dat" + } + rw.Header().Set("Content-Disposition", "attachment; filename="+fileName) } if req.Method == "HEAD" && req.FormValue("verifycontents") != "" { diff --git a/server/camlistored/ui/index.html b/server/camlistored/ui/index.html index 20eca705a..6c4c47e30 100644 --- a/server/camlistored/ui/index.html +++ b/server/camlistored/ui/index.html @@ -79,6 +79,7 @@ limitations under the License. config: CAMLISTORE_CONFIG, eventTarget: window, history: window.history, + openWindow: function(url) { return window.open(url); }, location: window.location, scrolling: { target: window, diff --git a/server/camlistored/ui/index.js b/server/camlistored/ui/index.js index fbf27dfe9..f743677d1 100644 --- a/server/camlistored/ui/index.js +++ b/server/camlistored/ui/index.js @@ -80,6 +80,7 @@ cam.IndexPage = React.createClass({ config: React.PropTypes.object.isRequired, eventTarget: React.PropTypes.shape({addEventListener:React.PropTypes.func.isRequired}).isRequired, history: React.PropTypes.shape({pushState:React.PropTypes.func.isRequired, replaceState:React.PropTypes.func.isRequired, go:React.PropTypes.func.isRequired, state:React.PropTypes.object}).isRequired, + openWindow: React.PropTypes.func.isRequired, location: React.PropTypes.shape({href:React.PropTypes.string.isRequired, reload:React.PropTypes.func.isRequired}).isRequired, scrolling: cam.BlobItemContainerReact.originalSpec.propTypes.scrolling, serverConnection: React.PropTypes.instanceOf(cam.ServerConnection).isRequired, @@ -574,6 +575,10 @@ cam.IndexPage = React.createClass({ }.bind(this)); }, + handleOpenWindow_: function(url) { + this.props.openWindow(url); + }, + handleKeyPress_: function(e) { if (e.target.tagName == 'INPUT' || e.target.tagName == 'TEXTAREA') { return; @@ -681,28 +686,57 @@ cam.IndexPage = React.createClass({ ); }, - getSidebar_: function(selectedAspect) { - // We don't support the sidebar in other aspects (maybe we should though). - if (!selectedAspect || selectedAspect.fragment != 'search') + getViewOriginalSelectionItem_: function() { + if (goog.object.getCount(this.state.selection) != 1) { return null; + } - return cam.Sidebar({ - isExpanded: this.state.sidebarVisible, - mainControls: [ - { - "displayTitle": "Update Tags", - "control": this.getTagsControl_() - } - ].filter(goog.functions.identity), - selectionControls: [ - this.getClearSelectionItem_(), - this.getCreateSetWithSelectionItem_(), - this.getSelectAsCurrentSetItem_(), - this.getAddToCurrentSetItem_(), - this.getDeleteSelectionItem_(), - ].filter(goog.functions.identity), - selectedItems: this.state.selection - }); + var blobref = goog.object.getAnyKey(this.state.selection); + var rm = this.childSearchSession_.getResolvedMeta(blobref); + if (!rm || !rm.file) { + return null; + } + + var fileName = ''; + if (rm.file.fileName) { + fileName = goog.string.subs('/%s', rm.file.fileName); + } + + var downloadUrl = goog.string.subs('%s/%s%s', this.props.config.downloadHelper, rm.blobRef, fileName); + return React.DOM.button( + { + key:'viewSelection', + onClick: this.handleOpenWindow_.bind(this, downloadUrl), + }, + 'View original' + ); + }, + + getSidebar_: function(selectedAspect) { + if (selectedAspect) { + if (selectedAspect.fragment == 'search' || selectedAspect.fragment == 'contents') { + return cam.Sidebar( { + isExpanded: this.state.sidebarVisible, + mainControls: [ + { + "displayTitle": "Update Tags", + "control": this.getTagsControl_() + } + ].filter(goog.functions.identity), + selectionControls: [ + this.getClearSelectionItem_(), + this.getCreateSetWithSelectionItem_(), + this.getSelectAsCurrentSetItem_(), + this.getAddToCurrentSetItem_(), + this.getDeleteSelectionItem_(), + this.getViewOriginalSelectionItem_(), + ].filter(goog.functions.identity), + selectedItems: this.state.selection + }); + } + } + + return null; }, getTagsControl_: function() {