Skip to content

Commit

Permalink
Release 2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Commenter25 committed Dec 2, 2023
1 parent 1086496 commit 1ef2908
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 51 deletions.
16 changes: 14 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,22 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/), and

Past versions will link to their respective commit. Current versions will not due to temporal paradoxes.

## 2023-12-02 - 2.0.0
### Added:
- Recognizes JXL files
- YAPLtag variable
- whenErr runs when a file fails to download
### Changed:
- onFail is now totalFail, return false to stop loading
- Console logs are now commented out (except errors)
### Removed:
- getExtension function
- jshint comments

## 2023-01-10 - 1.0.1
Fixed:
### Fixed:
- Only counts files once if multiple events are fired from one asset
- Assets are no longer shown in a11y tree
- Assets are no longer shown in accessibility tree
- Assets are no longer focusable

## 2023-01-07 - [1.0.0](https://github.com/Commenter25/YAPL/blob/cc3600cc1c7ed7c3f2eac171fceb687a1e11dfff/yapl.js)
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# <img src="logo.svg" alt="" style="display:inline; height:1em; position:relative; top: 4px"> YAPL - Yet Another PreLoader
The simplest JavaScript preloader I could think of. Probably too simple.

Made for a private web game, because everything else I found looked complicated and scary, so I just made my own thing because I'm insane. Released as I felt others might find it useful. Besides the rest of that game, this is my first JavaScript project, so it probably sucks. This requires ES6, but it's so basic I think it could be refactored for ES3. I won't, because if you want that, I think you're probably more insane than me.
Made for [Crazy Chrimble Catastrophy](https://chrimble.commenter.cc/), because everything else I found looked complicated and scary, so I just made my own thing because I'm insane. Released as I felt others might find it useful. Besides the rest of that game, this is my first JavaScript project, so it probably sucks. This requires ES6, but it's so basic I think it could be refactored for ES3. I won't, because if you want that, I think you're probably more insane than me.

Every file will be added to the DOM as a 1x1 pixel with 0.01 opacity, all within a div the script creates for you, which is fixed to the bottom left of the viewport. Everything is technically always visible and therefore the browser should always load and cache it, but it should be imperceivable to any human. If anyone spots it, say it's a reference to CRAM dots, because it is ;D

Expand All @@ -26,9 +26,9 @@ If you use this ANYWHERE besides your own machine, ***KEEP YOUR LIST AS SHORT AS

## Using functions

You can optionally pass 3 functions in order: one for after all files are parsed, one for every time a file's parsed, and one if YAPL completely fails. Two variables are also accessible, `YAPLloaded` and `YAPLfailed`. You can add these together to get the total number of files processed.
You can optionally pass 4 functions in order: one for after all files are parsed, one for every time a file's parsed, one for every time a file fails to load, and one if YAPL completely fails. For the third function, if you want to stop loading if one file is inaccessible, you can `return true`. Two variables are also accessible, `YAPLloaded`, `YAPLfailed`. You can add these together to get the total number of files processed. There is also `YAPLtag` to access the element which files are loaded into.

I personally loaded YAPL with defer, then contained my assets and functions in an inline `<script>` wrapped in a `DOMContentLoaded` listener. For each file, it updated a loading indicator in a disabled button. Then when done, it'd add a new `<script>` tag to `<head>`, loading a script contained all my actual code, which I only wanted to run once everything was loaded. In my new script, I activated the button to allow starting the game. Here's an code block showing that usage:
I personally loaded YAPL with defer, then contained my assets and functions in a `DOMContentLoaded` listener. For each file, it updated a loading indicator in a disabled button. Then when done, it'd add a new `<script>` tag to `<head>`, loading a script contained all my actual code, which I only wanted to run once everything was loaded. In my new script, I activated the button to allow starting the game. If anything failed, I wouldn't tolerate it, I'd simply shut everything down. Here's an code block showing that usage:

```javascript
document.addEventListener("DOMContentLoaded", ()=> {
Expand All @@ -45,13 +45,14 @@ document.addEventListener("DOMContentLoaded", ()=> {
}

function incr() {
document.getElementById("loadbutton").innerHTML = `Loading... ${YAPLloaded + YAPLfailed + "/" + assets.length}`;
document.getElementById("loadbutton").innerHTML = `Loading... ${YAPLloaded + "/" + assets.length}`;
}

function fail() {
document.getElementById("loadbutton").innerHTML = "Something has gone horribly wrong!";
return true;
}

YAPLload(folder, assets, done, incr, fail);
YAPLload(folder, assets, done, incr, fail, fail);
});
```
101 changes: 57 additions & 44 deletions yapl.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,49 @@
/*! @license Yet Another PreLoader v1.0.1 | Copyright (c) 2023 Commenter25 | MIT License */
/*! @license Yet Another PreLoader v2.0.0 | Copyright (c) 2023 Commenter25 | MIT License */
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT License */
/* jshint esversion: 6, browser: true, devel: true, strict: global */ "use strict";
"use strict";

let YAPLloaded = 0, YAPLfailed = 0;
let YAPLloaded = 0, YAPLfailed = 0;

const YAPLtag = document.createElement("div");
YAPLtag.id = "yet-another-preloader";
YAPLtag.style = "position: fixed; top: 99.9vh; left: 0; display: flex; opacity: 0.01; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; pointer-events: none; cursor: default;";
YAPLtag.setAttribute("aria-hidden", "true");
document.body.prepend(YAPLtag);

/**
* @param {string} filename - String ending with a file extension, like "cool-img.webp" or "wacky-sound.ogg"
* @returns {string} Returns the file extension at the end of a string.
* @author Tomalak // https://stackoverflow.com/a/680982
*/
function getExtension(string) {
return /(?:\.([^.]+))?$/.exec(string)[1];
}

/**
* Adds a series of files to the DOM so the browser caches them
* @param {string} location - Path containing all files, relative to the current page
* @param {array} files - Array of strings with file paths relative to folder param - If using in ANY non-localhost context, KEEP AS SHORT AS POSSIBLE!!!!
* @param {function} whenDone - Optional - Runs when all files have been parsed
* @param {function} whenIncr - Optional - Runs every time a file is parsed, useful for progress indication
* @param {function} onFail - Optional - For the event of complete failure - Using the phrase "Something has gone horribly wrong!" somewhere is recommended
* @param {function} whenErr - Optional - Runs when a file is unable to load, return true to prevent running whenDone
* @param {function} totalFail - Optional - For the event of complete failure - Using the phrase "Something has gone horribly wrong!" somewhere is recommended
* @returns {Promise} Promise resolving when all files have been parsed
* @throws Returns false and logs an exception to console if not given an array
*/
function YAPLload(location, files, whenDone = false, whenIncr = false, onFail = false) {
*/
function YAPLload( location, files, whenDone = false, whenIncr = false, whenFail = false, totalFail = false ) {
try { return new Promise( (resolve)=> {
if (files === undefined || !Array.isArray(files)) {
throw "Was not given an array in the files parameter!";
}

YAPLloaded = 0; YAPLfailed = 0;
let shouldStop = false;

// always have folder end in a slash, unless blank, so it makes a file path
let folder = location;
if (folder !== "" && folder.slice(-1) !== "/") folder = folder + '/';

const tagLoader = document.createElement("div");
tagLoader.id = "yet-another-preloader";
tagLoader.style = "position: fixed; top: 99.9vh; left: 0; display: flex; opacity: 0.01; user-select: none; pointer-events: none";
tagLoader.setAttribute('aria-hidden', 'true');
document.body.prepend(tagLoader);
if (folder !== "" && folder.slice(-1) !== "/") folder += "/";

const increment = worked => {
worked ? YAPLloaded++ : YAPLfailed++; // jshint ignore:line
worked ? YAPLloaded++ : YAPLfailed++;

if (shouldStop) return;
if (whenIncr) whenIncr();

if (YAPLloaded + YAPLfailed === files.length) {
console.log(`YAPL: Execution complete! ${YAPLloaded} successful, ${YAPLfailed} failed`);
if (whenDone) whenDone();
// console.log(`YAPL: Execution complete! ${YAPLloaded} successful, ${YAPLfailed} failed`);
if (whenDone) whenDone();
resolve();
}
};
Expand All @@ -54,25 +52,35 @@ try { return new Promise( (resolve)=> {
let done = false;
function good() {
if (done) return;
YAPLtag.appendChild(tag);
// console.log(`YAPL: ${file} loaded successfully!`);
tagLoader.appendChild(tag);
increment(true); done = true;
done = true; increment(true);
tag.removeEventListener("error", bad);
}
function bad() {
if (done) return;
if (whenFail) shouldStop = whenFail();
console.error(`YAPL: ${file} couldn't load!`);
increment(false); done = true;
done = true; increment(false);
}
tag.src = file;
tag.style.width = "1px"; tag.style.height = "1px";


tag.style.width = "2px"; tag.style.height = "2px";
tag.tabIndex = -1;
tag.setAttribute('aria-hidden', 'true');
tag.alt = "";
tag.controls = true;
tag.addEventListener("load", good);
tag.addEventListener("canplay", good);
tag.addEventListener("error", bad);
tag.setAttribute("aria-hidden", "true");
tag.src = file;

tag.addEventListener("error", bad, {once: true});
switch (tag.tagName) {
case "AUDIO": case "VIDEO":
tag.addEventListener("canplay", good, {once: true});
break;
case "IMG":
tag.alt = "";
tag.addEventListener("load", good, {once: true});
break;
}

return true; // returns loadFile as true
};

Expand All @@ -81,7 +89,7 @@ try { return new Promise( (resolve)=> {
switch (type) {
// images
case "webp": case "png": case "gif":
case "jpg": case "jpeg": case "avif":
case "jpg": case "jpeg": case "avif": case "jxl":
tag = new Image();
return loadTag(tag, file);
// sounds
Expand All @@ -93,17 +101,22 @@ try { return new Promise( (resolve)=> {
tag = document.createElement("video");
return loadTag(tag, file);
default:
if (whenFail) shouldStop = whenFail();
console.error(`YAPL: ${file} is unrecognized file type ${type}!`);
return false;
}
};

for (let i of files) loadFile(folder + i, getExtension(i));

console.log(`YAPL: Attempting to load all files...`);
});} catch (e) {
console.error("YAPL: Execution failure! " + e);
if (onFail) onFail();
for (const file of files) {
const ext = (/(?:\.([^.]+))?$/u).exec(file)[1]; // credit for this horrid regex to https://stackoverflow.com/a/680982
const validFile = loadFile(folder + file, ext);
if (!validFile && shouldStop) break;
}

// console.log(`YAPL: Attempting to load files...`);
});} catch (err) {
console.error(`YAPL: Execution failure! ${err}`);
if (totalFail) totalFail();
return false;
}}

Expand Down

0 comments on commit 1ef2908

Please sign in to comment.