render
находится в одном объекте, который под ключом "settings".data
– в другом объекте, который под ключом "template".const store = [
{
template: {
data: [1, 2, 3],
},
settings: {
get render() {
console.log(store[0].template.data);
},
},
},
];
store[0].settings.render // [ 1, 2, 3 ]
const dateTwoMonthsBack = new Date();
dateTwoMonthsBack.setMonth(dateTwoMonthsBack.getMonth() - 2);
const id = 'testId'; // TODO: remove
const params = {
page_size: 200,
manager: id,
last_kpi_graded__lte: dateTwoMonthsBack.toISOString().substring(0, 10),
};
const url =
'http://10.1.5.65/api/personal/users/?' +
Object.entries(params)
.map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
.join('&');
console.log(url);
// http://10.1.5.65/api/personal/users/?page_size=200&manager=testId&last_kpi_graded__lte=2022-09-16
// fetch(url);
_________zzzoooABCuuu
xxxABCiii |||
xxxABCiii |||
xxxABCiii |||
... |||
xxxABCiii
...
xxxABCiii
Начать ещё до их пересечения – это максимально возможное их несовпадение.function mostCommon(a, b) {
const A = a.split('');
const B = b.split('');
const min = {
diff: A.length + B.length,
index: -A.length,
start: undefined,
finish: undefined,
};
for (let offset = -A.length; offset < B.length; offset++) {
let diff = Math.max(0, -offset) + Math.max(offset + A.length - B.length, 0);
const initialDiff = Math.max(0, -offset) + Math.max(offset + A.length - B.length, 0);
const start = Math.min(Math.max(0, offset), B.length);
const finish = Math.min(Math.max(0, offset + A.length), B.length);
let matchStart;
let matchFinish;
for (let i = start, isMatchStarted = false; i < finish; i++) {
if (B[i] !== A[i - offset]) diff++;
else {
if (!isMatchStarted) {
matchStart = i;
isMatchStarted = true;
}
matchFinish = i;
}
}
if (diff < min.diff) {
min.diff = diff;
min.index = offset;
min.start = matchStart;
min.finish = matchFinish;
}
}
console.log(min, b.substring(min.start, min.finish + 1));
return min;
}
mostCommon('xxx>abcABCxxx', 'bbbzzz>abcAXCiiiqqq');
// { diff: 7, index: 3, start: 6, finish: 12 } >abcAXC
mostCommon("1246380924534", "88899212465809");
// { diff: 6, index: 6, start: 6, finish: 13 } 12465809
// в относительных единицах от старта песни
const hits = [ { time: 0 }, { time: 24 }, { time: 36 }, ];
// on play start
const timeK = 1200; // в зависимости от темпа
const playStartTime = Date.now();
const events = hits.map(hit => {
hit.ts = playStartTime + timeK * hit.time;
return hit;
});
// теперь у каждой ноты есть время ts, когда она должна сыграть
// внутри цикла requestAnimationFrame, который часто-часто,
// сраниваем текущее время с нотами,
// если разница менее 100 мс, ноту можно "играть"
const now = Date.now();
events.filter(note => Math.abs(note.ts - now) < 100).forEach(note =>play(note));
Наверное, надо смотреть и «в прошлом» пропущенные ноты – мало ли, комп притормозил.. И убирать сыгранные ноты из массива, чтобы не возвращаться к ним. const boxState = {
"block-ad-123": 1668436835032,
"block-ad-456": 1668436842279,
};
Хранить этот объект можно в localStorage, переведя в строку: JSON.stringify(boxState)
const boxKey = 'BOX_STATE'; // ключ для хранения в localStorage
const boxState = JSON.parse(localStorage.getItem(boxKey)) ?? {};
const TTL = 36e5; // сколько держать блок скрытым, в миллисекундах (1 час)
const expiredIds = [];
Object.entries(boxState)
.forEach((key, value) => {
if (value + TTL < Date.now()) {
// устарел, более не скрываем
expiredIds.push(key);
} else {
// актуален, скрываем блок
document.getElementById(key).classList.add("hide");
}
});
if (expiredIds.length) {
expiredIds.forEach(id => delete boxState[id]);
localStorage.setItem(boxKey, JSON.stringify(boxState));
}
Date.now()
, const onClose = ({ target }) => {
const block = target.closest('div.block');
const { id } = block;
boxState[id] = Date.now();
localStorage.setItem(boxKey, JSON.stringify(boxState));
block.classList.add("hide");
};
document.querySelectorAll('img.x-button')
.addEventListener('click', onClose);
0
(январь) до 11
(декабрь).new Date()
getMonth()
0..11
в слово, как вариант, можно составить массив имён месяцев:const monthNames = ['январь', 'февраль', ... 'декабрь'];
Удобно: под индексом 0
тут как раз "январь", под 11
"декабрь". #search_table VS #search_card
input[name^=name] VS [data-item-name="name"]
val() VS text()
const addFilter = (listenSelector, findSelector, methodName) => {
$(listenSelector).keyup(function search() {
const search = this;
const searchValue = $(search).val().toLowerCase();
$("#tabname tbody tr")
.find(findSelector)
.each(function () {
const currentValue = $(this)[methodName]().toLowerCase();
$(this).closest("tr").toggle(currentValue.includes(searchValue));
});
});
};
addFilter('#search_table', 'input[name^=name]', 'val');
addFilter('#search_card', '[data-item-name="name"]', 'text');
Promise.allSettled()
– передать в него массив промисов запросов Axios, и в следующий then() попадёт массив с результатами:const batch = new Array(214)
.fill()
.map((_, i) => `https://example.com/api/${i}`) // URL запросов
.map(url => axios.get(url));
Promise.allSettled(batch)
.then(axiosResults => {
const results = [];
const errors = [];
axiosResults.forEach(({ status, res }) => {
if (status === 'fullfilled') {
results.push(res);
} else if (status === 'rejected') {
errors.push(res);
}
});
return { results, errors };
})
.then(({ results, errors }) => {
console.log('Вот результаты: %o, а вот ошибки: %o', results, errors);
});
let isExpanded = false; // единственный источник правды
el.addEventListener('click', () => {
isExpanded = !isExpanded; // переключить
// показать
linkusersnew.innerText = isExpanded ? 'Свернуть' : 'Развернуть';
userwrap.style.height = isExpanded ? '600px' : '400px';
newdel.style.display = isExpanded ? 'flex' : 'none';
});
- const signinbtn = document.queryselector('.signn-btn');
- const signupbtn = document.queryselector('.signup-btn');
- const formbox = document.queryselector('.formbox');
+ const signinbtn = document.querySelector('.signin-btn'); // имя класса
+ const signupbtn = document.querySelector('.signup-btn');
+ const formbox = document.querySelector('.formbox');
addEventListener
и classList
.querySelector()
– чуть другое.v
всегда число ("v" for "value"),c
— опциональный массив дочерних элементов ("c" for "children").if (last && Array.isArray(last.v)) {
тут, видимо, лишняя.v
это массив.. Так что нужна, если данные именно такие.if (last && typeof last.c === 'object') {
, за исключением корневого свойства, где это таки объект.last
- el.parentNode.replaceChild(customSelect, el);
+ el.parentNode.replaceChild(customSelect.cloneNode(true), el);
settParent
.settParent.addEventListener('input', ({ target }) => console.log(target.value));
computed
свойство emailObjects
emailObjects() {
return this.emails.map(email => ({
email,
isActive: email.includes(this.search),
});
},
т.е. тут вместо массива просто-email'ов делается массив объектов, где и email и свойство isActive, которое для данного адреса означает, включает он искомое или нет. .
начало
---|---|---
к | 1
о -
н | 2 1
е -
ц | 3 2 1
if - else if - else
function ranges(int $a, int $b): array
{
$start = 20;
$finish = 30;
$result = [
'before' => null,
'match' => null,
'after' => null,
];
if ($a < $start) {
if ($b < $start) {
$result['before'] = [$a, $b];
} else {
$result['before'] = [$a, $start];
if ($b < $finish) {
$result['match'] = [$start, $b];
} else {
$result['match'] = [$start, $finish];
$result['after'] = [$finish, $b];
}
}
} else if ($a < $finish) {
if ($b < $finish) {
$result['match'] = [$a, $b];
} else {
$result['match'] = [$a, $finish];
$result['after'] = [$finish, $b];
}
} else {
$result['after'] = [$a, $b];
}
return $result;
}
print(json_encode(ranges(5, 25))); // {"before":[5,20],"match":[20,25],"after":null}
$arr = [$start, $finish, $a, $b];
sort($arr, SORT_NUMERIC);