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

Opera 10.50: скоро

22-го декабря компания «Опера» пообещала показать версию 10.50 pre-alpha. Ключевым изменением называется скорость (что не может не радовать), а не поддержка всякого из CSS3 (border-radius, CSS-анимация), о котором я писал ранее.

Это подарок компании к Рождеству.

8 комментариев

Safari, Chrome и «решётка»

У браузеров на движке WebKit какое-то своё, фашисткое отношение к «решётке» (#), после которой указывается локальный якорь в URL.

Во-первых, когда устанавливаешь location.hash, где более одной «решётки», Safari и Chrome иногда перезагружают страницу (зачем?).

Во-вторых, вторая и последующие «решётки» кодируются как «%23» (ни один браузер больше так не делает).

В-третьх, если постоянно что-то делать с частью после решётки (например, каждые 10 миллисекунд прибавлять и убавлять один символ), то эти два браузера-моих-кровопийцы не позволят редактировать адрес.

Иногда я верю, что один браузер это хорошо.

Иногда.

Добавлено 13 декабря 0:40: в комментариях мне подсказываю, что, кодируя «решётку» как «%23», WebKit поступает по RFC. То есть, формально, претензий никаких. По смыслу же, мне кажется, что «решётку» тут кодировать не надо.

14 комментариев

Опера ест память

Опера есть память (5.75КиБ)

Это очень странно, но стоит включить Flash в «Опере», как она начинает нещадно есть память. На скриншоте (открыто всего 12 закладок) далеко не худшая ситуация, я видел как она съедала вдвое большее количество. Помогает только снятие задачи (закрыть не получается, «Опера» продолжает висеть в памяти) и запуск заново.

Ситуация повторяется на обоих моих ноутах, под разными ОС (на одном — Windows XPSP3, на втром — Windows 7) и с разными версиями браузера (10.10 и 10.20).

Добавлено 11 декабря 2009 13:55: в комментах говорят, что с Flash так себя ведёт любой браузер. Видимо, новые версии Flash имеют какие-то дикие утечки памяти. Надо поискать user.js для «Оперы», который включает Flash по клику.

23 комментария

User.js и FF

Сегодня написал небольшой user.js для «Оперы» и решил его переписать под плагин «Greasemonkey», под «Firefox». Оказалось, что есть немаловажные различия.

Во-первых, объект window браузера напрямую недоступен — нужно пользоваться «unsafeWindow», но руководство не рекомендует его использовать. Мне в user.js window браузера нужен был для доступа к jQuery, который был подгружен на странице, где работает скрипт, мне было удобно использовать этот framework. Объект «window» тоже есть, это внутренний объект Greasemonkey и выглядит как настоящий, только не радует на него, например, рекомендуется вешать все события.

Во-вторых, обращаться к функциям, определённым на странице, рекомендуется через

location.href="javascript:void(pageFunc(123))"

, утвержается, что это более безопасно, видимо, чтобы не передавать контекст выполнения наружу. Говорят, что в Chrome 4 это единственный способ добраться до «window».

В-третьих, из скриптов, выполняющихся из Greasemonkey, можно использовать функции «GM_xmlhttpRequest» (XHR с возможностью делать запросы на любые адреса), «GM_log» (логгирование, как можно догадаться) и так далее.

Ну и можно использовать localStorage (FF 3.5+) и globalStorage (FF 2.0+) для сохранения данных user.js.

8 комментариев

TestLink

Время от времени занимаюсь модификацией используемого внутри компании инструмента «TestLink». Сложная задача — приделать к нему ЧПУ (TestLink целиком на фреймах, у него не то что ЧПУ, обычных-то URL нет).

С задачей справился чуть менее, чем полностью — осталась пара мелочей, а в пятницу по половины одиннадцатого вечера боролся с деревом тест-кейсов. Всё просто — получили линк на test case, нужно раскрыть дерево на определённом узле. Дерево выполнено не на православном jQuery, а на сатанинском ExtJS (кстати, привет авторам ExtJS и вопрос — для чего вы делали собственные ID, но не потрудились сделать возможность привязаться к ним из select и get?).

Осложняется всё тем, что дерево снаружи недоступно (изолируется внутри функции), а менять JS-код продукта я не могу, это крайне нежелательно. Пришлось эмулировать события, чем я раньше никогда не занимался. Оказывается на эту тему есть весьма развесистые плагины (в том числе и для jQuery), я эмулировал вполне конкретное событие — клик мышью, поэтому сделал свою небольшую функцию, как водится, две ветки — для IE и всего остального. Запишу сюда, чтобы не потерять:

function fireEvent(element, eventname){
    if (document.createEventObject){
        return element.fireEvent('on' + eventname, document.createEventObject())
    } else{
        var event = document.createEvent("HTMLEvents")
        event.initEvent(eventname, true, true)
        return !element.dispatchEvent(event)
    }
}

В итоге получилась дикая вещь — когда человек вводит этот самый понятный ему URL, браузер спрашивает у сервера путь по дереву, получает его, по таймеру долбит дерево в плюсики (дерево грузит каждый узер через AJAX), чтобы развернуть каждый узел по пути следования к test case, а когда добирается до цели, таймер тушится.

Такие развесистые клюквы там приходится программировать на каждом шагу. Зато все URL абсолютно понятны пользователю и роутинг правится очень просто.

Добавлено 8 декабря 2009 0:41: потом я переписал всё на чистом ExtJS, воспользовавшись getCmp, expandPath и внутренней реализацией fireevent, но код всё равно тут оставлю — пригодится.

3 комментария

Presto 2.4

На Web Standards Days увидел, наконец, новый движок «Оперы» — Presto 2.4 в действии! Новую «Оперу» показывал Вадим Макеев (он работает в этой компании), версия 10.50 (название кодовое) поддерживает border-radius и целую кучу других интересных вещей. Первые публичные сборки появятся, вероятно, уже в начале следующего года.

Кстати говоря, Presto 2.4 уже работает в Opera Mobile 10 beta, которую можно скачать, но, к сожалению, эти самые интересные вещи (и border-radius тоже) в ней отключены.

8 комментариев

Input multiple-2

По мотивам предыдущего поста. Чтобы Opera 9+ (а так же 3.5—6.05), Firefox 3.6+, Chrome 3.0.191.0+ и Safari 4.0.1+ позволили выбрать несколько файлов в диалоге загрузки файлов, нужно написать вот такой код:

<form enctype="multipart/form-data" method="post">
   <input type="file" min="1" max="9999" name="file[]" multiple="true" />
   <input type="submit" name="submit" />
</form>

Я указал «file[]» для того, чтобы PHP сразу разложил полученные файлы по массиву $_FILES. К сожалению, запрос от «Оперы» PHP понимает неверно, так как «Опера» шлёт такой запрос в формате multipart/mixed. К счастью, PHP в этом случае положит содержимое файлов одним MIME-куском прямо в $_POST[’file’][0], а там его уже можно разобрать (надеюсь, директива magic_quotes_gpc у вас отключена).

Я попробовал, это несложно. Для того, чтобы разобрать MIME-секцию, я использовал PECL-модуль mailparse (есть версия для Windows):

if (isset($_POST['file'], $_POST['file'][0])) {

    if ($idx = strpos($_POST['file'][0], "\n")) {
        $bound = substr($_POST['file'][0], 2, $idx-2);

        $body  = "MIME-Version: 1.0\nContent-type: multipart/form-data; boundary={$bound}\n\n".
                 $_POST['file'][0];

        unset($_POST['file'][0]);
        $f = &$_FILES['file'];

        $f['name'] = $f['type'] = $f['tmp_name'] = $f['error'] = $f['size'];

        $msg = mailparse_msg_create();

        if (mailparse_msg_parse($msg, $body)) {
            $i = 0;

            foreach(mailparse_msg_get_structure($msg) as $st) {

                $section = mailparse_msg_get_part($msg, $st);

                $data = mailparse_msg_get_part_data($section);

                if ($data['content-type'] == 'multipart/form-data') {
                    continue; 
                }
            
                ob_start();
                if (mailparse_msg_extract_part($section, $body)) {
                    $tmp = tempnam(sys_get_temp_dir(), 'php');
                    file_put_contents($tmp, ob_get_clean());

                    $f['name'][$i] = $data['disposition-filename'];
                    $f['type'][$i] = $data['content-type'];
                    $f['tmp_name'][$i] = $tmp;
                    $f['error'][$i] = 0;
                    $f['size'][$i] = filesize($tmp);

                    $i++;
                } else {
                    ob_end_clean();
                }
            }
        }
        unset($f);

        mailparse_msg_free($msg);
    }
}

var_dump($_FILES); // результат помещатся в $_FILES, не забудьте удалить временные файлы после обработки!

У меня ожидается, что содержимое файлов будет передано как параметр «file[]» (в $_POST это будет $_POST[’file’][0]), но пример несложно переделать на любое другое имя или сделать это имя параметром.

5 комментариев

Input multiple

Я как-то пропустил, хотя сам участвовал в голосовании за эту фичу, что бете FF 3.6 появилась возможность выбрать несколько файлов при загрузке (это часть стандарта WebForms 2). Простой пример использования:

<input type="file" name="input" multiple="true" />

Ещё более интересно, что в свежей бете (№4) этого браузера есть возможность (как я понял) получить доступ к выбранным файлам из веб-приложения.

Попробовал посмотреть как выгдядит прикрепление нескольких файлов со стороны PHP, оказалось всё просто — достаточно сказать PHP, что из входящих данных нужно сделать массив и всё работает (например, указать name=«input[]»): в каждом поле каждого элемента массива $_FILES содержится массив значений. Вот как это выглядит для двух файлов:

array(1) {
  ["input"]=>
  array(5) {
    ["name"]=>
    array(2) {
      [0]=>
      string(14) "2009.09.23.jpg"
      [1]=>
      string(14) "2009.08.25.jpg"
    }
    ["type"]=>
    array(2) {
      [0]=>
      string(10) "image/jpeg"
      [1]=>
      string(10) "image/jpeg"
    }
    ["tmp_name"]=>
    array(2) {
      [0]=>
      string(18) "Z:\tmp\php3740.tmp"
      [1]=>
      string(18) "Z:\tmp\php3741.tmp"
    }
    ["error"]=>
    array(2) {
      [0]=>
      int(0)
      [1]=>
      int(0)
    }
    ["size"]=>
    array(2) {
      [0]=>
      int(35005)
      [1]=>
      int(63030)
    }
  }
}

Конструкция работает в Chrome с версии 3.0.191.0 и в Safari с версии 4.0.1. К сожалению, в Opera 10.20 alpha 1 поддержки нет, в IE8 — тоже.

Добавлено 29 ноября 2009 23:08: оказывается, «Опера» поддерживала с версии 3.5 загрузку сразу нескольких файлов в обычном, «однофайловом» диалоге, но в 7-й версии эту возможность открутили. Так что «Опера» первый браузер, где это реализовали.

Добавлено 29 ноября 2009 23:14: «Опера» 9.0 и выше поддерживает загрузку множества файлов в одном контроле, достаточно указать параметры min и max:

<form enctype="multipart/form-data" method="post">
   <input type="file" min="1" max="9999" name="file" />
   <input type="submit" name="submit" />
</form>

Плохие новости заключаются в том, что PHP такой запрос от «Оперы» разбирать не умеет.

Добавлено через год: в «Опере» 11 атрибуты «min» и «max» удалили, но зато работает «multiple».

2 комментария

Функциональное тестирование и Selenium

Посмотрел «Selenium» — прекрасный, на мой взгляд, инструмент для автоматизации функционального тестирования. Из аналогов я нашёл только «Watir», но он мне показался сильно беднее (или только показался?). Платных аналогов много, в том числе от именитых IBM и HP, но хочется именно бесплатного.

Собственный опыт у меня пока небольшой (я написал несколько тестов и бегло прочитал документацию), а из прочитанного в сети я сделал вывод, что у «Селениум» есть проблемы. Вроде как он не любит фреймы (сомнительно) и стабильно работает только в Firefox (мне FF пока достаточно).

Я пока использовал только версию для Firefox (дополнение Selenium IDE). Самый простой способ изготовить тест выглядит следующим образом: открываем Selenium IDE, создаём новый тест, подготавливаем браузер (переходим на страницу, с которой тест начнётся), жмём на красную кнопку записи (справа на панели инструментов), в браузере выполняем какие-то действия, останавливаем запись и смотрим что получилось.

После того как последовательность действий в браузере была записана «Селениумом», нужно посмотреть что получилось, возможно что-то поправить. Язык простой и очень понятный, нужно лишь немного знать английский. В своём первом тесте я лишь вынес в переменную вводимую строку, чтобы позже использовать её в assertion и переделал селектор элемента с XPath на CSS (элементы можно выбирать через XPath, CSS, DOM, ID элемента, regexp и ещё несколькими способами), а так же добавил сам assert, ведь «Селениум» не знает что является успешным завершением теста.

Вот простенький тест, который я записал, что проиллюстрировать принцип:

сохраняем тестовую строку
store THIS-IS-TEST-STRING testPhrase

 открываем страницу в браузере
open /EvgenyStepanischev

 жмём на ссылку, в которой содержится указанное значение и ждём, когда браузер её полностью загрузит
clickAndWait link=EvgenyStepanischev / Тестирование

 жмём на ссылку, которая выбирается CSS-селектором
clickAndWait css=.edittab a.b-button-yellow

 печатаем
type postText ${testPhrase}

 жмём на клавишу с указанным ID
clickAndWait really_save_button1

 проверяем есть ли на странице наш текст
assertTextPresent ${testPhrase}

Чтобы тест выполнился, нужно указать для него базовый URL (по которому будет выполняться тест и нажать кнопку запуска теста и тест сьюта). На нашей внутренней «Вики» в «Яндексе» этот тест откроет мой кластер, найдёт там страницу «Тестирование», нажмёт на ней кнопку редактирования, напечатает в страницу «THIS-IS-TEST-STRING», сохранит изменение и убедится, что введённая строка появилась на странице.

Большинство потребностей покрывается языком «Селениума», для какие-то совсем уж сложных вещей можно использовать JavaScript (блок javascript { … }).

Есть возможность удалённого запуска тестов на нескольких браузерах и использование языков C#, Perl, Ruby, Python, PHP и Java, но я пока с этим богатством не разбирался, первые потребности вполне покрываются тем, что я уже знаю, дальнейшее — дело будущего.

Добавлено 22 ноября 2009 13:40: Андрей Ларионов подсказал ещё один бесплатный продукт — «Tellurium», но я не вижу преимуществ перед «Селениумом», зато вижу недостатки, например, усложнённый (по сравнению с «Селениумом») язык описания тестов.

8 комментариев

mod_rewrite: просмотр списка правил только один раз

У модуля mod_rewrite сервера «Апач» есть особенность, которая иногда портит много крови — после каждого переписывания URL, он просматривает список правил снова. Если ничего не предпринять, иногда происходит зацикливание, что ввергает новичков в ступор.

Мне эта особенность ни разу не пригодилась, но избавляться от неё приходится постоянно. В комментариях на «Хабре» к статье, название которой я вынес в заголовок, подсказали очень хороший способ, добавить первым правилом следующее:

# Don't loop.
RewriteCond %{ENV:REDIRECT_STATUS} !^$
RewriteRule .* - [L]

Если перезапись URL уже происходила, то любой URL оставляем без изменений и следующего цикла обработки уже не происходит.

10 комментариев

IE9

В блоге Microsoft, посвящённом их браузеру появилась статья об Internet Explorer 9. То, что есть сейчас уже очень неплохо — IE9 по скорости (если верить данным Microsoft) лишь чуть-чуть отстаёт от FF 3.6 и всего в два раза медленнее Chrome 4 (учитывая насколько он шустрый, это совсем неплохо).

Internet Explorer 9.0 проходит тест селекторов CSS3 с результатом 574 из 578 (IE8 — 330/578), тест ACID3 — 32% (IE8 — 20%), поддерживает border-radius (несмотря на более ранние заявления Microsoft, что CSS3 ещё пока слишком сырой, чтобы что-то из него реализовывать, кроме селекторов) и это только начало — ведь это даже ещё не альфа-версия!

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

P.S. Кстати, если покопаться, то можно найти как выглядит user-agent нового браузера: «Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/4.0)», IP, откуда заходили этим браузером, принадлежит городу Редмонд (в нём работает около 30 тысяч сотрудников Microsoft).

Движок, как видим, всё ещё называется «Trident», хотя номер смущает — 4.0, как мы знаем, версия, которая входит в IE8.

7 комментариев

Flash и безопасность

В качестве вялых воскресных препирательств, на «Хабре» как-то неожиданно вылезла мнимая проблема Flash — что загрузив ролик, можно попытаться получить доступ к cookie сайта или сделать какие-то другие интересные недобрые вещи.

Между тем, правил для защиты от таких «уязвимостей» всего два: выдавать при обращении к заливаемым пользователем Flash заголовки для скачивания (а то и вообще отдавать все пользовательские ролики с другого домена, порта или протокола) и указывать правильные параметры для проигрываемых роликов, залитых пользователем. Последнее — нехитрая наука, таких параметров всего три: allowScriptAccess, allowNetworking и allowFullScreen.

Их назначение легко расшифровывается по названию.

Параметр allowScriptAccess (введен во Flash 6.0.40.0) управляет доступом к JavaScript/DOM браузера и имеет три возможных значения: always, sameDomain и never. Пояснения, на мой взгляд, требует только значение sameDomain. Если выбрано это значение, то доступ предоставляется только скриптам, которые загружены с того же домена, что и страница, куда они подключены.

Следующий параметр, allowNetworking (работает, начиная с Flash 9.0) разрешает или запрещает обращение Flash к собственным сетевым функциям и сетевым функциям браузера. Имеет значения all, internal (запрещает использование сетевых функций браузера) и none.

Параметр allowFullScreen (Flash 9 и выше) принимает два возможных значения — false (выставлено по умолчанию) или true, которые (соотвественно) запрещают или разрешают использование полноэкранного режима.

Очевидно, что наиболее безопасные параметры — allowScriptAccess="never", allowNetworking="none" и allowFullScreen="false":

<object height="400" width="500">
<param name="allowScriptAccess" value="never" />
<param name="allowNetworking" value="none" />
<param name="movie" value="ролик.swf" />

<embed type="application/x-shockwave-flash"
     allowScriptAccess="never" allowNetworking="none" src="ролик.swf" height="400" width="500" />

</object>

Очень жаль, но значение «never» для параметра для параметра «allowScriptAccess» сейчас является deprecated, так же как и использование параметра allowNetworking, когда страница, на которой подключен ролик и сам ролик загружаются с одного и того же домена.

Насколько я понимаю, это связано с тем, что фирма Adobe, текущий владелец технологии Flash, не хочет брать на себя ответственно за утечку критичных данных через Flash-ролики. Вместо использования этих значений параметров рекомендуется загружать Flash-ролики с другого домена и не допускать того, чтобы критичные данные и ролики были доступны с одного домена.

12 комментариев

Локальные переменные и JS

Читал тут по диагонали стандарт ECMAScript и подумалось мне, что сэмулировать локальные переменные (да, я осознаю, что это свойства объекта) можно вот так:

