feat(media): add external media library support, Uploadcare integration (#1602)
This commit is contained in:
11
packages/netlify-cms-media-library-uploadcare/README.md
Normal file
11
packages/netlify-cms-media-library-uploadcare/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Docs coming soon!
|
||||
|
||||
Netlify CMS was recently converted from a single npm package to a "monorepo" of over 20 packages.
|
||||
That's over 20 Readme's! We haven't created one for this package yet, but we will soon.
|
||||
|
||||
In the meantime, you can:
|
||||
|
||||
1. Check out the [main readme](https://github.com/netlify/netlify-cms/#readme) or the [documentation
|
||||
site](https://www.netlifycms.org) for more info.
|
||||
2. Reach out to the [community chat](https://gitter.im/netlify/netlifycms/) if you need help.
|
||||
3. Help out and [write the readme yourself](https://github.com/netlify/netlify-cms/edit/master/packages/netlify-cms-media-library-uploadcare/README.md)!
|
33
packages/netlify-cms-media-library-uploadcare/package.json
Normal file
33
packages/netlify-cms-media-library-uploadcare/package.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "netlify-cms-media-library-uploadcare",
|
||||
"description": "Uploadcare integration for Netlify CMS",
|
||||
"version": "0.1.0",
|
||||
"repository": "https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-media-library-uploadcare",
|
||||
"bugs": "https://github.com/netlify/netlify-cms/issues",
|
||||
"main": "dist/netlify-cms-media-library-uploadcare.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"netlify",
|
||||
"netlify-cms",
|
||||
"uploadcare",
|
||||
"media",
|
||||
"assets",
|
||||
"files",
|
||||
"uploads"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"watch": "webpack -w",
|
||||
"develop": "npm run watch",
|
||||
"build": "cross-env NODE_ENV=production webpack"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^5.2.0",
|
||||
"webpack": "^4.16.1",
|
||||
"webpack-cli": "^3.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"netlify-cms-lib-util": "^2.0.4"
|
||||
},
|
||||
"private": true
|
||||
}
|
146
packages/netlify-cms-media-library-uploadcare/src/index.js
Normal file
146
packages/netlify-cms-media-library-uploadcare/src/index.js
Normal file
@ -0,0 +1,146 @@
|
||||
import { loadScript } from 'netlify-cms-lib-util';
|
||||
|
||||
/**
|
||||
* Default Uploadcare widget configuration, can be overriden via config.yml.
|
||||
*/
|
||||
const defaultConfig = {
|
||||
previewStep: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine whether an array of urls represents an unaltered set of Uploadcare
|
||||
* group urls. If they've been changed or any are missing, a new group will need
|
||||
* to be created to represent the current values.
|
||||
*/
|
||||
function isFileGroup(files) {
|
||||
const basePatternString = `~${files.length}/nth/`;
|
||||
const mapExpression = (val, idx) => new RegExp(`${basePatternString}${idx}/$`);
|
||||
const expressions = Array.from({ length: files.length }, mapExpression);
|
||||
return expressions.every(exp => files.some(url => exp.test(url)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fileGroupInfo object wrapped in a promise-like object.
|
||||
*/
|
||||
function getFileGroup(files) {
|
||||
/**
|
||||
* Capture the group id from the first file in the files array.
|
||||
*/
|
||||
const groupId = new RegExp(`^.+/([^/]+~${files.length})/nth/`).exec(files[0])[1];
|
||||
|
||||
/**
|
||||
* The `openDialog` method handles the jQuery promise object returned by
|
||||
* `fileFrom`, but requires the promise returned by `loadFileGroup` to provide
|
||||
* the result of it's `done` method.
|
||||
*/
|
||||
return new Promise(resolve =>
|
||||
window.uploadcare.loadFileGroup(groupId).done(group => resolve(group)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a url or array/List of urls to Uploadcare file objects wrapped in
|
||||
* promises, or Uploadcare groups when possible. Output is wrapped in a promise
|
||||
* because the value we're returning may be a promise that we created.
|
||||
*/
|
||||
function getFiles(value, cdnBase) {
|
||||
if (typeof value === 'object') {
|
||||
const arr = Array.isArray(value) ? value : value.toJS();
|
||||
return isFileGroup(arr) ? getFileGroup(arr) : arr.map(val => getFile(val, cdnBase));
|
||||
}
|
||||
return value && typeof value === 'string' ? getFile(value, cdnBase) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a single url to an Uploadcare file object wrapped in a promise-like
|
||||
* object. Group urls that get passed here were not a part of a complete and
|
||||
* untouched group, so they'll be uploaded as new images (only way to do it).
|
||||
*/
|
||||
function getFile(url, cdnBase) {
|
||||
const groupPattern = /~\d+\/nth\/\d+\//;
|
||||
const baseUrls = ['https://ucarecdn.com', cdnBase].filter(v => v);
|
||||
const uploaded = baseUrls.some(baseUrl => url.startsWith(baseUrl) && !groupPattern.test(url));
|
||||
return window.uploadcare.fileFrom(uploaded ? 'uploaded' : 'url', url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the standalone dialog. A single instance is created and destroyed for
|
||||
* each use.
|
||||
*/
|
||||
function openDialog(files, config, handleInsert) {
|
||||
window.uploadcare.openDialog(files, config).done(({ promise }) =>
|
||||
promise().then(({ cdnUrl, count }) => {
|
||||
if (config.multiple) {
|
||||
const urls = Array.from({ length: count }, (val, idx) => `${cdnUrl}nth/${idx}/`);
|
||||
handleInsert(urls);
|
||||
} else {
|
||||
handleInsert(cdnUrl);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization function will only run once, returns an API object for Netlify
|
||||
* CMS to call methods on.
|
||||
*/
|
||||
async function init({ options = { config: {} }, handleInsert }) {
|
||||
const { publicKey, ...globalConfig } = options.config;
|
||||
const baseConfig = { ...defaultConfig, ...globalConfig };
|
||||
|
||||
window.UPLOADCARE_LIVE = false;
|
||||
window.UPLOADCARE_MANUAL_START = true;
|
||||
window.UPLOADCARE_PUBLIC_KEY = publicKey;
|
||||
|
||||
/**
|
||||
* Loading scripts via url because the uploadcare widget includes
|
||||
* non-strict-mode code that's incompatible with our build system
|
||||
*/
|
||||
await loadScript('https://unpkg.com/uploadcare-widget@^3.6.0/uploadcare.full.js');
|
||||
await loadScript(
|
||||
'https://unpkg.com/uploadcare-widget-tab-effects@^1.2.1/dist/uploadcare.tab-effects.js',
|
||||
);
|
||||
|
||||
/**
|
||||
* Register the effects tab by default because the effects tab is awesome. Can
|
||||
* be disabled via config.
|
||||
*/
|
||||
window.uploadcare.registerTab('preview', window.uploadcareTabEffects);
|
||||
|
||||
return {
|
||||
/**
|
||||
* On show, create a new widget, cache it in the widgets object, and open.
|
||||
* No hide method is provided because the widget doesn't provide it.
|
||||
*/
|
||||
show: ({ value, config: instanceConfig = {}, imagesOnly }) => {
|
||||
const config = { ...baseConfig, imagesOnly, ...instanceConfig };
|
||||
const files = getFiles(value);
|
||||
|
||||
/**
|
||||
* Resolve the promise only if it's ours. Only the jQuery promise objects
|
||||
* from the Uploadcare library will have a `state` method.
|
||||
*/
|
||||
if (files && !files.state) {
|
||||
files.then(result => openDialog(result, config, handleInsert));
|
||||
} else {
|
||||
openDialog(files, config, handleInsert);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Uploadcare doesn't provide a "media library" widget for viewing and
|
||||
* selecting existing files, so we return `false` here so Netlify CMS only
|
||||
* opens the Uploadcare widget when called from an editor control. This
|
||||
* results in the "Media" button in the global nav being hidden.
|
||||
*/
|
||||
enableStandalone: () => false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The object that will be registered only needs a (default) name and `init`
|
||||
* method. The `init` method returns the API object.
|
||||
*/
|
||||
const uploadcareMediaLibrary = { name: 'uploadcare', init };
|
||||
|
||||
export default uploadcareMediaLibrary;
|
@ -0,0 +1,3 @@
|
||||
const { getConfig } = require('../../scripts/webpack.js');
|
||||
|
||||
module.exports = getConfig();
|
Reference in New Issue
Block a user