diff --git a/modules/deployment.xq b/modules/deployment.xq index c8cad1cb..457bcd6f 100644 --- a/modules/deployment.xq +++ b/modules/deployment.xq @@ -585,12 +585,8 @@ declare function deploy:package($collection as xs:string, $expathConf as element xmldb:store("/db/system/repo", $name, $xar, "application/zip") }; -declare function deploy:download($collection as xs:string, $expathConf as element()?, $expand-xincludes as xs:boolean, $indent as xs:boolean, $omit-xml-declaration as xs:boolean) { - let $name := - if ($expathConf) then - concat($expathConf/@abbrev, "-", $expathConf/@version, ".xar") - else - replace($collection, "^.+/([^/]+)$", "$1") || ".zip" +declare function deploy:download($collection as xs:string, $expathConf as element(), $expand-xincludes as xs:boolean, $indent as xs:boolean, $omit-xml-declaration as xs:boolean) { + let $name := concat($expathConf/@abbrev, "-", $expathConf/@version, ".xar") let $entries := (: compression:zip uses default serialization parameters, so we'll construct entries manually :) dbutil:scan(xs:anyURI($collection), function($coll as xs:anyURI, $res as xs:anyURI?) { @@ -602,7 +598,6 @@ declare function deploy:download($collection as xs:string, $expathConf as elemen {$res} else { - (: workaround until https://github.com/eXist-db/exist/issues/2394 is resolved :) util:declare-option( "exist:serialize", "expand-xincludes=" diff --git a/modules/load.xq b/modules/load.xq index 36f77cb9..860f39e0 100644 --- a/modules/load.xq +++ b/modules/load.xq @@ -19,6 +19,7 @@ xquery version "3.0"; import module namespace config="http://exist-db.org/xquery/apps/config" at "config.xqm"; +import module namespace dbutil="http://exist-db.org/xquery/dbutil" at "dbutils.xqm"; declare function local:get-run-path($path) { let $appRoot := repo:get-root() @@ -34,43 +35,78 @@ declare function local:get-run-path($path) { }; let $path := request:get-parameter("path", ()) -let $download := request:get-parameter("download", ()) +let $download := request:get-parameter("download", false()) cast as xs:boolean let $indent := request:get-parameter("indent", true()) cast as xs:boolean let $expand-xincludes := request:get-parameter("expand-xincludes", false()) cast as xs:boolean let $omit-xml-declaration := request:get-parameter("omit-xml-decl", true()) cast as xs:boolean -let $mime := xmldb:get-mime-type($path) -let $isBinary := util:is-binary-doc($path) +let $isBinary := util:binary-doc-available($path) +let $isCollection := xmldb:collection-available($path) +let $name := replace($path, "^.+/([^/]+)$", "$1") (: Disable betterFORM filter :) let $attribute := request:set-attribute("betterform.filter.ignoreResponseBody", "true") -let $header := response:set-header("Content-Type", if ($mime) then $mime else "application/binary") -let $header := response:set-header("X-Link", local:get-run-path($path)) -let $header2 := - if ($download) then - response:set-header("Content-Disposition", concat("attachment; filename=", replace($path, "^.*/([^/]+)$", "$1"))) - else - () return - if (config:access-allowed($path, sm:id()//sm:real/sm:username/string())) then - if ($isBinary) then - let $data := util:binary-doc($path) - return - response:stream-binary($data, $mime, ()) + if (config:access-allowed($path, sm:id()//sm:real/sm:username)) then + if ($isCollection and $download) then + let $entries := + (: compression:zip uses default serialization parameters, so we'll construct entries manually :) + dbutil:scan(xs:anyURI($path), function($coll as xs:anyURI, $res as xs:anyURI?) { + (: compression:zip doesn't seem to store empty collections, so we'll scan for only resources :) + if (exists($res)) then + let $relative-path := $name || "/" || substring-after($res, $path || "/") + return + if (util:binary-doc-available($res)) then + {$res} + else + { + util:declare-option( + "exist:serialize", + "expand-xincludes=" + || (if ($expand-xincludes) then "yes" else "no") + || " indent=" + || (if ($indent) then "yes" else "no") + || " omit-xml-declaration=" + || (if ($omit-xml-declaration) then "yes" else "no") + ), + doc($res) + } + else + () + }) + let $archive := compression:zip($entries, true()) + let $archive-name := $name || ".zip" + return + ( + response:set-header("Content-Disposition", concat("attachment; filename=", $archive-name)), + response:stream-binary($archive, "application/zip", $archive-name) + ) else - if (doc-available($path)) then + let $mime := xmldb:get-mime-type($path) + let $headers := ( - (: workaround until https://github.com/eXist-db/exist/issues/2394 is resolved :) - util:declare-option( - "exist:serialize", - "indent=" - || (if ($indent) then "yes" else "no") - || " expand-xincludes=" + response:set-header("Content-Type", if (exists($mime)) then $mime else "application/binary"), + response:set-header("X-Link", local:get-run-path($path)), + if ($download) then + response:set-header("Content-Disposition", concat("attachment; filename=", $name)) + else + () + ) + return + if ($isBinary) then + let $data := util:binary-doc($path) + return + response:stream-binary($data, $mime, $name) + else + ( + util:declare-option( + "exist:serialize", + "expand-xincludes=" || (if ($expand-xincludes) then "yes" else "no") + || " indent=" + || (if ($indent) then "yes" else "no") || " omit-xml-declaration=" || (if ($omit-xml-declaration) then "yes" else "no") - ), - doc($path) - ) - else - response:set-status-code(404) + ), + doc($path) + ) else response:set-status-code(404) diff --git a/src/deployment.js b/src/deployment.js index 7f529ea5..e5360c41 100644 --- a/src/deployment.js +++ b/src/deployment.js @@ -230,19 +230,7 @@ eXide.edit.PackageEditor = (function () { var indentOnDownloadPackage = $("#indent-on-download-package").is(":checked"); var expandXIncludesOnDownloadPackage = $("#expand-xincludes-on-download-package").is(":checked"); var omitXMLDeclatarionOnDownloadPackage = $("#omit-xml-declaration-on-download-package").is(":checked"); - const url = "modules/deployment.xq?download=true&collection=" + encodeURIComponent(collection) + "&indent=" + indentOnDownloadPackage + "&expand-xincludes=" + expandXIncludesOnDownloadPackage + "&omit-xml-declaration=" + omitXMLDeclatarionOnDownloadPackage; - fetch(url) - .then(resp => resp.blob()) - .then(blob => { - const url = window.URL.createObjectURL(blob); - const a = document.createElement('a'); - a.style.display = 'none'; - a.href = url; - a.download = decodeURI(collection.split("/").slice(-1)[0]); - document.body.appendChild(a); - a.click(); - window.URL.revokeObjectURL(url); - }) + window.location.href = "modules/deployment.xq?download=true&collection=" + encodeURIComponent(collection) + "&indent=" + indentOnDownloadPackage + "&expand-xincludes=" + expandXIncludesOnDownloadPackage + "&omit-xml-decl=" + omitXMLDeclatarionOnDownloadPackage; }; /** diff --git a/src/eXide.js b/src/eXide.js index 1ea37762..0e427e17 100644 --- a/src/eXide.js +++ b/src/eXide.js @@ -290,19 +290,13 @@ eXide.app = (function(util) { $("#open-dialog").dialog("close"); }, - downloadSelectedDocument: function(docs, close) { - var resources = docs; + downloadSelectedResources: function(resources, close) { if (resources) { - resources.filter(res => res.isCollection).forEach(collection => { - deploymentEditor.download(collection.key); - }); - - resources.filter(res => !res.isCollection).forEach(resource => { + resources.forEach(resource => { app.download(resource.key); }) - }else { - util.Dialog.warning("Invalid selection","The Download Selected command requires that resources be selected. Please select a resources for download.") + util.Dialog.warning("Invalid selection","The Download Selected command requires that resources be selected. Please select resources for download.") } if (close == undefined || close) $("#open-dialog").dialog("close"); diff --git a/src/resources.js b/src/resources.js index b5d401e5..c162a184 100644 --- a/src/resources.js +++ b/src/resources.js @@ -780,7 +780,7 @@ eXide.browse.Browser = (function () { $(button).click(function (ev) { ev.preventDefault(); const selected = $this.resources.getSelected(); - eXide.app.downloadSelectedDocument(selected, false); + eXide.app.downloadSelectedResources(selected, false); }); this.btnCopy = createButton(toolbar, "Copy", "copy", 7, "copy");