var a = 10;
with ( { a : 20 }) {
    alert(a);
}
alert(a);

Ожидаемый результат: сначала код выведет «20», потом — «10». Я ещё не задумывался над тем насколько это практично и изящно, просто придумалось.

Кстати, обратите внимание, что следующий код выведет «30», «30», «10», «30»:

var a = 10, b = 10;

with ({a:20}) {
    var a = 30, b = 30;
    alert(a);
    alert(b);
}

alert(a);
alert(b);

Добавлено 10 ноября 10:55: в комментариях почему-то подумали, что я не знаю о лексических замыканиях. Знаю, конечно.

6 комментариев

Полезные rgba в IE

Вадим Макишвили описал несколько примеров применения rgba в Internet Explorer. Примеры очень и очень полезны, и я скопирую их (без картинок, за ними идите в исходный пост) к себе:

Сегодня, благодаря этому новому знанию, я понял как решить две труднорешаемые задачи. Издавна, чтобы сделать фон блока полупрозрачным, мы вынуждены были использовать или png-24 картинку в фоне или opacity-свойство.

Но в случае с png-24, для ИЕ6 нужно писать AlphaImageLoader фильтр, который катастрофически замедляет рендеринг страницы. А в случае с opacity приходилось придумывать трюки, чтобы дети блока не бледнели от родительского opacity.

