diff --git a/docs/quick-start.md b/docs/quick-start.md index d2943745c7fb..d3e1ac6cb1ed 100755 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -110,6 +110,8 @@ This configuration adds a new setting, `public_folder`. While `media_folder` spe >If `public_folder` is not set, Netlify CMS will default to the same value as `media_folder`, adding an opening `/` if one is not included. +The `media_folder` and `public_folder` settings can also be applied for individual [Image and File widgets](widgets#imagefile-widget). + ### Collections Collections define the structure for the different content types on your static site. Since every site is different, the `collections` settings will be very different from one site to the next. Let's say your site has a blog, with the posts stored in `_posts/blog`, and files saved in a date-title format, like `1999-12-31-lets-party.md`. Each post begins with settings in yaml-formatted front matter, like so: diff --git a/docs/widgets.md b/docs/widgets.md index 4f4d484540fe..7db095ae5a36 100644 --- a/docs/widgets.md +++ b/docs/widgets.md @@ -61,3 +61,15 @@ collections: searchFields: [name, twitterHandle] valueField: name ``` + +### Image/File Widget + +If you store your images and files in different folders, you can add `media_folder` and `public_folder` properties to the widget configuration: + +```yaml + - label: Image + name: image + widget: image + media_folder: repo/path/to/assets + public_folder: /public/path/to/assets +``` diff --git a/src/components/Widgets/FileControl.js b/src/components/Widgets/FileControl.js index 468b41074253..ccd019b5f1bb 100644 --- a/src/components/Widgets/FileControl.js +++ b/src/components/Widgets/FileControl.js @@ -46,6 +46,11 @@ export default class FileControl extends React.Component { const fileList = e.dataTransfer ? e.dataTransfer.files : e.target.files; const files = [...fileList]; const imageType = /^image\//; + const assetProxyOpts = { + isPrivate: this.props.field.get('private', false), + mediaFolder: this.props.field.get('media_folder'), + publicFolder: this.props.field.get('public_folder'), + }; // Return the first file on the list const file = files[0]; @@ -53,7 +58,7 @@ export default class FileControl extends React.Component { this.props.onRemoveAsset(this.props.value); if (file) { this.setState({ processing: true }); - this.promise = createAssetProxy(file.name, file, false, this.props.field.get('private', false)) + this.promise = createAssetProxy(file.name, file, false, assetProxyOpts) .then((assetProxy) => { this.setState({ processing: false }); this.props.onAddAsset(assetProxy); diff --git a/src/components/Widgets/ImageControl.js b/src/components/Widgets/ImageControl.js index cd8fb46b4637..3567150511ed 100644 --- a/src/components/Widgets/ImageControl.js +++ b/src/components/Widgets/ImageControl.js @@ -46,6 +46,10 @@ export default class ImageControl extends React.Component { const fileList = e.dataTransfer ? e.dataTransfer.files : e.target.files; const files = [...fileList]; const imageType = /^image\//; + const assetProxyOpts = { + mediaFolder: this.props.field.get('media_folder'), + publicFolder: this.props.field.get('public_folder'), + }; // Iterate through the list of files and return the first image on the list const file = files.find((currentFile) => { @@ -57,7 +61,7 @@ export default class ImageControl extends React.Component { this.props.onRemoveAsset(this.props.value); if (file) { this.setState({ processing: true }); - this.promise = createAssetProxy(file.name, file) + this.promise = createAssetProxy(file.name, file, false, assetProxyOpts) .then((assetProxy) => { this.setState({ processing: false }); this.props.onAddAsset(assetProxy); diff --git a/src/valueObjects/AssetProxy.js b/src/valueObjects/AssetProxy.js index e88b2c1b0f36..1474ae926e1e 100644 --- a/src/valueObjects/AssetProxy.js +++ b/src/valueObjects/AssetProxy.js @@ -8,14 +8,16 @@ export const setStore = (storeObj) => { store = storeObj; }; -export default function AssetProxy(value, fileObj, uploaded = false) { +export default function AssetProxy(value, fileObj, uploaded = false, opts = {}) { const config = store.getState().config; + const mediaFolder = opts.mediaFolder || config.get('media_folder'); + const publicFolder = opts.publicFolder || config.get('public_folder'); this.value = value; this.fileObj = fileObj; this.uploaded = uploaded; this.sha = null; - this.path = config.get('media_folder') && !uploaded ? resolvePath(value, config.get('media_folder')) : value; - this.public_path = !uploaded ? resolvePath(value, config.get('public_folder')) : value; + this.path = mediaFolder && !uploaded ? resolvePath(value, mediaFolder) : value; + this.public_path = !uploaded ? resolvePath(value, publicFolder) : value; } AssetProxy.prototype.toString = function () { @@ -39,20 +41,25 @@ AssetProxy.prototype.toBase64 = function () { }); }; -export function createAssetProxy(value, fileObj, uploaded = false, privateUpload = false) { +export function createAssetProxy(value, fileObj, uploaded = false, opts = {}) { const state = store.getState(); + const privateUpload = opts.isPrivate || false; + const assetProxyOpts = { + mediaFolder: opts.mediaFolder, + publicFolder: opts.publicFolder + }; const integration = selectIntegration(state, null, 'assetStore'); if (integration && !uploaded) { const provider = integration && getIntegrationProvider(state.integrations, currentBackend(state.config).getToken, integration); return provider.upload(fileObj, privateUpload).then( response => ( - new AssetProxy(response.assetURL.replace(/^(https?):/, ''), null, true) + new AssetProxy(response.assetURL.replace(/^(https?):/, ''), null, true, assetProxyOpts) ), - error => new AssetProxy(value, fileObj, false) - ); + error => new AssetProxy(value, fileObj, false, assetProxyOpts) + ); } else if (privateUpload) { throw new Error('The Private Upload option is only avaible for Asset Store Integration'); } - - return Promise.resolve(new AssetProxy(value, fileObj, uploaded)); + + return Promise.resolve(new AssetProxy(value, fileObj, uploaded, assetProxyOpts)); }