180 lines
4.6 KiB
JavaScript
180 lines
4.6 KiB
JavaScript
import Vue from 'vue';
|
|
|
|
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);
|
|
Vue.set(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 = items.map(x => x instanceof model ? x : new model(x, args));
|
|
this.model = model;
|
|
this.url = url;
|
|
this.unique = unique;
|
|
this.max = max;
|
|
this.storeKey = storeKey;
|
|
}
|
|
|
|
get length() { return this.items.length }
|
|
indexOf(...args) { return this.items.indexOf(...args); }
|
|
|
|
/**
|
|
* Fetch multiple items from server
|
|
*/
|
|
static fetch(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 this.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() {
|
|
if(this.storeKey)
|
|
window.localStorage.setItem(this.storeKey, JSON.stringify(
|
|
this.items.map(i => i.data)));
|
|
}
|
|
|
|
push(item, {args={}}={}) {
|
|
item = item instanceof this.model ? item : new this.model(item, args);
|
|
if(this.unique && this.items.find(x => x.id == item.id))
|
|
return;
|
|
if(this.max && this.items.length >= this.max)
|
|
this.items.splice(0,this.items.length-this.max)
|
|
|
|
this.items.push(item);
|
|
this._updated()
|
|
}
|
|
|
|
remove(item, {args={}}={}) {
|
|
item = item instanceof this.model ? item : new this.model(item, args);
|
|
let index = this.items.findIndex(x => x.id == item.id);
|
|
if(index == -1)
|
|
return;
|
|
|
|
this.items.splice(index,1);
|
|
this._updated()
|
|
}
|
|
|
|
_updated() {
|
|
Vue.set(this, 'items', this.items);
|
|
this.store();
|
|
}
|
|
}
|
|
|
|
Set[Symbol.iterator] = function () {
|
|
return this.items[Symbol.iterator]();
|
|
}
|
|
|