«Консультант» и IE
Вчера на «Хабре» люди в очередной раз подняли тему сайта «Консультанта» и Internet Explorer — первый, своей интересной частью, работает только на втором. Как я и ожидал, код завязан на особенности Internet Explorer, браузер богатый на возможности, на сайте использовано их немало. Впрочем, всё, если вдуматься, переводится и на более стандартные рельсы.
У меня давно руки чесались разобраться поподробнее как устроены userjs в «Опере» и посмотреть на отличия реализации
По результатам появился 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 по ссылке на исходный пост.
iPhone и снимки с GPS
iPhone, который, не спрашивая, записывает в снимок информацию с GPS, чувствую, доставит ещё немало лулзов в интернетах. Одна тётечка, сфоткавшись обнажённой, уже спалилась — координаты есть, дом на Google Maps видно, тем более, что он частный. И это только начало.
Подводная река

Красиво — фотография Анатолия Белощина, сделана под водой, в Мексике, на глубине 28 метров, «река», над которой видно дайвера — это течёт сероводород (обязательно посмотрите оригинал).