Compare commits
2 Commits
d767e335f9
...
7853c6e285
| Author | SHA1 | Date | |
|---|---|---|---|
| 7853c6e285 | |||
| f674b0d934 |
@@ -4,6 +4,7 @@ var webpack = require("webpack");
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const SymlinkWebpackPlugin = require('symlink-webpack-plugin');
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
@@ -16,29 +17,28 @@ module.exports = {
|
||||
},
|
||||
devtool: "inline-source-map",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
rules: [{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader'
|
||||
}, {
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
exclude: file => (/node_modules/.test(file) && !/\.vue\.js/.test(file)),
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env'],
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
}, {
|
||||
test: /\.html$/i,
|
||||
loader: "html-loader",
|
||||
},
|
||||
{
|
||||
}, {
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
type: 'asset/resource'
|
||||
},
|
||||
{
|
||||
}, {
|
||||
test: /\.s[ac]ss$/i,
|
||||
use: [
|
||||
'style-loader',
|
||||
'vue-style-loader',
|
||||
'css-loader',
|
||||
'resolve-url-loader',
|
||||
{
|
||||
@@ -49,12 +49,10 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
}, {
|
||||
test: /\.css$/i,
|
||||
use: ["style-loader", "css-loader"],
|
||||
},
|
||||
{
|
||||
use: ["vue-style-loader", "css-loader"],
|
||||
}, {
|
||||
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||
use: {
|
||||
loader: "url-loader",
|
||||
@@ -92,7 +90,12 @@ module.exports = {
|
||||
}]
|
||||
}),
|
||||
new SymlinkWebpackPlugin({ origin: '../files/', symlink: 'files' }),
|
||||
new CleanWebpackPlugin()
|
||||
new CleanWebpackPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
__VUE_OPTIONS_API__: 'true',
|
||||
__VUE_PROD_DEVTOOLS__: 'false'
|
||||
}),
|
||||
new VueLoaderPlugin()
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['', '.js'],
|
||||
|
||||
@@ -11,6 +11,9 @@ admin_config = Config
|
||||
admin_upload = Upload
|
||||
save = Save
|
||||
admin_save_success = Saved
|
||||
admin_create_success= Created
|
||||
admin_delete_success= Deleted
|
||||
no_auth = No authorization
|
||||
|
||||
track_main = Main track
|
||||
track_off-track = Off-track
|
||||
@@ -64,7 +67,7 @@ id_project = Project ID
|
||||
project = Project
|
||||
projects = Projects
|
||||
new_project = New Project
|
||||
update_project = Update Project
|
||||
update_project = Update project messages
|
||||
hikes = Hikes
|
||||
mode = Mode
|
||||
mode_previz = Project in preparation
|
||||
@@ -76,6 +79,7 @@ end = End
|
||||
feeds = Feeds
|
||||
id_feed = Feed ID
|
||||
ref_feed_id = Ref. Feed ID
|
||||
new_feed = New feed
|
||||
id_spot = Spot ID
|
||||
name = Name
|
||||
status = Status
|
||||
|
||||
@@ -11,6 +11,9 @@ admin_config = Configuración
|
||||
admin_upload = Cargar
|
||||
save = Guardar
|
||||
admin_save_success = Guardado
|
||||
admin_create_success= Creado
|
||||
admin_delete_success= Eliminado
|
||||
no_auth = No autorización
|
||||
|
||||
track_main = Camino principal
|
||||
track_off-track = Variante
|
||||
@@ -64,7 +67,7 @@ id_project = Proyecto ID
|
||||
project = Proyecto
|
||||
projects = Proyectos
|
||||
new_project = Nuevo proyecto
|
||||
update_project = Actualizar el proyecto
|
||||
update_project = Actualizar los mensajes del proyecto
|
||||
hikes = Senderos
|
||||
mode = Modo
|
||||
mode_previz = Proyecto en preparación
|
||||
@@ -76,6 +79,7 @@ end = Fin
|
||||
feeds = Feeds
|
||||
id_feed = ID Feed
|
||||
ref_feed_id = ID Feed ref.
|
||||
new_feed = Nuevo feed
|
||||
id_spot = ID Spot
|
||||
name = Descripción
|
||||
status = Estado
|
||||
|
||||
@@ -11,6 +11,9 @@ admin_config = Paramètres
|
||||
admin_upload = Uploader
|
||||
save = Sauvegarder
|
||||
admin_save_success = Sauvegardé
|
||||
admin_create_success= Créé
|
||||
admin_delete_success= Supprimé
|
||||
no_auth = Pas d'authorisation
|
||||
|
||||
track_main = Trajet principal
|
||||
track_off-track = Variante
|
||||
@@ -64,7 +67,7 @@ id_project = ID projet
|
||||
project = Projet
|
||||
projects = Projets
|
||||
new_project = Nouveau projet
|
||||
update_project = Mettre à jour le projet
|
||||
update_project = Mettre à jour les messages du projet
|
||||
hikes = Randonnées
|
||||
mode = Mode
|
||||
mode_previz = Projet en cours de préparation
|
||||
@@ -76,6 +79,7 @@ end = Arrivée
|
||||
feeds = Feeds
|
||||
id_feed = ID Feed
|
||||
ref_feed_id = ID Feed ref.
|
||||
new_feed = Nouveau feed
|
||||
id_spot = ID Spot
|
||||
name = Description
|
||||
status = Statut
|
||||
|
||||
58
lib/Spot.php
58
lib/Spot.php
@@ -709,40 +709,66 @@ class Spot extends Main
|
||||
return self::getJsonResult($bSuccess, $sDesc, array($sType=>array($asResult)));
|
||||
}
|
||||
|
||||
public function delAdminSettings($sType, $iId) {
|
||||
public function createAdminSettings($sType) {
|
||||
$bSuccess = false;
|
||||
$sDesc = '';
|
||||
$asResult = array();
|
||||
|
||||
switch($sType) {
|
||||
case 'project':
|
||||
$oProject = new Project($this->oDb);
|
||||
$iNewProjectId = $oProject->createProjectId();
|
||||
|
||||
$oFeed = new Feed($this->oDb);
|
||||
$oFeed->createFeedId($iNewProjectId);
|
||||
|
||||
$bSuccess = $iNewProjectId > 0;
|
||||
$asResult = array(
|
||||
'project' => array($oProject->getProject()),
|
||||
'feed' => array($oFeed->getFeed())
|
||||
);
|
||||
break;
|
||||
case 'feed':
|
||||
$oFeed = new Feed($this->oDb);
|
||||
$iNewFeedId = $oFeed->createFeedId($this->oProject->getProjectId());
|
||||
$bSuccess = $iNewFeedId > 0;
|
||||
$asResult = array(
|
||||
'feed' => array($oFeed->getFeed())
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return self::getJsonResult($bSuccess, $sDesc, $asResult);
|
||||
}
|
||||
|
||||
public function deleteAdminSettings($sType, $iId) {
|
||||
$bSuccess = false;
|
||||
$sDesc = '';
|
||||
$asResult = array();
|
||||
|
||||
switch($sType) {
|
||||
case 'project':
|
||||
$oProject = new Project($this->oDb, $iId);
|
||||
$asResult = $oProject->delete();
|
||||
$sDesc = $asResult['project'][0]['desc'];
|
||||
$bSuccess = $asResult['project'][0]['del'];
|
||||
break;
|
||||
case 'feed':
|
||||
$oFeed = new Feed($this->oDb, $iId);
|
||||
$asResult = array('feed'=>array($oFeed->delete()));
|
||||
$asResult = array('feed' => array($oFeed->delete()));
|
||||
$sDesc = $asResult['feed'][0]['desc'];
|
||||
$bSuccess = $asResult['feed'][0]['del'];
|
||||
break;
|
||||
case 'user':
|
||||
$asResult = array('user' => array($this->oUser->removeUser($iId)));
|
||||
$sDesc = $asResult['user'][0]['desc'];
|
||||
$bSuccess = $asResult['user'][0]['result'];
|
||||
break;
|
||||
}
|
||||
$bSuccess = ($sDesc=='');
|
||||
|
||||
return self::getJsonResult($bSuccess, $sDesc, $asResult);
|
||||
}
|
||||
|
||||
public function createProject() {
|
||||
$oProject = new Project($this->oDb);
|
||||
$iNewProjectId = $oProject->createProjectId();
|
||||
|
||||
$oFeed = new Feed($this->oDb);
|
||||
$oFeed->createFeedId($iNewProjectId);
|
||||
|
||||
return self::getJsonResult($iNewProjectId>0, '', array(
|
||||
'project' => array($oProject->getProject()),
|
||||
'feed' => array($oFeed->getFeed())
|
||||
));
|
||||
}
|
||||
|
||||
public static function decToDms($dValue, $sType) {
|
||||
if($sType=='lat') $sDirection = ($dValue >= 0)?'N':'S'; //Latitude
|
||||
else $sDirection = ($dValue >= 0)?'E':'W'; //Longitude
|
||||
|
||||
114
lib/User.php
114
lib/User.php
@@ -20,6 +20,7 @@ class User extends PhpObject {
|
||||
//Cookie
|
||||
const COOKIE_ID_USER = 'subscriber';
|
||||
const COOKIE_DURATION = 60 * 60 * 24 * 365; //1 year
|
||||
|
||||
/**
|
||||
* Database Handle
|
||||
* @var Db
|
||||
@@ -33,7 +34,7 @@ class User extends PhpObject {
|
||||
public function __construct(Db &$oDb) {
|
||||
parent::__construct(__CLASS__);
|
||||
$this->oDb = &$oDb;
|
||||
$this->iUserId = 0;
|
||||
$this->setUserId(0);
|
||||
$this->asUserInfo = array(
|
||||
'id' => 0,
|
||||
Db::getId(self::USER_TABLE) => 0,
|
||||
@@ -47,6 +48,51 @@ class User extends PhpObject {
|
||||
$this->checkUserCookie();
|
||||
}
|
||||
|
||||
public function getUserId() {
|
||||
return $this->iUserId;
|
||||
}
|
||||
|
||||
public function setUserId($iUserId) {
|
||||
$this->iUserId = 0;
|
||||
|
||||
if($iUserId > 0) {
|
||||
$asUser = $this->getActiveUserInfo($iUserId);
|
||||
if(!empty($asUser)) {
|
||||
$this->iUserId = $iUserId;
|
||||
$this->asUserInfo = $asUser;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getUserInfo() {
|
||||
return $this->asUserInfo;
|
||||
}
|
||||
|
||||
public function getActiveUserInfo($iUserId) {
|
||||
$asUsersInfo = array();
|
||||
if($iUserId > 0) $asUsersInfo = $this->getActiveUsersInfo($iUserId);
|
||||
return empty($asUsersInfo)?array():array_shift($asUsersInfo);
|
||||
}
|
||||
|
||||
public function getActiveUsersInfo($iUserId=-1) {
|
||||
|
||||
//Mapping between user fields and DB fields
|
||||
$asSelect = array_keys($this->asUserInfo);
|
||||
$asSelect[array_search('id', $asSelect)] = Db::getId(self::USER_TABLE)." AS id";
|
||||
|
||||
//Non-admin cannot access clearance info
|
||||
if(!$this->checkUserClearance(self::CLEARANCE_ADMIN)) unset($asSelect['clearance']);
|
||||
|
||||
$asInfo = array(
|
||||
'select' => $asSelect,
|
||||
'from' => self::USER_TABLE,
|
||||
'constraint'=> array('active'=>self::USER_ACTIVE)
|
||||
);
|
||||
if($iUserId != -1) $asInfo['constraint'][Db::getId(self::USER_TABLE)] = $iUserId;
|
||||
|
||||
return $this->oDb->selectRows($asInfo);
|
||||
}
|
||||
|
||||
public function getLang() {
|
||||
return $this->asUserInfo['language'];
|
||||
}
|
||||
@@ -95,20 +141,25 @@ class User extends PhpObject {
|
||||
return Spot::getResult($bSuccess, $sDesc);
|
||||
}
|
||||
|
||||
public function removeUser() {
|
||||
public function removeUser($iUserId=0) {
|
||||
$iUserId = ($iUserId > 0)?$iUserId:$this->getUserId();
|
||||
$bSelf = ($iUserId == $this->getUserId());
|
||||
$bSuccess = false;
|
||||
$sDesc = '';
|
||||
|
||||
if($this->iUserId > 0) {
|
||||
$iUserId = $this->oDb->updateRow(self::USER_TABLE, $this->getUserId(), array('active'=>self::USER_INACTIVE));
|
||||
if($iUserId==0) $sDesc = 'lang:error_commit_db';
|
||||
else {
|
||||
$sDesc = 'lang:nl_unsubscribed';
|
||||
$this->updateCookie(-60 * 60); //Set Cookie in the past, deleting it
|
||||
$bSuccess = true;
|
||||
if($bSelf || $this->checkUserClearance(self::CLEARANCE_ADMIN)) {
|
||||
if($this->getUserId() > 0) {
|
||||
$iUserId = $this->oDb->updateRow(self::USER_TABLE, $iUserId, array('active' => self::USER_INACTIVE));
|
||||
if($iUserId==0) $sDesc = 'lang:error_commit_db';
|
||||
else {
|
||||
$sDesc = 'lang:nl_unsubscribed';
|
||||
if($bSelf) $this->updateCookie(-60 * 60); //Set Cookie in the past, deleting it
|
||||
$bSuccess = true;
|
||||
}
|
||||
}
|
||||
else $sDesc = 'lang:nl_unknown_email';
|
||||
}
|
||||
else $sDesc = 'lang:nl_unknown_email';
|
||||
else $sDesc = 'lang:no_auth';
|
||||
|
||||
return Spot::getResult($bSuccess, $sDesc);
|
||||
}
|
||||
@@ -131,49 +182,6 @@ class User extends PhpObject {
|
||||
}
|
||||
}
|
||||
|
||||
public function getUserId() {
|
||||
return $this->iUserId;
|
||||
}
|
||||
|
||||
public function setUserId($iUserId) {
|
||||
$this->iUserId = 0;
|
||||
|
||||
$asUser = $this->getActiveUserInfo($iUserId);
|
||||
if(!empty($asUser)) {
|
||||
$this->iUserId = $iUserId;
|
||||
$this->asUserInfo = $asUser;
|
||||
}
|
||||
}
|
||||
|
||||
public function getUserInfo() {
|
||||
return $this->asUserInfo;
|
||||
}
|
||||
|
||||
public function getActiveUserInfo($iUserId) {
|
||||
$asUsersInfo = array();
|
||||
if($iUserId > 0) $asUsersInfo = $this->getActiveUsersInfo($iUserId);
|
||||
return empty($asUsersInfo)?array():array_shift($asUsersInfo);
|
||||
}
|
||||
|
||||
public function getActiveUsersInfo($iUserId=-1) {
|
||||
|
||||
//Mapping between user fields and DB fields
|
||||
$asSelect = array_keys($this->asUserInfo);
|
||||
$asSelect[array_search('id', $asSelect)] = Db::getId(self::USER_TABLE)." AS id";
|
||||
|
||||
//Non-admin cannot access clearance info
|
||||
if(!$this->checkUserClearance(self::CLEARANCE_ADMIN)) unset($asSelect['clearance']);
|
||||
|
||||
$asInfo = array(
|
||||
'select' => $asSelect,
|
||||
'from' => self::USER_TABLE,
|
||||
'constraint'=> array('active'=>self::USER_ACTIVE)
|
||||
);
|
||||
if($iUserId != -1) $asInfo['constraint'][Db::getId(self::USER_TABLE)] = $iUserId;
|
||||
|
||||
return $this->oDb->selectRows($asInfo);
|
||||
}
|
||||
|
||||
public function checkUserClearance($iClearance)
|
||||
{
|
||||
return ($this->asUserInfo['clearance'] >= $iClearance);
|
||||
|
||||
@@ -71,17 +71,17 @@ if($sAction!='')
|
||||
case 'add_comment':
|
||||
$sResult = $oSpot->addComment($iId, $sContent);
|
||||
break;
|
||||
case 'admin_new':
|
||||
$sResult = $oSpot->createProject();
|
||||
break;
|
||||
case 'admin_get':
|
||||
$sResult = $oSpot->getAdminSettings();
|
||||
break;
|
||||
case 'admin_set':
|
||||
$sResult = $oSpot->setAdminSettings($sType, $iId, $sField, $oValue);
|
||||
break;
|
||||
case 'admin_del':
|
||||
$sResult = $oSpot->delAdminSettings($sType, $iId);
|
||||
case 'admin_create':
|
||||
$sResult = $oSpot->createAdminSettings($sType);
|
||||
break;
|
||||
case 'admin_delete':
|
||||
$sResult = $oSpot->deleteAdminSettings($sType, $iId);
|
||||
break;
|
||||
case 'generate_cron':
|
||||
$sResult = $oSpot->genCronFile();
|
||||
|
||||
338
package-lock.json
generated
338
package-lock.json
generated
@@ -28,14 +28,19 @@
|
||||
"sass-loader": "^13.3.2",
|
||||
"simplebar": "^6.2.5",
|
||||
"style-loader": "^3.3.3",
|
||||
"url-loader": "^4.1.1"
|
||||
"url-loader": "^4.1.1",
|
||||
"vue": "^3.3.8",
|
||||
"vue-style-loader": "^4.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
"@babel/preset-env": "^7.23.2",
|
||||
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
||||
"babel-loader": "^9.1.3",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"symlink-webpack-plugin": "^1.1.0",
|
||||
"vue-loader": "^17.3.1",
|
||||
"vue-template-compiler": "^2.7.15",
|
||||
"webpack": "^5.89.0",
|
||||
"webpack-cli": "^5.1.4"
|
||||
}
|
||||
@@ -457,7 +462,6 @@
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz",
|
||||
"integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -1863,6 +1867,126 @@
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue-leaflet/vue-leaflet": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@vue-leaflet/vue-leaflet/-/vue-leaflet-0.10.1.tgz",
|
||||
"integrity": "sha512-RNEDk8TbnwrJl8ujdbKgZRFygLCxd0aBcWLQ05q/pGv4+d0jamE3KXQgQBqGAteE1mbQsk3xoNcqqUgaIGfWVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"vue": "^3.2.25"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/leaflet": "^1.5.7",
|
||||
"leaflet": "^1.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/leaflet": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.8.tgz",
|
||||
"integrity": "sha512-hN/NNBUECw8SusQvDSqqcVv6gWq8L6iAktUR0UF3vGu2OhzRqcOiAno0FmBJWwxhYEXRlQJT5XnoKsVq1WZx4g==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@vue/shared": "3.3.8",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.8.tgz",
|
||||
"integrity": "sha512-+PPtv+p/nWDd0AvJu3w8HS0RIm/C6VGBIRe24b9hSyNWOAPEUosFZ5diwawwP8ip5sJ8n0Pe87TNNNHnvjs0FQ==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.3.8",
|
||||
"@vue/shared": "3.3.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.8.tgz",
|
||||
"integrity": "sha512-WMzbUrlTjfYF8joyT84HfwwXo+8WPALuPxhy+BZ6R4Aafls+jDBnSz8PDz60uFhuqFbl3HxRfxvDzrUf3THwpA==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@vue/compiler-core": "3.3.8",
|
||||
"@vue/compiler-dom": "3.3.8",
|
||||
"@vue/compiler-ssr": "3.3.8",
|
||||
"@vue/reactivity-transform": "3.3.8",
|
||||
"@vue/shared": "3.3.8",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.5",
|
||||
"postcss": "^8.4.31",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.8.tgz",
|
||||
"integrity": "sha512-hXCqQL/15kMVDBuoBYpUnSYT8doDNwsjvm3jTefnXr+ytn294ySnT8NlsFHmTgKNjwpuFy7XVV8yTeLtNl/P6w==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.3.8",
|
||||
"@vue/shared": "3.3.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.8.tgz",
|
||||
"integrity": "sha512-ctLWitmFBu6mtddPyOKpHg8+5ahouoTCRtmAHZAXmolDtuZXfjL2T3OJ6DL6ezBPQB1SmMnpzjiWjCiMYmpIuw==",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.3.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity-transform": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.8.tgz",
|
||||
"integrity": "sha512-49CvBzmZNtcHua0XJ7GdGifM8GOXoUMOX4dD40Y5DxI3R8OUhMlvf2nvgUAcPxaXiV5MQQ1Nwy09ADpnLQUqRw==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@vue/compiler-core": "3.3.8",
|
||||
"@vue/shared": "3.3.8",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.8.tgz",
|
||||
"integrity": "sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.3.8",
|
||||
"@vue/shared": "3.3.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.8.tgz",
|
||||
"integrity": "sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==",
|
||||
"dependencies": {
|
||||
"@vue/runtime-core": "3.3.8",
|
||||
"@vue/shared": "3.3.8",
|
||||
"csstype": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.8.tgz",
|
||||
"integrity": "sha512-zVCUw7RFskvPuNlPn/8xISbrf0zTWsTSdYTsUTN1ERGGZGVnRxM2QZ3x1OR32+vwkkCm0IW6HmJ49IsPm7ilLg==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.3.8",
|
||||
"@vue/shared": "3.3.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.3.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
|
||||
"integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
|
||||
@@ -2639,6 +2763,11 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
|
||||
},
|
||||
"node_modules/d3": {
|
||||
"version": "7.8.5",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz",
|
||||
@@ -3009,6 +3138,12 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/de-indent": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
|
||||
"integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
@@ -3203,6 +3338,11 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||
},
|
||||
"node_modules/esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
@@ -3516,6 +3656,12 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/hash-sum": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz",
|
||||
"integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
|
||||
@@ -3528,6 +3674,15 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/html-loader": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/html-loader/-/html-loader-4.2.0.tgz",
|
||||
@@ -4045,6 +4200,17 @@
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.5",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
|
||||
"integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
@@ -4100,6 +4266,14 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
@@ -5260,6 +5434,166 @@
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.8.tgz",
|
||||
"integrity": "sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.3.8",
|
||||
"@vue/compiler-sfc": "3.3.8",
|
||||
"@vue/runtime-dom": "3.3.8",
|
||||
"@vue/server-renderer": "3.3.8",
|
||||
"@vue/shared": "3.3.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vue-loader": {
|
||||
"version": "17.3.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.3.1.tgz",
|
||||
"integrity": "sha512-nmVu7KU8geOyzsStyyaxID/uBGDMS8BkPXb6Lu2SNkMawriIbb+hYrNtgftHMKxOSkjjjTF5OSSwPo3KP59egg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
"watchpack": "^2.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"webpack": "^4.1.0 || ^5.0.0-0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/compiler-sfc": {
|
||||
"optional": true
|
||||
},
|
||||
"vue": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vue-loader/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-loader/node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-loader/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-loader/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vue-loader/node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-loader/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-style-loader": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
|
||||
"integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==",
|
||||
"dependencies": {
|
||||
"hash-sum": "^1.0.2",
|
||||
"loader-utils": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-style-loader/node_modules/hash-sum": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
|
||||
"integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA=="
|
||||
},
|
||||
"node_modules/vue-style-loader/node_modules/json5": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-style-loader/node_modules/loader-utils": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
|
||||
"integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-template-compiler": {
|
||||
"version": "2.7.15",
|
||||
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.15.tgz",
|
||||
"integrity": "sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
"@babel/preset-env": "^7.23.2",
|
||||
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
||||
"babel-loader": "^9.1.3",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"symlink-webpack-plugin": "^1.1.0",
|
||||
"vue-loader": "^17.3.1",
|
||||
"vue-template-compiler": "^2.7.15",
|
||||
"webpack": "^5.89.0",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
@@ -40,6 +43,8 @@
|
||||
"sass-loader": "^13.3.2",
|
||||
"simplebar": "^6.2.5",
|
||||
"style-loader": "^3.3.3",
|
||||
"url-loader": "^4.1.1"
|
||||
"url-loader": "^4.1.1",
|
||||
"vue": "^3.3.8",
|
||||
"vue-style-loader": "^4.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
67
src/Spot.vue
Normal file
67
src/Spot.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<script>
|
||||
import Project from './components/project.vue';
|
||||
import Admin from './components/admin.vue';
|
||||
|
||||
const aoRoutes = {
|
||||
'project': Project,
|
||||
'admin': Admin
|
||||
};
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
//spot: window.oSpot,
|
||||
hash: {}
|
||||
};
|
||||
},
|
||||
inject: ['spot'],
|
||||
computed: {
|
||||
currentView() {
|
||||
this.spot.vars('page', this.hash.page);
|
||||
return aoRoutes[this.hash.page];
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('hashchange', () => {this.onHashChange();});
|
||||
var oEvent = new Event('hashchange');
|
||||
window.dispatchEvent(oEvent);
|
||||
}
|
||||
,
|
||||
methods: {
|
||||
_hash(hash, bReboot) {
|
||||
bReboot = bReboot || false;
|
||||
if(!hash) return window.location.hash.slice(1);
|
||||
else window.location.hash = '#'+hash;
|
||||
|
||||
if(bReboot) location.reload();
|
||||
},
|
||||
onHashChange() {
|
||||
let asHash = this.getHash();
|
||||
if(asHash.hash !='' && asHash.page != '') this.hash = asHash;
|
||||
else if(!this.hash.page) this.setHash(this.spot.consts.default_page);
|
||||
},
|
||||
getHash() {
|
||||
let sHash = this._hash();
|
||||
let asHash = sHash.split(this.spot.consts.hash_sep);
|
||||
let 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 != '') {
|
||||
let sItems = (asItems.length > 0)?this.spot.consts.hash_sep+asItems.join(this.spot.consts.hash_sep):'';
|
||||
this._hash(sPage+sItems, bReboot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div id="#main">
|
||||
<component :is="currentView" />
|
||||
</div>
|
||||
</template>
|
||||
231
src/components/admin.vue
Normal file
231
src/components/admin.vue
Normal file
@@ -0,0 +1,231 @@
|
||||
<script>
|
||||
import SpotButton from './spotButton.vue';
|
||||
import AdminInput from './adminInput.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SpotButton,
|
||||
AdminInput
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
elems: {},
|
||||
feedbacks: []
|
||||
};
|
||||
},
|
||||
inject: ['spot'],
|
||||
methods: {
|
||||
l(id) {
|
||||
return this.spot.lang(id);
|
||||
},
|
||||
async setProjects() {
|
||||
let aoElemTypes = await this.spot.get2('admin_get');
|
||||
|
||||
for(const [sType, aoElems] of Object.entries(aoElemTypes)) {
|
||||
this.elems[sType] = {};
|
||||
for(const [iKey, oElem] of Object.entries(aoElems)) {
|
||||
oElem.type = sType;
|
||||
this.elems[sType][oElem.id] = oElem;
|
||||
}
|
||||
}
|
||||
},
|
||||
createElem(sType) {
|
||||
this.spot.get2('admin_create', {type: sType})
|
||||
.then((aoNewElemTypes) => {
|
||||
console.log(aoNewElemTypes);
|
||||
for(const [sType, aoNewElems] of Object.entries(aoNewElemTypes)) {
|
||||
for(const [iKey, oNewElem] of Object.entries(aoNewElems)) {
|
||||
oNewElem.type = sType;
|
||||
this.elems[sType][oNewElem.id] = oNewElem;
|
||||
this.spot.onFeedback('success', this.spot.lang('admin_create_success'), {'create':sType});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((sMsg) => {console.log(sMsg);this.spot.onFeedback('error', sMsg, {'create':sType});});
|
||||
},
|
||||
deleteElem(oElem) {
|
||||
const asInputs = {
|
||||
type: oElem.type,
|
||||
id: oElem.id
|
||||
};
|
||||
|
||||
this.spot.get(
|
||||
'admin_delete',
|
||||
(asData) => {
|
||||
delete this.elems[asInputs.type][asInputs.id];
|
||||
this.spot.onFeedback('success', this.spot.lang('admin_delete_success'), asInputs);
|
||||
},
|
||||
asInputs,
|
||||
(sError) => {
|
||||
this.spot.onFeedback('error', sError, asInputs);
|
||||
}
|
||||
);
|
||||
},
|
||||
updateElem(oElem, oEvent) {
|
||||
if(typeof this.spot.tmp('wait') != 'undefined') clearTimeout(this.spot.tmp('wait'));
|
||||
|
||||
let sOldVal = this.elems[oElem.type][oElem.id][oEvent.target.name];
|
||||
let sNewVal = oEvent.target.value;
|
||||
if(sOldVal != sNewVal) {
|
||||
let asInputs = {
|
||||
type: oElem.type,
|
||||
id: oElem.id,
|
||||
field: oEvent.target.name,
|
||||
value: sNewVal
|
||||
};
|
||||
|
||||
this.spot.get2('admin_set', asInputs)
|
||||
.then((asData) => {
|
||||
this.elems[oElem.type][oElem.id][oEvent.target.name] = sNewVal;
|
||||
this.spot.onFeedback('success', this.spot.lang('admin_save_success'), asInputs);
|
||||
})
|
||||
.catch((sError) => {
|
||||
oEvent.target.value = sOldVal;
|
||||
this.spot.onFeedback('error', sError, asInputs);
|
||||
});
|
||||
}
|
||||
},
|
||||
queue(oElem, oEvent) {
|
||||
if(typeof this.spot.tmp('wait') != 'undefined') clearTimeout(this.spot.tmp('wait'));
|
||||
this.spot.tmp('wait', setTimeout(() => {this.updateElem(oElem, oEvent);}, 2000));
|
||||
},
|
||||
updateProject() {
|
||||
this.spot.get2('update_project')
|
||||
.then((asData, sMsg) => {this.spot.onFeedback('success', sMsg, {'update':'project'});})
|
||||
.catch((sMsg) => {this.spot.onFeedback('error', sMsg, {'update':'project'});});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.spot.addPage('admin', {
|
||||
onFeedback: (sType, sMsg, asContext) => {
|
||||
delete asContext.a;
|
||||
delete asContext.t;
|
||||
sMsg += ' (';
|
||||
for(const [sKey, sElem] of Object.entries(asContext)) {
|
||||
sMsg += sKey+'='+sElem+' / ' ;
|
||||
}
|
||||
sMsg = sMsg.slice(0, -3)+')';
|
||||
|
||||
this.feedbacks.push({type:sType, msg:sMsg});
|
||||
}
|
||||
});
|
||||
this.setProjects();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div id="admin">
|
||||
<a name="back" class="button" href="#project"><i class="fa fa-back push"></i>{{ l('nav_back') }}</a>
|
||||
<h1>{{ l('projects') }}</h1>
|
||||
<div id="project_section">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l('id_project') }}</th>
|
||||
<th>{{ l('project') }}</th>
|
||||
<th>{{ l('mode') }}</th>
|
||||
<th>{{ l('code_name') }}</th>
|
||||
<th>{{ l('start') }}</th>
|
||||
<th>{{ l('end') }}</th>
|
||||
<th>{{ l('delete') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="project in elems.project">
|
||||
<td>{{ project.id }}</td>
|
||||
<td><AdminInput :type="'text'" :name="'name'" :elem="project" /></td>
|
||||
<td>{{ project.mode }}</td>
|
||||
<td><AdminInput :type="'text'" :name="'codename'" :elem="project" /></td>
|
||||
<td><AdminInput :type="'date'" :name="'active_from'" :elem="project" /></td>
|
||||
<td><AdminInput :type="'date'" :name="'active_to'" :elem="project" /></td>
|
||||
<td><SpotButton :iconClass="'close fa-lg'" @click="deleteElem(project)" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<SpotButton :buttonClass="'new'" :buttonText="l('new_project')" :iconClass="'new'" @click="createElem('project')" />
|
||||
</div>
|
||||
<h1>{{ l('feeds') }}</h1>
|
||||
<div id="feed_section">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l('id_feed') }}</th>
|
||||
<th>{{ l('ref_feed_id') }}</th>
|
||||
<th>{{ l('id_spot') }}</th>
|
||||
<th>{{ l('id_project') }}</th>
|
||||
<th>{{ l('name') }}</th>
|
||||
<th>{{ l('status') }}</th>
|
||||
<th>{{ l('last_update') }}</th>
|
||||
<th>{{ l('delete') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="feed in elems.feed">
|
||||
<td>{{ feed.id }}</td>
|
||||
<td><AdminInput :type="'text'" :name="'ref_feed_id'" :elem="feed" /></td>
|
||||
<td><AdminInput :type="'number'" :name="'id_spot'" :elem="feed" /></td>
|
||||
<td><AdminInput :type="'number'" :name="'id_project'" :elem="feed" /></td>
|
||||
<td>{{ feed.name }}</td>
|
||||
<td>{{ feed.status }}</td>
|
||||
<td>{{ feed.last_update }}</td>
|
||||
<td><SpotButton :iconClass="'close fa-lg'" @click="deleteElem(feed)" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<SpotButton :buttonClass="'new'" :buttonText="l('new_feed')" :iconClass="'new'" @click="createElem('feed')" />
|
||||
</div>
|
||||
<h1>Spots</h1>
|
||||
<div id="spot_section">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l('id_spot') }}</th>
|
||||
<th>{{ l('ref_spot_id') }}</th>
|
||||
<th>{{ l('name') }}</th>
|
||||
<th>{{ l('model') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="spot in elems.spot">
|
||||
<td>{{ spot.id }}</td>
|
||||
<td>{{ spot.ref_spot_id }}</td>
|
||||
<td>{{ spot.name }}</td>
|
||||
<td>{{ spot.model }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h1>{{ l('active_users') }}</h1>
|
||||
<div id="user_section">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l('id_user') }}</th>
|
||||
<th>{{ l('user_name') }}</th>
|
||||
<th>{{ l('language') }}</th>
|
||||
<th>{{ l('time_zone') }}</th>
|
||||
<th>{{ l('clearance') }}</th>
|
||||
<th>{{ l('delete') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="user in elems.user">
|
||||
<td>{{ user.id }}</td>
|
||||
<td>{{ user.name }}</td>
|
||||
<td>{{ user.language }}</td>
|
||||
<td>{{ user.timezone }}</td>
|
||||
<td><AdminInput :type="'number'" :name="'clearance'" :elem="user" /></td>
|
||||
<td><SpotButton :iconClass="'close fa-lg'" @click="deleteElem(user)" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h1>{{ l('toolbox') }}</h1>
|
||||
<div id="toolbox">
|
||||
<SpotButton :buttonClass="'refresh'" :buttonText="l('update_project')" :iconClass="'refresh'" @click="updateProject" />
|
||||
</div>
|
||||
<div id="feedback" class="feedback">
|
||||
<p v-for="feedback in feedbacks" :class="feedback.type">{{ feedback.msg }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
17
src/components/adminInput.vue
Normal file
17
src/components/adminInput.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
type: String,
|
||||
name: String,
|
||||
elem: Object
|
||||
},
|
||||
computed: {
|
||||
value() {
|
||||
return this.elem[this.name];
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<input :type="type" :name="name" :value="value" @change="$parent.updateElem(elem, $event)" @keyup="$parent.queue(elem, $event)" />
|
||||
</template>
|
||||
44
src/components/project.vue
Normal file
44
src/components/project.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<script>
|
||||
//Leaflet
|
||||
import 'leaflet';
|
||||
import 'leaflet-geometryutil';
|
||||
import 'leaflet.heightgraph';
|
||||
import '../scripts/leaflet.helpers';
|
||||
import { LMap, LTileLayer } from "@vue-leaflet/vue-leaflet";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LMap,
|
||||
LTileLayer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
server: this.spot.consts.server,
|
||||
zoom: 13
|
||||
};
|
||||
},
|
||||
inject: ['spot'],
|
||||
mounted() {
|
||||
if(this.$parent.hash.items.length==0) this.$parent.setHash(this.$parent.hash.page, [this.spot.vars('default_project_codename')]);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="projects">
|
||||
<div id="background"></div>
|
||||
<div id="submap">
|
||||
<div class="loader fa fa-fw fa-map flicker" id="map_loading"></div>
|
||||
</div>
|
||||
<div id="map">
|
||||
<l-map ref="map" v-model:zoom="zoom" :center="[47.41322, -1.219482]">
|
||||
<l-tile-layer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
layer-type="base"
|
||||
name="OpenStreetMap"
|
||||
></l-tile-layer>
|
||||
</l-map>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mobile" class="mobile"></div>
|
||||
</template>
|
||||
22
src/components/spotButton.vue
Normal file
22
src/components/spotButton.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script>
|
||||
import SpotIcon from './spotIcon.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SpotIcon
|
||||
},
|
||||
props: {
|
||||
buttonClass: String,
|
||||
buttonText: String,
|
||||
iconClass: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
margin: !!this.buttonText
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<button :class="buttonClass"><SpotIcon :iconClass="iconClass" :margin="margin" />{{ buttonText }}</button>
|
||||
</template>
|
||||
17
src/components/spotIcon.vue
Normal file
17
src/components/spotIcon.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
iconClass: String,
|
||||
margin: Boolean,
|
||||
otherClasses: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
classNames: 'fa fa-'+this.iconClass+(this.margin?' push':'')+(this.otherClasses?' '+this.otherClasses:'')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<i :class="classNames"></i>
|
||||
</template>
|
||||
@@ -1,71 +0,0 @@
|
||||
<div id="admin">
|
||||
<a name="back" class="button" href="[#]server[#]"><i class="fa fa-back push"></i>[#]lang:nav_back[#]</a>
|
||||
<h1>[#]lang:projects[#]</h1>
|
||||
<div id="project_section">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>[#]lang:id_project[#]</th>
|
||||
<th>[#]lang:project[#]</th>
|
||||
<th>[#]lang:mode[#]</th>
|
||||
<th>[#]lang:code_name[#]</th>
|
||||
<th>[#]lang:start[#]</th>
|
||||
<th>[#]lang:end[#]</th>
|
||||
<th>[#]lang:delete[#]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
<div id="new"></div>
|
||||
</div>
|
||||
<h1>[#]lang:feeds[#]</h1>
|
||||
<div id="feed_section">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>[#]lang:id_feed[#]</th>
|
||||
<th>[#]lang:ref_feed_id[#]</th>
|
||||
<th>[#]lang:id_spot[#]</th>
|
||||
<th>[#]lang:id_project[#]</th>
|
||||
<th>[#]lang:name[#]</th>
|
||||
<th>[#]lang:status[#]</th>
|
||||
<th>[#]lang:last_update[#]</th>
|
||||
<th>[#]lang:delete[#]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h1>Spots</h1>
|
||||
<div id="spot_section">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>[#]lang:id_spot[#]</th>
|
||||
<th>[#]lang:ref_spot_id[#]</th>
|
||||
<th>[#]lang:name[#]</th>
|
||||
<th>[#]lang:model[#]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h1>[#]lang:active_users[#]</h1>
|
||||
<div id="user_section">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>[#]lang:id_user[#]</th>
|
||||
<th>[#]lang:user_name[#]</th>
|
||||
<th>[#]lang:language[#]</th>
|
||||
<th>[#]lang:time_zone[#]</th>
|
||||
<th>[#]lang:clearance[#]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h1>[#]lang:toolbox[#]</h1>
|
||||
<div id="toolbox"></div>
|
||||
<div id="feedback" class="feedback"></div>
|
||||
</div>
|
||||
@@ -20,12 +20,12 @@
|
||||
<meta name="msapplication-config" content="images/icons/browserconfig.xml?v=GvmqYyKwbb">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<script type="text/javascript">window.params = [#]GLOBAL_VARS[#];</script>
|
||||
<script type="text/javascript" src="[#]filepath_js[#]"></script>
|
||||
<title>Spotty</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="main"></div>
|
||||
</div>
|
||||
<script type="module" src="[#]filepath_js[#]"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -16,21 +16,26 @@ console.log(Logo);
|
||||
|
||||
//Masks
|
||||
import Spot from './spot.js';
|
||||
import Project from './page.project.js';
|
||||
import Upload from './page.upload.js';
|
||||
import Admin from './page.admin.js';
|
||||
//import Project from './page.project.js';
|
||||
//import Upload from './page.upload.js';
|
||||
//import Admin from './page.admin.js';
|
||||
|
||||
//const Upload = () => import('@scripts/page.upload.js');
|
||||
window.oSpot = new Spot(params);
|
||||
|
||||
let oSpot = new Spot(params);
|
||||
//let oProject = new Project(oSpot);
|
||||
//oSpot.addPage('project', oProject);
|
||||
|
||||
let oProject = new Project(oSpot);
|
||||
oSpot.addPage('project', oProject);
|
||||
//let oUpload = new Upload(oSpot);
|
||||
//oSpot.addPage('upload', oUpload);
|
||||
|
||||
let oUpload = new Upload(oSpot);
|
||||
oSpot.addPage('upload', oUpload);
|
||||
//let oAdmin = new Admin(oSpot);
|
||||
//oSpot.addPage('admin', oAdmin);
|
||||
|
||||
let oAdmin = new Admin(oSpot);
|
||||
oSpot.addPage('admin', oAdmin);
|
||||
//$(() => {oSpot.init();});
|
||||
|
||||
$(() => {oSpot.init();});
|
||||
import { createApp } from 'vue';
|
||||
import SpotVue from '../Spot.vue';
|
||||
|
||||
const oSpotVue = createApp(SpotVue);
|
||||
oSpotVue.provide('spot', window.oSpot);
|
||||
oSpotVue.mount('#main');
|
||||
@@ -75,7 +75,7 @@ export default class Spot {
|
||||
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 fOnSuccess(oData.data, oData.desc);
|
||||
else if(fOnSuccess) fOnSuccess(oData.data, oData.desc);
|
||||
})
|
||||
.fail((jqXHR, textStatus, errorThrown) => {
|
||||
fonProgress('fail');
|
||||
@@ -83,6 +83,32 @@ export default class Spot {
|
||||
});
|
||||
}
|
||||
|
||||
async get2(sAction, oVars) {
|
||||
oVars = oVars || {};
|
||||
oVars['a'] = sAction;
|
||||
oVars['t'] = this.consts.timezone;
|
||||
|
||||
let oUrl = new URL(this.consts.server+this.consts.process_page);
|
||||
oUrl.search = new URLSearchParams(oVars).toString();
|
||||
|
||||
try {
|
||||
let oUrl = new URL(this.consts.server+this.consts.process_page);
|
||||
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) throw new Error('Error HTTP '+oRequest.status+': '+oRequest.statusText);
|
||||
else {
|
||||
let oResponse = await oRequest.json();
|
||||
if(oResponse.desc.substr(0, this.consts.lang_prefix.length)==this.consts.lang_prefix) oResponse.desc = this.lang(oData.desc.substr(this.consts.lang_prefix.length));
|
||||
|
||||
if(oResponse.result == this.consts.error) return Promise.reject(oResponse.desc);
|
||||
else return Promise.resolve(oResponse.data, oResponse.desc);
|
||||
}
|
||||
}
|
||||
catch(oError) {
|
||||
throw oError;
|
||||
}
|
||||
}
|
||||
|
||||
lang(sKey, asParams) {
|
||||
asParams = asParams || [];
|
||||
if(typeof asParams == 'string') asParams = [asParams];
|
||||
@@ -176,6 +202,7 @@ export default class Spot {
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user