drapcode-builder
Version:
Drapcode Builder Library
179 lines (155 loc) • 4.51 kB
JavaScript
import Backbone from "backbone";
import fetch from "utils/fetch";
import { isUndefined, isFunction } from "underscore";
export default Backbone.Model.extend({
fetch,
defaults: {
urlStore: "",
urlLoad: "",
params: {},
beforeSend() {},
onComplete() {},
contentTypeJson: false,
credentials: "include",
fetchOptions: ""
},
/**
* Triggered before the request is started
* @private
*/
onStart() {
const em = this.get("em");
const before = this.get("beforeSend");
before && before();
},
/**
* Triggered on request error
* @param {Object} err Error
* @param {Function} [clbErr] Error callback
* @private
*/
onError(err, clbErr) {
const btnSave = document.querySelector(".btn-save");
if (err) {
/*
** Add text-wraning class if there's any error on Save from canvas
*/
btnSave.classList.add("text-warning");
} else {
btnSave.classList.remove("text-warning");
}
if (clbErr) {
const em = this.get("em");
em && em.logError(err);
clbErr(err);
} else {
const em = this.get("em");
console.error(err);
em && em.logError(err);
em && em.trigger("storage:error", err);
}
},
/**
* Triggered on request response
* @param {string} text Response text
* @private
*/
onResponse(text, clb) {
const em = this.get("em");
const complete = this.get("onComplete");
const typeJson = this.get("contentTypeJson");
const parsable = text && typeof text === "string";
const res = typeJson && parsable ? JSON.parse(text) : text;
complete && complete(res);
clb && clb(res);
em && em.trigger("storage:response", res);
},
store(data, clb, clbErr) {
const body = {};
for (let key in data) {
body[key] = data[key];
}
let orgUrlStore = this.get("urlStore");
if (this.get("isDeleteContent")) {
/*
** Overriding StorageManager Store URL to Delete route
** to manage full Page Content Delete from Canvas
*/
orgUrlStore += "/delete";
}
this.request(orgUrlStore, { body }, clb, clbErr);
this.resetAttributes();
},
resetAttributes() {
/*
** Resetting StorageManager isDeleteContent attr to Default
** to manage Save/Delete Route of Canvas
*/
this.set("isDeleteContent", false); // Reset isDeleteContent to Default
},
load(keys, clb, clbErr) {
this.request(this.get("urlLoad"), { method: "get" }, clb, clbErr);
},
/**
* Execute remote request
* @param {string} url Url
* @param {Object} [opts={}] Options
* @param {Function} [clb=null] Callback
* @param {Function} [clbErr=null] Error callback
* @private
*/
request(url, opts = {}, clb = null, clbErr = null) {
const typeJson = this.get("contentTypeJson");
const headers = this.get("headers") || {};
const params = this.get("params");
const reqHead = "X-Requested-With";
const typeHead = "Content-Type";
const bodyObj = opts.body || {};
let fetchOptions;
let body;
for (let param in params) {
bodyObj[param] = params[param];
}
if (isUndefined(headers[reqHead])) {
headers[reqHead] = "XMLHttpRequest";
}
// With `fetch`, have to send FormData without any 'Content-Type'
// https://stackoverflow.com/questions/39280438/fetch-missing-boundary-in-multipart-form-data-post
if (isUndefined(headers[typeHead]) && typeJson) {
headers[typeHead] = "application/json; charset=utf-8";
}
if (typeJson) {
body = JSON.stringify(bodyObj);
} else {
body = new FormData();
for (let bodyKey in bodyObj) {
body.append(bodyKey, bodyObj[bodyKey]);
}
}
fetchOptions = {
method: opts.method || "post",
credentials: this.get("credentials"),
headers
};
// Body should only be included on POST method
if (fetchOptions.method === "post") {
fetchOptions.body = body;
}
const fetchOpts = this.get("fetchOptions") || {};
const addOpts = isFunction(fetchOpts)
? fetchOpts(fetchOptions)
: fetchOptions;
this.onStart();
this.fetch(url, {
...fetchOptions,
...(addOpts || {})
})
.then(res =>
((res.status / 200) | 0) == 1
? res.text()
: res.text().then(text => Promise.reject(text))
)
.then(text => this.onResponse(text, clb))
.catch(err => this.onError(err, clbErr));
}
});