aircox/assets/public/model.js

208 lines
5.1 KiB
JavaScript

function getCookie(name) {
if(document.cookie && document.cookie !== '') {
const cookie = document.cookie.split(';')
.find(c => c.trim().startsWith(name + '='))
return cookie ? decodeURIComponent(cookie.split('=')[1]) : null;
}
return null;
}
var csrfToken = null;
export function getCsrf() {
if(csrfToken === null)
csrfToken = getCookie('csrftoken')
return csrfToken;
}
// TODO: prevent duplicate simple fetch
export default class Model {
constructor(data, {url=null}={}) {
this.url = url;
this.commit(data);
}
/**
* Get instance id from its data
*/
static getId(data) {
return data.id;
}
/**
* Return fetch options
*/
static getOptions(options) {
return {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRFToken': getCsrf(),
},
...options,
}
}
/**
* Fetch item from server
*/
static fetch(url, options=null, args=null) {
options = this.getOptions(options)
return fetch(url, options)
.then(response => response.json())
.then(data => new this(data, {url: url, ...args}));
}
/**
* Fetch data from server.
*/
fetch(options) {
options = this.constructor.getOptions(options)
return fetch(this.url, options)
.then(response => response.json())
.then(data => this.commit(data));
}
/**
* Call API action on object.
*/
action(path, options, commit=false) {
options = this.constructor.getOptions(options)
const promise = fetch(this.url + path, options);
return commit ? promise.then(data => data.json())
.then(data => { this.commit(data); this.data })
: promise;
}
/**
* Update instance's data with provided data. Return None
*/
commit(data) {
this.id = this.constructor.getId(data);
this.data = data;
}
/**
* Save instance into localStorage.
*/
store(key) {
window.localStorage.setItem(key, JSON.stringify(this.data));
}
/**
* Load model instance from localStorage.
*/
static storeLoad(key) {
let item = window.localStorage.getItem(key);
return item === null ? item : new this(JSON.parse(item));
}
}
/**
* List of models
*/
export class Set {
constructor(model, {items=[],url=null,args={},unique=null,max=null,storeKey=null}={}) {
this.items = [];
this.model = model;
this.url = url;
this.unique = unique;
this.max = max;
this.storeKey = storeKey;
for(var item of items)
this.push(item, {args: args, save: false});
}
get length() { return this.items.length }
/**
* Fetch multiple items from server
*/
static fetch(model, url, options=null, args=null) {
options = this.getOptions(options)
return fetch(url, options)
.then(response => response.json())
.then(data => (data instanceof Array ? data : data.results)
.map(d => new model(d, {url: url, ...args})))
}
/**
* Load list from localStorage
*/
static storeLoad(model, key, args={}) {
let items = window.localStorage.getItem(key);
return new this(model, {...args, storeKey: key, items: items ? JSON.parse(items) : []});
}
/**
* Store list into localStorage
*/
store() {
this.storeKey && window.localStorage.setItem(this.storeKey, JSON.stringify(
this.items.map(i => i.data)));
}
/**
* Save item
*/
save() {
this.storeKey && this.store();
}
/**
* Get item at index
*/
get(index) { return this.items[index] }
/**
* Find an item by id or using a predicate function
*/
find(pred) {
return pred instanceof Function ? this.items.find(pred)
: this.items.find(x => x.id == pred.id);
}
/**
* Find item index by id or using a predicate function
*/
findIndex(pred) {
return pred instanceof Function ? this.items.findIndex(pred)
: this.items.findIndex(x => x.id == pred.id);
}
/**
* Add item to set, return index.
*/
push(item, {args={},save=true}={}) {
item = item instanceof this.model ? item : new this.model(item, args);
if(this.unique) {
let index = this.findIndex(item);
if(index > -1)
return index;
}
if(this.max && this.items.length >= this.max)
this.items.splice(0,this.items.length-this.max)
this.items.push(item);
save && this.save();
return this.items.length-1;
}
/**
* Remove item from set by index
*/
remove(index, {save=true}={}) {
this.items.splice(index,1);
save && this.save();
}
}
Set[Symbol.iterator] = function () {
return this.items[Symbol.iterator]();
}