Bye bye spot.js
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
export default class Api {
|
||||
|
||||
constructor({server, processPage, timezone, errorCode, lang}) {
|
||||
this.server = server;
|
||||
this.processPage = processPage;
|
||||
this.timezone = timezone;
|
||||
this.errorCode = errorCode;
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
async get(action, params = {}) {
|
||||
const requestParams = {
|
||||
...params,
|
||||
a: action,
|
||||
t: this.timezone
|
||||
};
|
||||
|
||||
const url = new URL(this.processPage, this.server);
|
||||
url.search = new URLSearchParams(requestParams).toString();
|
||||
|
||||
const request = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {'Content-Type': 'application/json'}
|
||||
});
|
||||
|
||||
if(!request.ok) {
|
||||
throw new Error('Error HTTP ' + request.status + ': ' + request.statusText);
|
||||
}
|
||||
|
||||
const response = await request.json();
|
||||
response.desc = this.lang.parse(response.desc);
|
||||
|
||||
if(response.result == this.errorCode) {
|
||||
throw response.desc;
|
||||
}
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
+22
-7
@@ -1,8 +1,12 @@
|
||||
//Librairies
|
||||
import Api from './api.js';
|
||||
import Lang from './lang.js';
|
||||
import Spot from './spot.js';
|
||||
import Projects from './projects.js';
|
||||
import User from './user.js';
|
||||
import { createApp } from 'vue';
|
||||
import SpotVue from '../Spot.vue';
|
||||
|
||||
//Main template
|
||||
import Spot from '../Spot.vue';
|
||||
|
||||
//Style
|
||||
import Css from './../styles/spot.scss';
|
||||
@@ -11,11 +15,22 @@ import Css from './../styles/spot.scss';
|
||||
const appConfig = JSON.parse(document.getElementById('app-config').textContent);
|
||||
|
||||
//Instances
|
||||
const oProjects = new Projects(appConfig.projects);
|
||||
const oUser = new User(appConfig.user, appConfig.consts.default_timezone);
|
||||
const oLang = new Lang({translations: appConfig.consts.lang, prefix: appConfig.consts.lang_prefix});
|
||||
const oSpot = new Spot(appConfig, oLang);
|
||||
const oApi = new Api({
|
||||
server: appConfig.consts.server,
|
||||
processPage: appConfig.consts.process_page,
|
||||
timezone: oUser.timezone,
|
||||
errorCode: appConfig.consts.error,
|
||||
lang: oLang
|
||||
});
|
||||
|
||||
//Mount app
|
||||
const oSpotVue = createApp(SpotVue);
|
||||
oSpotVue.provide('spot', oSpot);
|
||||
oSpotVue.provide('lang', oLang);
|
||||
oSpotVue.mount('#container');
|
||||
const oSpot = createApp(Spot);
|
||||
oSpot.provide('appConfig', appConfig);
|
||||
oSpot.provide('api', oApi);
|
||||
oSpot.provide('lang', oLang);
|
||||
oSpot.provide('projects', oProjects);
|
||||
oSpot.provide('user', oUser);
|
||||
oSpot.mount('#container');
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
export default class Projects {
|
||||
|
||||
constructor(asProjects = {}) {
|
||||
Object.assign(this, asProjects);
|
||||
}
|
||||
|
||||
getDefaultCodeName() {
|
||||
for(const [sCodeName, asProject] of Object.entries(this)) {
|
||||
if(asProject.default) return sCodeName;
|
||||
}
|
||||
}
|
||||
|
||||
getDefaultProject() {
|
||||
const sCodeName = this.getDefaultCodeName();
|
||||
return this[this.getDefaultCodeName()];
|
||||
}
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
import { copyArray, getElem, setElem } from './common.js';
|
||||
|
||||
export default class Spot {
|
||||
|
||||
constructor(asGlobals, oLang) {
|
||||
this.consts = asGlobals.consts;
|
||||
this.consts.hash_sep = '-';
|
||||
this.consts.title = 'Spotty';
|
||||
this.consts.default_page = 'project';
|
||||
//this.consts.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || this.consts.default_timezone;
|
||||
this.lang = oLang;
|
||||
|
||||
this.pages = {};
|
||||
|
||||
//Variables & constants from php
|
||||
this.vars('tmp', 'object');
|
||||
this.vars('page', 'string');
|
||||
Object.entries(asGlobals.vars).forEach(([sKey, oValue]) => {this.vars(sKey, oValue);});
|
||||
|
||||
//page elem
|
||||
this.elem = {};
|
||||
}
|
||||
|
||||
/* Initialization */
|
||||
|
||||
/*
|
||||
init() {
|
||||
this.elem.container = $('#container');
|
||||
this.elem.main = $('#main');
|
||||
|
||||
//On Key down
|
||||
$('html').on('keydown', (oEvent) => {this.onKeydown(oEvent);});
|
||||
|
||||
//on window resize
|
||||
$(window).on('resize', () => {this.onResize();});
|
||||
|
||||
//Hash management
|
||||
$(window)
|
||||
.on('hashchange', () => {this.onHashChange();})
|
||||
.trigger('hashchange');
|
||||
}
|
||||
*/
|
||||
|
||||
/* Variable Management */
|
||||
|
||||
vars(oVarName, oValue) {
|
||||
var asVarName = (typeof oVarName == 'object')?oVarName:[oVarName];
|
||||
|
||||
//Set, name & type / default value (init)
|
||||
if(typeof oValue !== 'undefined') setElem(this.vars, copyArray(asVarName), oValue);
|
||||
|
||||
//Get, only name parameter
|
||||
return getElem(this.vars, asVarName);
|
||||
}
|
||||
|
||||
tmp(sVarName, oValue) {
|
||||
var asVarName = (typeof sVarName == 'object')?sVarName:[sVarName];
|
||||
asVarName.unshift('tmp');
|
||||
return this.vars(asVarName, oValue);
|
||||
}
|
||||
|
||||
/* Interface with server */
|
||||
|
||||
/*
|
||||
get(sAction, fOnSuccess, oVars, fOnError, fonProgress) {
|
||||
oVars = oVars || {};
|
||||
fOnError = fOnError || function(sError) {console.log(sError);};
|
||||
fonProgress = fonProgress || function(sState){};
|
||||
fonProgress('start');
|
||||
|
||||
oVars['a'] = sAction;
|
||||
oVars['t'] = this.consts.timezone;
|
||||
return $.ajax(
|
||||
{
|
||||
url: this.consts.process_page,
|
||||
data: oVars,
|
||||
dataType: 'json'
|
||||
})
|
||||
.done((oData) => {
|
||||
fonProgress('done');
|
||||
if(oData.desc.substr(0, this.consts.lang_prefix.length)==this.consts.lang_prefix) oData.desc = this.lang(oData.desc.substr(5));
|
||||
|
||||
if(oData.result==this.consts.error) fOnError(oData.desc);
|
||||
else if(fOnSuccess) fOnSuccess(oData.data, oData.desc);
|
||||
})
|
||||
.fail((jqXHR, textStatus, errorThrown) => {
|
||||
fonProgress('fail');
|
||||
fOnError(textStatus+' '+errorThrown);
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
async get2(sAction, oVars, bLoading) {
|
||||
oVars = oVars || {};
|
||||
oVars['a'] = sAction;
|
||||
oVars['t'] = this.consts.timezone;
|
||||
bLoading = true;
|
||||
|
||||
try {
|
||||
let oUrl = new URL(this.consts.process_page, this.consts.server);
|
||||
oUrl.search = new URLSearchParams(oVars).toString();
|
||||
const oRequest = await fetch(oUrl, {method: 'GET', /*body: JSON.stringify(oVars),*/ headers: {"Content-Type": "application/json"}});
|
||||
if(!oRequest.ok) {
|
||||
bLoading = false;
|
||||
throw new Error('Error HTTP '+oRequest.status+': '+oRequest.statusText);
|
||||
}
|
||||
else {
|
||||
let oResponse = await oRequest.json();
|
||||
bLoading = false;
|
||||
oResponse.desc = this.lang.parse(oResponse.desc);
|
||||
|
||||
if(oResponse.result == this.consts.error) return Promise.reject(oResponse.desc);
|
||||
else return oResponse.data;
|
||||
}
|
||||
}
|
||||
catch(oError) {
|
||||
bLoading = false;
|
||||
throw oError;
|
||||
}
|
||||
}
|
||||
|
||||
isMobile() {
|
||||
const mobileElem = document.getElementById('mobile');
|
||||
return !!mobileElem && getComputedStyle(mobileElem).display !== 'none';
|
||||
}
|
||||
|
||||
/* Page Switch - Trigger & Event catching */
|
||||
|
||||
/*
|
||||
onHashChange() {
|
||||
var asHash = this.getHash();
|
||||
if(asHash.hash !='' && asHash.page != '') this.switchPage(asHash); //page switching
|
||||
else if(this.vars('page')=='') this.setHash(this.consts.default_page); //first page
|
||||
}
|
||||
|
||||
getHash() {
|
||||
var sHash = this.hash();
|
||||
var asHash = sHash.split(this.consts.hash_sep);
|
||||
var sPage = asHash.shift() || '';
|
||||
return {hash:sHash, page:sPage, items:asHash};
|
||||
}
|
||||
|
||||
setHash(sPage, asItems, bReboot) {
|
||||
bReboot = bReboot || false;
|
||||
sPage = sPage || '';
|
||||
asItems = asItems || [];
|
||||
if(typeof asItems == 'string') asItems = [asItems];
|
||||
|
||||
if(sPage != '') {
|
||||
var sItems = (asItems.length > 0)?this.consts.hash_sep+asItems.join(this.consts.hash_sep):'';
|
||||
this.hash(sPage+sItems, bReboot);
|
||||
}
|
||||
}
|
||||
|
||||
hash(hash, bReboot) {
|
||||
bReboot = bReboot || false;
|
||||
if(!hash) return window.location.hash.slice(1);
|
||||
else window.location.hash = '#'+hash;
|
||||
|
||||
if(bReboot) location.reload();
|
||||
}
|
||||
|
||||
updateHash(sType, iId) {
|
||||
sType = sType || '';
|
||||
iId = iId || 0;
|
||||
|
||||
var asHash = this.getHash();
|
||||
if(iId) this.setHash(asHash.page, [asHash.items[0], sType, iId]);
|
||||
}
|
||||
|
||||
flushHash(asTypes) {
|
||||
asTypes = asTypes || [];
|
||||
var asHash = this.getHash();
|
||||
if(asHash.items.length > 1 && (asTypes.length == 0 || asTypes.indexOf(asHash.items[1]) != -1)) this.setHash(asHash.page, [asHash.items[0]]);
|
||||
}
|
||||
*/
|
||||
|
||||
/* Page Events */
|
||||
|
||||
pageInit(asHash) {
|
||||
let sPage = this.vars('page');
|
||||
if(this.pages[sPage].pageInit) this.pages[sPage].pageInit(asHash);
|
||||
else console.log('no init for the page: '+asHash.page);
|
||||
}
|
||||
|
||||
onSamePageMove(asNewHash, asOldHash) {
|
||||
let sPage = this.vars('page');
|
||||
return (this.pages[sPage] && this.pages[sPage].onSamePageMove)?this.pages[sPage].onSamePageMove(asNewHash, asOldHash):false;
|
||||
}
|
||||
|
||||
onQuitPage() {
|
||||
let sPage = this.vars('page');
|
||||
return (this.pages[sPage] && this.pages[sPage].onQuitPage)?this.pages[sPage].onQuitPage():true;
|
||||
}
|
||||
|
||||
onResize() {
|
||||
let sPage = this.vars('page');
|
||||
if(this.pages[sPage].onResize) this.pages[sPage].onResize();
|
||||
}
|
||||
|
||||
onFeedback(sType, sMsg, asContext) {
|
||||
asContext = asContext || {};
|
||||
let sPage = this.vars('page');
|
||||
if(this.pages[sPage].onFeedback) this.pages[sPage].onFeedback(sType, sMsg, asContext);
|
||||
else console.log({type:sType, msg:sMsg, context:asContext});
|
||||
}
|
||||
|
||||
onKeydown(oEvent) {
|
||||
let sPage = this.vars('page');
|
||||
if(this.pages[sPage].onKeydown) this.pages[sPage].onKeydown(oEvent);
|
||||
}
|
||||
|
||||
/* Page Switch - DOM Replacement */
|
||||
|
||||
/*
|
||||
getActionLink(sAction, oVars) {
|
||||
if(!oVars) oVars = {};
|
||||
let sVars = '';
|
||||
|
||||
for(i in oVars) sVars += '&'+i+'='+oVars[i];
|
||||
|
||||
return this.consts.process_page+'?a='+sAction+sVars;
|
||||
}
|
||||
*/
|
||||
|
||||
addPage(sPage, oPage) {
|
||||
this.pages[sPage] = oPage;
|
||||
}
|
||||
|
||||
/*
|
||||
switchPage(asHash) {
|
||||
var sPageName = asHash.page;
|
||||
var bSamePage = (this.vars('page') == sPageName);
|
||||
var bFirstPage = (this.vars('page') == '');
|
||||
|
||||
if(!this.consts.pages[sPageName]) { //Page does not exist
|
||||
if(bFirstPage) this.setHash(this.consts.default_page);
|
||||
else this.setHash(this.vars('page'), this.vars(['hash', 'items']));
|
||||
}
|
||||
else if(this.onQuitPage(bSamePage) && !bSamePage || this.onSamePageMove(asHash))
|
||||
{
|
||||
//Delete tmp variables
|
||||
this.vars('tmp', {});
|
||||
|
||||
//Officially a new page
|
||||
this.vars('page', sPageName);
|
||||
this.vars('hash', asHash);
|
||||
|
||||
//Update Page Title
|
||||
this.setPageTitle(sPageName+' '+(asHash.items[0] || ''));
|
||||
|
||||
//Replacing DOM
|
||||
var $Dom = $(this.consts.pages[sPageName]);
|
||||
if(bFirstPage) this.splash($Dom, asHash, bFirstPage); //first page
|
||||
else this.elem.main.stop().fadeTo('fast', 0, () => {this.splash($Dom, asHash, bFirstPage);}); //Switching page
|
||||
}
|
||||
else if(bSamePage) this.vars('hash', asHash);
|
||||
}
|
||||
|
||||
splash($Dom, asHash, bFirstPage)
|
||||
{
|
||||
//Switch main content
|
||||
this.elem.main.empty().html($Dom);
|
||||
|
||||
//Page Bootstrap
|
||||
this.pageInit(asHash, bFirstPage);
|
||||
|
||||
//Show main
|
||||
var $FadeInElem = bFirstPage?this.elem.container:this.elem.main;
|
||||
$FadeInElem.hide().fadeTo('slow', 1);
|
||||
}
|
||||
*/
|
||||
|
||||
setPageTitle(sTitle) {
|
||||
document.title = this.consts.title+' - '+sTitle;
|
||||
}
|
||||
|
||||
getNaturalDuration(iHours) {
|
||||
var iTimeMinutes = 0, iTimeHours = 0, iTimeDays = Math.floor(iHours/8); //8 hours a day
|
||||
if(iTimeDays > 1) iTimeDays = Math.round(iTimeDays * 2) / 2; //Round down to the closest half day
|
||||
else {
|
||||
iTimeDays = 0;
|
||||
iTimeHours = Math.floor(iHours);
|
||||
iHours -= iTimeHours;
|
||||
|
||||
iTimeMinutes = Math.floor(iHours * 4) * 15; //Round down to the closest 15 minutes
|
||||
}
|
||||
return '~ '
|
||||
+(iTimeDays>0?(iTimeDays+(iTimeDays%2==0?'':'½')+' '+this.lang.get(iTimeDays>1?'unit_days':'unit_day')):'') //Days
|
||||
+((iTimeHours>0 || iTimeDays==0)?iTimeHours+this.lang.get('unit_hour'):'') //Hours
|
||||
+((iTimeDays>0 || iTimeMinutes==0)?'':iTimeMinutes) //Minutes
|
||||
|
||||
}
|
||||
|
||||
checkClearance(sClearance) {
|
||||
return (this.vars(['user', 'clearance']) >= sClearance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export default class User {
|
||||
|
||||
constructor(asUserInfo = {}, sDefaultTimeZone = '') {
|
||||
Object.assign(this, asUserInfo);
|
||||
this.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || this.timezone || sDefaultTimeZone;
|
||||
}
|
||||
|
||||
hasClearance(sClearance) {
|
||||
return this.clearance >= sClearance;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user