added tag26
This commit is contained in:
@@ -400,14 +400,14 @@ Projektarbeit
|
|||||||
|
|
||||||
- Import von Modulen in JS (Browserseitig)
|
- Import von Modulen in JS (Browserseitig)
|
||||||
- Separation of Concerns
|
- Separation of Concerns
|
||||||
- Projekt: Produktmanager II mit JSON
|
- Projekt: Produktmanager final
|
||||||
- DOM Traversal Befehle & alle DOM Bereiche
|
- DOM Traversal Befehle & alle DOM Bereiche
|
||||||
- insertBefore(), appendChil(), append(), prepend(), before(), after()
|
- insertBefore(), appendChild(), append(), prepend(), before(), after()
|
||||||
- Refactoring von Produktmanager mit Template
|
- Refactoring von Produktmanager mit Template
|
||||||
|
|
||||||
**Übungen:**
|
**Übungen:**
|
||||||
|
|
||||||
Übung 17 - 18 + optionale Übungen
|
Übung 18 + optionale Übungen
|
||||||
**Projektarbeit / Content Factory**
|
**Projektarbeit / Content Factory**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
@@ -97,13 +97,38 @@
|
|||||||
const $ = (qs) => document.querySelector(qs);
|
const $ = (qs) => document.querySelector(qs);
|
||||||
const $$ = (qs) => Array.from(document.querySelectorAll(qs));
|
const $$ = (qs) => Array.from(document.querySelectorAll(qs));
|
||||||
|
|
||||||
|
const productList = $('#product_specification');
|
||||||
|
const orderedList = $('.model');
|
||||||
|
const selectBox = $('#buy_form select');
|
||||||
|
|
||||||
// Übung 15: — Teil 7
|
// Übung 15: — Teil 7
|
||||||
// Verändere die Produktseite der Binär-Tasse mithilfe von JavaScript. Du kannst wieder die JS-Konsole verwenden.
|
// Verändere die Produktseite der Binär-Tasse mithilfe von JavaScript. Du kannst wieder die JS-Konsole verwenden.
|
||||||
|
|
||||||
// 1. Füge in der Liste der Product Specifications mithilfe von JavaScript folgenden Listenpunkt hinzu:
|
// 1. Füge in der Liste der Product Specifications mithilfe von JavaScript folgenden Listenpunkt hinzu:
|
||||||
// Capacity: 11 oz.
|
// Capacity: 11 oz.
|
||||||
|
$('#product_specification').innerHTML += '<li>Capacity: 11 oz.</li>';
|
||||||
|
|
||||||
|
const newListItem = document.createElement('li');
|
||||||
|
newListItem.textContent = 'Capacity: 11 oz.';
|
||||||
|
newListItem.style.color = 'orange';
|
||||||
|
newListItem.style.backgroundColor = 'black';
|
||||||
|
|
||||||
|
productList.appendChild(newListItem); //productList.append(newListItem)
|
||||||
|
|
||||||
// 2. Erweitere die Select-Box neben dem buy-Button mithilfe von JavaScript um den Eintrag: 5 items.
|
// 2. Erweitere die Select-Box neben dem buy-Button mithilfe von JavaScript um den Eintrag: 5 items.
|
||||||
|
const newOption = document.createElement('option');
|
||||||
|
newOption.textContent = '5 items';
|
||||||
|
selectBox.append(newOption);
|
||||||
|
// newOption.style.textContent = 'red';
|
||||||
|
|
||||||
|
$('#buy_form select').innerHTML += '<option>5 items</option>';
|
||||||
|
|
||||||
|
// optional Listenpunkt in ordered List (.model) hinzugefügt
|
||||||
|
const listItem2 = document.createElement('li');
|
||||||
|
listItem2.textContent = 'fuente item hinzugefügt als Newitem';
|
||||||
|
listItem2.style.color = 'orange';
|
||||||
|
listItem2.style.backgroundColor = 'black';
|
||||||
|
orderedList.append(listItem2);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
@@ -101,8 +101,14 @@
|
|||||||
// Verändere erneut die Produktseite der Binär-Tasse mithilfe von JavaScript. Du kannst auch hier wieder die JS-Konsole verwenden.
|
// Verändere erneut die Produktseite der Binär-Tasse mithilfe von JavaScript. Du kannst auch hier wieder die JS-Konsole verwenden.
|
||||||
|
|
||||||
// 1. Entferne die Überschrift Description mit der remove-Methode.
|
// 1. Entferne die Überschrift Description mit der remove-Methode.
|
||||||
|
const firstH2El = $('h2');
|
||||||
|
firstH2El.remove(); // IE 11
|
||||||
|
// firstH2El.parentNode.removeChild(firstH2El)
|
||||||
|
|
||||||
// 2. Entferne mit der remove-Methode den Text "010010000100111101010100" aus der Hauptüberschrift.
|
// 2. Entferne mit der remove-Methode den Text "010010000100111101010100" aus der Hauptüberschrift.
|
||||||
|
const remSpan0100 = $('h1.article > span.keyword'); // $('h1 .keyword');
|
||||||
|
remSpan0100.remove();
|
||||||
|
// remSpan0100.parentNode.removeChild(remSpan0100);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
@@ -105,6 +105,34 @@
|
|||||||
// Capacity: 11 oz.
|
// Capacity: 11 oz.
|
||||||
|
|
||||||
// Füge den Listenpunkt aber dieses Mal nicht am Ende der Liste ein, sondern vor dem Eintrag Materials: Ceramic.
|
// Füge den Listenpunkt aber dieses Mal nicht am Ende der Liste ein, sondern vor dem Eintrag Materials: Ceramic.
|
||||||
|
const list = $('#product_specification');
|
||||||
|
const item5 = $$('#product_specification li')[4];
|
||||||
|
// const listItem5 = $('#product_specification li:nth-child(5)');
|
||||||
|
// const listItem5 = $('#product_specification').lastElementChild.previousElementSibling; // DOM Traversal
|
||||||
|
|
||||||
|
console.log(item5);
|
||||||
|
|
||||||
|
const newList = document.createElement('li');
|
||||||
|
newList.textContent = 'Capacity: 11 oz.';
|
||||||
|
|
||||||
|
list.insertBefore(newList, item5);
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
|
||||||
|
const prodSpecEl = $('#product_specification');
|
||||||
|
const prodSpecLiEls = $$('#product_specification li');
|
||||||
|
|
||||||
|
// einzufügenden Listenpunkt erstellen
|
||||||
|
const liCapacity = document.createElement('li');
|
||||||
|
liCapacity.textContent = 'Capacity: 11 oz.';
|
||||||
|
|
||||||
|
// Nu suchen an welcher Stelle - also den listenpunkt mit dem text Materials: Ceramic
|
||||||
|
const refLi = prodSpecLiEls.find((el) => {
|
||||||
|
return el.textContent === 'Materials: Ceramic';
|
||||||
|
});
|
||||||
|
|
||||||
|
// und einfügen
|
||||||
|
prodSpecEl.insertBefore(liCapacity, refLi);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
const onClickRemove = (e) => {
|
const onClickRemove = (e) => {
|
||||||
const btnEl = e.currentTarget;
|
const btnEl = e.currentTarget;
|
||||||
const currentRowEl = btnEl.parentNode.parentNode;
|
const currentRowEl = btnEl.parentNode.parentNode; // parentNode -> td - parentNode -> tr
|
||||||
|
|
||||||
currentRowEl.remove(); // kein IE11 support
|
currentRowEl.remove(); // kein IE11 support
|
||||||
// DOM.tBody.removeChild(currentRowEl);
|
// DOM.tBody.removeChild(currentRowEl);
|
||||||
|
|||||||
11
03_dom/unterricht/tag26/01_product-manager-final/.gitignore
vendored
Normal file
11
03_dom/unterricht/tag26/01_product-manager-final/.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
.DS_Store
|
||||||
|
*.log
|
||||||
|
.vite/
|
||||||
|
coverage/
|
||||||
|
.idea/
|
||||||
|
# .vscode/
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
*,
|
||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile first */
|
||||||
|
.product-manager table tfoot .row > * {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.product-manager table tfoot .row > * {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-manager table .th-actions {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-manager table tbody td button {
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
// === DOM & VARS =======
|
||||||
|
|
||||||
|
const module = document.querySelector('.product-manager') || console.error('Product Manager not found');
|
||||||
|
|
||||||
|
if (!module) return;
|
||||||
|
|
||||||
|
const DOM = {
|
||||||
|
module,
|
||||||
|
table: module.querySelector('.table-products'),
|
||||||
|
tBody: module.querySelector('tbody'),
|
||||||
|
inputName: module.querySelector('.input-product-name'),
|
||||||
|
inputPrice: module.querySelector('.input-product-price'),
|
||||||
|
btnAdd: module.querySelector('.button-product-add'),
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(DOM);
|
||||||
|
|
||||||
|
// === INIT =============
|
||||||
|
const init = () => {
|
||||||
|
console.log('init');
|
||||||
|
// Funktionaufrufe zu beginn der Anwendung
|
||||||
|
initProducts();
|
||||||
|
// Event-Lauscher zu beginn der Anwendung
|
||||||
|
DOM.btnAdd.addEventListener('click', onClickAdd);
|
||||||
|
};
|
||||||
|
|
||||||
|
// === EVENTHANDLER =====
|
||||||
|
const onClickAdd = (e) => {
|
||||||
|
console.log('click');
|
||||||
|
|
||||||
|
const product = {
|
||||||
|
name: DOM.inputName.value,
|
||||||
|
price: Number(DOM.inputPrice.value),
|
||||||
|
};
|
||||||
|
|
||||||
|
addProduct(product);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClickRemove = (e) => {
|
||||||
|
const btnEl = e.currentTarget;
|
||||||
|
const currentRowEl = btnEl.parentNode.parentNode; // parentNode -> td - parentNode -> tr
|
||||||
|
|
||||||
|
currentRowEl.remove(); // kein IE11 support
|
||||||
|
// DOM.tBody.removeChild(currentRowEl);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClickMoveUp = (e) => {
|
||||||
|
const btnEl = e.currentTarget;
|
||||||
|
const currentRowEl = btnEl.parentNode.parentNode; // aktuelle Zeile (tr) mit dem Button
|
||||||
|
|
||||||
|
// ParentNode.insertBefore(referenceElement, targetElement)
|
||||||
|
DOM.tBody.insertBefore(currentRowEl, currentRowEl.previousElementSibling);
|
||||||
|
|
||||||
|
console.log('move up');
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClickMoveDown = (e) => {
|
||||||
|
const btnEl = e.currentTarget;
|
||||||
|
const currentRowEl = btnEl.parentNode.parentNode; // aktuelle Zeile (tr) mit dem Button
|
||||||
|
|
||||||
|
// ParentNode.insertBefore(referenceElement, targetElement)
|
||||||
|
DOM.tBody.insertBefore(currentRowEl, currentRowEl.nextElementSibling.nextElementSibling);
|
||||||
|
console.log('move down');
|
||||||
|
};
|
||||||
|
|
||||||
|
// === XHR/FETCH ========
|
||||||
|
|
||||||
|
// === FUNCTIONS ========
|
||||||
|
const initProducts = () => {
|
||||||
|
PRODUCTS.forEach((product) => {
|
||||||
|
addProduct(product);
|
||||||
|
});
|
||||||
|
|
||||||
|
// PRODUCTS.forEach(addProduct);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addProduct = (product) => {
|
||||||
|
const { name, price } = product;
|
||||||
|
|
||||||
|
const tdName = createTd(name, 'td-name');
|
||||||
|
const tdPrice = createTd(price, 'td-price');
|
||||||
|
const tdActions = createTdWithActions();
|
||||||
|
|
||||||
|
const trEl = createTr(tdName, tdPrice, tdActions);
|
||||||
|
|
||||||
|
DOM.tBody.appendChild(trEl); // Im DOM hinzufügen
|
||||||
|
};
|
||||||
|
|
||||||
|
const createTdWithActions = () => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.classList.add('td-actions');
|
||||||
|
|
||||||
|
const btnRemove = createButtonRemove();
|
||||||
|
const btnMoveUp = createButtonMoveUp();
|
||||||
|
const btnMoveDown = createButtonMoveDown();
|
||||||
|
|
||||||
|
// td.append(btnRemove, btnMoveUp, btnMoveDown)
|
||||||
|
td.appendChild(btnRemove);
|
||||||
|
td.appendChild(btnMoveUp);
|
||||||
|
td.appendChild(btnMoveDown);
|
||||||
|
|
||||||
|
return td;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createButtonRemove = () => {
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
const icon = document.createElement('i');
|
||||||
|
const span = document.createElement('span');
|
||||||
|
|
||||||
|
btn.classList.add('btn', 'btn-sm', 'btn-danger', 'button-product-remove');
|
||||||
|
icon.classList.add('fas', 'fa-trash-can');
|
||||||
|
span.classList.add('visually-hidden');
|
||||||
|
span.textContent = 'Remove Product';
|
||||||
|
|
||||||
|
btn.addEventListener('click', onClickRemove);
|
||||||
|
// btn.append(icon,span)
|
||||||
|
btn.appendChild(icon);
|
||||||
|
btn.appendChild(span);
|
||||||
|
|
||||||
|
return btn;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createButtonMoveUp = () => {
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
const icon = document.createElement('i');
|
||||||
|
const span = document.createElement('span');
|
||||||
|
|
||||||
|
btn.classList.add('btn', 'btn-sm', 'btn-secondary', 'button-product-move-up');
|
||||||
|
icon.classList.add('fas', 'fa-caret-up');
|
||||||
|
span.classList.add('visually-hidden');
|
||||||
|
span.textContent = 'Move Up';
|
||||||
|
|
||||||
|
btn.addEventListener('click', onClickMoveUp);
|
||||||
|
// btn.append(icon,span)
|
||||||
|
btn.appendChild(icon);
|
||||||
|
btn.appendChild(span);
|
||||||
|
|
||||||
|
return btn;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createButtonMoveDown = () => {
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
const icon = document.createElement('i');
|
||||||
|
const span = document.createElement('span');
|
||||||
|
|
||||||
|
btn.classList.add('btn', 'btn-sm', 'btn-secondary', 'button-product-move-down');
|
||||||
|
icon.classList.add('fas', 'fa-caret-down');
|
||||||
|
span.classList.add('visually-hidden');
|
||||||
|
span.textContent = 'Move Down';
|
||||||
|
|
||||||
|
btn.addEventListener('click', onClickMoveDown);
|
||||||
|
// btn.append(icon,span)
|
||||||
|
btn.appendChild(icon);
|
||||||
|
btn.appendChild(span);
|
||||||
|
|
||||||
|
return btn;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createTd = (text, className = '') => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.classList.add(className);
|
||||||
|
td.textContent = text;
|
||||||
|
|
||||||
|
return td;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createTr = (...tds) => {
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
tr.append(...tds);
|
||||||
|
|
||||||
|
// tds.forEach((td) => {
|
||||||
|
// tr.appendChild(td);
|
||||||
|
// });
|
||||||
|
return tr;
|
||||||
|
};
|
||||||
|
|
||||||
|
init();
|
||||||
|
})();
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// Konfigurationsvariable
|
||||||
|
const PRODUCTS = [
|
||||||
|
{ name: '3Doodler 3D Printing Pen', price: 29.99 },
|
||||||
|
{ name: 'Powerstation 5- E. Maximus Chargus', price: 44.95 },
|
||||||
|
{ name: '8-Bit Legendary Hero Heat-Change Mug', price: 6.99 },
|
||||||
|
{ name: '16-Bit Legendary Hero Heat-Change Mug', price: 10.99 },
|
||||||
|
];
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
{ "name": "3Doodler 3D Printing Pen", "price": 29.99 },
|
||||||
|
{ "name": "Powerstation 5- E. Maximus Chargus", "price": 44.95 },
|
||||||
|
{ "name": "8-Bit Legendary Hero Heat-Change Mug", "price": 6.99 }
|
||||||
|
]
|
||||||
89
03_dom/unterricht/tag26/01_product-manager-final/index.html
Normal file
89
03_dom/unterricht/tag26/01_product-manager-final/index.html
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Product Manager</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css" />
|
||||||
|
<link rel="stylesheet" href="assets/css/main.css" />
|
||||||
|
<script src="data/products.js"></script>
|
||||||
|
<script src="assets/js/main.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<div class="product-manager my-5">
|
||||||
|
<div class="container">
|
||||||
|
<!-- table.table.table-striped.table-products>(thead.table-dark>tr>th{Name}+th{Price in €})+tbody>tr>td*2 -->
|
||||||
|
<table class="table table-striped table-products">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th class="th-name">Name</th>
|
||||||
|
<th class="th-price">Price in €</th>
|
||||||
|
<th class="th-actions">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- <tr>
|
||||||
|
<td class="td-name">[PRODUCT_NAME]</td>
|
||||||
|
<td class="td-price">[PRODUCT_PRICE]</td>
|
||||||
|
<td class="td-actions">
|
||||||
|
<button class="btn btn-sm btn-danger button-product-remove">
|
||||||
|
<i class="fas fa-trash-can"></i>
|
||||||
|
<span class="visually-hidden">Remove Product</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-secondary button-product-move-up">
|
||||||
|
<i class="fas fa-caret-up"></i>
|
||||||
|
<span class="visually-hidden">Move Up</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-secondary button-product-move-down">
|
||||||
|
<i class="fas fa-caret-down"></i>
|
||||||
|
<span class="visually-hidden">Move Down</span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr> -->
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-6 col-lg-6">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="form-control input-product-name"
|
||||||
|
name="product-name"
|
||||||
|
placeholder="Insert product name"
|
||||||
|
aria-label="Product Name" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-6 col-lg-3">
|
||||||
|
<div class="input-group">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name="product-price"
|
||||||
|
class="form-control input-product-price"
|
||||||
|
placeholder="00.00"
|
||||||
|
aria-label="Product Price"
|
||||||
|
step="0.01"
|
||||||
|
min="0" />
|
||||||
|
<span class="input-group-text">€</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-6 col-lg">
|
||||||
|
<button class="btn btn-dark button-product-add">
|
||||||
|
<i class="fas fa-plus"></i>
|
||||||
|
Add product
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- ▲ /row ▲ -->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "01_product-manager",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"type": "module"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user