const parseValue = str => {
const values = str.match(/[^\s,]+/g) || [ null ];
return values.length > 1 ? values : values[0];
};
const parseStyleStr = str =>
str.split(';').reduce((acc, n) => {
const [ k, v ] = n.split(':').map(n => n.trim());
if (k && v) {
const f = [...v.matchAll(/([\w]+?)\((.+?)\)/g)];
acc[k] = f.length
? Object.fromEntries(f.map(n => [ n[1], parseValue(n[2]) ]))
: parseValue(v);
}
return acc;
}, {});
Хорошо бы если на чистом css
но и js тоже можно
document.addEventListener('click', ({ target: { tagName, parentNode: p } }) => {
if (tagName === 'SUMMARY') {
document.querySelectorAll('details').forEach(n => n.open = n.open && n === p);
}
});
// или
const details = document.querySelectorAll('details');
const onClick = e => details.forEach(n => n.open = n.open && n === e.target.parentNode);
details.forEach(n => n.children[0].addEventListener('click', onClick));
const obj = arr.find(n => n.id === newObj.id);
if (obj) {
obj.counter++;
} else {
arr.push({ ...newObj, counter: 1 });
}
on
на one
. Но что если запрос окажется неудачным? Наверное, надо оставить пользователю возможность повторить действие. Вон, у вас там класс добавляется - так проверяйте его наличие, если уже есть, ничего делать не надо; также добавьте обработку неудавшихся запросов, там надо будет класс снять. Object.values(arr1.reduce((acc, { user_id: id, ...n }) => {
Object.entries(n).forEach(([ k, v ]) => acc[id][k] = (acc[id][k] || 0) + v);
return acc;
}, Object.fromEntries(arr2.map(n => [ n.id, {...n} ]))))
Map
:[...arr1.reduce((acc, { user_id: id, ...n }) => {
const obj = acc.get(id);
Object.entries(n).forEach(([ k, v ]) => obj[k] = (obj[k] || 0) + v);
return acc;
}, new Map(arr2.map(n => [ n.id, {...n} ]))).values()]
Object.values
извлекаем данные из объекта через map
по исходному массиву:arr2.map(function(n) {
return this[n.id];
}, arr1.reduce((acc, { user_id: id, ...n }) => (
Object.keys(n).forEach(k => acc[id][k] = (acc[id][k] || 0) + n[k]),
acc
), Object.fromEntries(arr2.map(n => [ n.id, {...n} ]))))
const getReversedPaths = (arr, path = []) =>
arr.reduce((acc, { childItems, ...item }) => {
path.push(item);
if (childItems) {
acc.push(...getReversedPaths(childItems, path));
} else {
acc.push(path.length > 1
? path.map(({ packingLevel }, i, a) => ({ ...a[a.length - i - 1], packingLevel }))
: [ path[0] ]
);
}
path.pop();
return acc;
}, []);
const reverseThere = arr =>
getReversedPaths(arr).map(n =>
n.reduceRight((child, parent) => ({ ...parent, childItems: [ child ] }))
);
const reverseBackAgain = arr =>
(function createTree(arr) {
return Object.values(arr.reduce((acc, [ head, ...tail ]) => {
if (tail.length) {
(acc[head.name] = acc[head.name] || { ...head, childItems: [] }).childItems.push(tail);
} else {
acc[head.name] = head;
}
return acc;
}, {})).map(n => (n.childItems && (n.childItems = createTree(n.childItems)), n));
})(getReversedPaths(arr));
const newArr2 = arr2.filter(n => arr1.some(m => m === n.name));
// или
const obj2 = arr2.reduce((acc, n) => (
(acc[n.name] = acc[n.name] ?? []).push(n),
acc
), {});
const newArr2 = arr1.flatMap(n => obj2[n] ?? []);
// или
const newArr2 = [];
for (const n of arr2) {
for (const m of arr1) {
if (m === n.name) {
newArr2.push(n);
break;
}
}
}
arr2.reduceRight((_, n, i, a) => ~arr1.indexOf(n.name) || a.splice(i, 1), null);
// или
arr2.splice(0, arr2.length, ...arr2.filter(function(n) {
return this.has(n.name);
}, new Set(arr1)));
// или
arr2.length -= arr2.reduce((acc, n, i, a) => (
a[i - acc] = n,
acc + !arr1.includes(n.name)
), 0);
<select>
<option value="" hidden>здесь ваше описание</option>
...
select.innerHTML = '<option value="" hidden>...</option>' + select.innerHTML;
select.insertAdjacentHTML('afterbegin', '<option value="" hidden>...</option>');
const option = document.createElement('option');
option.value = '';
option.hidden = true;
option.innerText = '...';
select.prepend(option);
const option = new Option('...', '');
option.style.display = 'none';
select.insertBefore(option, select.firstElementChild);
<div id="items"></div>
document.querySelector('.map__filters').addEventListener('change', function() {
const values = Array.from(
this.querySelectorAll('.map__checkbox:checked'),
n => n.value
);
const filtered = values.length
? data.filter(n => values.every(m => n.features.includes(m)))
: [];
document.querySelector('#items').innerHTML = filtered
.map(n => `<div>${JSON.stringify(n, null, 2)}</div>`)
.join('');
});
function filter(obj, key, f) {
const keys = Object.keys(obj);
return (obj[key] || []).reduce((acc, n, i) => (
f(n) && keys.forEach(k => acc[k].push(obj[k][i])),
acc
), keys.reduce((acc, k) => (acc[k] = [], acc), {}));
}
const result = filter(obj, 'years', n => 2012 <= n && n <= 2014);
function filter(obj, f) {
const keys = Object.keys(obj);
const length = keys.length && obj[keys[0]].length;
const result = Object.fromEntries(keys.map(k => [ k, [] ]));
for (let i = 0; i < length; i++) {
if (f(i, obj)) {
keys.forEach(k => result[k].push(obj[k][i]));
}
}
return result;
}
const result = filter(obj, (i, { years: { [i]: n } }) => 2012 <= n && n <= 2014);
const selector = '[type="tel"]';
const event = 'input';
const minLength = 10;
const classNames = [ 'какой-то класс', 'какой-то другой класс' ];
$(selector).on(event, function() {
const isLengthOK = $(this).val().length >= minLength;
$(this)
.toggleClass(classNames[0], !isLengthOK)
.toggleClass(classNames[1], isLengthOK);
});
document.querySelectorAll(selector).forEach(function(n) {
n.addEventListener(event, this);
}, ({ target: t }) => {
const isLengthOK = +(t.value.length >= minLength);
classNames.forEach((n, i) => t.classList.toggle(n, isLengthOK === i));
});
- .dropdown__block.open {
+ .dropdown.open .dropdown__block {
const containerSelector = '.dropdown';
const buttonSelector = `${containerSelector} .dropdown__toggler`;
const activeClass = 'open';
// jquery, как вы и хотели
$(document).on('click', ({ target: t }) => {
const $container = $(t).closest(containerSelector);
const $button = $(t).closest(buttonSelector);
if ($button.length) {
$container.toggleClass(activeClass);
}
$(containerSelector).not($container).removeClass(activeClass);
});
// или, к чёрту jquery
document.addEventListener('click', ({ target: t }) => {
const container = t.closest(containerSelector);
const button = t.closest(buttonSelector);
if (button) {
container.classList.toggle(activeClass);
}
document.querySelectorAll(containerSelector).forEach(n => {
if (n !== container) {
n.classList.remove(activeClass);
}
});
});
const itemSelector = '.item-service';
.function toggleUntilNextItem(el) {
while ((el = el.nextElementSibling) && !el.matches(itemSelector)) {
el.hidden ^= 1;
// или (в стили надо будет добавить .hidden { display: none; })
el.classList.toggle('hidden');
}
}
document.querySelectorAll(itemSelector).forEach(function(n) {
n.addEventListener('click', this);
}, e => toggleUntilNextItem(e.currentTarget));
document.addEventListener('click', ({ target: t }) =>
(t = t.closest(itemSelector)) && toggleUntilNextItem(t)
);
Object.entries(obj).filter(n => Number.isInteger(+n[0])).map(n => n[1]).join(';')
// или
Object.keys(obj).reduce((acc, n) => (`${+n}` === n && acc.push(obj[n]), acc), []).join(';')
// или
Array.from(obj).join(';')
// или
JSON.stringify(obj).match(/(?<="\d+":").*?(?=")/g).join(';')
$('.links').on('mouseover', 'a', function() {
$(this).closest('.block').find('img').attr('src', $(this).data('src'));
});
document.addEventListener('mouseover', ({ target: t }) => {
const { src } = t.dataset;
if (src) {
t.closest('.block').querySelector('img').src = src;
}
});
document.querySelectorAll('[data-src]').forEach(function(n) {
n.addEventListener('mouseenter', this);
}, ({ target: t }) => t
.parentNode
.parentNode
.nextElementSibling
.setAttribute('src', t.getAttribute('data-src'))
);
const key = 'id';
const attr = `data-${key}`;
const getVal = el => $(el).data(key);
// или
const getVal = el => $(el).attr(attr);
// или
const getVal = el => el.dataset[key];
// или
const getVal = el => el.getAttribute(attr);
// или
const getVal = el => el.attributes[attr].value;
const buttonSelector = '.open-category';
const contentSelector = button => `.d-none[${attr}="${getVal(button)}"]`;
const activeClass = 'active';
const toggle = button => $(contentSelector(button)).toggleClass(activeClass);
// или
const toggle = button => document
.querySelector(contentSelector(button))
.classList
.toggle(activeClass);
$(buttonSelector).click(function() {
toggle(this);
});
// или
document.querySelectorAll(buttonSelector).forEach(function(n) {
n.addEventListener('click', this);
}, e => toggle(e.currentTarget));
$(document).on('click', buttonSelector, e => toggle(e.currentTarget));
// или
document.addEventListener('click', ({ target: t }) =>
(t = t.closest(buttonSelector)) && toggle(t)
);
идет смещение индексов, но как это обойти, уже не знаю
for (let i = arr.length; i--;) {
invItems.splice(arr[i], 1);
}
for (const n of [...arr].reverse()) {
invItems.splice(n, 1);
}
for (const [ i, n ] of arr.entries()) {
invItems.splice(n - i, 1);
}
invItems.splice(
0,
invItems.length,
...invItems.filter((n, i) => !arr.includes(i))
);
invItems.length -=
invItems.reduce((acc, n, i, a) => (
a[i - acc] = n,
acc + (i === arr[acc])
), 0);
async function fetchRecursive(arr) {
const result = [];
if (Array.isArray(arr)) {
for (const n of arr) {
try {
result.push({ status: true, result: await fetch(n.url).then(r => r.json()) });
} catch(error) {
result.push({ status: false, error });
}
result.push(...await fetchRecursive(n.children));
}
}
return result;
}
const flat = arr =>
(arr || []).flatMap(n => [ n.url, ...flat(n.children) ]);
const fetchRecursive = arr =>
Promise.allSettled(flat(arr).map(n => fetch(n).then(r => r.json())));
<div class="comment" data-id="187">
<a class="comment-edit">Редактировать</a>
<span class="comment-panel"></span>
</div>
.comment .comment-panel {
display: none;
}
.comment.editing .comment-panel {
display: inline;
}
.comment.editing .comment-edit {
color: red;
}
const containerSelector = '.comment';
const buttonSelector = '.comment-edit';
const activeClass = 'editing';
// вот вам ваш jquery
$(containerSelector).on('click', buttonSelector, e => {
const id = $(e.delegateTarget).toggleClass(activeClass).data('id');
console.log(id);
});
// или, к чёрту jquery
document
.querySelectorAll(`${containerSelector} ${buttonSelector}`)
.forEach(n => n.addEventListener('click', onClick));
function onClick() {
const container = this.closest(containerSelector);
container.classList.toggle(activeClass);
const { id } = container.dataset;
console.log(id);
}
const containerSelector = '.class-1';
const tag = 'div';
const key = 'name';
const attrSelector = `[data-${key}]`;
$(containerSelector).prepend(function() {
return $(`<${tag}>`).text($(attrSelector, this).data(key));
});
document.querySelectorAll(containerSelector).forEach(n => {
const val = n.querySelector(attrSelector).dataset[key];
// можем добавлять разметку
n.insertAdjacentHTML('afterbegin', `<${tag}>${val}</${tag}>`);
// или элемент
const el = document.createElement(tag);
el.textContent = val;
n.prepend(el);
// или
// n.firstChild.before(el);
// n.insertBefore(el, n.firstChild);
// n.insertAdjacentElement('afterbegin', el);
// n.firstChild.replaceWith(el, n.firstChild);
});