Skuid Community,
We had a request to download selected files into a single zip file. We looked at solutions that involved some JavaScript libraries and some Apex. Based on a posting by another community member Nicholas L. we found that Salesforce’s page that allows you to download a file also supports downloading a Zip file with multiple selected files.
Here is the format of the URL. You just need the ContentVersionId for each selected file separated by a ‘/’:
/sfc/servlet.shepherd/version/download/068xxxxxxxxxxxxxxx/068yyyyyyyyyyyyyyy
You can find more details here: http://cropredysfdc.com/2016/03/16/download-multiple-contentversion-files-as-zip
Here is a sample Skuid page that contains a snippet to get the selected file ids and download the selected files as a Zip. It should work in any Salesforce org. This is a Version 1 Skuid page. The page loads a contact record and its related files. This ‘hack’ only works with Salesforce/Chatter Files.
To demonstrate this feature:
- Install the page
- Upload some files to the Files tab
- Check the box next to the files that you want to download
- Click the mass action 'Download Selected as Zip'
Bill
<skuidpage showheader="true" personalizationmode="server" showsidebar="true" tabtooverride="Contact">
<models>
<model id="Contact" datasource="salesforce" createrowifnonefound="false" query="true" sobject="Contact" limit="1">
<fields>
<field id="FirstName"/>
<field id="LastName"/>
<field id="CreatedDate"/>
<field id="MailingCity"/>
<field id="MailingStreet"/>
<field id="MailingState"/>
<field id="MailingCountry"/>
<field id="MailingPostalCode"/>
<field id="LastModifiedDate"/>
<field id="Phone"/>
<field id="Email"/>
<field id="Id"/>
<field id="AccountId"/>
<field id="Account.Name"/>
<field id="Birthdate"/>
<field id="Description"/>
</fields>
<conditions>
<condition type="param" value="id" enclosevalueinquotes="true" field="Id" operator="="/>
</conditions>
<actions/>
</model>
<model id="ContentDocumentLink" datasource="salesforce" createrowifnonefound="false" query="true" sobject="ContentDocumentLink" limit="20">
<fields>
<field id="ContentDocumentId"/>
<field id="ContentDocument.Title"/>
<field id="LinkedEntityId"/>
<field id="LinkedEntity.Name"/>
<field id="ContentDocument.LatestPublishedVersionId"/>
<field id="ContentDocument.LatestPublishedVersion.Title"/>
<field id="Id"/>
<field id="ContentDocument.Id"/>
<field id="ContentDocument.LatestPublishedVersion.Id"/>
</fields>
<conditions>
<condition type="modelmerge" value="" model="Contact" enclosevalueinquotes="true" field="LinkedEntityId" operator="=" mergefield="Id" novaluebehavior="noquery" fieldtargetobjects="Contact"/>
</conditions>
<actions/>
</model>
<model id="LastUploaded" datasource="salesforce" createrowifnonefound="false" query="false" sobject="ContentDocumentLink" limit="1" orderby="SystemModstamp DESC">
<fields>
<field id="ContentDocumentId"/>
<field id="ContentDocument.Title"/>
<field id="LinkedEntityId"/>
<field id="LinkedEntity.Name"/>
<field id="ContentDocument.LatestPublishedVersionId"/>
<field id="ContentDocument.LatestPublishedVersion.Title"/>
<field id="Id"/>
<field id="ContentDocument.Id"/>
<field id="SystemModstamp"/>
</fields>
<conditions>
<condition type="modelmerge" value="" model="Contact" enclosevalueinquotes="true" field="LinkedEntityId" operator="=" mergefield="Id" novaluebehavior="noquery" fieldtargetobjects="Contact"/>
</conditions>
<actions/>
</model>
<model id="Selected" query="true" createrowifnonefound="true" datasource="Ui-Only" processonclient="true">
<fields>
<field id="CurrentIndex" displaytype="DOUBLE" label="CurrentIndex" length="3" defaultvaluetype="fieldvalue" ogdisplaytype="TEXT" precision="3" scale="0"/>
</fields>
<conditions/>
<actions/>
</model>
</models>
<components>
<pagetitle uniqueid="sk-2nnOO--83" model="Contact">
<maintitle>
<template>{{FirstName}} {{LastName}}</template>
</maintitle>
<subtitle>
<template>{{Model.label}}</template>
</subtitle>
<actions>
<action type="savecancel" uniqueid="sk-zZmyt-88" window="self">
<models>
<model>ContentDocumentLink</model>
</models>
<savehotkeys>
<hotkey key="s" modifiers="ctrl"/>
</savehotkeys>
</action>
</actions>
</pagetitle>
<tabset uniqueid="sk-2nnZAZ-122" renderas="" defertabrendering="true" rememberlastusertab="true">
<tabs>
<tab name="Demographics">
<components>
<grid uniqueid="sk-1JOn4K-289">
<divisions>
<division verticalalign="top" behavior="specified" width="250px">
<components>
<image source="url" uniqueid="sk-2om0aY-1786" datasource="salesforce" behavior="button" model="Contact" url="/sfc/servlet.shepherd/version/download/{{{Description}}}" alt="Click to select another image">
<styles>
<styleitem type="itemsize" width="auto" height="auto"/>
<styleitem type="border"/>
</styles>
<interactions>
<interaction type="tap">
<action type="requeryModel" model="ContentDocumentLink" behavior="standard"/>
<action type="showPopup">
<popup title="Select Image" width="70%">
<components>
<deck searchmethod="server" searchbox="false" columngutter=".75em" rowgutter=".75em" model="ContentDocumentLink" filtersposition="top" filterswidth="150px" showsavecancel="false" behavior="flex" verticalalign="top" ratio="1" minwidth="150px" uniqueid="sk-2oqyo7-658" buttonposition="" pagesize="5" emptysearchbehavior="query">
<components>
<wrapper uniqueid="sk-2or6aG-702">
<components>
<image source="url" uniqueid="sk-2or1Bk-683" datasource="salesforce" behavior="none" model="ContentDocumentLink" url="/sfc/servlet.shepherd/version/download/{{{ContentDocument.LatestPublishedVersionId}}}">
<styles>
<styleitem type="itemsize" width="custom">
<styles>
<styleitem property="width" value="350px"/>
</styles>
</styleitem>
<styleitem type="border"/>
</styles>
<conditions>
<condition type="contextrow" field="Id" mergefield="Id"/>
</conditions>
</image>
</components>
<styles>
<styleitem type="background"/>
<styleitem type="border"/>
<styleitem type="size" width="custom" height="collapse">
<styles>
<styleitem property="max-width" value="300px"/>
</styles>
</styleitem>
</styles>
</wrapper>
</components>
<massactions/>
<interactions>
<interaction type="tap" direction="either">
<action type="updateRow" fieldmodel="Contact" affectedrows="context" field="Description" enclosevalueinquotes="true" value="{{ContentDocument.LatestPublishedVersionId}}">
<models/>
<popup title="{{Model.label}}: {{Name}}" width="80%">
<components/>
</popup>
</action>
<action type="save" rollbackonanyerror="true">
<models>
<model>Contact</model>
</models>
<onerroractions>
<action type="blockUI" message="There was an error" timeout="3000"/>
<action type="unblockUI" message="There was an error" timeout="3000"/>
</onerroractions>
</action>
<action type="closeTopmostPopup"/>
</interaction>
</interactions>
<actions/>
<styles>
<styleitem type="border"/>
</styles>
<searchfields/>
</deck>
</components>
</popup>
</action>
</interaction>
</interactions>
</image>
<file storeas="contentdocumentwithrecord" displayas="filename" uniqueid="sk-2oxn1B-383" datasource="salesforce" model="Contact" label="New Contact Image">
<uploadsuccessactions>
<action type="requeryModel" model="LastUploaded" behavior="standard"/>
<action type="updateRow" fieldmodel="Contact" affectedrows="context" field="Description" enclosevalueinquotes="true" value="{{{$Model.LastUploaded.data.0.ContentDocument.LatestPublishedVersionId}}}"/>
<action type="save">
<models>
<model>Contact</model>
</models>
</action>
</uploadsuccessactions>
<uploadfailureactions/>
</file>
</components>
</division>
<division verticalalign="top" behavior="flex" ratio="1" minwidth="100px">
<components>
<basicfieldeditor uniqueid="sk-2nnOO--84" model="Contact" mode="read" buttonposition="" showsavecancel="false" layout="" showheader="true">
<columns>
<column width="50%">
<sections>
<section title="Basics" collapsible="no">
<fields>
<field id="FirstName" type="" uniqueid="sk-zZmzM-96" valuehalign=""/>
<field id="LastName" uniqueid="sk-zZmzP-98"/>
<field id="Phone" uniqueid="sk-zaxUD-370" cssclass="" snippet="businessPhoneRender"/>
<field id="Email" type="" uniqueid="sk-13zjI1-245" valuehalign=""/>
<field id="AccountId" uniqueid="sk-1VHq5D-261" pagesize="5" optionsource="" redirecttype="datasourcedefault">
<searchfields soslfields="All Fields" usesosl="true"/>
<filters/>
<renderconditions logictype="and" onhidedatabehavior="keep"/>
<enableconditions/>
</field>
<field id="Birthdate" uniqueid="sk-22tbDe-276"/>
</fields>
</section>
<section title="Image" collapsible="no">
<fields>
<field uniqueid="sk-2ovbdg-953" id="Description"/>
</fields>
</section>
</sections>
</column>
<column width="50%">
<sections>
<section title="Address" collapsible="no">
<fields>
<field id="MailingStreet" uniqueid="sk-zZmzp-115"/>
<field id="MailingCity" uniqueid="sk-zZmzq-117"/>
<field id="MailingState" uniqueid="sk-zZmzr-119"/>
<field id="MailingPostalCode" uniqueid="sk-zZmzv-121"/>
<field id="MailingCountry" uniqueid="sk-zZmzz-123"/>
</fields>
</section>
</sections>
</column>
</columns>
</basicfieldeditor>
</components>
</division>
</divisions>
<styles>
<styleitem type="background" bgtype="none"/>
</styles>
</grid>
</components>
</tab>
<tab name="Files" loadlazypanels="true">
<components>
<file datasource="salesforce" uniqueid="sk-1Yfw5z-376" model="Contact" displayas="filename" storeas="contentdocumentwithrecord">
<uploadsuccessactions>
<action type="requeryModels" behavior="standard" model="ContactFeed">
<models>
<model>ContentDocumentLink</model>
</models>
</action>
</uploadsuccessactions>
<uploadfailureactions/>
<renderconditions logictype="and"/>
</file>
<skootable uniqueid="sk-1MPZvX-293" model="ContentDocumentLink" mode="read" buttonposition="" createrecords="true" pagesize="10" showexportbuttons="false" searchbox="true" searchmethod="server" showerrorsinline="true" showsavecancel="false" showconditions="true" allowcolumnreordering="true" responsive="true" alwaysresetpagination="false">
<fields>
<field id="ContentDocumentId" uniqueid="fi-1MPhMg-312" hideable="true"/>
<field type="COMBO" hideable="true" uniqueid="fi-2ooSE_-1827" allowhtml="true">
<label>View</label>
<template>&lt;a target="_blank" href="/sfc/servlet.shepherd/version/download/{{{ContentDocument.LatestPublishedVersionId}}}"&gt;{{{ContentDocument.Title}}}&lt;/a&gt;</template>
</field>
<field type="IMAGE" hideable="true" uniqueid="fi-IA_-437">
<label>Image</label>
<url>/sfc/servlet.shepherd/version/renditionDownload?rendition=THUMB240BY180&amp;versionId={{{ContentDocument.LatestPublishedVersion.Id}}}</url>
</field>
</fields>
<rowactions>
<action type="edit"/>
<action type="delete"/>
<action type="multi" label="Set {{ContentDocument.Title}} as Image" icon="sk-icon-personal-info">
<actions>
<action type="updateRow" fieldmodel="Contact" affectedrows="context" field="Description" enclosevalueinquotes="true" value="{{{ContentDocument.LatestPublishedVersionId}}}"/>
<action type="save" rollbackonanyerror="true">
<models>
<model>Contact</model>
</models>
<onerroractions>
<action type="blockUI" message="There was an error" timeout="3000"/>
<action type="unblockUI" message="There was an error" timeout="3000"/>
</onerroractions>
</action>
<action type="requeryModel" model="Contact" behavior="standard"/>
</actions>
</action>
</rowactions>
<massactions usefirstitemasdefault="true">
<action type="multi" label="Download Selected as Zip" icon="fa-download">
<actions>
<action type="custom" snippet="downloadSnippet"/>
</actions>
</action>
<action type="massupdate"/>
<action type="massdelete"/>
</massactions>
<views>
<view type="standard"/>
</views>
<actions defaultlabel="Global Actions" defaulticon="sk-icon-magic" usefirstitemasdefault="true"/>
</skootable>
</components>
<oninitialshowactions/>
<onshowactions/>
</tab>
</tabs>
</tabset>
</components>
<resources>
<labels/>
<css/>
<javascript>
<jsitem location="inlinesnippet" name="downloadSnippet" cachelocation="false">var params = arguments 0],
$ = skuid.$;
// Get the Ids of the selected items as an Array
var selectedItems = arguments 0].list.getSelectedItems();
var idsArray = skuid.$.map(selectedItems,function(item){
return item.row.ContentDocument.LatestPublishedVersionId;
});
// Pass these Ids over to our Visualforce Page
window.top.location =
" /sfc/servlet.shepherd/version/download/"
+ idsArray.join("/");
// /sfc/servlet.shepherd/version/download/{{#$Model.ContentDocumentLink.data}}{{{ContentDocument.LatestPublishedVersionId}}}/{{/$Model.ContentDocumentLink.data}}</jsitem>
</javascript>
<actionsequences uniqueid="sk-2RUGHd-473"/>
</resources>
<styles>
<styleitem type="background" bgtype="none"/>
</styles>
<interactions/>
</skuidpage>