mirror of https://github.com/artf/grapesjs.git
4 changed files with 134 additions and 126 deletions
@ -1,66 +0,0 @@ |
|||
import { isUndefined, isFunction, isString } from 'underscore'; |
|||
import fetch from '../../utils/fetch'; |
|||
|
|||
export default class RemoteStorage { |
|||
async store(data, opts = {}) { |
|||
await this.request(opts.urlStore, this.__props(opts, data), opts); |
|||
} |
|||
|
|||
async load(opts) { |
|||
return await this.request(opts.urlLoad, this.__props(opts), opts); |
|||
} |
|||
|
|||
request(url, props = {}, opts = {}) { |
|||
return fetch(url, props) |
|||
.then(res => { |
|||
const result = res.text(); |
|||
const isOk = ((res.status / 200) | 0) === 1; |
|||
return isOk ? result : result.then(Promise.reject); |
|||
}) |
|||
.then(text => { |
|||
const parsable = text && isString(text); |
|||
return opts.contentTypeJson && parsable ? JSON.parse(text) : text; |
|||
}); |
|||
} |
|||
|
|||
__props(opts = {}, data) { |
|||
const typeJson = opts.contentTypeJson; |
|||
const headers = opts.headers || {}; |
|||
const fetchOpts = opts.fetchOptions || {}; |
|||
const reqHead = 'X-Requested-With'; |
|||
const typeHead = 'Content-Type'; |
|||
let body; |
|||
|
|||
if (isUndefined(headers[reqHead])) { |
|||
headers[reqHead] = 'XMLHttpRequest'; |
|||
} |
|||
|
|||
if (isUndefined(headers[typeHead]) && typeJson) { |
|||
headers[typeHead] = 'application/json; charset=utf-8'; |
|||
} |
|||
|
|||
if (data) { |
|||
if (typeJson) { |
|||
body = JSON.stringify(data); |
|||
} else { |
|||
body = new FormData(); |
|||
|
|||
for (let key in data) { |
|||
body.append(key, data[key]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
const result = { |
|||
method: body ? 'POST' : 'GET', |
|||
credentials: opts.credentials, |
|||
headers, |
|||
body, |
|||
}; |
|||
|
|||
return { |
|||
...result, |
|||
...(isFunction(fetchOpts) ? fetchOpts(result) : fetchOpts), |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,127 @@ |
|||
import Editor from '../../editor'; |
|||
import { isUndefined, isFunction, isString } from 'underscore'; |
|||
import fetch from '../../utils/fetch'; |
|||
import IStorage, { ProjectData } from './IStorage'; |
|||
import { ModelFetchOptions } from 'backbone'; |
|||
|
|||
type AnyObject = Record<string, any>; |
|||
|
|||
export interface RemoteStorageConfig { |
|||
/** |
|||
* Custom headers. |
|||
* @default {} |
|||
*/ |
|||
headers?: AnyObject; |
|||
|
|||
/** |
|||
* Endpoint URL where to store data project. |
|||
*/ |
|||
urlStore?: string; |
|||
|
|||
/** |
|||
* Endpoint URL where to load data project. |
|||
*/ |
|||
urlLoad?: string; |
|||
|
|||
/** |
|||
* Use JSON contentType. |
|||
* @default true |
|||
*/ |
|||
contentTypeJson?: boolean; |
|||
|
|||
/** |
|||
* Credentials option for the fetch API. |
|||
* @default 'include' |
|||
*/ |
|||
credentials?: RequestCredentials; |
|||
|
|||
/** |
|||
* Pass custom options to fetch API (remote storage) |
|||
* You can pass a simple object: { someOption: 'someValue' } |
|||
* or a function which returns and object to add: |
|||
* @example |
|||
* fetchOptions: currentOpts => { |
|||
* return currentOpts.method === 'POST' ? { method: 'PATCH' } : {}; |
|||
* }, |
|||
*/ |
|||
fetchOptions?: string | ((opts: AnyObject) => object); |
|||
|
|||
/** |
|||
* The remote storage sends the project data as a body of the request. |
|||
* You can use this method to update the body before the store call in order to align |
|||
* with your API requirements. |
|||
* @default data => data |
|||
*/ |
|||
onStore?: (data: AnyObject, editor: Editor) => AnyObject; |
|||
|
|||
/** |
|||
* The remote storage loads the project data directly from the request response. |
|||
* You can use this method to properly extract the project data from the response. |
|||
* @default data => data |
|||
*/ |
|||
onLoad?: (data: AnyObject, editor: Editor) => AnyObject; |
|||
} |
|||
|
|||
export default class RemoteStorage implements IStorage<RemoteStorageConfig> { |
|||
async store(data: ProjectData, opts: RemoteStorageConfig = {}) { |
|||
await this.request(opts.urlStore!, this.__props(opts, data), opts); |
|||
} |
|||
|
|||
async load(opts: RemoteStorageConfig = {}) { |
|||
return await this.request(opts.urlLoad!, this.__props(opts), opts); |
|||
} |
|||
|
|||
request(url: string, props: RequestInit = {}, opts: RemoteStorageConfig = {}) { |
|||
return fetch(url, props) |
|||
.then((res: any) => { |
|||
const result = res.text(); |
|||
const isOk = ((res.status / 200) | 0) === 1; |
|||
return isOk ? result : result.then(Promise.reject); |
|||
}) |
|||
.then(text => { |
|||
const parsable = text && isString(text); |
|||
return opts.contentTypeJson && parsable ? JSON.parse(text) : text; |
|||
}); |
|||
} |
|||
|
|||
__props(opts: RemoteStorageConfig = {}, data?: ProjectData): RequestInit { |
|||
const typeJson = opts.contentTypeJson; |
|||
const headers = opts.headers || {}; |
|||
const fetchOpts = opts.fetchOptions || {}; |
|||
const reqHead = 'X-Requested-With'; |
|||
const typeHead = 'Content-Type'; |
|||
let body; |
|||
|
|||
if (isUndefined(headers[reqHead])) { |
|||
headers[reqHead] = 'XMLHttpRequest'; |
|||
} |
|||
|
|||
if (isUndefined(headers[typeHead]) && typeJson) { |
|||
headers[typeHead] = 'application/json; charset=utf-8'; |
|||
} |
|||
|
|||
if (data) { |
|||
if (typeJson) { |
|||
body = JSON.stringify(data); |
|||
} else { |
|||
body = new FormData(); |
|||
|
|||
for (let key in data) { |
|||
body.append(key, data[key]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
const result = { |
|||
method: body ? 'POST' : 'GET', |
|||
credentials: opts.credentials, |
|||
headers, |
|||
body, |
|||
}; |
|||
|
|||
return { |
|||
...result, |
|||
...(isFunction(fetchOpts) ? fetchOpts(result) : fetchOpts), |
|||
}; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue