Артем

Артем

С нами с 15 октября 2017; Место в рейтинге пользователей: #157
18 июля 2020, 21:56
+2
Поля unpublished у тикетов нет, они же наследуются от обычных ресурсов.
'where' => ['published' => 0]
14 июля 2020, 02:27
+2
Hi Julien! I think you should take a look on a manual. There is a separate section about that you are looking for. Keyword is «Сообщения».
Btw, Quiz is a paid component. That means you have a one year tech support provided by author of this component. Please, sign in to your Modstore account and use Support tab to directly contact the author.
04 июля 2020, 18:39
+1
Думаю, вряд ли ты найдешь что-то готовое, поскольку задача решается в 10-20 строк кода:
— ловишь нажатие кнопки, отправляешь ajax запрос на сервер с каким-нибудь экшном типа modal/show
— на сервере проверяешь, что это ajax запрос и сравниваешь экшн, если это modal/show, то рендеришь свой чанк с модалкой через pdoTools::getChunk() или modX::getChunk(), а затем возвращаешь ответ на фронт
— на фронте достаешь из ответа html и вставляешь на страницу через append/innerHTML.
02 июля 2020, 17:58
+1
А за итоговое число лет отвечает $diff, правильно?
Не совсем, в $diff находится объект, который содержит в себе всю информацию об интервале между текущей датой и той, которая указана в from. Ты можешь распечатать его через print_f и посмотреть, что там есть. Оттуда можно достать даже точное количество дней между этими датами.
Подробнее можно почитать тут и тут.

Пытался подставить в функцию format_by_count, но не работает
вместо
return $diff->format('%Y');
пишешь
$output = $diff->format('%Y');
return format_by_count($output);
02 июля 2020, 16:53
1
+1
$from = $modx->getOption('from', $scriptProperties);
try {
    $date = new DateTime($from);
    $diff = (new DateTime())->diff($date);
    return $diff->format('%Y');
} catch (Exception $e) {
    return 'An error occurred while calculating experience: ' . $e->getMessage();
}
На вход принимает один параметр — from, где ты должен указать полную дату (02.06.1990, например), от которой нужно отсчитывать опыт.
На выходе получаешь точное количество лет опыта.
01 июля 2020, 21:21
0
Правильно выше сказали — достаточно просто динамически подсчитывать стаж на основе даты заполнения.
Т.е. у каждого преподавателя должна быть дата, от которой нужно отсчитывать стаж, а затем нужно банально вычесть эту дату из текущей, округлив до лет.

Подсчитывать такие вещи через крон на сервере — лишняя головная боль.
29 июня 2020, 17:36
+1
Напишу продолжение, как время будет.
С нетерпением ждем!

P.S. Закинул небольшую спасибку
29 июня 2020, 16:56
+2
Вот за что люблю твои заметки, так это за то, что они читаются на одном дыхании и всегда до жути интересные, даже если на уже знакомую тему. Знакомую потому, что лично я уже успел прошерстить исходники Vesp Core задолго до заметки. В общем, подача 11/10, как обычно.
Спасибо за еще одну отличную заметку!

