Removing jQuery altogether
This commit is contained in:
@@ -1,13 +1,11 @@
|
||||
<script>
|
||||
import 'maplibre-gl/dist/maplibre-gl.css';
|
||||
import { Map, NavigationControl, Marker, LngLatBounds, LngLat, Popup } from 'maplibre-gl';
|
||||
import { createApp, defineComponent, nextTick, ref, defineCustomElement, provide, inject } from 'vue';
|
||||
import { createApp, ref, provide, inject } from 'vue';
|
||||
import Simplebar from 'simplebar-vue';
|
||||
|
||||
import autosize from 'autosize';
|
||||
import mousewheel from 'jquery-mousewheel';
|
||||
import waitforimages from 'jquery.waitforimages';
|
||||
import lightbox from '../scripts/lightbox.js';
|
||||
import { getOuterWidth } from '../scripts/common.js';
|
||||
|
||||
import SpotIcon from './spotIcon.vue';
|
||||
import SpotIconStack from './spotIconStack.vue';
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import projectMapLink from './projectMapLink.vue';
|
||||
import projectRelTime from './projectRelTime.vue';
|
||||
import { LngLat } from 'maplibre-gl';
|
||||
import { copyTextToClipboard } from '../scripts/common.js';
|
||||
|
||||
import autosize from 'autosize';
|
||||
|
||||
|
||||
@@ -1,87 +1,127 @@
|
||||
<script>
|
||||
import SpotIcon from './spotIcon.vue';
|
||||
import SpotButton from './spotButton.vue';
|
||||
import "blueimp-file-upload/js/vendor/jquery.ui.widget.js";
|
||||
import "blueimp-file-upload/js/jquery.iframe-transport.js";
|
||||
import "blueimp-file-upload/js/jquery.fileupload.js";
|
||||
|
||||
export default {
|
||||
name: 'upload',
|
||||
components: { SpotButton, SpotIcon },
|
||||
inject: ['spot', 'projects', 'consts', 'user'],
|
||||
data() {
|
||||
return {
|
||||
project: this.projects[this.spot.vars('default_project_codename')],
|
||||
files: [],
|
||||
logs: [],
|
||||
progress: 0
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.spot.addPage('upload', {});
|
||||
|
||||
if(this.project.editable) {
|
||||
$('#fileupload')
|
||||
.fileupload({
|
||||
dataType: 'json',
|
||||
formData: {t: this.user.timezone},
|
||||
acceptFileTypes: /(\.|\/)(gif|jpe?g|png|mov)$/i,
|
||||
done: (e, asData) => {
|
||||
$.each(asData.result.files, (iKey, oFile) => {
|
||||
let bError = ('error' in oFile);
|
||||
|
||||
//Feedback
|
||||
this.logs.push(bError?oFile.error:(this.spot.lang('upload_success', [oFile.name])));
|
||||
|
||||
//Comments
|
||||
oFile.content = '';
|
||||
if(!bError) this.files.push(oFile);
|
||||
});
|
||||
},
|
||||
progressall: (e, data) => {
|
||||
this.progress = parseInt(data.loaded / data.total * 100, 10);
|
||||
}
|
||||
});
|
||||
}
|
||||
else this.logs = [this.spot.lang('upload_mode_archived', [this.project.name])];
|
||||
},
|
||||
methods: {
|
||||
addComment(oFile) {
|
||||
this.spot.get2('add_comment', {id: oFile.id, content: oFile.content})
|
||||
.then((asData) => {this.logs.push(this.spot.lang('media_comment_update', asData.filename));})
|
||||
.catch((sMsgId) => {this.logs.push(this.spot.lang(sMsgId));});
|
||||
},
|
||||
addPosition() {
|
||||
if(navigator.geolocation) {
|
||||
this.logs.push('Determining position...');
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(position) => {
|
||||
this.logs.push('Sending position...');
|
||||
this.spot.get2('add_position', {'latitude':position.coords.latitude, 'longitude':position.coords.longitude, 'timestamp':Math.round(position.timestamp / 1000)})
|
||||
.then((asData) => {this.logs.push(self.lang(sMsgId));})
|
||||
.catch((sMsgId) => {this.logs.push(self.lang(sMsgId));});
|
||||
},
|
||||
(error) => {
|
||||
this.logs.push(error.message);
|
||||
}
|
||||
);
|
||||
}
|
||||
else this.logs.push('This browser does not support geolocation');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div id="upload">
|
||||
<a name="back" class="button" href="#project"><SpotIcon :icon="'back'" :text="spot.lang('nav_back')" /></a>
|
||||
<h1>{{ spot.lang('upload_media_title') }}</h1>
|
||||
<h2>{{ this.project.name }}</h2>
|
||||
<div class="section" v-if="project.editable">
|
||||
<input id="fileupload" type="file" name="files[]" :data-url="this.spot.getActionLink('upload')" multiple />
|
||||
</div>
|
||||
<div class="section progress" v-if="progress > 0">
|
||||
<div class="bar" :style="{width:progress+'%'}"></div>
|
||||
</div>
|
||||
<script>
|
||||
import { markRaw } from 'vue';
|
||||
import Uppy from '@uppy/core';
|
||||
import XHRUpload from '@uppy/xhr-upload';
|
||||
import '@uppy/core/css/style.min.css';
|
||||
|
||||
import SpotIcon from './spotIcon.vue';
|
||||
import SpotButton from './spotButton.vue';
|
||||
|
||||
export default {
|
||||
name: 'upload',
|
||||
components: { SpotButton, SpotIcon },
|
||||
inject: ['spot', 'projects', 'consts', 'user'],
|
||||
data() {
|
||||
return {
|
||||
project: this.projects[this.spot.vars('default_project_codename')],
|
||||
files: [],
|
||||
logs: [],
|
||||
progress: 0,
|
||||
uppy: null
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.spot.addPage('upload', {});
|
||||
|
||||
if(!this.project.editable) {
|
||||
this.logs = [this.spot.lang('upload_mode_archived', [this.project.name])];
|
||||
return;
|
||||
}
|
||||
|
||||
this.initUploader();
|
||||
},
|
||||
beforeUnmount() {
|
||||
if(this.uppy) {
|
||||
this.uppy.destroy();
|
||||
this.uppy = null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initUploader() {
|
||||
const endpoint = `${this.consts.process_page}?a=upload`;
|
||||
|
||||
this.uppy = markRaw(new Uppy({
|
||||
autoProceed: true,
|
||||
restrictions: {
|
||||
allowedFileTypes: ['.gif', '.jpg', '.jpeg', '.png', '.mov', '.mp4']
|
||||
}
|
||||
}));
|
||||
|
||||
this.uppy.setMeta({t: this.user.timezone});
|
||||
|
||||
this.uppy.use(XHRUpload, {
|
||||
endpoint,
|
||||
fieldName: 'files[]',
|
||||
formData: true,
|
||||
allowedMetaFields: ['t', 'name', 'type'],
|
||||
getResponseData(xhr) {
|
||||
return JSON.parse(xhr.responseText || '{}');
|
||||
}
|
||||
});
|
||||
|
||||
this.uppy.on('progress', (progress) => {
|
||||
this.progress = progress;
|
||||
});
|
||||
|
||||
this.uppy.on('upload-success', (file, response) => {
|
||||
const uploadedFiles = response?.body?.files || [];
|
||||
uploadedFiles.forEach((uploadedFile) => {
|
||||
const hasError = Object.prototype.hasOwnProperty.call(uploadedFile, 'error');
|
||||
this.logs.push(hasError ? uploadedFile.error : this.spot.lang('upload_success', [uploadedFile.name]));
|
||||
if(!hasError) this.files.push({...uploadedFile, content: ''});
|
||||
});
|
||||
});
|
||||
|
||||
this.uppy.on('upload-error', (file, error, response) => {
|
||||
const message = response?.body?.error || error?.message || this.spot.lang('error');
|
||||
this.logs.push(message);
|
||||
});
|
||||
|
||||
this.uppy.on('complete', () => {
|
||||
this.progress = 0;
|
||||
});
|
||||
},
|
||||
onFileChange(event) {
|
||||
const files = Array.from(event.target.files || []);
|
||||
if(files.length > 0 && this.uppy) this.uppy.addFiles(files.map((file) => ({source: 'local', name: file.name, type: file.type, data: file})));
|
||||
event.target.value = '';
|
||||
},
|
||||
addComment(oFile) {
|
||||
this.spot.get2('add_comment', {id: oFile.id, content: oFile.content})
|
||||
.then((asData) => {this.logs.push(this.spot.lang('media_comment_update', asData.filename));})
|
||||
.catch((sMsgId) => {this.logs.push(this.spot.lang(sMsgId));});
|
||||
},
|
||||
addPosition() {
|
||||
if(navigator.geolocation) {
|
||||
this.logs.push('Determining position...');
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(position) => {
|
||||
this.logs.push('Sending position...');
|
||||
this.spot.get2('add_position', {'latitude':position.coords.latitude, 'longitude':position.coords.longitude, 'timestamp':Math.round(position.timestamp / 1000)})
|
||||
.then((asData) => {this.logs.push(this.spot.lang('success'));})
|
||||
.catch((sMsgId) => {this.logs.push(this.spot.lang(sMsgId));});
|
||||
},
|
||||
(error) => {
|
||||
this.logs.push(error.message);
|
||||
}
|
||||
);
|
||||
}
|
||||
else this.logs.push('This browser does not support geolocation');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div id="upload">
|
||||
<a name="back" class="button" href="#project"><SpotIcon :icon="'back'" :text="spot.lang('nav_back')" /></a>
|
||||
<h1>{{ spot.lang('upload_media_title') }}</h1>
|
||||
<h2>{{ this.project.name }}</h2>
|
||||
<div class="section" v-if="project.editable">
|
||||
<input id="fileupload" type="file" name="files[]" multiple accept=".gif,.jpg,.jpeg,.png,.mov,.mp4" @change="onFileChange" />
|
||||
</div>
|
||||
<div class="section progress" v-if="progress > 0">
|
||||
<div class="bar" :style="{width:progress+'%'}"></div>
|
||||
</div>
|
||||
<div class="section comment" v-for="file in files">
|
||||
<img class="thumb" :src="file.thumbnail" />
|
||||
<div class="form">
|
||||
@@ -98,4 +138,4 @@ export default {
|
||||
<p class="log" v-for="log in logs">{{ log }}.</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
//jQuery
|
||||
import './jquery.helpers.js';
|
||||
|
||||
//Common
|
||||
import * as common from './common.js';
|
||||
window.copyArray = common.copyArray;
|
||||
window.getElem = common.getElem;
|
||||
window.setElem = common.setElem;
|
||||
window.getDragPosition = common.getDragPosition;
|
||||
window.copyTextToClipboard = common.copyTextToClipboard;
|
||||
window.getOuterWidth = common.getOuterWidth;
|
||||
import Css from './../styles/spot.scss';
|
||||
|
||||
//Masks
|
||||
|
||||
@@ -1,30 +1,4 @@
|
||||
$.prototype.addInput = function(sType, sName, sValue, aoEvents) {
|
||||
aoEvents = aoEvents || [];
|
||||
let $Input = $('<input>', {type: sType, name: sName, value: sValue}).data('old_value', sValue);
|
||||
$.each(aoEvents, (iIndex, aoEvent) => {
|
||||
$Input.on(aoEvent.on, aoEvent.callback);
|
||||
});
|
||||
return $(this).append($Input);
|
||||
};
|
||||
|
||||
$.prototype.addButton = function(sIcon, sText, sName, fOnClick, sClass)
|
||||
{
|
||||
sText = sText || '';
|
||||
sClass = sClass || '';
|
||||
var $Btn = $('<button>', {name: sName, 'class':sClass})
|
||||
.addIcon('fa-'+sIcon, (sText != ''))
|
||||
.append(sText)
|
||||
.click(fOnClick);
|
||||
|
||||
return $(this).append($Btn);
|
||||
};
|
||||
|
||||
$.prototype.addIcon = function(sIcon, bMargin, sStyle)
|
||||
{
|
||||
bMargin = bMargin || false;
|
||||
sStyle = sStyle || '';
|
||||
return $(this).append($('<i>', {'class':'fa'+sStyle+' '+sIcon+(bMargin?' push':'')}));
|
||||
};
|
||||
import { getDragPosition } from './common.js';
|
||||
|
||||
$.prototype.defaultVal = function(sDefaultValue)
|
||||
{
|
||||
@@ -57,31 +31,6 @@ $.prototype.checkForm = function(sSelector)
|
||||
return bOk;
|
||||
};
|
||||
|
||||
$.prototype.cascadingDown = function(sDuration)
|
||||
{
|
||||
return $(this).slideDown(sDuration, function(){$(this).next().cascadingDown(sDuration);});
|
||||
};
|
||||
|
||||
$.prototype.hoverSwap = function(sDefault, sHover)
|
||||
{
|
||||
return $(this)
|
||||
.data('default', sDefault)
|
||||
.data('hover', sHover)
|
||||
.hover(function(){
|
||||
var $This = $(this),
|
||||
sHover = $This.data('hover');
|
||||
sDefault = $This.data('default');
|
||||
|
||||
if(sDefault!='' && sHover != '') {
|
||||
$This.fadeOut('fast', function() {
|
||||
var $This = $(this);
|
||||
$This.text((sDefault==$This.text())?sHover:sDefault).fadeIn('fast');
|
||||
});
|
||||
}
|
||||
})
|
||||
.text(sDefault);
|
||||
};
|
||||
|
||||
$.prototype.onSwipe = function(fOnStart, fOnMove, fOnEnd){
|
||||
return $(this)
|
||||
.on('dragstart', (e) => {
|
||||
@@ -126,4 +75,4 @@ $.prototype.onSwipe = function(fOnStart, fOnMove, fOnEnd){
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
31
src/scripts/lang.js
Normal file
31
src/scripts/lang.js
Normal file
@@ -0,0 +1,31 @@
|
||||
export default class Lang {
|
||||
|
||||
constructor({ translations = {}, prefix = '' } = {}) {
|
||||
this.translations = translations;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
lang(key = '', params = []) {
|
||||
if(key === '') return '';
|
||||
|
||||
const normalizedParams = Array.isArray(params) ? params : [params];
|
||||
|
||||
if(Object.prototype.hasOwnProperty.call(this.translations, key)) {
|
||||
let text = this.translations[key];
|
||||
normalizedParams.forEach((param, index) => {
|
||||
text = text.replace('$' + index, param);
|
||||
});
|
||||
return text;
|
||||
}
|
||||
|
||||
console.warn('Missing translation:', key);
|
||||
return key;
|
||||
}
|
||||
|
||||
parse(message = '') {
|
||||
if(this.prefix && typeof message === 'string' && message.startsWith(this.prefix)) {
|
||||
return this.lang(message.slice(this.prefix.length));
|
||||
}
|
||||
return message;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
import { copyArray, getElem, setElem } from './common.js';
|
||||
import Lang from './lang.js';
|
||||
|
||||
export default class Spot {
|
||||
|
||||
constructor(asGlobals) {
|
||||
@@ -6,6 +9,11 @@ export default class Spot {
|
||||
this.consts.title = 'Spotty';
|
||||
this.consts.default_page = 'project';
|
||||
//this.consts.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || this.consts.default_timezone;
|
||||
|
||||
this.translator = new Lang({
|
||||
translations: this.consts.lang || {},
|
||||
prefix: this.consts.lang_prefix || ''
|
||||
});
|
||||
|
||||
this.pages = {};
|
||||
|
||||
@@ -104,9 +112,7 @@ export default class Spot {
|
||||
else {
|
||||
let oResponse = await oRequest.json();
|
||||
bLoading = false;
|
||||
if(oResponse.desc.substr(0, this.consts.lang_prefix.length)==this.consts.lang_prefix) {
|
||||
oResponse.desc = this.lang(oResponse.desc.substr(this.consts.lang_prefix.length));
|
||||
}
|
||||
oResponse.desc = this.translator.parse(oResponse.desc);
|
||||
|
||||
if(oResponse.result == this.consts.error) return Promise.reject(oResponse.desc);
|
||||
else return oResponse.data;
|
||||
@@ -119,22 +125,7 @@ export default class Spot {
|
||||
}
|
||||
|
||||
lang(sKey, asParams = []) {
|
||||
if(sKey == '') return '';
|
||||
if(typeof asParams !== 'object') asParams = [asParams];
|
||||
|
||||
var sLang = '';
|
||||
if(sKey in this.consts.lang) {
|
||||
sLang = this.consts.lang[sKey];
|
||||
for(let i in asParams) {
|
||||
sLang = sLang.replace('$'+i, asParams[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('missing translation: '+sKey);
|
||||
sLang = sKey;
|
||||
}
|
||||
|
||||
return sLang;
|
||||
return this.translator.lang(sKey, asParams);
|
||||
}
|
||||
|
||||
isMobile() {
|
||||
@@ -313,4 +304,4 @@ export default class Spot {
|
||||
checkClearance(sClearance) {
|
||||
return (this.vars(['user', 'clearance']) >= sClearance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user