misc/class
lib/jquery_pnotify, lib/moment, lib/lodash, misc/notification, site/engine, misc/social
if( $.browser.msie && $.browser.version <= 8 ) include('lib/respond'); $._social.__cfg = {"init":[{"service":"basic"},{"fb_app_id":"1997094873850041","service":"fb"},{"vk_app_id":"2978320","service":"vk"},{"service":"twi"}],"like":[{"service":"fb"},{"service":"vk"},{"via":"","channel":"","hash_tag":"","service":"twi"}]}; window._SiteEngine = new classes.SiteEngine( { user_id: 0, controller: 'content_tape', action: 'view', content_css_version: '1459538664', social_enabled: 0} );

Faiwer

Блог web-программиста

String.split и RegExp

9 марта 2016

При написании тестов столкнулся с интересной проблемой. Метод String.split работал не так, как я от него ожидал. Я долго возился с различными вариантами жадного и ленивого поиска, пока наконец не понял, что дело не в них. Перейду сразу к сути:

'aaaa'.split(/a+/); // ["", ""]
'aaaa'.split(/(a+)/); // ["", "aaaa", ""] WAT?
'aaaa'.split(/(?:a+)/); // ["", ""]

Полез в дебри документации:

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

Всё просто. Если знаешь. 

CLI-скрипты и stdout

5 марта 2016

При написании подручных консольных криптов неизбежно встаёт вопрос, а как запускать внешнюю программу так, чтобы не потерять её вывод. Ситуация осложняется тем, что вывод может быть сложнее, нежели просто груда текста. К примеру ffmpeg рисует что-то вроде progressbar-а в поледней строке выдачи. Помимо прочего не хочется терять цвета. 

Стандартная библиотека предоставляет ряд методов для запуска сторонних программ. Я перебрал несколько из них, но всё как-то мимо. К примеру при ручном перенаправлении spawn-а за счёт pipe в process.stdout выдачи я не добился. При ручной обработке on('data', нет цветной выдачи и затирания уже отрисованного текста. Ну и т.д. 

Как обычно великий stackoverflow помог:

require('child_process').spawn('ffmpeg',
	[
		'-i', fname,
		'-f', ext,
		'-vcodec', vcodec,
		'-acodec', acodec,
		'-ss', fromS,
		'-to', endS,
		result
	], { stdio: 'inherit' });

Весь рецепт в третьем параметре ― { stdio: 'inherit' }

UPD0. Помимо цветного вывода и затирания текста прекрасно работает пользовательский ввод (пример: ffmpeg спрашивает перезаписать ли сущ-ий файл). Получается, что stdin тоже пробрасывается.

IE8 и babel

3 марта 2016

В одном из проектов требуется на уровне ТЗ поддержка Internet Explorer 8. Спасибо, что не 7 :) Дошли руки до перевода кодовой базы на es6. Воткнул как обычно preset es2015, потестил, вроде всё работает, но дёрнул меня чёрт проверить и в старом ослике. Подохло там всё. Причём глюк настолько странный, что я невольно задвигал бровями. Перейду сразу к сути:

function init(){ console.log(1); }
var a = { init: function(){ console.log(2); } };
init();

Результат, конечно же, 1. Однако babel превратит сий код в:

"use strict";

function init() {
  console.log(1);
}
var a = { init: function init() {
    console.log(2);
  } };
init();

Ключевое отличие ― именование метода. Теперь он тоже init. Зачем? Не ко мне вопрос. Может быть для упрощения отладки. Но с этого момента старый ишак возвращает 2. Оказывается это старый баг тогдашнего jscript-а.

Лечение: добавляем: plugins: ["transform-jscript"] к настройкам babel-я. Ну и соответственно тащим этот плагин. С этого момента babel будет генерировать вот таких вот монстров:

"use strict";

function init() {
  console.log(1);
}
var a = { init: function() {
    function init(){ console.log(2); }
    init();
  } };
init();

Очень бредово, если честно. Ведь можно было сохранить изначальный код в первозданном виде.

Загрузка binary-файла

28 января 2016

Возникла задача ― загрузить с сервера XLSX-файл. Запрос ― POST. Файл, понятное дело, бинарный. На проекте уже подключена jQuery, и, первым делом, я решил воспользоваться её стандартным $.ajax. Сколько не бился ― так и не удалось получить blob-результат от запроса. Использовать же решение через iframe-ы и form-ы тоже не хотелось. Во-первых уж больно костыльно (привет 90-ые). во-вторых нужно будет ещё чудить с передачей параметров POST-запроса (content-type: json). Гуглил-гуглил, но ни одного вменяемого решения (которое не стыдно было бы утащить в проект) я так и не нашёл. Но, т.к. интересует поддержка только последних версий современных браузеров, удалось найти и применить более изящное и функциональное решение. Итак…

  1. Забудем про jQuery и воспользуемся нативным XMLHttpRequest-ом
  2. Указав ему responseType = 'blob'.
  3. Получившийся результат (blob) загоняем в URL.createObjectURL.
  4. В результате получим псевдо-URL ссылку, начинающуюся с "blob:".

Ну а дальше уже по-желанию. Я генерирую новый <a/>-тег, задаю ему нужные аттрибуты download и href (та самая blob-ссылка), вызываю у ссылки .click(). Апосля ссылку удаляю. Проверял в Firefox-е и Chrome-е.

Небольшая заготовка:

function loadBlob(params, data)
{
	return new Promise((resolve, reject) =>
		{
			const xhr = _.assign(new XMLHttpRequest(),
				{
					onload(){ resolve(xhr.response); },
					onerror(e){ reject(e.target.status); }
				});
			xhr.open(params.method || 'POST', params.url);
			xhr.responseType = 'blob';

			const contentType = params.contentType || 'application/json';
			xhr.setRequestHeader('content-type', contentType);

			if(contentType === 'application/json')
				data = JSON.stringify(data);
			xhr.send(data);
		});
}

подробности…

For-of и браузеры

28 января 2016

Оказывается, браузеры по-разному относятся к итерированию цикла for-of. Судите сами:

for(const a of []) ; // chrome: ok, ff: syntax error

На что ругается Firefox? Говорит, что a указана, как константа, а используется как переменная. Но почему?

for(let a of [1, 2])
  setTimeout(() => alert(a));
  • Chrome: 1, 2
  • Firefox: 2, 2

Всё просто. Chrome каждую итерацию пересоздаёт scope, а Firefox довольствуется одним. И если с const ошибка вылезет сразу (правда только в Firefox). То в случае чего-нибудь асинхронного ждите трудно-вылавливаемые баги, которые проявятся только в Firefox-е. В спеку мне лезть лень, но код генерируемый babel-ем ближе к Chrome-варианту. Кто прав?