Выкрутасы Opera

    Сразу замечу, данный пост не попытка подлить масла в огонь браузерной холивар. Это маленький рассказ об одном моем открытии в браузере Opera.
    Многие наверняка слышали, что Опера «фиксит» работу некоторых сайтов (и js библиотек), чтобы те в свою очередь нормально работали в этом браузере. Я как то натыкался на страницу с перечислением какие сайты и какие проблемы на них исправлены. Но как то не задумывался, как же они это «правят».

    И вот сегодня один из пользователей прислал нам «баг репорт» о том что наш сервис (ajax приложение) не работает в Опера 9.24, и прислал сообщение об ошибке из «Консоли ошибок». Странность в этом то, что еще недавно все работало в этой и других (более младших) версиях Оперы, а новых релизов у нас не было более полутора месяцев. Открыл Оперу, прошел на урл — у меня тоже не работает. Причем вылетает в самом начале. Ругается на странную строчку, ищу в своих скриптах. Нет такой. Тут вспомнил про «патчи» Оперы для сайтов — может там? После непродолжительных поисков нашел файл с хаками — который по сути обычный JS файл (называется browser.js), грузится самым первым и делает некоторую работу. Там то и оказалась злосчастная строчка. Немного осмотрелся: к чему это, что такое. Оказывается этот файл обновляется сам, и последний его update был 13 декабря (для этой версии) в нем так и написано, а закачался ко мне 20 декабря, когда я запускал оперу последний раз.
    По большей части все костыли в этом файле адресные, то есть предназначены для конкретных сайтов (да! проверяется location.hostname). Но часть общих. В частности, в моем случае проблему вызвал следующий код:
        Array.prototype.concat = function(){  // working around incompatibility with prototype, bug 241832
            var array = [];
            for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
            for(var i = 0, length = arguments.length; i < length; i++) {
              if(arguments[i].constructor == Array) {
            for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
              array.push(arguments[i][j]);
              } else {
            array.push(arguments[i]);
              }
            }
            return array;
        }
    

    Насторожило. Где то это я уже видел. Смотрю на комментарий (потому как не понятно к чему это они сюда приляпали) — точно: «working around incompatibility with prototype». В prototype я как раз это и видел. Посмотрел prototype, на машине оказалась версия 1.5 в которой есть:
    if (window.opera){
      // тот же код
    }
    

    Что за бред? В свое время сломал голову осмысливая данные строки в prototype. Я не знаю чем их не устроила реализация concat в Опера, но я не нашел тогда отличий от других реализации в других браузерах. Однако в Опере решили сделать как в prototype, создавая патовую ситуацию для приложений, когда arguments[i] имеет значение null или undefined (проверочку бы не помешало сделать). И не важно что вы пишите и какие библиотеки используете, в опера concat работает как в prototype.
    Ломаю голову как чинить (до этого были маленькие проблемы только с методомы Array.splice, но тут то что/как?!).
    А вообще всем рекомендую изучить этот browser.js, особенно тем кому интересно изучить работу Оперы изнутри. К тому же очень занятны комментарии, например:
    // 194334, Y!Mail remove selectSingleNode and selectNodes
    /* because Yahoo mail is better at emulating proprietary IE functions than we are.. */
    Node.prototype.selectSingleNode=undefined;
    Node.prototype.selectNodes=undefined;
    

    Кстати все эти танцы с бубном в Opera называют «magic fixes». Действительно «magic»!

    ЗЫ Пока писал каким то чудесным образом баг починился, но только у меня. Файл browser.js тот же самый, но ошибок не выдает. У остальных ничего не работает и пишет в консоль ошибку.
    UPDATE Выяснилось почему у меня «починился» баг. Дело в том, что в начале файла browser.js содержится подпись содержимого. Соответственно если поменять содержимое файла (я как раз поставил перевод строки в одном месте), то подпись уже будет другой и Опера перестает использовать этот файл, так как считает битым и ждет следующего обновления. Браузер еженедельно проверяет обновления этого файла, скачивает и использует, если конечно это не отключено в конфиге (например, opera6.ini). Настройка называется Browser Javascript. Спасибо rsa2048 за наводку.
    Поделиться публикацией

    Похожие публикации

    Комментарии 49

      0
      Действительно магия!
        +2
        Поправьте опечатку: "magick".

        Если бы это не был танец с бубном, то назывался он бы logical fixes :)
          0
          большое спасибо автору за столь интересный материал
            0
            Как заботливо сохраняются ссылки на "родные" методы!
            • НЛО прилетело и опубликовало эту надпись здесь
                0
                он идет вместе с оперой в комплекте...
                у меня он(мандрива) лежит в .opera в домашнем каталоге... в винде наверно в Document and Setings - вообщем поиск рулит...
                • НЛО прилетело и опубликовало эту надпись здесь
                    +1
                    В винде %APPDATA%/Opera/[папка в которой установлена опера]/profile/browser.js
                  +1
                  Прямо искусственный интеллект какой-то :)
                    0
                    Весьма интересно. Подскажите пожалуйста, а как вы просматриваете скачанные оперой js-файлы?
                    Есть что-то аналогичное Firebug'у? Очень пригодилось бы.

                    В своё время искал, но нашел только Developer Console на официальном сайте.
                    Тоже полезно, но просматривать js-файлы не позволяет.
                      0
                      вот еще очень полезная вещь
                      http://operawiki.info/WebDevToolbar

                      разработчики оперы обещют в новом году(в январе) выпустить какую то тулзу(подробнее http://operafan.net/content/view/290/40/ ) к браузеру по возможностям превосходящюю Firebug... ждемс..
                      0
                      У меня не работал один сайт в новой Опере (9.5), и я решил написать баг-репорт. Нажал соответствующую кнопочку, отправил. Через неделю где-то сайт чудесным образом заработал, хотя никаких видимых обновлений браузера не было. Списал на то, что сам "недостаточно усердно пытался открывать".
                        0
                        Спасибо, интересная информация. Файл читать интересно.
                        В принципе они правильные действия делают. Я первый раз натыкаюсь на то, что они кому-то подложили свинью и полагаю (и надеюсь), что таких случаев немного и за этим следят.
                        P.S.: Заметил что у гугля фиксят календарь, почту и таблицы. Вот бы еще записную книжку сделали писабельной.
                          0
                          Не соглашусь с вами. Что правильного в том что они фиксят работу своего продукта под конкретные условия. А что если его (сайт) завтра переделают, или пофиксят под оперу? В итоге сайт не будет работать потому что опера фиксит то что уже исправлено/изменено. Мне кажется разработчики сайта должны сами заботиться о работоспособности оного в разных браузерах + Опера заботиться чтобы работали сайты без костылей. А так выглядит все таким образом что программу подгоняют под тесты, то есть на данном наборе данных работает, а чуть в сторону все - не работает. А потом разработчики ломают голову почему один и тот же код на этом сайте работает, а на моем нет :(
                            +3
                            Да, понимаю, поддерживаю.
                            Но мне всё равно нравится подход взять и приделать хотя бы костыль, позаботиться о пользователе.
                            Я могу быть десять раз верстальщиком/разработчиком сайтов и апологетом стандартов, но мне почти всегда всё равно почему именно криво отображается чей-то сайт. Особенно, если я в нем не был заинтересован. Чаще всего я потребитель.
                            В Opera могли бы пенять на разработчиков сайтов и прочие отмазы - но они просто со старанием делают своё дело. За это им моё уважение и я с ними надеюсь, что костыли когда-нибудь не понадобятся :)
                              +1
                              Согласен. Особенно учитывая, что тот же Гугль никогда не станет впрягаться, чтобы фиксить свои сервисы для Оперы.
                                –1
                                >Но мне всё равно нравится подход взять и приделать хотя бы костыль, позаботиться о пользователе.

                                ага, и создать 10^n лишних действий для разработчика.
                                а еще орут за стандарты. кхм на таких костылях до финиша первыми не добежать.
                                +1
                                с какой стороны смотреть - по мне так идея крайне простая и здравая: разработчики сайта заботятся о фиксах для оперы(наверняка опера кантактирует с тем же гуглом), опера фиксает на уровне браузера свои проблемы - ну а всё остальное что пока не исправлено в конкретном сайте(или по каким то причинам - на уровне движка оперы) временно поправлено костылем - пользователь ведь хочет видеть рабочий сайт уже сейчас.
                                а под тесты никто ничего не подгоняет - тем более что эти фиксы никак не пытаются скрыть(хотели бы скрыть - скрыли бы;))
                                  0
                                  Я к тому что вряд ли в Opera отслеживают изменения на сайтах. И если сайт исправил, что-то то костыль так может и остаться, хотя он и не нужен уже.
                              +1
                              "баг починился, но только у меня. Файл browser.js тот же самый, но ошибок не выдает. У остальных ничего не работает и пишет в консоль ошибку"

                              это тебя опера зауважала... и, в порядке исключения, пустила код работать...

                              А остальные её "не раскусили", поэтому опера им не дала... работающего кода... :)))
                                0
                                Не думаю :)
                                Больше всего расстраивает в этом тот факт, что не ясно почему так. И так постоянно. Если смотреть на другие браузеры, то там либо работает, либо не работает. А в Опере может работать, а может и не работать - причем причину выяснить часто (как в данном случае) просто невозможно.
                                Хотя может мы чего то не знаем?
                                  +1
                                  Идеология Оперы — в поддержке как стандартов, так и т.н. quirks. В том числе и таким способом.
                                0
                                афигеть! а вырубить это можно?
                                  0
                                  Боюсь что нет. Или заставить всех пользователей Опера потереть этот файл? И то мне кажется не поможет, потому что он постоянно обновляется и подгружается.
                                    –2
                                    просто на мой взгляд, это не есть хорошо :)

                                    это же не опера мини. это обычная опера. и если сайты, которые работают везде, не работают в ней - надо и чинить ее, а не сайты...
                                      0
                                      О чем и речь.
                                      Починить это поведение (то что у меня не работает) можно, но ведь это не особенность работы браузера, а просто заплатка для того чтобы сайты на Prototype работали, и которая "вроде бы никому не мешает". Проверили пару сайтов, на том и успокоились. Теперь я должен сделать заплатку в своем приложении. Завтра они ее "отменят", заплатка будет ненужной. И т.д.?
                                      Что-то мне не нравятся перспективы :)
                                      0
                                      Ручками можно.

                                      about:config

                                      Browser JavaScript:

                                      Whether to download and use the browser.js file. Enable by setting to 1, Opera will then download the file and set to 2.
                                      0 = Never download or use
                                      2 = Use and check for updates weekly (default)
                                      1 = browser.js signature invalid. On next check for update, a new browser.js will be downloaded and the value set to 2.

                                      http://www.opera.com/support/usingopera/operaini/
                                        0
                                        Ага! Предлагаете это всем пользователям писать: "Если у вас Опера и сайт не работает, то сделайте следующее: ...". Боюсь что так сайт только потеряет пользователей.
                                      0
                                      Может, стоит в блог оперы перенести?
                                        0
                                        Перенес :)
                                        0
                                        Буду краток. (с)
                                        Здесь все о.
                                        Просто ссылка в тему.
                                          0
                                          Да как раз про этот перечень я и говорил в тексте. Одно "но". Статья эта давно не обновлялась, и не отражает все фиксы.
                                          0
                                          Еще нюанс. Оперу можно заставить маскироваться под IE и FF. А вот реализация-то JS (правильная или нет — уже другая дискуссия) не меняется... Вот здесь BrowserJS фикс для prototype и пригодится.
                                          Это гипотеза, проверю позже.
                                            +1

                                            Когда Opera маскируется под другой браузер, то просто меняет значение UserAgent, все остальное остается прежним.

                                            А насчет правильного фикса, то вот пример того как это делаю я, без ущерба для окружающих. У Оперы есть проблема с методом splice когда второй параметр не указан, то опера ведет себя неверно. Вот фикс:

                                            (function(){ 
                                            var native = Array.prototype.splice;
                                            if ([1,2,3,4,5].splice(3).length == 2)
                                            Array.prototype.splice =
                                            function(){
                                            var params;
                                            for (var i = 0; i < arguments.length; i++)
                                            params.push(arguments);
                                            if (params.length < 2)
                                            params[1] = this.length;
                                            return native.apply(this, params);
                                            }
                                            })();

                                            Как тут можно заметить, фикс не проверяет - является ли браузер Оперой или другим, он просто знает что у определнных браузеров есть такая проблема - проверяет есть ли у данного. Если да, делаем подмену, если нет - то ничего не меняем.

                                              0
                                              да. вот бы всему прототайпу такой подход...
                                              еще бы кэшировать результат теста неплохо.
                                                0
                                                Зачем кешировать результат теста, если это выполняется один раз?
                                                  0
                                                  Упс, сорри, проглядел.
                                                0
                                                В общем, вы правы насчет userAgent'a. По typeof window.opera Опера вычисляется на раз.
                                              0
                                              Представляю, какой вой поднялся бы в комментах, если бы это было обнаружено в MS Explorer-е...
                                                0
                                                Буквально третьего дня подгонял скрипт под ослика. Матерился на builder.js и prototype.js метод чтойтотам._each (тот самый, который самыйглавный). C builder'ом решилось просто — сделал workaround, с each основной секс еще предстоит. Нутром чую — дело в аргументах, но вот как их отловить? Фаербага-то нет. Как представлю, что придется "назад к алертам", аж вою. Мегабайты вывода console.log() тоже парсить не улыбается.
                                                +1
                                                Попробовал изменить browser.js на своей опере - фигвам.
                                                После изменения опера устанавливает Browser JavaScript с 2 на 1 (\Opera9\profile\opera6.ini) и перестает использовать измененный browser.js.

                                                Browser JavaScript
                                                Whether to download and use the browser.js file. Enable by setting to 1, Opera will then download the file and set to 2.
                                                0 = Never download or use
                                                2 = Use and check for updates weekly
                                                1 = browser.js signature invalid. On next check for update, a new browser.js will be downloaded and the value set to 2.

                                                Похоже опера где-то хранит чексумму оригинального browser.js и не дает использовать
                                                модифицированный?
                                                  +1
                                                  Как ни странно, в начале файла browser.js.
                                                  Вот почему у меня заработало чудесным образом, я немного поменял этот файл (добавил один перевод строки), и фикс перестал использоваться. Не перестаю удивляться.
                                                    0
                                                    Эта чексумма напоминает MIME/UUE coded 2048 битный хэш.
                                                    Кто-ть как знает его рассчитать?
                                                  +1
                                                  Дневник разработчика из Opera Software, который, в основном, и поддерживает скрипты в browser.js.
                                                    0
                                                    думаю проблема не так страшна - баг репорт - и жс-ник пофиксают в ближайшее время, а т.к. он обнавляется автоматом - то и проблемы с сапортом предыдущих версий нет.
                                                      0
                                                      Раньше помню под Делфю пишу код... ну всё правильно нигде не накосячил не компилит хоть что делай: еггоги, варнинги... Ну, думаю Борланд накосячил... потом решаю написать чтоли багрепорт - оставляю до утра. Уторм со свожей головы нахожу свой косяк - вся работает.

                                                      Натыкался на такую граблю раза 3. Отсюда мораль: "если думаешь что косячит компилер(браузер,...) значит косячишь ты!"
                                                        0
                                                        а может стоило все таки дебаггером пройтись и проверить? тут человек проверил!

                                                        хотя помню именно в delphi была похожая магия, приходилось несколько раз подряд перезапускать :)
                                                        0
                                                        Мдя, отладку данная особенность Оперы затрудняет порой в разы. Сталкивался, причем на примере того же Prototype.

                                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                        Самое читаемое