Compare commits
No commits in common. "fb62fbccf7b22c5ca92d9dc6221f302892de7f53" and "b194eef0c5bc27eb19fefb278c06b0aeb3055829" have entirely different histories.
fb62fbccf7
...
b194eef0c5
@ -18,7 +18,7 @@ The web interface has mobile optimizations, letting you sort images/files on the
|
|||||||
### Screenshots
|
### Screenshots
|
||||||
<span style="display:inline-block; max-width: 70%; max-height: 510px ; margin-right: 4px">
|
<span style="display:inline-block; max-width: 70%; max-height: 510px ; margin-right: 4px">
|
||||||
<img style="display:block; max-width:100%; max-height: 250px; " src="resources/imgsort2-landscape.png" alt="Desktop interface"></img>
|
<img style="display:block; max-width:100%; max-height: 250px; " src="resources/imgsort2-landscape.png" alt="Desktop interface"></img>
|
||||||
<img style="display:block; max-width:100%; max-height: 250px; margin-top: 10px" src="resources/imgsort2-configuration.png" alt="Configuration interface"></img>
|
<img style="display:block; max-width:100%; max-height: 250px; margin-top: 10px" src="resources/configuration.png" alt="Configuration interface"></img>
|
||||||
</span>
|
</span>
|
||||||
<img style="display:inline-block; max-width: 30%; max-height: 510px" src="resources/imgsort2-vertical.png" alt="Mobile interface"></img>
|
<img style="display:inline-block; max-width: 30%; max-height: 510px" src="resources/imgsort2-vertical.png" alt="Mobile interface"></img>
|
||||||
|
|
||||||
|
BIN
resources/configuration.png
Normal file
After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 832 KiB After Width: | Height: | Size: 601 KiB |
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 298 KiB |
@ -1,149 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="256"
|
|
||||||
height="256"
|
|
||||||
viewBox="0 0 67.733332 67.733333"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="logo.svg"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#000000"
|
|
||||||
borderopacity="0.25"
|
|
||||||
inkscape:showpageshadow="2"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:zoom="2.2173472"
|
|
||||||
inkscape:cx="146.34605"
|
|
||||||
inkscape:cy="134.39483"
|
|
||||||
inkscape:window-width="1896"
|
|
||||||
inkscape:window-height="1026"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="layer1" />
|
|
||||||
<defs
|
|
||||||
id="defs1">
|
|
||||||
<filter
|
|
||||||
style="color-interpolation-filters:sRGB;"
|
|
||||||
inkscape:label="Drop Shadow"
|
|
||||||
id="filter20"
|
|
||||||
x="0"
|
|
||||||
y="0"
|
|
||||||
width="1.0278316"
|
|
||||||
height="1.0385704">
|
|
||||||
<feFlood
|
|
||||||
result="flood"
|
|
||||||
in="SourceGraphic"
|
|
||||||
flood-opacity="1.000000"
|
|
||||||
flood-color="rgb(157,0,6)"
|
|
||||||
id="feFlood19" />
|
|
||||||
<feGaussianBlur
|
|
||||||
result="blur"
|
|
||||||
in="SourceGraphic"
|
|
||||||
stdDeviation="0.000000"
|
|
||||||
id="feGaussianBlur19" />
|
|
||||||
<feOffset
|
|
||||||
result="offset"
|
|
||||||
in="blur"
|
|
||||||
dx="1.000000"
|
|
||||||
dy="0.990099"
|
|
||||||
id="feOffset19" />
|
|
||||||
<feComposite
|
|
||||||
result="comp1"
|
|
||||||
operator="in"
|
|
||||||
in="flood"
|
|
||||||
in2="offset"
|
|
||||||
id="feComposite19" />
|
|
||||||
<feComposite
|
|
||||||
result="comp2"
|
|
||||||
operator="over"
|
|
||||||
in="SourceGraphic"
|
|
||||||
in2="comp1"
|
|
||||||
id="feComposite20" />
|
|
||||||
</filter>
|
|
||||||
<filter
|
|
||||||
style="color-interpolation-filters:sRGB;"
|
|
||||||
inkscape:label="Drop Shadow"
|
|
||||||
id="filter23"
|
|
||||||
x="0"
|
|
||||||
y="0"
|
|
||||||
width="1.0529345"
|
|
||||||
height="1.0377">
|
|
||||||
<feFlood
|
|
||||||
result="flood"
|
|
||||||
in="SourceGraphic"
|
|
||||||
flood-opacity="1.000000"
|
|
||||||
flood-color="rgb(157,0,6)"
|
|
||||||
id="feFlood22" />
|
|
||||||
<feGaussianBlur
|
|
||||||
result="blur"
|
|
||||||
in="SourceGraphic"
|
|
||||||
stdDeviation="0.000000"
|
|
||||||
id="feGaussianBlur22" />
|
|
||||||
<feOffset
|
|
||||||
result="offset"
|
|
||||||
in="blur"
|
|
||||||
dx="1.000000"
|
|
||||||
dy="0.990099"
|
|
||||||
id="feOffset22" />
|
|
||||||
<feComposite
|
|
||||||
result="comp1"
|
|
||||||
operator="in"
|
|
||||||
in="flood"
|
|
||||||
in2="offset"
|
|
||||||
id="feComposite22" />
|
|
||||||
<feComposite
|
|
||||||
result="comp2"
|
|
||||||
operator="over"
|
|
||||||
in="SourceGraphic"
|
|
||||||
in2="comp1"
|
|
||||||
id="feComposite23" />
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
<g
|
|
||||||
inkscape:label="Ebene 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<rect
|
|
||||||
style="fill:#ebdbb2;stroke-width:2.91042"
|
|
||||||
id="rect1"
|
|
||||||
width="67.733337"
|
|
||||||
height="67.733337"
|
|
||||||
x="0"
|
|
||||||
y="0"
|
|
||||||
ry="18.676485" />
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-size:37.0417px;font-family:Impact;-inkscape-font-specification:Impact;text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:2.28782;filter:url(#filter20)"
|
|
||||||
x="34.285786"
|
|
||||||
y="31.511433"
|
|
||||||
id="text1"><tspan
|
|
||||||
id="tspan1"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:37.0417px;font-family:'Ubuntu Nerd Font';-inkscape-font-specification:'Ubuntu Nerd Font';text-align:center;text-anchor:middle;fill:#3c3836;stroke-width:2.28782"
|
|
||||||
x="34.285786"
|
|
||||||
y="31.511433"
|
|
||||||
sodipodi:role="line">Im</tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:37.0417px;font-family:'Ubuntu Nerd Font';-inkscape-font-specification:'Ubuntu Nerd Font';text-align:center;text-anchor:middle;fill:#ebdbb2;stroke-width:2.91042;filter:url(#filter23)"
|
|
||||||
x="31.940487"
|
|
||||||
y="61.066525"
|
|
||||||
id="text2"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan2"
|
|
||||||
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:37.0417px;font-family:'Ubuntu Nerd Font';-inkscape-font-specification:'Ubuntu Nerd Font Italic';fill:#3c3836;stroke-width:2.91042"
|
|
||||||
x="31.940487"
|
|
||||||
y="61.066525">2</tspan></text>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 4.6 KiB |
@ -5,7 +5,6 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Imgsort 2 - Config</title>
|
<title>Imgsort 2 - Config</title>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.png">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@ -28,9 +27,6 @@
|
|||||||
<button type="submit" name="submit">Add</button>
|
<button type="submit" name="submit">Add</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<h2>Save / Load</h2>
|
|
||||||
<button onclick="saveMappings()" id="save-button">Save mappings to file</button>
|
|
||||||
<button onclick="loadMappings()" id="load-button">Load mappings from file</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="second-box" style="max-height: 100%">
|
<div class="second-box" style="max-height: 100%">
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
* Handle mappings
|
* Handle mappings
|
||||||
* Mappings are stored in local storage as a Map (key: directory)
|
* Mappings are stored in local storage as a Map (key: directory)
|
||||||
*/
|
*/
|
||||||
const invalidFileNameCharsRe =/[^\\\|:\*\?"<>]/; // dont allow \/|:*?<>
|
|
||||||
const invalidFileNameChars = "\\|:*?<>";
|
|
||||||
|
|
||||||
let statusLine = document.getElementById('status');
|
let statusLine = document.getElementById('status');
|
||||||
|
|
||||||
@ -65,56 +63,6 @@ function addMapping(key, directory) {
|
|||||||
renderMappings();
|
renderMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Save/Load from file
|
|
||||||
*/
|
|
||||||
function saveMappings() {
|
|
||||||
const mappings = new Map(JSON.parse(localStorage.getItem('mappings')) || []);
|
|
||||||
let dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(Array.from(mappings)));
|
|
||||||
let downloadElement = document.createElement('a');
|
|
||||||
downloadElement.style = "display: none;";
|
|
||||||
downloadElement.setAttribute("href", dataStr);
|
|
||||||
downloadElement.setAttribute("download", "mappings.json");
|
|
||||||
document.body.appendChild(downloadElement); // required for firefox
|
|
||||||
downloadElement.click();
|
|
||||||
downloadElement.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function loadMappings() {
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.type = 'file';
|
|
||||||
input.accept = '.json';
|
|
||||||
|
|
||||||
input.onchange = async (event) => {
|
|
||||||
const file = event.target.files[0];
|
|
||||||
if (!file) {
|
|
||||||
statusLine.textContent = "No file selected";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const fileText = await file.text();
|
|
||||||
const jsonData = JSON.parse(fileText);
|
|
||||||
|
|
||||||
// check is valid
|
|
||||||
if (typeof jsonData !== 'object' || jsonData === null) {
|
|
||||||
statusLine.textContent = "Invalid JSON structure";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO possibly implement sanity checks
|
|
||||||
localStorage.setItem('mappings', JSON.stringify(jsonData));
|
|
||||||
renderMappings();
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);;
|
|
||||||
statusLine = "Error loading file";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
input.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// event listener for add mapping form
|
// event listener for add mapping form
|
||||||
document.getElementById('addMappingForm').addEventListener('submit', function(event) {
|
document.getElementById('addMappingForm').addEventListener('submit', function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -5,10 +5,7 @@
|
|||||||
// All paths require trailing slashes!
|
// All paths require trailing slashes!
|
||||||
$rootDir = __DIR__ . '/../images/';
|
$rootDir = __DIR__ . '/../images/';
|
||||||
// The URI at which the rootDir will be served
|
// The URI at which the rootDir will be served
|
||||||
// Use /images/ for testing
|
$rootPath = 'images/';
|
||||||
// When the app is not served at the root https://example.com/ but at a sublocation like https://example.com/imgsort2/,
|
|
||||||
// you might need to set it to just `images` without the /
|
|
||||||
$rootPath = '/images/';
|
|
||||||
// Path of the directory containing all the files to be sorted, relative to $rootDir
|
// Path of the directory containing all the files to be sorted, relative to $rootDir
|
||||||
$stagingDirName = '.sort/';
|
$stagingDirName = '.sort/';
|
||||||
|
|
||||||
@ -80,23 +77,27 @@
|
|||||||
/**
|
/**
|
||||||
* Move a file from staging to the destination directory
|
* Move a file from staging to the destination directory
|
||||||
* @param file relative to stagingDir
|
* @param file relative to stagingDir
|
||||||
* @param dest new filename relative to rootDir
|
* @param dir relative to rootDir
|
||||||
*/
|
*/
|
||||||
function moveFile($file, $dest) {
|
function moveFile($file, $dir) {
|
||||||
global $stagingDir, $rootDir;
|
global $stagingDir, $rootDir;
|
||||||
$fullFile = $stagingDir . $file;
|
$fullFile = $stagingDir . $file;
|
||||||
$fullDest = $rootDir . $dest;
|
$fullDir = $rootDir . $dir . "/";
|
||||||
|
$fullDest = $fullDir . basename($fullFile);
|
||||||
return saveMove($fullFile, $fullDest);
|
return saveMove($fullFile, $fullDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like movefile, except reversed
|
* Move a file from destination directory back to the staging directory
|
||||||
|
* @param dir relative to rootDir
|
||||||
|
* @param file relative to rootDir/dir
|
||||||
*/
|
*/
|
||||||
function undoFile($file, $dest) {
|
function undoFile($file, $dir) {
|
||||||
global $stagingDir, $rootDir;
|
global $stagingDir, $rootDir;
|
||||||
$fullFile = $stagingDir . $file;
|
$fullDir = $rootDir . $dir . "/";
|
||||||
$fullDest = $rootDir . $dest;
|
$fullFile = $fullDir . $file;
|
||||||
return saveMove($fullDest, $fullFile);
|
$fullDest = $stagingDir . basename($fullFile);
|
||||||
|
return saveMove($fullFile, $fullDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Imgsort 2</title>
|
<title>Imgsort 2</title>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.png">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="index.js" async></script>
|
<script src="index.js" async></script>
|
||||||
@ -22,12 +21,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="second-box">
|
<div class="second-box">
|
||||||
<div class="buttons" id="buttons">
|
<div id="buttons">
|
||||||
<input id="filename" placeholder="filename" type="text" class="filename-input"></input>
|
<button onclick="undo()" id="undo-button">Undo</button>
|
||||||
<button onclick="undo()" class="move-button" id="undo-button">Undo</button>
|
<button onclick="skip()" id="skip-button">Skip</button>
|
||||||
<button onclick="skip()" class="move-button" id="skip-button">Skip</button>
|
|
||||||
<span class="move-buttons" id="move-buttons"></span>
|
<span class="move-buttons" id="move-buttons"></span>
|
||||||
<br>
|
|
||||||
<button onclick="window.location.href='config.html';" id="configure-button">Configure</button>
|
<button onclick="window.location.href='config.html';" id="configure-button">Configure</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="file-list">
|
<div class="file-list">
|
||||||
|
88
src/index.js
@ -1,10 +1,7 @@
|
|||||||
const imageExtensions = ['gif','jpg','jpeg','png', 'webp', 'svg', 'pdf'];
|
const imageExtensions = ['gif','jpg','jpeg','png', 'webp'];
|
||||||
const videoExtensions =['mpg', 'mp2', 'mpeg', 'mpe', 'mpv', 'mp4'];
|
const videoExtensions =['mpg', 'mp2', 'mpeg', 'mpe', 'mpv', 'mp4'];
|
||||||
const audioExtensions =['mp3', 'ogg', 'wav', 'flac'];
|
const audioExtensions =['mp3', 'ogg', 'wav', 'flac'];
|
||||||
|
|
||||||
const invalidFileNameCharsRe =/[\\/\|:\*\?"<>]/; // dont allow \/|:*?<>
|
|
||||||
const invalidFileNameChars = "\\/|:*?<>";
|
|
||||||
|
|
||||||
const mappings = new Map(JSON.parse(localStorage.getItem('mappings')) || []);
|
const mappings = new Map(JSON.parse(localStorage.getItem('mappings')) || []);
|
||||||
let statusLine = document.getElementById('status');
|
let statusLine = document.getElementById('status');
|
||||||
// store for when done with sorting TODO display
|
// store for when done with sorting TODO display
|
||||||
@ -78,13 +75,13 @@ function renderMoveButtons() {
|
|||||||
const buttons = document.getElementById('move-buttons');
|
const buttons = document.getElementById('move-buttons');
|
||||||
buttons.innerHTML = '';
|
buttons.innerHTML = '';
|
||||||
mappings.forEach((directory, key) => {
|
mappings.forEach((directory, key) => {
|
||||||
const moveButton = document.createElement('button');
|
const removeButton = document.createElement('button');
|
||||||
moveButton.innerHTML = `<span class="key">${key}</span> <span class="directory">${directory}</span>`;
|
removeButton.innerHTML = `<span class="key">${key}</span> <span class="directory">${directory}</span>`;
|
||||||
moveButton.onclick = function() {
|
removeButton.onclick = function() {
|
||||||
moveFile(directory);
|
moveFile(directory);
|
||||||
};
|
};
|
||||||
moveButton.className = "move-button";
|
removeButton.class = "move-button";
|
||||||
buttons.appendChild(moveButton);
|
buttons.appendChild(removeButton);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,71 +203,23 @@ function setCurrentFile() {
|
|||||||
currentFile = "";
|
currentFile = "";
|
||||||
statusLine.textContent = "No more files to sort";
|
statusLine.textContent = "No more files to sort";
|
||||||
}
|
}
|
||||||
|
|
||||||
// set filename in input field
|
|
||||||
const fileNameNoExt = currentFile.replace(/\.[^/.]+$/, "");
|
|
||||||
document.getElementById('filename').value = fileNameNoExt;
|
|
||||||
|
|
||||||
renderCurrentFile();
|
renderCurrentFile();
|
||||||
renderFileList();
|
renderFileList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function setCurrentFileFromName(filename) {
|
|
||||||
let idx = fileList.indexOf(filename);
|
|
||||||
if (idx < 0) {
|
|
||||||
message = `Can not set file from name '${filename}': Not found in list`;
|
|
||||||
statusLine.textContent = message;
|
|
||||||
console.error(message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
currentFileIdx = idx;
|
|
||||||
setCurrentFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event delegation
|
|
||||||
document.getElementById('file-list').addEventListener('click', function(event) {
|
|
||||||
if (event.target && event.target.tagName === 'P') {
|
|
||||||
// Call the function with the content of the clicked paragraph
|
|
||||||
if (event.target.textContent != "No files") {
|
|
||||||
setCurrentFileFromName(event.target.textContent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function moveFile(directory) {
|
async function moveFile(directory) {
|
||||||
if (!currentFile) {
|
if (!currentFile) {
|
||||||
statusLine.textContent = "No file to process!";
|
statusLine.innerHTML = "No file to process!";
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
const userSetFilename = document.getElementById('filename').value;
|
const response = await fetch(`imgsort.php?action=moveFile&file=${escape(currentFile)}&dest=${directory}`);
|
||||||
if (!userSetFilename) {
|
|
||||||
statusLine.textContent = "Filename must not be empty";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// file names invalid on windows not handled
|
|
||||||
if (invalidFileNameCharsRe.test(userSetFilename)) {
|
|
||||||
statusLine.textContent = `Filename must not contain ${invalidFileNameChars}`;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// re-add the extension
|
|
||||||
const fileExt = currentFile.split('.').pop();
|
|
||||||
let filename = userSetFilename + '.' + fileExt;
|
|
||||||
|
|
||||||
let newFilePath = directory + '/' + filename;
|
|
||||||
const response = await fetch(`imgsort.php?action=moveFile&file=${escape(currentFile)}&dest=${escape(newFilePath)}`);
|
|
||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
// console.log(text);
|
// console.log(text);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
if (filename != currentFile) {
|
statusLine.textContent = `Moved '${currentFile}' to '${directory}'`;
|
||||||
statusLine.textContent = `Moved '${currentFile}' to '${directory}'`;
|
history.push([currentFile, directory]);
|
||||||
} else {
|
|
||||||
statusLine.textContent = `Moved '${currentFile}' to '${directory}' as '${filename}'`;
|
|
||||||
}
|
|
||||||
history.push([currentFile, newFilePath]);
|
|
||||||
// remove file from list
|
// remove file from list
|
||||||
fileList.splice(currentFileIdx, 1);
|
fileList.splice(currentFileIdx, 1);
|
||||||
// set next file
|
// set next file
|
||||||
@ -288,12 +237,12 @@ async function undo() {
|
|||||||
statusLine.textContent = "Nothing to undo"
|
statusLine.textContent = "Nothing to undo"
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const [file, newFilePath] = history.pop();
|
const [file, directory] = history.pop();
|
||||||
const response = await fetch(`imgsort.php?action=undoFile&file=${escape(file)}&dest=${escape(newFilePath)}`);
|
const response = await fetch(`imgsort.php?action=undoFile&file=${escape(file)}&dest=${directory}`);
|
||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
// console.log(text);
|
// console.log(text);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
statusLine.textContent = `Undo: move '${file}' to '${newFilePath}'`;
|
statusLine.innerHTML = `Undo: move '${file}' to '${directory}'`;
|
||||||
await setFileList()
|
await setFileList()
|
||||||
setCurrentFile();
|
setCurrentFile();
|
||||||
}
|
}
|
||||||
@ -311,15 +260,13 @@ function skip() {
|
|||||||
|
|
||||||
|
|
||||||
async function initialize() {
|
async function initialize() {
|
||||||
// remove the value on reload
|
|
||||||
document.getElementById('filename').value = "";
|
|
||||||
await setStagingPath();
|
await setStagingPath();
|
||||||
await setFileList();
|
await setFileList();
|
||||||
renderMoveButtons();
|
renderMoveButtons();
|
||||||
renderFileList();
|
renderFileList();
|
||||||
// setCurrentFile();
|
// setCurrentFile();
|
||||||
preloadNextFile();
|
preloadNextFile();
|
||||||
statusLine.textContent = "Ready";
|
statusLine.textContent = "Loaded";
|
||||||
}
|
}
|
||||||
|
|
||||||
// load existing mappings on page load
|
// load existing mappings on page load
|
||||||
@ -329,11 +276,6 @@ window.onload = function() {
|
|||||||
|
|
||||||
// handle keyboard
|
// handle keyboard
|
||||||
document.onkeypress = function(e) {
|
document.onkeypress = function(e) {
|
||||||
// dont handle keys while user is typing in filename box
|
|
||||||
if (document.querySelector('input') === document.activeElement) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
e = e || window.event;
|
e = e || window.event;
|
||||||
let keydebug = document.getElementById("keydebug");
|
let keydebug = document.getElementById("keydebug");
|
||||||
if (keydebug) {
|
if (keydebug) {
|
||||||
|
@ -24,13 +24,10 @@ $file-height: 300px
|
|||||||
$splash-font-size: 40px
|
$splash-font-size: 40px
|
||||||
$button-font-size: $font-size
|
$button-font-size: $font-size
|
||||||
$button-padding: 8px
|
$button-padding: 8px
|
||||||
$move-button-font-size: $font-size - 2px
|
|
||||||
$move-button-padding: $button-padding - 2px
|
|
||||||
|
|
||||||
*
|
*
|
||||||
font-family: "Ubuntu", Verdana, sans-serif
|
font-family: "Ubuntu", Verdana, sans-serif
|
||||||
color: $fg
|
color: $fg
|
||||||
// font-size: $font-size
|
|
||||||
|
|
||||||
|
|
||||||
html, body // fill entire screen so that footer is always on bottom
|
html, body // fill entire screen so that footer is always on bottom
|
||||||
@ -97,7 +94,6 @@ footer
|
|||||||
min-height: $footer-height // idk why but this is required
|
min-height: $footer-height // idk why but this is required
|
||||||
overflow-x: scroll
|
overflow-x: scroll
|
||||||
overflow-y: hidden
|
overflow-y: hidden
|
||||||
white-space: nowrap
|
|
||||||
*
|
*
|
||||||
color: $bg
|
color: $bg
|
||||||
.statusline
|
.statusline
|
||||||
@ -121,7 +117,6 @@ a
|
|||||||
border-width: 1px
|
border-width: 1px
|
||||||
border-color: $fg0-hard
|
border-color: $fg0-hard
|
||||||
border-radius: 4px
|
border-radius: 4px
|
||||||
font-family: $monofont
|
|
||||||
|
|
||||||
// p
|
// p
|
||||||
// text-align: justify
|
// text-align: justify
|
||||||
@ -148,13 +143,8 @@ button, input
|
|||||||
filter: drop-shadow(0.1rem 0.1rem 0 $accent)
|
filter: drop-shadow(0.1rem 0.1rem 0 $accent)
|
||||||
font-family: $monofont
|
font-family: $monofont
|
||||||
margin: 0.2rem
|
margin: 0.2rem
|
||||||
.move-buttons
|
.move-buttons
|
||||||
margin: 0
|
margin: 0
|
||||||
|
|
||||||
.move-button
|
|
||||||
font-size: $move-button-font-size
|
|
||||||
padding: $move-button-padding
|
|
||||||
|
|
||||||
button:hover
|
button:hover
|
||||||
color: $button-fg-hl
|
color: $button-fg-hl
|
||||||
background-color: $button-bg-hl
|
background-color: $button-bg-hl
|
||||||
@ -171,11 +161,6 @@ button:hover
|
|||||||
width: 20px
|
width: 20px
|
||||||
text-align: center
|
text-align: center
|
||||||
// #directory
|
// #directory
|
||||||
#save-button
|
|
||||||
filter: drop-shadow(0.1rem 0.1rem 0 $light-red)
|
|
||||||
#load-button
|
|
||||||
filter: drop-shadow(0.1rem 0.1rem 0 $light-blue)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.add-mapping-form
|
.add-mapping-form
|
||||||
@ -198,10 +183,6 @@ button:hover
|
|||||||
// width: 50%
|
// width: 50%
|
||||||
|
|
||||||
|
|
||||||
.filename-input
|
|
||||||
width: 90%
|
|
||||||
margin: auto
|
|
||||||
padding: 0.1rem
|
|
||||||
.file-list
|
.file-list
|
||||||
width: 90%
|
width: 90%
|
||||||
margin: auto
|
margin: auto
|
||||||
@ -216,20 +197,13 @@ button:hover
|
|||||||
margin: 0
|
margin: 0
|
||||||
padding: 0.1rem
|
padding: 0.1rem
|
||||||
text-align: left
|
text-align: left
|
||||||
.file-list-item:hover
|
|
||||||
background: $dark-blue !important
|
|
||||||
color: $bg1
|
|
||||||
cursor: pointer
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.file-list-item:nth-child(even)
|
.file-list-item:nth-child(even)
|
||||||
background: $bg1
|
background: $bg1
|
||||||
.file-list-item:nth-child(odd)
|
.file-list-item:nth-child(odd)
|
||||||
background: $bg2
|
background: $bg2
|
||||||
|
|
||||||
.selected-file-list-item
|
.selected-file-list-item
|
||||||
background: $light-blue !important
|
background: $dark-blue !important
|
||||||
color: $bg1
|
color: $bg1
|
||||||
|
|
||||||
|
|
||||||
@ -238,7 +212,6 @@ button:hover
|
|||||||
main
|
main
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: row
|
flex-direction: row
|
||||||
padding-bottom: $footer-height + 2 * $footer-padding-y
|
|
||||||
.main-box
|
.main-box
|
||||||
width: 75%
|
width: 75%
|
||||||
max-height: calc(100vh - $footer-height - 2 * $footer-padding-y)
|
max-height: calc(100vh - $footer-height - 2 * $footer-padding-y)
|
||||||
@ -259,8 +232,6 @@ button:hover
|
|||||||
width: 100%
|
width: 100%
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
footer
|
footer
|
||||||
width: 100%
|
width: 100%
|
||||||
position: fixed
|
position: fixed
|
||||||
|
@ -102,7 +102,6 @@ a {
|
|||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-color: #1d2021;
|
border-color: #1d2021;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-family: "UbuntuMono", monospace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
@ -131,16 +130,10 @@ button, input {
|
|||||||
font-family: "UbuntuMono", monospace;
|
font-family: "UbuntuMono", monospace;
|
||||||
margin: 0.2rem;
|
margin: 0.2rem;
|
||||||
}
|
}
|
||||||
|
button .move-buttons, input .move-buttons {
|
||||||
.move-buttons {
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.move-button {
|
|
||||||
font-size: 14px;
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
button:hover {
|
||||||
color: #282828;
|
color: #282828;
|
||||||
background-color: #ebdbb2;
|
background-color: #ebdbb2;
|
||||||
@ -167,14 +160,6 @@ button:hover {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#save-button {
|
|
||||||
filter: drop-shadow(0.1rem 0.1rem 0 #9d0006);
|
|
||||||
}
|
|
||||||
|
|
||||||
#load-button {
|
|
||||||
filter: drop-shadow(0.1rem 0.1rem 0 #076678);
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-mapping-form {
|
.add-mapping-form {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding-bottom: 0.4rem;
|
padding-bottom: 0.4rem;
|
||||||
@ -199,12 +184,6 @@ button:hover {
|
|||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filename-input {
|
|
||||||
width: 90%;
|
|
||||||
margin: auto;
|
|
||||||
padding: 0.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-list {
|
.file-list {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
@ -224,12 +203,6 @@ button:hover {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-list-item:hover {
|
|
||||||
background: #458588 !important;
|
|
||||||
color: #ebdbb2;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-list-item:nth-child(even) {
|
.file-list-item:nth-child(even) {
|
||||||
background: #ebdbb2;
|
background: #ebdbb2;
|
||||||
}
|
}
|
||||||
@ -239,7 +212,7 @@ button:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.selected-file-list-item {
|
.selected-file-list-item {
|
||||||
background: #076678 !important;
|
background: #458588 !important;
|
||||||
color: #ebdbb2;
|
color: #ebdbb2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +220,6 @@ button:hover {
|
|||||||
main {
|
main {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding-bottom: 24px;
|
|
||||||
}
|
}
|
||||||
.main-box {
|
.main-box {
|
||||||
width: 75%;
|
width: 75%;
|
||||||
|