95 заметок с тегом

javascript

Позднее Ctrl + ↑

Странное с Флешем

Я с «Флешем» в последние годы не сталкивался, но и прежде подобного поведения не наблюдал. В общем, решил я вчера обновить в нашем продукте библиотеку ВебКамДжиЭс, она у нас для получения фотографии с камеры используется. Прежняя была 0.9, а тут я случайно обнаружил, что релиз вышел.

В прежней изображение с камеры получалось через Флеш, а релизная умеет использовать АПИ браузера, если таковое имеется. Правда, в «Сафари», которым я пользуюсь, этого АПИ нет и всё равно используется Флеш. Вот тут-то и столкнулся с трудностями — прежняя версия работала прекрасно, а новая отказывалась — в окне Флеша изображение с камеры есть, но ДжаваСкрипт был уверен, что всё плохо и, самое главное, не мог достучаться до Флеша.

В принципе, можно было откатиться на предыдущую версию, но смущало, что на демо-сайте ВебКама в «Сафари» всё работало нормально. Я попробовал несколько вариантов, прежде чем мне пришла в голову идея посмотреть заголовки запросов. И заметил разницу, показавшуюся несущественной, но всё-таки я решил попробовать её устранить — mime type различался.

У нас сервер отдавал Флеш с типом «application/x-shockwave-flash», а в демо-примере был «binary/octet-stream». Стоило поменять этот заголовок, и всё заработало.

Беглое гугление света не пролило, но если столкнётесь с похожей проблемой, имейте ввиду, возможное решение — смена типа для отдаваемого флеш-ролика.

2014   flash   javascript   safari   программирование

Короткий способ определять IE

А какой сейчас самый короткий способ определять Эксплорер? Я понимаю, что привязываться к браузеру нехорошо, но у меня конкретная задача, которую никак не обойти — нужно проиграть звук в браузере (PCM wave), а ИЕ на запрос «сможешь проиграть?» к тегу AUDIO, говорит maybe. Т. е. давайте сюда свой звук, может и смогу. Я-то знаю, что не сможет — аудиотег в этом браузере «вавки» не играет, нужен EMBED.

Все короткие способы, которые раньше работали (условная компиляция, сравнение вертикального пробела с буквой v, хитрый хак с массивом и прочее) в 11-й версии работать перестали. Даже строку агента поменяли — там теперь нет MSIE.

В общем, я пока остановился на такой версии:

if (top.VBArray) {
    // IE
} else {
    // остальные браузеры
}

Но буду признателен за что-то более короткое или очевидное.

2014   ie   javascript   программирование

Почему у null в JS тип «object»?

На «Хабре» вышла статья, проливающая свет на загадку — почему же у null в Джаваскрипте тип «объект». Причём, если попытаться этому «объекту» добавить какое-то свойство, то браузер воспротивится: скажет, что null объектом не является.

Null как объект (13.48КиБ)

Вообще, я этому особого значения не придавал. Ну да, примитивное значение, имеет тип объект, хотя по факту им не является, смысла я в этом не вижу, это мешает, но поменять это нельзя.

Оказывается, это баг. Точнее даже не баг, а просто «так получилось». В ранних интерпретаторах Джаваскрипта тип хранился в первых трёх битах значения. Для типа «а это у нас null» значения не хватило, ему дали тип «объект», а под значение выделили нулевой указатель. Ну typeof, особо не заморачиваясь, выдавала object.

К сожалению, программисты поленились сделать дополнительную проверку. Можно было при наличии нулевого указателя попросить typeof выводить «null» и дело в шляпе. Сейчас, как оказалось, куча кода завязано на это поведение и ломать уже ничего никто не будет.

2014   javascript   программирование

«Яндекс.Фотки» и Ретина

Мне нравятся «Яндекс.Фотки». Не за архаичный дизайн и вёрстку таблицами, конечно, а за отсутствие ненужных мне сервисов и безразмерное (действительно безразмерное) хранилище.

Не нравится только, что я на Ретине не могу выдеть свои фотографии в том качестве, в каком мог бы. Я сейчас болею, кашляю, чтобы никого не будить, ушёл на кухню и сделал userjs для браузера «Сафари», который меняет дизайн «Фоток» и просмотр фотографий так, чтобы им было приятнее пользовать на Ретине.

Может ещё кому-нибудь пригодится:

// ==UserScript==
// @name      Retina Yandex Fotki
// @include   http://fotki.yandex.ru/*
// ==/UserScript==
(function () {
    function $(sel, attrs) {
        var os = typeof sel == "object" ? [sel] : document.querySelectorAll(sel);
        for (var e = 0, l = os.length; e < l; e++) {
            var o = os[e];
            for (var i in attrs) {
                if (attrs.hasOwnProperty(i)) {
                    if (typeof attrs[i] == 'number') {
                        attrs[i] *= o[i] || document.defaultView.getComputedStyle(o, null)[i];
                    }
                    o[i] = o.style[i] = attrs[i];
                }
            }
        }
        return os[0];
    }
    var img = document.querySelector(".js-img-link img");
    if (img) {
        $(".js-img-link img", {
            marginLeft: 1280 - img.width * 2 + 'px',
            zoom: '.5',
        });
        $(".b-preview__size_xxxl", {
            width: Math.max(640, img.width / 2) + 'px',
            height: img.height / 2 + 'px',
            overflow: 'hidden',
        });
    }
    $(".b-head-logo__img", {
        src: 'http://yandex.st/morda-logo/i/logo.svg',
        width: '89px',
        height: '60px',
        marginBottom: '-30px',
        position: 'relative',
        zIndex: '-1',
    });
    $(".b-head-menu .an-upload", {
        width: '80px',
        height: '17px',
    });
    var img = $(":-webkit-any(.user100, .b-userpic-small) img", {
        width: '40px',
        height: '40px',
        float: 'left',
    });

    if (img && img.src.substr(-6) == '-small') {
        img.src = img.src.substr(0, 84) + 'normal';
        $(img, {
            width: '20px',
            height: '20px',
        });
    }
    $(".b-round", {
        display: 'none',
    });
    $(":-webkit-any(.b-preview, .b-foto-actions, .b-foto-listing-i)", {
        borderRadius: '0px',
        webkitBorderRadius: '0px',
        backgroundColor: 'inherit',
    });
    var imgs = document.getElementsByTagName('img');
    for (var i = 0, l = imgs.length; i < l; i++) {
        imgs[i].src = imgs[i].src.replace(/S$/, 'M').replace(/XM$/, 'S').replace(/XS$/, 'S');
    }
})();

Сложнее всего было что-то сделать с тем, что часть атрибутов элементов на экране рассчитывается «Фотками» через ДжаваСкрипт, минимум в одном месте — показе большого фото, пришлось серьёзно подумать.

2013   javascript   программирование

Как узнать, что пользователь печатает веб-страницу на принтере?

У нас тут задача в процессе производства продукта появилась — занести в лог, что пользователь сделал попытку печати чего-либо в браузере. Есть событие onbeforeprint, но оно есть только в Эксплорере и Файерфоксе.

Придумал такое решение — перед печатью браузер накладывает стиль CSS для печати, если он есть, этим можно воспользоваться:

@media print {
    body {
        background: url(http://example.org/user-tries-to-print.php);
    }
}

Браузер попытается загрузить фоновое изображение (и загружает, я попробовал), выполнится серверный скрипт и положит в логи то, что нужно.

2013   css   javascript   программирование

JavaScript, совмещённый с Brainf*ck: «hello friends»

Помните моё поздравление с Новым годом, написанное на запутанном Джаваскрипте? Такой же принцип я использовал для привлекающего внимание баннера нашей компании.

Я давно уже заметил, что это сильно похоже на язык Брейнфак. Давно хотелось попробовать смешать эти два языка в одном листинге. Со стороны Брейнфака всё довольно гладко — надо только балансировать квадратные скобки (но Джаваскрипт требует того же) и избегать вечных циклов (тут уже сложнее, так как листинги на запутанном Джаваскрипте часто требуют пустых циклов), незнакомые символы этот язык пропускает. В Джаваскрипте синтаксис построже, там нужно было помучаться больше.

Получилась следующая программа (используется расцветка для Брейнфака, чтобы было видно какие части программы он пропускает):

($=!{}+[/-/]+/\+@+@+!+/)[-!{$:/>/+/!+>/+/<</}]+
(_=!-{}+[-$]+/>/)[-~(/>[->+>+<<]>>[-<+<+>>]<<</)]+
(_$=[-$][-{}]+[-$]+/>>/)[$$=-(~-~$+~-~$-!+{$:/!+>+>+>+>+>+<<<<</})]+
_[$$+=~-~{$:/[->++++>+>++++++++>++++++++>+++++++++++[<]]/}]+
_$[-~{}]+
_$[$$+~{_:-$>/[.>]/}]+
$[-+-$$]

Оба интерпретатора выполняют её с разным результатом, Брейнфак выводит «hello», а Джаваскрипт — «friends»:

bolk@Bolk ~$ ./brainfuck <(echo '($=!{}+[/-/]+/\+@+@+!+/)[-!{$:/>/+/!+>/+/<</}]+(_=!-{}+[-$]+/>/)[-~(/>[->+>+<<]>>[-<+<+>>]<<</)]+(_$=[-$][-{}]+[-$]+/>>/)
[$$=-(~-~$+~-~$-!+{$:/!+>+>+>+>+>+<<<<</})]+_[$$+=~-~{$:/[->++++>+>++++++++>++++++++>+++++++++++[<]]/}]+_$[-~{}]+_$[$$+~{_:-$>/[.>]/}]+$[-+-$$]')

hello

bolk@Bolk ~$ v8 -e 'print(($=!{}+[/-/]+/+@+@+!+/)[-!{$:/>/+/!+>/+/<</}]+(_=!-{}+[-$]+/>/)[-~(/>[->+>+<<]>>[-<+<+>>]<<</)]+(_$=[-$][-{}]+[-$]+/>>/)
[$$=-(~-~$+~-~$-!+{$:/!+>+>+>+>+>+<<<<</})]+_[$$+=~-~{$:/[->++++>+>++++++++>++++++++>+++++++++++[<]]/}]+_$[-~{}]+_$[$$+~{_:-$>/[.>]/}]+$[-+-$$])'

friends

Повозиться пришлось прилично, если честно, некоторые конструкции ДжЭс делит с Брейфаком (большинство квадратных скобок), а кое-где торчат чистые инструкции Брейнфака, засунутые в те места программы, где они не могут помешать своему соседу. Пустые циклы, которые образуются квадратными скобками я старался сводить к операции зануления ячейки („[-]“), сильно мешали плюсы, используемые в Джаваскрипте для объединения букв — они увеличивали содержимое ячейки в Брейнфаке на единицу, это приходилось учитывать.

Слово «friends» я выбрал потому что его легко записать:

"false"[0]+"true"[1]+"undefined"[5]+"true"[3]+"undefined"[1]+"undefined"[2]+"false"[3]

Принцип я когда-то более-менее подробно разбирал.

2013   brainfuck   javascript

Юникодные часы

В Юникоде есть несколько символов часов (не знаю, отобразятся ли они у вас, вот они): «🕐🕜🕑🕝🕒🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🕛🕧.»

Тут, как видите, шаг полчаса. Я вчера за завтраком сделал Юникодные часы, которые «ходят» поворотом символа (через ЦСС-трансформации). Часовая стрелка очень некрасиво скачет (я только для Вебкита делал и испытывал только в Сафари), потому что мне приходится вращать символ, чтобы минутная стрелка двигалась, а потом переходить на следующий символ. В общем, просто разминка для пальцев.

Юникодные часы (3.72КиБ)

Рассказать я хотел не об этом. Я и раньше встречался с тем, что часть Юникода не воспринимается многими программами нормально, особенно что касается раздела «Эмодзи, например „Яндекс.Фотки“ не так давно порадовали меня следующим (стоило переименовать картинку, всё стало в порядке):

«Яндекс.Фотки» (52.51КиБ)

Редактор „Сублиме Текст 2“ часто падает, если в тексте программы встречаются эти символы, а вот „Сафари“ удивил больше всех. Он их, вроде бы, понимает, но как-то не до конца:

"🕐".length; // 2
'🕐'[0]; // строка со «сломанным» символом
escape('🕐'); // "%uD83D%uDD50"

То есть, он считает символы Эмодзи не одним символом, а двумя. Такой вот баг. Мне пришлось в коде на ДжаваСкрипте это учитывать.

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

2013   javascript   safari   программирование

Скрипт для перевода даты из старого стиля в новый

Часто перевожу даты из юлианского календаря в григорианский (со старого стиля на новый), так как занимаюсь исследованием своих предков. Устал использовать для этого всякие веб-сервисы, написал по-быстрому JS, который переводит одну дату в другую, надо будет оформить как виджет или скриптлет и прицепить к своему браузеру.

function Jul2Greg(day, month, year) {
    // «сахар» для создания даты
    var d = function(day, month, year) {
        return new Date(year, month - 1, day, 12, 12, 12);
    }

    var date = d(day, month, year);

    // коррекция дней исходя из года
    var correction = date <= d(28, 2, 1700) ? 10 : 0 | (year / 100 - 17 + 11);

    // корректируем левый конец диапазона
    if (year % 100 == 0 && month < 3) {
        correction--;
    }

    return d(day + correction, month, year);
}
2012   javascript   программирование

Brainf★ck в highlight.js

Я как-то писал, что ко Дню программиста сделал подсветку синтаксиса языка Brainfuck для библиотеки highlight.js.

Оказывается, я пропустил выход версии 7.3, куда вошла моя подсветка, теперь Brainfuck входит в список поддерживаемых языков.

Побочный эффект оператора «delete» в JavaScript

Как говорится «век живи, век учись, дураком помрёшь»:

Объяснение (по крайней мере для Хрома) очень простое: когда вы делаете delete testedObject[i].obj, V8 нормализует объект testedObject[i] — трансформирует его из быстрого компактного представления в медленное и раздутое представление на основе словаря, который еще и выделяется с запасом по размеру. При этом V8 не замечает, что после удаления в словаре будет пусто — и словарь (800 байтов) остается болтаться в воздухе. И так для каждого из ваших объектов.

Из коментария к статье на «Хабре», которая описывает странный эффект — при использовании оператора delete что-то продолжает занимать память.

2012   javascript   программирование
Ранее Ctrl + ↓