fix eslint errors, only allow im- and export of <20 templates
This commit is contained in:
parent
ff7ec9b0e9
commit
99f07115b3
|
@ -2,7 +2,7 @@
|
|||
* Item for list of Tamplates
|
||||
*/
|
||||
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { t } from 'ttag';
|
||||
|
||||
|
@ -26,7 +26,6 @@ const TemplateItem = ({
|
|||
if (!previewImg) {
|
||||
return;
|
||||
}
|
||||
console.log('rerendering image', imageId, previewImg);
|
||||
const bitmap = await createImageBitmap(previewImg);
|
||||
imgRef.current.getContext('bitmaprenderer')
|
||||
.transferFromImageBitmap(bitmap);
|
||||
|
@ -67,6 +66,7 @@ const TemplateItem = ({
|
|||
evt.stopPropagation();
|
||||
startEditing(title);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{t`Edit`}
|
||||
</button>
|
||||
|
@ -76,6 +76,7 @@ const TemplateItem = ({
|
|||
dispatch(selectCanvas(canvasId));
|
||||
dispatch(setViewCoordinates([x + width / 2, y + height / 2]));
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{t`Go to`}
|
||||
</button>
|
||||
|
|
|
@ -93,7 +93,7 @@ const TemplateItemEdit = ({
|
|||
</div>
|
||||
<div
|
||||
className="centered-on-img modallink"
|
||||
onClick={(evt) => fileRef.current?.click()}
|
||||
onClick={() => fileRef.current?.click()}
|
||||
>{t`Select File`}</div>
|
||||
<input
|
||||
type="file"
|
||||
|
@ -114,7 +114,7 @@ const TemplateItemEdit = ({
|
|||
type="text"
|
||||
onChange={(evt) => {
|
||||
const newTitle = evt.target.value;
|
||||
setTitleUnique(!templateList.some((t) => t.title === newTitle));
|
||||
setTitleUnique(!templateList.some((z) => z.title === newTitle));
|
||||
setTitle(evt.target.value);
|
||||
}}
|
||||
placeholder={t`Template Name`}
|
||||
|
@ -152,8 +152,9 @@ const TemplateItemEdit = ({
|
|||
co = coordsFromUrl(co) || co;
|
||||
evt.target.value = co;
|
||||
const newCoords = co.split('_').map((z) => parseInt(z, 10));
|
||||
setCoords((!newCoords.some(Number.isNaN) && newCoords.length === 2)
|
||||
? newCoords : null,
|
||||
setCoords(
|
||||
(!newCoords.some(Number.isNaN) && newCoords.length === 2)
|
||||
? newCoords : null,
|
||||
);
|
||||
}}
|
||||
/></span>
|
||||
|
@ -171,35 +172,34 @@ const TemplateItemEdit = ({
|
|||
stopEditing(initTitle);
|
||||
templateLoader.deleteTemplate(initTitle);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{t`Delete`}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={(evt) => stopEditing(title)}
|
||||
onClick={() => stopEditing(title)}
|
||||
type="button"
|
||||
>
|
||||
{t`Cancel`}
|
||||
</button>
|
||||
<button
|
||||
disabled={!canSubmit}
|
||||
onClick={async (evt) => {
|
||||
onClick={async () => {
|
||||
if (!canSubmit) {
|
||||
return;
|
||||
}
|
||||
const [x, y] = coords;
|
||||
if (!initTitle) {
|
||||
console.log('Create new template');
|
||||
await templateLoader.addFile(file, title, canvasId, x, y);
|
||||
} else {
|
||||
if (file && imageId) {
|
||||
console.log('file changed for id', imageId);
|
||||
await templateLoader.updateFile(imageId, file);
|
||||
}
|
||||
if (initTitle
|
||||
&& (initTitle !== title || initX !== x
|
||||
|| initY !== y || initCanvasId !== canvasId
|
||||
)) {
|
||||
console.log(`template ${title} changed`);
|
||||
templateLoader.changeTemplate(initTitle, {
|
||||
title, canvasId, x, y,
|
||||
});
|
||||
|
@ -207,6 +207,7 @@ const TemplateItemEdit = ({
|
|||
}
|
||||
stopEditing(initTitle);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{t`Save`}
|
||||
</button>
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* Settings for minimap / overlay
|
||||
*/
|
||||
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
|
||||
import React, { useState, useCallback, useRef } from 'react';
|
||||
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
|
||||
import fileDownload from 'js-file-download';
|
||||
|
@ -37,7 +39,7 @@ const TemplateSettings = () => {
|
|||
const dispatch = useDispatch();
|
||||
|
||||
const toggleEditing = useCallback((title) => {
|
||||
const index = list.findIndex((t) => t.title === title);
|
||||
const index = list.findIndex((z) => z.title === title);
|
||||
const ind = editingIndices.indexOf(index);
|
||||
setEditingIndices((ind === -1)
|
||||
? [...editingIndices, index]
|
||||
|
@ -45,13 +47,14 @@ const TemplateSettings = () => {
|
|||
);
|
||||
}, [list, editingIndices]);
|
||||
|
||||
console.log('list', list);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>{t`Templates`}</h2>
|
||||
<p>
|
||||
{t`Tired of always spaming one single color? Want to create art instead, but you have to count pixels from some other image? Templates can help you with that! Templates can show as overlay and you can draw over them. One pixel on the template, should be one pixel on the canvas.`}
|
||||
{
|
||||
// eslint-disable-next-line max-len
|
||||
t`Tired of always spaming one single color? Want to create art instead, but you have to count pixels from some other image? Templates can help you with that! Templates can show as overlay and you can draw over them. One pixel on the template, should be one pixel on the canvas.`
|
||||
}
|
||||
</p>
|
||||
<SettingsItem
|
||||
title={t`Enable Overlay`}
|
||||
|
@ -64,10 +67,12 @@ const TemplateSettings = () => {
|
|||
<SettingsItem
|
||||
title={t`Small Pixels Overlay`}
|
||||
value={oSmallPxls}
|
||||
deactivated={!oVEnabled}
|
||||
onToggle={() => dispatch(toggleSmallPxls())}
|
||||
>
|
||||
{t`Show overlay as small individual pixels (will only show in high zoomlevels).`}
|
||||
{
|
||||
// eslint-disable-next-line max-len
|
||||
t`Show overlay as small individual pixels (will only show in high zoomlevels).`
|
||||
}
|
||||
</SettingsItem>
|
||||
|
||||
<div className="setitem">
|
||||
|
@ -144,9 +149,11 @@ const TemplateSettings = () => {
|
|||
className="modallink"
|
||||
onClick={async () => {
|
||||
const data = await templateLoader.exportEnabledTemplates();
|
||||
fileDownload(
|
||||
JSON.stringify(data), 'PixelplanetTemplates.json',
|
||||
);
|
||||
if (data) {
|
||||
fileDownload(
|
||||
JSON.stringify(data), 'PixelplanetTemplates.json',
|
||||
);
|
||||
}
|
||||
}}
|
||||
>{t`Export enabled templates`}</span>
|
||||
</React.Fragment>
|
||||
|
|
|
@ -50,7 +50,7 @@ const PencilButton = () => {
|
|||
}
|
||||
}
|
||||
dispatch(selectHoldPaint(nextMode));
|
||||
}, [holdPaint, dispatch]);
|
||||
}, [holdPaint, easterEgg, dispatch]);
|
||||
|
||||
const onShortPress = useCallback(() => {
|
||||
let nextMode;
|
||||
|
|
|
@ -153,7 +153,8 @@ export function createKeyDownHandler(store) {
|
|||
if (event.location === KeyboardEvent.DOM_KEY_LOCATION_RIGHT) {
|
||||
// right shift
|
||||
store.dispatch(selectHoldPaint(
|
||||
(store.getState().gui.easterEgg) ? HOLD_PAINT.OVERLAY : HOLD_PAINT.HISTORY,
|
||||
(store.getState().gui.easterEgg)
|
||||
? HOLD_PAINT.OVERLAY : HOLD_PAINT.HISTORY,
|
||||
true,
|
||||
));
|
||||
return;
|
||||
|
|
|
@ -111,7 +111,6 @@ export default (store) => (next) => (action) => {
|
|||
case 's/REM_TEMPLATE':
|
||||
case 's/UPD_TEMPLATE_IMG':
|
||||
case 's/SET_O_OPACITY':
|
||||
//
|
||||
case 'REQ_BIG_CHUNK':
|
||||
case 'PRE_LOADED_BIG_CHUNK':
|
||||
case 'REC_BIG_CHUNK':
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* class for storing templates for minimap / overlay
|
||||
*/
|
||||
|
||||
import { t } from 'ttag';
|
||||
|
||||
import FileStorage from '../utils/FileStorage';
|
||||
import {
|
||||
removeTemplate,
|
||||
|
@ -11,6 +13,7 @@ import {
|
|||
templatesReady,
|
||||
receivedTemplate,
|
||||
} from '../store/actions/templates';
|
||||
import { pAlert } from '../store/actions';
|
||||
import { bufferToBase64, base64ToBuffer } from '../core/utils';
|
||||
import Template from './Template';
|
||||
|
||||
|
@ -32,6 +35,7 @@ class TemplateLoader {
|
|||
this.#store.dispatch(templatesReady());
|
||||
await this.syncDB();
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(`Couldn't initialize Templates: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +63,6 @@ class TemplateLoader {
|
|||
if (template) {
|
||||
return template.image;
|
||||
}
|
||||
// TODO some store action when available
|
||||
this.loadExistingTemplate(id);
|
||||
return null;
|
||||
}
|
||||
|
@ -72,7 +75,6 @@ class TemplateLoader {
|
|||
if (template) {
|
||||
return template.imageSmall;
|
||||
}
|
||||
// TODO some store action when available
|
||||
this.loadExistingTemplate(id);
|
||||
return null;
|
||||
}
|
||||
|
@ -119,10 +121,10 @@ class TemplateLoader {
|
|||
async syncDB() {
|
||||
try {
|
||||
const { list } = this.#store.getState().templates;
|
||||
const ids = list.map((t) => t.imageId);
|
||||
const ids = list.map((z) => z.imageId);
|
||||
const deadIds = await this.#fileStorage.sync(ids);
|
||||
list.filter((t) => deadIds.includes(t.imageId)).forEach((t) => {
|
||||
this.#store.dispatch(removeTemplate(t.title));
|
||||
list.filter((z) => deadIds.includes(z.imageId)).forEach((z) => {
|
||||
this.#store.dispatch(removeTemplate(z.title));
|
||||
});
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -137,7 +139,7 @@ class TemplateLoader {
|
|||
*/
|
||||
async loadAllMissing() {
|
||||
const { templates } = this.#store.getState();
|
||||
const ids = templates.list.map((t) => t.imageId);
|
||||
const ids = templates.list.map((z) => z.imageId);
|
||||
const toLoad = ids.filter((i) => !this.#templates.has(i));
|
||||
for (const id of toLoad) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
|
@ -156,7 +158,6 @@ class TemplateLoader {
|
|||
throw new Error('File does not exist in indexedDB');
|
||||
}
|
||||
const { mimetype, buffer } = fileData;
|
||||
console.log('mime', mimetype, 'buffer', buffer);
|
||||
const template = new Template(imageId);
|
||||
await template.fromBuffer(buffer, mimetype);
|
||||
this.#templates.set(imageId, template);
|
||||
|
@ -222,13 +223,20 @@ class TemplateLoader {
|
|||
async exportEnabledTemplates() {
|
||||
const { list } = this.#store.getState().templates;
|
||||
const tDataList = list.filter((z) => z.enabled);
|
||||
if (!tDataList.length || tDataList.length > 20) {
|
||||
this.#store.dispatch(pAlert(
|
||||
t`Error :(`,
|
||||
t`Can not export more than 20 or no template!`,
|
||||
'error',
|
||||
));
|
||||
return null;
|
||||
}
|
||||
const temps = await this.#fileStorage.loadFile(
|
||||
tDataList.map((z) => z.imageId),
|
||||
);
|
||||
const serilizableObj = [];
|
||||
for (let i = 0; i < tDataList.length; i += 1) {
|
||||
const { buffer, mimetype } = temps[i];
|
||||
console.log('mimetype', mimetype);
|
||||
serilizableObj.push({
|
||||
...tDataList[i],
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
|
@ -241,13 +249,20 @@ class TemplateLoader {
|
|||
|
||||
async importTemplates(file) {
|
||||
const tDataList = JSON.parse(await file.text());
|
||||
if (!tDataList.length || tDataList.length > 20) {
|
||||
this.#store.dispatch(pAlert(
|
||||
t`Error :(`,
|
||||
t`Can not import more than 20 or no template!`,
|
||||
'error',
|
||||
));
|
||||
return;
|
||||
}
|
||||
const bufferList = await Promise.all(
|
||||
tDataList.map((z) => base64ToBuffer(z.buffer)),
|
||||
);
|
||||
const fileList = [];
|
||||
for (let i = 0; i < tDataList.length; i += 1) {
|
||||
const { mimetype } = tDataList[i];
|
||||
console.log('mimetype', mimetype, 'buffer', bufferList[i]);
|
||||
fileList.push(new Blob([bufferList[i]], { type: mimetype }));
|
||||
}
|
||||
const { list } = this.#store.getState().templates;
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
const CURRENT_VERSION = 1;
|
||||
const DB_NAME = 'ppfun_files';
|
||||
|
||||
// TODO make sure we get sane errors on reject()
|
||||
|
||||
class FileStorage {
|
||||
type;
|
||||
static db;
|
||||
|
@ -28,10 +26,10 @@ class FileStorage {
|
|||
const request = window.indexedDB.open(DB_NAME, CURRENT_VERSION);
|
||||
|
||||
request.onsuccess = (event) => {
|
||||
console.log('Successfully opened indexedDB');
|
||||
const db = event.target.result;
|
||||
|
||||
db.onerror = (evt) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('indexedDB error:', evt.target.error);
|
||||
};
|
||||
|
||||
|
@ -48,6 +46,7 @@ class FileStorage {
|
|||
};
|
||||
|
||||
request.onerror = () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Error on opening indexedDB:', request.error);
|
||||
reject(request.error);
|
||||
};
|
||||
|
@ -61,25 +60,21 @@ class FileStorage {
|
|||
}
|
||||
const fileArray = Array.isArray(files) ? files : [files];
|
||||
const buffers = await Promise.all(fileArray.map((f) => f.arrayBuffer()));
|
||||
console.log('buffers', buffers);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const result = [];
|
||||
const transaction = db.transaction('files', 'readwrite');
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
console.log('Success on saving files to indexedDB', result);
|
||||
resolve(Array.isArray(files) ? result : result[0]);
|
||||
};
|
||||
transaction.onabort = (event) => {
|
||||
event.stopPropagation();
|
||||
console.log('Saving files to indexedDB aborted:', event, result);
|
||||
reject(event.target.error);
|
||||
};
|
||||
|
||||
const os = transaction.objectStore('files');
|
||||
fileArray.forEach((file, index) => {
|
||||
console.log('type', this.type, 'mime', file.type, 'buffer', buffers[index], 'file', file);
|
||||
result.push(null);
|
||||
os.add({
|
||||
type: this.type,
|
||||
|
@ -103,7 +98,6 @@ class FileStorage {
|
|||
|
||||
transaction.onabort = (event) => {
|
||||
event.stopPropagation();
|
||||
console.log('Saving files to indexedDB aborted:', event);
|
||||
reject(event.target.error);
|
||||
};
|
||||
|
||||
|
@ -128,12 +122,10 @@ class FileStorage {
|
|||
const transaction = db.transaction('files', 'readonly');
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
console.log('Success on loading file', result);
|
||||
resolve(Array.isArray(ids) ? result : result[0]);
|
||||
};
|
||||
transaction.onabort = (event) => {
|
||||
event.stopPropagation();
|
||||
console.log('Loading file from indexedDB aborted:', event.target.error);
|
||||
reject(event.target.error);
|
||||
};
|
||||
|
||||
|
@ -147,6 +139,7 @@ class FileStorage {
|
|||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
deleteFile(ids) {
|
||||
const { db } = FileStorage;
|
||||
if (!db) {
|
||||
|
@ -157,15 +150,11 @@ class FileStorage {
|
|||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction('files', 'readwrite');
|
||||
|
||||
transaction.oncomplete = (event) => {
|
||||
console.log(
|
||||
`Successfully deleted ${indicesArray.length} files from indexedDB`,
|
||||
);
|
||||
transaction.oncomplete = () => {
|
||||
resolve();
|
||||
};
|
||||
transaction.onabort = (event) => {
|
||||
event.stopPropagation();
|
||||
console.log('Saving files to indexedDB aborted:', event);
|
||||
reject(event.target.error);
|
||||
};
|
||||
|
||||
|
@ -188,12 +177,10 @@ class FileStorage {
|
|||
.getAllKeys(this.type);
|
||||
|
||||
request.onsuccess = (event) => {
|
||||
console.log('got all keys', event.target.result);
|
||||
resolve(event.target.result);
|
||||
};
|
||||
transaction.onabort = (event) => {
|
||||
event.stopPropagation();
|
||||
console.log('GetAllKeys aborted:', event.target);
|
||||
reject(event.target.error);
|
||||
};
|
||||
});
|
||||
|
@ -208,11 +195,13 @@ class FileStorage {
|
|||
const allKeys = await this.getAllKeys();
|
||||
const toDelete = allKeys.filter((i) => !ids.includes(i));
|
||||
if (toDelete.length) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Templaes: Keys in db but not in store', toDelete);
|
||||
await this.deleteFile(toDelete);
|
||||
}
|
||||
const deadIds = ids.filter((i) => !allKeys.includes(i));
|
||||
if (deadIds.length) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Templates: Keys in store but not in db', deadIds);
|
||||
}
|
||||
return deadIds;
|
||||
|
|
Loading…
Reference in New Issue
Block a user