• Почему некорректно работает swiper в tab-content блоке bootstrap?

    lazalu68
    @lazalu68
    Salmon
    Полагаю, суть вот в этой строчке из документации:

    swiperContainer - HTMLElement or string (with CSS Selector) of swiper container HTML element. Required.


    Как бы это ни было странно, вы должны передать один элемент или селектор который выберет один элемент. В доказательство вот вам демка из документации
    Ответ написан
    Комментировать
  • Как узнать, активизирована ли у пользователя функция - без перекрестного отслеживания?

    lazalu68
    @lazalu68
    Salmon
    Насколько я понял, в window.navigator об этом никакой инфы нету. А раз нету, то придётся по каким-то конкретным признакам определять запрещает ли браузер отслеживание, например через печенюхи. В любом случае, из найденных материалов мне показалось, что опция "Prevent cross site tracking" просто врубает ITP 2.x, о котором в интернетах достаточно инфы. Один из способов который я вижу основывается на том, что фрейм обращающийся к подконтрольному вам ресурсу сообщает родительскому документу получилось ли у него достучаться до каких-то важных печенюх или нет.

    ЗЫ: либо я нашел решение, либо одно из трёх - ITP 2.0 вводит метод document.hasStorageAccess, соответственно можно проверять какое значение возвращает этот метод и уже от этого плясать. Вот тут чувак накатал небольшой скрипт для подобной проверки. Проверил на восьмом ифоне этот метод, он возвращает false если опция "Prevent cross site tracking" выключена, и true - если включена.

    Если "Prevent cross site tracking" это действительно только об ITP 2.0 и вдобавок я нигде не ошибаюсь в рассуждениях, то функция проверки может выглядеть как-то так:

    async function ITPIsActive() {
    	if (document.hasStorageAccess && document.requestStorageAccess) {
            const access = await new Promise(function(res, rej) {
                document.hasStorageAccess().then(res, rej).catch(rej);
            });
    
            return access;
        } else {
            return false;
        }
    }
    Ответ написан
    1 комментарий
  • Linux ,python 3, opencv. Как распознаванать дорожные знаки с фотографий?

    lazalu68
    @lazalu68
    Salmon
    Думаю вот это можно считать решением проблемы: foxpy: road sign detection
    Ответ написан
    Комментировать
  • Как получить значение Javascript-Listener'a в Symfony?

    lazalu68
    @lazalu68
    Salmon
    Почитайте официальную доку, тут вроде бы описан механизм автоматизированного получения данных в бэкенде из зарегистрированных обработчиков
    Ответ написан
    5 комментариев
  • Как сделать страницы сайта вставленные через iframe доступными, а по прямой ссылке на самом сайте - недоступные?

    lazalu68
    @lazalu68
    Salmon
    Изучите механизм работы заголовка:
    config.action_dispatch.default_headers = {
        'X-Frame-Options' => 'ALLOWALL'
    }
    Ответ написан
    Комментировать
  • Как установить начало выполнения функции?

    lazalu68
    @lazalu68
    Salmon
    Когда-то делал сниппет добавлявший в jQuery метод onAppearanceApply суть которого заключалась в том, что он для коллекции элементов выполнял функцию при их появлении в поле зрения; собственно, в примере onAppearanceApply как раз используется для запуска анимации. При надобности переписать его на JS используя возможности современных движков не составит много труда
    Ответ написан
    Комментировать
  • Mixin в mixin есть ли возможность использовать?

    lazalu68
    @lazalu68
    Salmon
    Ответ из комментариев: инфу по теме можно найти в одном из issues по pug.js
    Ответ написан
    Комментировать
  • Почему не работает скролл в блоке для firefox?

    lazalu68
    @lazalu68
    Salmon
    Исправленная версия на подходе, комьюнити ждёт мелкомягких
    Ответ написан
    Комментировать
  • Как сделать задержку парсинга на node.js?

    lazalu68
    @lazalu68
    Salmon
    А что значит сайт падает с ошибкой? В смысле перестаёт возвращать адекватный ответ?

    Отвечая на вопрос: в своё время чтобы обходить всевозможные механизмы защиты от парсинга разбивал процедуру парсинга на много много частей: парсинг одного конкретного элемента, bunch (парсинг группы элементов), сессия (bunch состоящий из bunch'ей).

    В коде банч от сессии отличался только количеством обработанных элементов. То есть алгоритм парсинга получался какой-то такой:
    Обрабатываем элемент №i
      Если ошибка, то
        ждём SINGLE_REQUEST_TIMEOUT
        пробуем еще раз
      i++
      Если остаток от деления i на ITEMS_IN_BUNCH равен нулю, то
        ждём BUNCH_TIMEOUT
      Иначе Если остаток от деления i на ITEMS_IN_SESSION равен нулю, то
        ждём SESSION_TIMEOUT
      Иначе 
        ждём SINGLE_REQUEST_TIMEOUT

    Надеюсь понятно объяснил. Каждый из таймаутов охватывает временные промежутки разных масштабов - от секунд и минут, до часов и дней. Например, SINGLE_REQUEST_TIMEOUT может быть 1000мс, BUNCH_TIMEOUT - 30000мс, а SESSION_TIMEOUT может превосходить рамки часов/суток. С таким подходом пока ни разу не сталкивался с проблемами парсинга
    Ответ написан
    Комментировать
  • Что за ClipboardEvent.clipboardData?

    lazalu68
    @lazalu68
    Salmon
    Ну да, все правильно, ClipboardEvent.clipboardData это интерфейс для взаимодействия с буфером, который наследуется ивентами ClipboardEvent. На страничке ClipboardEvent:copy есть хороший пример. Только насчёт getData вы чуть-чуть переврали, там в аргументах только формат.
    Ответ написан
    Комментировать
  • Как объединить два асинхронных цикла?

    lazalu68
    @lazalu68
    Salmon
    Можно пользоваться async/await. С одной стороны конечно хорошо бы все же сделать плоский массив пользователей, но если условия позволяют, то можно забить на это:

    function delay(timeout) {
    	return new Promise(res => setTimeout(res, timeout));
    }
    
    async function sendMessage(user, message) {
    	/* example */
    	console.log(user, message);
    	/* example */
    }
    
    async function sendAllTheMessagesToOurLovelyUsers(mailing_data, delay_between_requests) {
    	for (let mailing_entry of Object.values(mailing_data)) {
    		for (let user of mailing_entry.users) {
    			await sendMessage(user, mailing_entry.msg);
    			await delay(delay_between_requests);			
    		}
    	}
    };
    
    sendAllTheMessagesToOurLovelyUsers([
    	{
    		users: [
    			{ user_id: 25 },
    			{ user_id: 14 },
    		],
    		msg: "message1"
    	}, 
    	{
    		users: [
    			{ user_id: 14 },
    			{ user_id: 6 }
    		],
    		msg: "message2"
    	}
    ], 500);


    Старый ответ

    Можно ведь из массива массивов пользователей сделать один массив и пользоваться async/await:
    function delay(timeout) {
    	return new Promise(res => setTimeout(res, timeout));
    }
    
    async function sendMessage(user) {
    	/* example */
    	console.log(user);
    	/* example */
    }
    
    async function sendAllTheMessagesToOurLovelyUsers(user_lists, delay_between_requests) {
    	const users = {};
    
    	for (let user of user_lists.flat()) {
    		/* пример процедуры получения массива уникальных пользователей */
    		if (!(users[ user.user_id ] in users)) {
    			users[ user.user_id ] = user;
    		}
    	}
    
    	for (let user of Object.values(users)) {
    		await sendMessage(user);
    		await delay(delay_between_requests);
    	}	
    };
    
    sendAllTheMessagesToOurLovelyUsers([
    	[
    		{ user_id: 25 },
    		{ user_id: 14 },
    	],
    	[
    		{ user_id: 14 },
    		{ user_id: 6 }
    	]
    ], 500);

    Ответ написан
    Комментировать
  • Почему не работают как надо шаблонные строки?

    lazalu68
    @lazalu68
    Salmon
    Template strings это не шаблон который вы можете в любой момент взять и забить нужными данными, это просто инструмент с помощью которого данные распихиваются по строке. То есть у вас на 36ой строке cOA.begin создаётся именно с теми данными которые доступны на тот момент, а т.к. classPet и name не существуют в текущей области видимости, то вместо них используется undefined.

    Кстате, как по мне, так эти template strings не самый удобный механизм для обработки шаблонов, как бы ни было обманчиво их название; если пользоваться ими, то на каждый шаблон придётся иметь свою функцию. Имхо проще обрабатывать шаблоны кастомно:

    (() => {
      const re_template = /{(.*?)}/g;
    
      String.prototype.process = function(data) {
        return this.replace(re_template, (entry, word) => data[ word ]);
      }
    })();
    
    let templates = {
      greeting: 'Hello, my name is {name} and my age is {age}'
    };
    
    // Напрямую:
    templates.greeting.process({ name: 'Yeshua', age: 2019 });
    // Hello, my name is Yeshua and my age is 2019
    templates.threat.process({ reason: 'i dont like you' });
    // TypeError: Cannot read property 'process' of undefined
    
    
    // Или автоматически вызывая process с помощью Proxy:
    // (то же можно было реализовать просто с помощью дополнительной функции)
    templates = new Proxy(templates, {
        get(target, prop) {
        	if (prop in target) {
            	return String.prototype.process.bind(target[prop]);
            } else {
            	throw new Error(`String "${ prop }" was not found in storage!`);
            }
        }
    });
    
    templates.greeting({ name: 'Yeshua', age: 2019 });
    // Hello, my name is Yeshua and my age is 2019
    templates.threat({ reason: 'i dont like you' });
    // Error: String "threat" was not found in storage!
    Ответ написан
    6 комментариев
  • Proxy js метод "get", почему не отрабатывает get?

    lazalu68
    @lazalu68
    Salmon
    Суть Proxy в том, что он перехватывает обращения к свойствам объекта. В вашем примере нету ни одного обращения, потому и get нигде не выполняется; в примере вы просто создаёте экземпляр Proxy после чего он благополучно удаляется сборщиком мусора так как на него нету ссылок. Возвращайте свежесозданный прокси в функции createProxy, потом к нему обращайтесь
    Ответ написан
    4 комментария
  • Что это за формат данных и как его распарсить средствами PHP?

    lazalu68
    @lazalu68
    Salmon
    Хмм, как интересно. Наверное для начала стоит определиться с терминологией. В моем описании будет много тавтологий, но если подходить с точки зрения терминологии JS, то всё будет понятно:
    1. Элемент это самостоятельная подстрока, при необходимости отделенная от другой запятой, и заключенная в кавычки если не описывает объект или массив,
    2. Элемент начинающийся с фигурной скобки и ею заканчивающийся можно назвать объектом если первым элементом идет количество значений в виде числа, или массивом если вдобавок к первому условию также все дочерние его элементы описывают объекты (как бы это странно ни звучало). Также вторым элементом в массиве идет какой-то непонятный ключ фиксированной длины (36), который в подавляющем большинстве случаев одинаковый, но иногда все таки другой. Интрига.
    3. Каждое значение описывается двумя элементами: первый описывает тип, второй - конкретное значение (извиняюсь за тавтологию). Типов существует 5: '#' - массив, 'S' - строка, 'N' - число, 'B' - boolean, 'D' - дата, unix timestamp.
    4. Свойства объектов описываются так: первый объект описывает ключ свойства, а второй - его значение,

    Наколеночный алгоритм на JS

    initial_string = `{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{14,{{"S","type"},{"S","order_change"}},{{"S","agent"},{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{5,{{"S","id"},{"S","42318"}},{{"S","id_1c"},{"S","ПР10"}},{{"S","id_crm"},{"S","00-00164917"}},{{"S","name"},{"S","Иванова Тест"}},{{"S","contact"},{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{3,{{"S","email"},{"S","K@mail.ru"}},{{"S","phone"},{"S","790000000"}},{{"S","contact_person"},{"S",""}}}}}}}},{{"S","id"},{"S","264762"}},{{"S","id_1c"},{"S","ЗА00-000000133586"}},{{"S","id_crm"},{"S","ЗА00-000000133586"}},{{"S","date"},{"S","2019-08-26"}},{{"S","time"},{"S","7:56:54"}},{{"S","amount"},{"N",215}},{{"S","delivery_date"},{"S","2019-08-26"}},{{"S","delivery_interval"},{"S","1-21-22"}},{{"S","items"},{"#",51e7a0d2-530b-11d4-b98a-008048da3034,{1,{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{9,{{"S","id_1c"},{"S","11014"}},{{"S","price"},{"N",215}},{{"S","quantity"},{"N",1}},{{"S","vat_rate"},{"N",0}},{{"S","name"},{"S","Вода 19л Классика"}},{{"S","discount_price"},{"S","0.00"}},{{"S","measure_code"},{"S","868"}},{{"S","measure_name"},{"S","бут"}},{{"S","type"},{"S","Товар"}}}}}}},{{"S","properties_values"},{"#",51e7a0d2-530b-11d4-b98a-008048da3034,{6,{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{2,{{"S","name"},{"S","Отменен"}},{{"S","value"},{"B",0}}}},{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{2,{{"S","name"},{"S","ПометкаУдаления"}},{{"S","value"},{"B",0}}}},{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{2,{{"S","name"},{"S","Финальный статус"}},{{"S","value"},{"B",0}}}},{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{2,{{"S","name"},{"S","Статус заказа"}},{{"S","value"},{"S","[N] Принят"}}}},{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{2,{{"S","name"},{"S","Статус заказа ИД"}},{{"S","value"},{"S","N"}}}},{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{2,{{"S","name"},{"S","Дата изменения статуса"}},{{"S","value"},{"D",20190826075719}}}}}}},{{"S","storage"},{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{2,{{"S","id_1c"},{"S","2"}},{{"S","name"},{"S","Благодатская"}}}}},{{"S","forwarder_group"},{"#",4238019d-7e49-4fc9-91db-b6b951d5cf8e,{0}}}}}`;
    
    // для удобства меняем все скобки на квадратные и оборачиваем ключи кавычками
    processed_string = initial_string
    	.replace(/{/g, '[').replace(/}/g, ']')
    	.replace(/[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}/gi, '"$&"');
    
    main_sequence = eval(processed_string);
    
    const parseThisFreakinOdinAssObject = (function() {
    	const registered_types = [ '#', 'S', 'N', 'B', 'D' ];
    
    	function processValue(type, value) {
    		switch (type) {
    			case 'S': {
    				value = value.toString();
    				break;
    			}
    			case 'N':
    			case 'D': {
    				value = Number(value);
    				break;
    			}
    			case 'B': {
    				value = Boolean(value);
    				break;
    			}
    			case '#': {
    				if (value) {
    					const	declared_length = value[0],
    							actual_length = value.length - 1;
    
    					if (declared_length !== actual_length) {
    						throw new Error(`The array actual length ${ actual_length } differs from declared length ${ declared_length }!`);
    					}
    
    					value = value.slice(1);
    				} else {
    					value = [];
    				}
    			}
    		}
    
    		return value;
    	}
    
    	return function parse(sequence) {
    		const type = sequence[0];
    
    		if (!registered_types.includes(type)) {
    			throw new Error(`Type '${ type }' is not registered!'`);
    		}
    
    		// есл значение - массив, то пропускаем волшебный ключ
    		let value = processValue(type, type === '#' ? sequence[2] : sequence[1]);
    
    		if (value instanceof Array) {
    			let temp_value;
    
    			// если дочерний элемент также массив, то значит текущий элемент не объект, а массив
    			if (value[0] && value[0][0] === '#') {
    				temp_value = [];
    
    				value.forEach(entry => {
    					temp_value.push( parse(entry) );
    				});
    			} else {
    				temp_value = {};
    				value.forEach(entry => {
    					temp_value[ parse(entry[0]) ] = parse(entry[1]);
    				});
    			}
    
    			value = temp_value;
    		}
    
    		return value;
    	}
    })();
    
    parseThisFreakinOdinAssObject(main_sequence);


    JSON-представление данных из примера

    {
        "type": "order_change",
        "agent": {
            "id": "42318",
            "id_1c": "ПР10",
            "id_crm": "00-00164917",
            "name": "Иванова Тест",
            "contact": {
                "email": "K@mail.ru",
                "phone": "790000000",
                "contact_person": ""
            }
        },
        "id": "264762",
        "id_1c": "ЗА00-000000133586",
        "id_crm": "ЗА00-000000133586",
        "date": "2019-08-26",
        "time": "7:56:54",
        "amount": 215,
        "delivery_date": "2019-08-26",
        "delivery_interval": "1-21-22",
        "items": [
            {
                "id_1c": "11014",
                "price": 215,
                "quantity": 1,
                "vat_rate": 0,
                "name": "Вода 19л Классика",
                "discount_price": "0.00",
                "measure_code": "868",
                "measure_name": "бут",
                "type": "Товар"
            }
        ],
        "properties_values": [
            {
                "name": "Отменен",
                "value": false
            },
            {
                "name": "ПометкаУдаления",
                "value": false
            },
            {
                "name": "Финальный статус",
                "value": false
            },
            {
                "name": "Статус заказа",
                "value": "[N] Принят"
            },
            {
                "name": "Статус заказа ИД",
                "value": "N"
            },
            {
                "name": "Дата изменения статуса",
                "value": 20190826075719
            }
        ],
        "storage": {
            "id_1c": "2",
            "name": "Благодатская"
        },
        "forwarder_group": {}
    }

    Ответ написан
    3 комментария
  • Как применить код к выделенному тексту в Sublime Text?

    lazalu68
    @lazalu68 Автор вопроса
    Salmon
    Задача расставлять переносы прямо в редакторе на самом деле не решена, но придуман обходной и вроде бы даже более адекватный способ: переносы расставляются при сборке проекта с помощью алгоритма Христова
    Ответ написан
    Комментировать
  • Как в angular 8 показать spinner загрузки?

    lazalu68
    @lazalu68
    Salmon
    Чаще всего для этого делают сервис типа AppLockService который посылает сообщения типа APP_LOCK/UNLOCK, которые в свою очередь ловит компонент типа AppLockComponent и на основе данных из сообщения скрывает или показывает оверлей с крутилочкой; достаточно вызвать например метод _appLockService.lock_ и крутилка появится. Бывает удобно выполнить этот метод в виде асинхронной функции, тогда можно автоматически отправлять сообщения - перед локом и после выхода из асинхронной процедуры, очень удобно. Естественно готовых решений в интернетах тонны
    Ответ написан
    Комментировать
  • Как сверстать блок с секциями?

    lazalu68
    @lazalu68 Автор вопроса
    Salmon
    Прошло сто лет, и я наконец решил эту фигню с помощью диких неадекватных таблиц, вот
    Ответ написан
    Комментировать