А теперь проблему opacity можно забыть, как страшный сон: .block { background: #rgba } * html .block { filter:progid:DXImageTransform.Microsoft.gradient (startColorstr=#99000000, endColorstr=#99000000); }

В начальной и конечной позиции один и тот же RGB (000000) и добавляю перед ним одно и то же значение Alpha (99) Значение Alpha указывается в 16-тиричной системе, где 00 — полностью прозрачный, а ff — непрозрачный пиксел

Я протестировал скорость рендеринга страницы, на которой выливается 300 элементов с gradient-фильтром — он не замедляет рендеринг и это сильно радует.

Но этот случай описывает ситуацию, когда нужно сделать однотонный полупрозрачный цвет, как например в модальных диалогах, когда вся остальная страница затемняется.

Иногда использовать png-24 всё-таки необходимо, как например в случае, когда нужно обрезать длинную неразрывную строку, уводя ее градиентом в непрозрачность.

В этом случае можно использовать второй способ. .block { background: url(image.png) } * html .block { filter:progid:DXImageTransform.Microsoft.gradient (startColorstr=#00ffffff, endColorstr=#ffffffff, GradientType=1); }

GradientType принимает значение 1, если градиент рисуется слева-направо; и 0, если градиент сверху-вниз.

MSIE хороший браузер.

7 комментариев

Компрессоры JavaScript и точка с запятой

Точка с запятой — один байт, перевод строки — один байт. Мне тут подумал, что лучше бы компрессоры JS выкидывали при сжатии не переводы строки, а точки с запятой (там где это возможно, конечно, например, пустой return в некоторых случаях нельзя завершить только переводом строки).

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

14 комментариев

Сколько нужно людей, чтобы получился Chrome

Бобук рассказывает про количество людей, имеющих отношение к появлению Chrome:

Итого, представь себе что 10 миллионов долларов в акциях размазывается между разработчиками проекта. Такие небольшие проекты как Chrome в гугле затрагивают очень небольшую группу, скажем всего 500-600 человек разработчиков, 50-100 дизайнеров, 200-300 маркетологов, под сотню админов, сотня менеджеров. Итого на нос получается в пике 10 тысяч на лицо. Теперь подумай, что такое в Калифорнии 10 тысяч долларов _В АКЦИЯХ_, т. е. после реализации акций и уплаты налогов — у тебя на руках 5 тыщ долларов.

В ответ на вопрос откуда информация и по поводу численности:

Про команду разработки? Есть некотрые инсайдеры. Не, вообще команда разработки там примерно в 3 раза меньше, но есть же масса людей, которые учавствуют в проекте «парттайм», а доля будет такая же, как и у тех кто работал только над ним.

После недавней фразы Брина «мы ведем исследования небольшими группами по 200-300 человек», я уже ничему не удивляюсь.

Почти тысяча человек даже в самом минимальном случае!

13 комментариев

IE и rgba

Век живи, век учись. Оказывается, в Internet Explorer есть возможность, через фильтры, указывать rgba-цвет:

.element{
    /*color = black, opacity = 0.6 */
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000,endColorstr=#99000000); /*AARRGGBB*/
    zoom: 1
}

Большая часть фильтров понимает цвет в формате argb (первая компонента — прозрачность).

4 комментария

«Консультант» и IE

Вчера на «Хабре» люди в очередной раз подняли тему сайта «Консультанта» и Internet Explorer — первый, своей интересной частью, работает только на втором. Как я и ожидал, код завязан на особенности Internet Explorer, браузер богатый на возможности, на сайте использовано их немало. Впрочем, всё, если вдуматься, переводится и на более стандартные рельсы.

У меня давно руки чесались разобраться поподробнее как устроены userjs в «Опере» и посмотреть на отличия реализации XSLT-процессинга в IE и остальных браузерах. Userjs в «Опере» устроены исключительно удобно (даже предусмотрели патчи к выполняемому коду), а с XSLT в IE нестандартно, зато много проще.

По результатам появился userjs, который позволяет увидеть две первые страницы базы «Консультанта» в «Опере», если кому-нибудь хочется, допилите его дальше, я это делал исключительно из интереса научиться полезному, сама база мне без надобности.

Текст userjs помещаю под кат.

// ==Userscript==
// @name         Make Consultant base works
// @namespace    /
// @description  Make Consultant base works in non-IE browsers.
// @include      http://base.consultant.ru/*
// @version      1.0
// @licence      MIT
// ==/UserScript==

(function(){

    /* TODO
       saveCard — это behavior userData, сделать эмуляцию
       VBArray  — одна из переменных использует этот специфический массив
       isBaseVisible, ForEachRow — убрать заглушку, сделать нормальную функцию
       showModalDialog — дописать с передачей параметров (например, через window.name)
    */


    document.addEventListener('load', function (e) {
        showModalDialog = window.open;

        return true;
    }, false);

    DOMParser.prototype.loadXML = function (text) {
        return this.parseFromString(text,"text/xml")
    }

    opera.addEventListener('BeforeScript', 
        function(e){
                if (e.element.getAttribute('for')) {
                    var script = e.element.text
                    var id     = e.element.getAttribute('for')
                    var ev     = e.element.getAttribute('event')

                    e.element.text = ''
                    document.addEventListener('load', new Function('',                     
                        'document.getElementById("' + id +
                        '").attachEvent("' + ev +
                        '", function () {'+ script + '})'
                    ))
                }

                var repl = {
                    'document\\.body\\.attachEvent'   : 'document.attachEvent',
                    'document\\.all\\.fieldsXML\\.XMLDocument\\.transformNode': 'document.transformNode',
                    'document\\.all'                  : 'document.getElementsByTagName("*")',
                    'document\\.frames\\('            : 'document.getElementsByTagName("iframe").item(',
                    '\\.XMLDocument\\.text'           : '.textContent',
                    'document\\.body'                 : 'document.documentElement',
                    '\\.parentElement'                : '.parentNode',
                    '\\.XMLDocument\\.documentElement': '',
                    '\\.XMLDocument'                  : '',
                    'basesRow\\.all\\.basesTable'     : 'document.getElementById("basesTable")',
                    '\\.all\\.tags\\('                : '.getElementsByTagName(',
                    '\\.all\\.([^\\.;\\s]+)'          : '.getElementById("$1")',
                    '\\.all\\('                       : '.getElementById(',
                    '\\w+\\.getElementById'           : 'document.getElementById',
                    'p\\.type\\.'                     : 'p.getAttribute("type").',
                    '\\.isEnabled\\s*=([^;]+)'        : '.setAttribute("isEnabled", $1)',
                    '\\.isEnabled'                    : '.getAttribute("isEnabled")',
                    '(\\w+)\\.loadXML'                : '$1=$1.loadXML',
                }

                for (var re in repl) {
                    e.element.text = e.element.text.replace(new RegExp(re, 'g'), repl[re])
                }
            }
        ,false);

    opera.defineMagicFunction('writeInsertion', function () {});

    opera.defineMagicFunction('getBasesTable', function (a, b, tDivRow) {

        var basesRow = tDivRow && tDivRow.id ? document.getElementById("bases_" + tDivRow.id) : null;
        return basesRow == null ? null : document.getElementById('basesTable');
    })

    opera.defineMagicFunction('forEachRow', function (a, b) { return true })

    opera.defineMagicFunction('createXMLStylesheet', function (a, b, url) {
        var r = new XMLHttpRequest()
        r.open('GET', url, false)
        r.send(null)

        if (r.status == 200) {
            var xml = new DOMParser()

            return xml.parseFromString(r.responseText, "text/xml")
        }

        return null
    })

    opera.defineMagicFunction('isBaseVisible', function (a, b, code) {
        return true
    })

    HTMLElement.prototype.transformNode = XMLDocument.prototype.transformNode = function (style) {
        var xsltProcessor=new XSLTProcessor();
        xsltProcessor.importStylesheet(style);

        if (typeof this == 'HTMLElement') {
            var resultDocument = (new DOMParser()).parseFromString(this.innerHTML, 'text/xml');
        } else {
            var resultDocument = xsltProcessor.transformToDocument(this);
        }
          
        var xmls = new XMLSerializer();  
        return xmls.serializeToString(resultDocument);
    }

    HTMLHtmlElement.prototype.selectSingleNode = HTMLInputElement.prototype.selectSingleNode = function (path) {
        var xpe = new XPathEvaluator();
        var nsResolver = xpe.createNSResolver(this.ownerDocument == null ? this.documentElement : this.ownerDocument.documentElement);
        var results = xpe.evaluate(path,this,nsResolver,XPathResult.FIRST_ORDERED_NODE_TYPE, null);
        return results.singleNodeValue;
    }

    ActiveXObject = function (str) {
        return new ({
            'Microsoft.XMLDOM':  DOMParser,
            'Microsoft.XMLHTTP': XMLHttpRequest,
            'Scripting.Dictionary': Array,
        })[str]
    }

})()

Кстати, «Опере» нужно не забыть сказать, чтобы она маскировалась под Internet Explorer (правая клавиша мыши, «Настройки сайта», закладка «Сеть»).

Обращаюсь к тем, кто читает RSS и трансляцию, текст userjs по ссылке на исходный пост.

7 комментариев

Сжатие исходящего трафика в браузере

Артель BrowserPlus выпустила плагин к браузеру («Опера», как обычно, не поддерживается, Linux — тоже), который позволяет использовать в браузере TAR и алгоритм сжатия LZMA.

TAR позволяет собрать несколько файлов в один, LZMA — упаковать их. Таким образом, файлы (или другие данные) на сервер можно отсылать уже упакованными. Ценно для заливки больших хорошо сжимаемых (например, текстовых) файлов.

Вообще говоря, работа с TAR и LZMA не единственное, что плагин позволяет делать, там очень много интересных возможностей, лучше посмотреть на сайте производителя. Тенденция, вообще-то, странная, на мой взгляд — выпускать разношестные плагины для браузеров (Google Gears, BrowserPlus) вместо того, чтобы пытаться договориться с W3C о внедрении каких-то возможностей в браузеры.

Я был бы рад увидеть браузерное хранилище от Google во всех браузерах, вместо зоопарка, который мы сейчас имеем, тем более, что этот зоопарк по возможностям сильно не дотягивает до того, что придумали в Google (по правде говоря, я был бы рад увидеть что-то ещё более мощное и интегрированное, чем Google Gears, но, видимо, возможности плагина просто ограничены — не всё можно реализовать как плагин).

4 комментария

99 бутылок: PowerShell

45. Windows Powershell. Наконец-то в Windows появился мощный, красивый язык командной строки. Язык построен на конвейерах, где по конвейеру передаётся не просто текст, а объекты. Особый интерес представляет интеграция с .NET Framework и WMI.

Язык просто изучается, имеет понятную структуру и широкие возможности. Я посмотрел первую версию языка, но уже доступна вторая версия оболочки.

Программа, выводящая песню о пиве (beer.ps1)

# Написал Евгений Степанищев aka BOLK

function bottles([int]$beer) {
    switch ($beer) {
        0       { "no bottles" }
        1       { "1 bottle" }
        default { "$beer bottles" }
    }
}

99..1 | ForEach-Object {
    $bottles = (bottles $_) + ' of beer'

    $bottles + ' on the wall, ' + $bottles + '.'
    'Take one down and pass it around, ' + (bottles($_-1)) + " of beer on the wall.`n"
}

'No more bottles of beer on the wall, no more bottles of beer. 
Go to the store and buy some more, 99 bottles of beer on the wall.'

Оставить комментарий

← 1 51 52 53 54 55 67 →