Конечно, было бы интересно почитать про JWT авторизацию, поскольку она кажется в разы более гибкой и интересной, нежели сессии и вот это все, особенно в контексте полного разделения фронтенда от бэкенда.
20 июня 2020, 15:33
+1
Обычная ajax подгрузка данных, примерно как с пагинацией, только подгружается не список, а одна конкретная новость. URL меняется через history.pushState.
06 июня 2020, 23:32
0
тогда можно написать свой простенький скрипт, который будет итеративно проходиться по всей таблице, выискивать старые сессии по колонке access, а затем их удалять
ну и потом на крон его повесить, разумеется
06 июня 2020, 23:14
0
я же кинул ссылку с объяснением и решением проблемы, лень открыть и прочитать?
03 июня 2020, 19:58
0
'where' => ['class_key:!=' => 'CollectionContainer', 'work:IN' => [1, 2, 3, 4, 5, 6]],
ну или если включена поддержка php, то можно упростить последний массив до range(1, 6)
01 июня 2020, 15:19
+1
querySelector настолько быстрый, что нет никакого смысла юзать getElementById ради скорости. В реальных сценариях в 99.9% случаев между ними не будет никакой разницы, потому что ощутить ее можно только при десятках тысяч операций. Более того, querySelector(All) — универсальный, поэтому можно ограничиться только им для всех сценариев, что в целом сделает твой код чуточку читабельнее.
31 мая 2020, 15:08
+1
Например, вот тут они достаточно хорошо описаны.
Практически всю нужную тебе инфу можно смотреть в рамках этого сайта. Просто пишешь прямо там в поиске нужный метод или фразу, а потом смотришь результаты.
31 мая 2020, 15:04
0
Но как определить, что этот инпут именно из той формы, за которой мы хотим следить?
Опять же, через closest.
Он поднимается вверх по DOM и ищет указанного родителя.
У тебя может быть хоть 150 одинаковых форм, но измененный инпут принадлежит только одной из них.
Поэтому ты делаешь, например, вот так
if (target.closest('.formClass') !== null) {}
и узнаешь, что измененный инпут принадлежит форме с классом formClass.
Более того, ты можешь сразу сохранить эту форму в переменную и в дальнейшем работать с ней, если есть такая необходимость.
const form = target.closest('.formClass');
if (form !== null) {}
если наш листенер повешен на весь объект документ, то он будет следить за всеми элементами всех форм и единственный способ решить задачу, который я вижу, это всем input задавать определенный класс и проверять на его наличие.
Верно, он будет следить за всеми элементами всех форм, в этом и есть его плюс, который называется делегирование.
Например, если у тебя на странице появятся еще 2 формы с таким же классом, то они автоматически подхватятся и в них тоже будут отслеживаться изменения.
И нет, не нужно задавать всем инпутам определенный класс.

Твоя задача
let form = document.getElementById('formtest');
 form.addEventListener('change', function (event) {}
решается вот так
document.addEventListener('change', e => {
    const target = e.target;
    if (target.closest('#formtest') !== null) {}
});
Это будет точно так же срабатывать, если изменения происходят только в рамках конкретной формы.
Твоя форма может быть присвоена переменной, как я уже показал выше, чтобы ты мог с ней работать и собирать из нее данные через FormData, например.

К слову, getElementById('formtest') уже практически не используется в новом коде, поэтому рекомендую заменять его на querySelector('#formtest').
30 мая 2020, 22:18
+2
Хорошая практика — вешать обработчик на document, а затем разруливать его таргет через обычный if.

document.addEventListener('change', e => {
    const target = e.target;

    if (target.matches('.some-selector')) { /* code */}
    // или можно прям на наличие класса проверять
    if (target.classList.contains('имя класса без точки')) { /* code */ }
});

Если тебе нужно отслеживать изменения внутри какой-то конкретной формы, то просто проверяешь ее наличие среди родителей через closest.
if (target.closest('.form') !== null) {}

Данные из формы удобнее всего собирать через FormData, как уже выше сказали. Иногда может потребоваться дополнительная обработка всяких чекбоксов, потому что по умолчанию неотмеченные чекбоксы вообще не собираются, например.
К слову, FormData — итерируемый объект, поэтому ты можешь легко по нему пройтись через цикл и поменять то, что тебе нужно:
for (const [key, value] of formDataInstance) {
    console.log(key, value);
}

fetch лично мне не зашел, слишком много телодвижений требуется для обычных ajax-запросов. Чтобы принять json на сервере, нужно лезть в php://input и оттуда его доставать, что может быть не всегда удобно по разным причинам. Тут либо написать свой простенький асинхронный метод-обертку для запросов, который будет построен на старом XMLHttpRequest, либо посылать данные в multipart/form-data, тогда проблем не будет.
Помимо этого, fetch до сих пор не умеет отслеживать прогресс загрузки, поэтому если нужна такая фича, можно смело от него отказываться.
26 мая 2020, 16:27
+1
2 варианта:
1. Убрать оплату из заказа и вернуть json_response в конфиг, тогда exit не будет вызываться, а в ответе будет номер заказа.
2. Брать номер заказа из сессии — он добавляется туда сразу после создания заказа.
26 мая 2020, 16:05
+1
это происходит, если в конфиге установлен json_response
16 мая 2020, 23:16
0
ну так я еще вчера описал проблему и подкрепил ссылкой для ознакомления, этого мало?