Upgrade web assets (#219)

* Update assets

* Upgrade linting and other improvments

* Correct linting

* Correction and type check improvements

* Correct type check lib

* Fix lint pathing for VSCode

* Remove duplicate babel config

* Remove editorconfig root attribute from web subdir

* Use double quotes around message

* Simplify ESLint config

* Update web assets

* Allow AMD loader in WebPack

* Bump web dependencies

* Only include FA icons in-use
This commit is contained in:
Tyler Vigario
2020-11-25 06:08:12 -08:00
committed by GitHub
parent c79d4cf977
commit ff5b1cb1ee
17 changed files with 8517 additions and 5744 deletions
+4 -4
View File
@@ -28,7 +28,7 @@ certificate =
[bot]
username = botamusique
comment = Hi, I'm here to play radio, local music or youtube/soundcloud music. Have fun!
comment = "Hi, I'm here to play radio, local music or youtube/soundcloud music. Have fun!"
# default volume from 0 to 1.
volume = 0.1
stereo = True
@@ -126,10 +126,10 @@ jazz = http://jazz-wr04.ice.infomaniak.ch/jazz-wr04-128.mp3 "Jazz Yeah !"
# ========================================================
# =========================================================
# WARNING: WE DO NOT SUGGEST YOU MODIFY THE FOLLOWING
# PARTS, EXCEPT YOU KNOW WHAT YOU ARE DOING.
# ========================================================
# PARTS, EXCEPT IF YOU KNOW WHAT YOU ARE DOING.
# =========================================================
[commands]
# This is a list of characters the bot recognizes as command prefix.
command_symbol = !:
+1 -1
View File
@@ -22,7 +22,7 @@ port = 64738
# 'username' is the user name of the bot.
# 'comment' is the comment displayed by the bot.
#username = botamusique
#comment = Hi, I'm here to play radio, local music or youtube/soundcloud music. Have fun!
#comment = "Hi, I'm here to play radio, local music or youtube/soundcloud music. Have fun!"
# 'language': Available languages can be found inside lang/ folder.
#language=en_US
-2
View File
@@ -1,5 +1,3 @@
root = true
[*]
charset = utf-8
insert_final_newline = true
+16 -14
View File
@@ -1,38 +1,40 @@
{
"parser": "@babel/eslint-parser",
"env": {
"browser": true,
"es6": true,
"es2017": true,
"es2020": true,
"es2021": true,
"jquery": true
},
"plugins": [
"node",
"@babel",
"import",
"jsdoc"
"jsdoc",
"jquery"
],
"extends": [
"eslint:recommended",
"google",
"plugin:node/recommended-module",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:jsdoc/recommended"
"plugin:jsdoc/recommended",
"plugin:jquery/deprecated"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parser": "babel-eslint",
"rules": {
"require-jsdoc": "off",
"valid-jsdoc": "off",
"jsdoc/require-jsdoc": "off",
"max-len": ["warn", {
"code": 120
}],
"linebreak-style": "off",
"jsdoc/require-jsdoc": "off",
"import/unambiguous": "error",
"import/no-commonjs": "error",
"import/no-amd": "error",
"linebreak-style": "off"
"import/no-nodejs-modules": "error",
"import/no-deprecated": "error",
"import/extensions": ["error", "always"],
"import/no-unresolved": ["error", {
"commonjs": true
}]
}
}
+1
View File
@@ -0,0 +1 @@
package-lock.json text eol=lf
+1
View File
@@ -1 +1,2 @@
!*
node_modules/
+5
View File
@@ -0,0 +1,5 @@
{
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
+15 -5
View File
@@ -1,13 +1,23 @@
import {library, dom} from '@fortawesome/fontawesome-svg-core/index.es';
import {fas} from '@fortawesome/free-solid-svg-icons/index.es';
import {far} from '@fortawesome/free-regular-svg-icons/index.es';
library.add(fas, far);
import {library, dom} from '@fortawesome/fontawesome-svg-core/index.es.js';
import {
faTimesCircle, faPlus, faCheck, faUpload, faTimes, faTrash, faPlay, faPause, faFastForward, faPlayCircle, faLightbulb,
faTrashAlt, faDownload, faSyncAlt, faEdit, faVolumeUp, faVolumeDown, faRobot, faRedo, faRandom, faTasks
} from '@fortawesome/free-solid-svg-icons/index.es.js';
import {faFileAlt} from '@fortawesome/free-regular-svg-icons/index.es.js';
library.add(
// Solid
faTimesCircle, faPlus, faCheck, faUpload, faTimes, faTrash, faPlay, faPause, faFastForward, faPlayCircle, faLightbulb,
faTrashAlt, faDownload, faSyncAlt, faEdit, faVolumeUp, faVolumeDown, faRobot, faRedo, faRandom, faTasks,
// Regular
faFileAlt
);
// Old application code
import './main.mjs';
// New application code
import Theme from './theme.mjs';
import Theme from './lib/theme.mjs';
document.addEventListener('DOMContentLoaded', () => {
Theme.init();
+42
View File
@@ -0,0 +1,42 @@
import {validateString, validateNumber} from './type.mjs';
/**
* Truncate string length by characters.
*
* @param {string} text String to format.
* @param {number} limit Maximum number of characters in resulting string.
* @param {string} ending Ending to use if string is trucated.
*
* @returns {string} Formatted string.
*/
export function limitChars(text, limit = 50, ending = '...') {
validateString(text);
validateNumber(limit);
validateString(ending);
// Check if string is already below limit
if (text.length <= limit) {
return text;
}
// Limit string length by characters
return text.substring(0, limit - ending.length) + ending;
}
/**
* Truncate string length by words.
*
* @param {string} text String to format.
* @param {number} limit Maximum number of words in resulting string.
* @param {string} ending Ending to use if string is trucated.
*
* @returns {string} Formatted string.
*/
export function limitWords(text, limit = 10, ending = '...') {
validateString(text);
validateNumber(limit);
validateString(ending);
// Limit string length by words
return text.split(' ').splice(0, limit).join(' ') + ending;
}
+1 -1
View File
@@ -1,6 +1,6 @@
export default class {
/**
* @property {boolean} #dark Interal state for dark theme activation.
* @property {boolean} dark Interal state for dark theme activation.
* @private
*/
static #dark = false;
+65
View File
@@ -0,0 +1,65 @@
/**
* Checks if `value` is the type `Object` excluding `Function` and `null`
*
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, otherwise `false`.
*/
export function isObject(value) {
return (Object.prototype.toString.call(value) === '[object Object]');
}
/**
* Checks if `value` is the type `string`
*
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a string, otherwise `false`.
*/
export function isString(value) {
return (typeof value === 'string');
}
/**
* Checks if `value` is the type `number`
*
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a number, otherwise `false`.
*/
export function isNumber(value) {
return (typeof value === 'number');
}
/**
* Validate parameter is of type object.
*
* @param {string} value Variable to validate.
* @throws Error if not an object.
*/
export function validateObject(value) {
if (!isObject(value)) {
throw new TypeError('Parameter "value" must be of type object.');
}
}
/**
* Validate parameter is of type string.
*
* @param {string} value Variable to validate.
* @throws Error if not an string.
*/
export function validateString(value) {
if (!isString(value)) {
throw new TypeError('Parameter "value" must be of type string.');
}
}
/**
* Validate parameter is of type number.
*
* @param {number} value Variable to validate.
* @throws Error if not an number.
*/
export function validateNumber(value) {
if (!isNumber(value)) {
throw new TypeError('Parameter "value" must be of type number.');
}
}
+12 -28
View File
@@ -3,13 +3,13 @@ export function isOverflown(element) {
}
export function hash(string) {
if (typeof string != "string") return 0;
if (typeof string != 'string') return 0;
let hash = 0;
if (string.length === 0) {
return hash;
}
for (let i = 0; i < string.length; i++) {
let char = string.charCodeAt(i);
const char = string.charCodeAt(i);
hash = ((hash<<5)-hash)+char;
hash = hash & hash; // Convert to 32bit integer
}
@@ -17,24 +17,25 @@ export function hash(string) {
}
export function getColor(string) {
let num = hash(string) % 8;
const num = hash(string) % 8;
switch (num) {
case 0:
return "primary";
return 'primary';
case 1:
return "secondary";
return 'secondary';
case 2:
return "success";
return 'success';
case 3:
return "danger";
return 'danger';
case 4:
return "warning";
return 'warning';
case 5:
return "info";
return 'info';
case 6:
return "light";
return 'light';
case 7:
return "dark";
return 'dark';
}
}
@@ -52,20 +53,3 @@ export function secondsToStr(seconds) {
const secs = seconds % 60;
return ('00' + mins).slice(-2) + ':' + ('00' + secs).slice(-2);
}
export function coverArtString(title) {
let nameOfSong = "";
// The maximum length before we start truncating
const maxLength = 50;
if (title.length > maxLength) {
// Name = longTitleTooLongToBeAGoodAltTex...
nameOfSong = title.substr(0, maxLength) + "\u2026";
} else {
// Name = shortTitle
nameOfSong = title;
}
return 'Cover art for ' + nameOfSong;
}
+35 -33
View File
@@ -1,18 +1,18 @@
import 'jquery/src/jquery';
import 'jquery-migrate/src/migrate';
import Popper from 'popper.js/dist/esm/popper';
import 'jquery/src/jquery.js';
import 'jquery-migrate/src/migrate.js';
import Popper from 'popper.js/dist/esm/popper.js';
import {
Modal,
Toast,
Tooltip,
} from 'bootstrap/js/src/index';
} from 'bootstrap/js/src/index.js';
import {
getColor,
isOverflown,
setProgressBar,
secondsToStr,
coverArtString,
} from './util';
} from './lib/util.mjs';
import {limitChars} from './lib/text.mjs';
$('#uploadSelectFile').on('change', function() {
// get the file name
@@ -125,7 +125,7 @@ function addPlaylistItem(item) {
pl_title_element.html(item.title);
pl_artist_element.html(item.artist);
pl_thumb_element.attr('src', item.thumbnail);
pl_thumb_element.attr('alt', coverArtString(item.title));
pl_thumb_element.attr('alt', limitChars(item.title));
pl_type_element.html(item.type);
pl_path_element.html(item.path);
@@ -488,8 +488,8 @@ function bindLibraryResultEvent() {
);
}
const lib_filter_tag_group = $("#filter-tags");
const lib_filter_tag_element = $(".filter-tag");
const lib_filter_tag_group = $('#filter-tags');
const lib_filter_tag_element = $('.filter-tag');
const lib_group = $('#library-group');
const id_element = $('.library-item-id');
@@ -503,7 +503,7 @@ const tag_edit_element = $('.library-item-edit');
// var notag_element = $(".library-item-notag");
// var tag_element = $(".library-item-tag");
let library_tags = [];
const library_tags = [];
function updateLibraryControls() {
$.ajax({
@@ -519,46 +519,46 @@ function updateLibraryControls(){
}
function displayLibraryControls(data) {
$("#maxUploadFileSize").val(data.max_upload_file_size);
$('#maxUploadFileSize').val(data.max_upload_file_size);
if (data.upload_enabled) {
$("#uploadDisabled").val("false");
$("#upload").show();
$('#uploadDisabled').val('false');
$('#upload').show();
} else {
$("#uploadDisabled").val("true");
$("#upload").hide();
$('#uploadDisabled').val('true');
$('#upload').hide();
}
if (data.delete_allowed) {
$("#deleteAllowed").val("true");
$(".library-delete").show();
$('#deleteAllowed').val('true');
$('.library-delete').show();
} else {
$("#uploadDisabled").val("false");
$(".library-delete").hide();
$('#uploadDisabled').val('false');
$('.library-delete').hide();
}
let select = $("#filter-dir");
let dataList = $("#upload-target-dirs");
select.find("option").remove();
dataList.find("option").remove();
const select = $('#filter-dir');
const dataList = $('#upload-target-dirs');
select.find('option').remove();
dataList.find('option').remove();
if (data.dirs.length > 0) {
console.log(data.dirs);
data.dirs.forEach(function(dir) {
$("<option value=\"" + dir + "\">" + dir + "</option>").appendTo(select);
$("<option value=\"" + dir + "\">").appendTo(dataList);
$('<option value="' + dir + '">' + dir + '</option>').appendTo(select);
$('<option value="' + dir + '">').appendTo(dataList);
});
}
// ----- Tag filters -----
let tags = [];
let tags_dict = {};
$(".filter-tag").each(function(i, tag_element){
const tags = [];
const tags_dict = {};
$('.filter-tag').each(function(i, tag_element) {
tags_dict[tag_element.innerHTML] = tag_element;
tags.push(tag_element.innerHTML);
});
if (data.tags.length > 0) {
for (const tag of data.tags) {
if (tags.includes(tag)) {
let index = tags.indexOf(tag);
const index = tags.indexOf(tag);
tags.splice(index, 1);
} else {
const tag_copy = lib_filter_tag_element.clone();
@@ -583,7 +583,7 @@ function displayLibraryControls(data){
tags_dict[tag].remove();
}
} else {
$(".filter-tag").remove();
$('.filter-tag').remove();
}
}
@@ -592,7 +592,7 @@ function addResultItem(item) {
title_element.html(item.title);
artist_element.html(item.artist ? ('- ' + item.artist) : '');
thumb_element.attr('src', item.thumb);
thumb_element.attr('alt', coverArtString(item.title));
thumb_element.attr('alt', limitChars(item.title));
type_element.html('[' + item.type + ']');
path_element.html(item.path);
@@ -890,7 +890,9 @@ document.getElementById('addTagModalSubmit').addEventListener('click', () => {
id: add_tag_modal_item_id.val(),
tags: tags.join(','),
},
complete: function () { updateResults(active_page); },
complete: function() {
updateResults(active_page);
},
});
});
@@ -1196,7 +1198,7 @@ function updatePlayerInfo(item) {
playerTitle.textContent = item.title;
playerArtist.textContent = item.artist;
playerArtwork.setAttribute('src', item.thumbnail);
playerArtwork.setAttribute('alt', coverArtString(item.title));
playerArtwork.setAttribute('alt', limitChars(item.title));
if (isOverflown(playerTitle)) {
playerTitle.classList.add('scrolling');
+8128 -5465
View File
File diff suppressed because it is too large Load Diff
+26 -29
View File
@@ -4,7 +4,6 @@
"type": "module",
"scripts": {
"lint": "eslint --config .eslintrc.json js/ --ext .mjs",
"lint:fix": "npm run lint -- --fix",
"build": "webpack --config webpack.config.cjs --progress",
"test": "echo \"Error: no test specified\" && exit 1"
},
@@ -19,38 +18,36 @@
},
"homepage": "https://github.com/azlux/botamusique#readme",
"devDependencies": {
"@babel/core": "^7.11.1",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/preset-env": "^7.11.0",
"autoprefixer": "^9.8.6",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"core-js": "^3.6.5",
"css-loader": "^4.2.1",
"eslint": "^7.7.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jsdoc": "^30.2.2",
"eslint-plugin-node": "^11.1.0",
"html-webpack-plugin": "^4.3.0",
"mini-css-extract-plugin": "^0.10.0",
"postcss-loader": "^3.0.0",
"@babel/core": "^7.12.9",
"@babel/eslint-parser": "^7.12.1",
"@babel/eslint-plugin": "^7.12.1",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/preset-env": "^7.12.7",
"autoprefixer": "^10.0.2",
"babel-loader": "^8.2.1",
"core-js": "^3.7.0",
"css-loader": "^5.0.1",
"eslint": "^7.14.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jquery": "^1.5.1",
"eslint-plugin-jsdoc": "^30.7.8",
"html-webpack-plugin": "^4.5.0",
"mini-css-extract-plugin": "^1.3.1",
"postcss-loader": "^4.1.0",
"regenerator-runtime": "^0.13.7",
"sass": "^1.26.10",
"sass-loader": "^9.0.3",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
"sass": "^1.29.0",
"sass-loader": "^10.1.0",
"webpack": "^5.6.0",
"webpack-cli": "^4.2.0"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.30",
"@fortawesome/free-brands-svg-icons": "^5.14.0",
"@fortawesome/free-regular-svg-icons": "^5.14.0",
"@fortawesome/free-solid-svg-icons": "^5.14.0",
"bootstrap": "^4.5.2",
"bootswatch": "^4.5.2",
"@fortawesome/fontawesome-svg-core": "^1.2.32",
"@fortawesome/free-regular-svg-icons": "^5.15.1",
"@fortawesome/free-solid-svg-icons": "^5.15.1",
"bootstrap": "^4.5.3",
"bootswatch": "^4.5.3",
"jquery": "^3.5.1",
"jquery-migrate": "^3.3.1",
"jquery-migrate": "^3.3.2",
"popper.js": "^1.16.1"
}
}
+7
View File
@@ -0,0 +1,7 @@
{
"parserOptions": {
"babelOptions": {
"configFile": "./web/babel.config.json"
}
}
}
+13 -17
View File
@@ -4,6 +4,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production',
devtool: 'source-map',
entry: {
main: [
'./js/app.mjs',
@@ -13,16 +14,9 @@ module.exports = {
'./sass/app-dark.scss',
],
},
devtool: 'source-map',
/*optimization: {
splitChunks: {
chunks: 'all',
},
},*/
output: {
filename: 'static/js/[name].js',
path: path.resolve(__dirname, '../'),
// ecmaVersion: 5,
},
plugins: [
new MiniCssExtractPlugin({
@@ -48,10 +42,15 @@ module.exports = {
{
loader: 'postcss-loader',
options: {
plugins: function() {
return [
require('autoprefixer'),
];
postcssOptions: {
plugins: [
[
'autoprefixer',
{
// Options
},
],
],
},
},
},
@@ -61,6 +60,9 @@ module.exports = {
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
resolve: {
fullySpecified: false,
},
use: {
loader: 'babel-loader',
options: {
@@ -73,15 +75,9 @@ module.exports = {
},
],
],
plugins: [
'@babel/plugin-proposal-class-properties',
],
},
},
},
],
},
/* experiments: {
mjs: true,
},*/
};