Как обмануть jQ при помощи jQ? (CamelCase в атрибутах)
Приветствую!
Столкнулся с любопытной проблемой. Нужно в рамках одного проекта под jQuery работать с SVG. Оказалось, что jQuery берёт на себя наглость принудительно все имена атрибутов переводить в нижний регистр, а SVG енто XML и к регистру более чем чувствителен... ;) Разрабы jQuery более 3-х лет гордо отказываются фиксить баг переводя его в разряд фичи... http://bugs.jquery.com/ticket/11166#propertyform :blink: Предвижу советы написать на нативном javascript, что-то вроде: document.getElementsByTagName('svg')[0].setAttribute('someAttributes', 'x') Но запутка в том, что практически весь DOM выводится и обновляется jQuery и в итоге получаю всё равно someattributes Вот и получается нужен костыль для победы над jQuery средствами самой jQuery. Первое, что пришло в голову каким ниб регулярным выражением пройтись и исправить написание. Но не пойму можно ли взять и переписать кусок сырого хэтэмэля без использования attr() setAttribute() и т.п.... А может ещё какие варианты есть? |
Это, конечно, совет не в тему, но попробуй всю работу с svg оформить с помощью Snap.svg.
UPD. Или покажи код, чтобы было ясно как именно при помощи jQuery выводится SVG. |
Не знаю... Библиотека, как таковая особо и не нужна.
Проблема в том, что требуется внедрять сырой SVG прямо в html вроде: <svg baseProfile="full" width="300" height="200" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg"> ...... </svg> А jQuery гадит ;) если тащить код svg ещё какой-то библиотекой, то наверное ничего не изменится... только ещё библиотеку осваивать... -- И да, от jQuery отказаться нельзя... там много чего с ним понакручено... |
document.body.setAttribute('A', 1) Chrome и Firefox добавят атрибут «а»: [JS]document.body.attributes[0].name //→ 'a' |
Хм.. та ки jQ плюёт на любой DOCTYPE и конвертит всё в нижний регистр. setAttribute нативного js работает корректно, но не в моём случае... Кроме костыля ничего не поможет... Разве что удалить toLowerCase() из кода jQ, но это как-то совсем грязно... ;)
|
Посмотрел у себя: в хроме и лисе в lowercase конвертит браузер, ишак регистр сохраняет.
|
Когда мы вставляем inline-svg в text/html контент с помощью innerHTML браузер выполняет преобразования и ничего с этим мы поделать не можем. В примере ниже атрибуты WIDTH и HEIGHT при вставке в документ без использования jQuery преобразуются в нижний регистр: <!DOCTYPE html> <html lang="en"> <head> <title>…</title> <meta charset="UTF-8"> </head> <body> <script> var inlineSVG = '<svg WIDTH="300" HEIGHT="200"><polygon points="100,10 40,198 190,78 10,78 160,198" style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;" /></svg>', tmpContainer = document.createElement('div'), svgElement; tmpContainer.innerHTML = inlineSVG; svgElement = document.body.appendChild(tmpContainer.firstChild); tmpContainer = null; alert([ svgElement.attributes[0].name, svgElement.attributes[1].name ]); </script> </body> </html> |
Э нет... Так да не так
Напр.: в Вашем примере добавим атрибут svg baseProfile <!DOCTYPE html> <html lang="en"> <head> <title>…</title> <meta charset="UTF-8"> </head> <body> <script> var inlineSVG = '<svg baseProfile="full" WIDTH="300" HEIGHT="200"><polygon points="100,10 40,198 190,78 10,78 160,198" style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;" /></svg>', tmpContainer = document.createElement('div'), svgElement; tmpContainer.innerHTML = inlineSVG; document.body.appendChild(tmpContainer.firstChild); tmpContainer = null; svgElement = document.querySelector('svg'); alert([ svgElement.attributes[0].name, svgElement.attributes[1].name, svgElement.attributes[2].name, ]); </script> </body> </html> PS. И енто логично.., иначе как бы браузеры вообще отображали бы svg (в полном объёме) PPS. А как добавит батон "посмотреть" к примеру? PPPS. И да результат будет корректный alert выдаст baseProfile..... ----- В коде jQ туева хуча конвертаций в нижний регистр, на подобии: // All attributes are lowercase // Grab necessary hook if one is defined if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { name = name.toLowerCase(); hooks = jQuery.attrHooks[ name ] || ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); } К сожалению я не настолько владею предметом, что бы найти непосредствено корень зла и пропатчить его. По этому написание костыля мне кажется более простой задачей, но и с ней я пока не справляюсь... ;) |
хм ну да isXMLDoc для inline-svg будет возвращать false…
можно попробовать декоратор для jQuery.isXMLDoc написать, который будет дополнительно проверять, что элемент не вложен в <svg>. |
Ченибудь типа такого
jQuery.isSVG = new function () { function isSVG(node) { return node.nodeName.toLowerCase() == 'svg'; } return function (elem) { while (elem) { if (isSVG(elem)) { return true; } elem = elem.parentNode; } return false; }; }; jQuery.isXMLDoc = new function () { var isXMLDoc = jQuery.isXMLDoc; return function (elem) { return jQuery.isSVG(elem) || isXMLDoc(elem); }; }; не проверял на работоспособность -------------------------- а блин там же в условии nType !== 1, весь jQuery.attr придется переопределять |
Попробую поковырять в этом направлении... Спасибо
|
|
Короче, трезво оценив свои силы, совершил акт вандализма по отношению к jQuery...
Заменил где нужно было toLowerCase() на нейтральный toString()... Пока так... Мне же не шашечки... мне ехать... ;) PS. Нормальное решение ждёт своего героя... |
если есть метод toLowerCase, то это уже строка, строку в строку через toString преобразовывать бессмысленно :)
Я бы добавил в jQuery.attr проверку elem.constructor.toString().indexOf('SVG') == 9 // 'function SVG...' рядом с nType !== 1 и isXMLDoc или там еще есть места, где арибуты в lowercase переделываются? |
toLowerCase() по коду более 40.
Мне хватило для своих целей пары исправлений (возможно хватило бы и одного, я вчера ночью уже запутался в своих экспериментах). На toString заменил именно по тому, что это бессмысленно и ничего не делает в данном случае. Проверка конечно намного более правильное решение, но всё равно нарушает аутентичность библиотеки... Эх... вот если бы патч какой сделать... Но пока видимо так придётся работать. |
Все что нужно сделать для jQuery, что бы он не тупил с SVG
jQuery.extend({ _originalAttr: jQuery.attr, attr: function(elem, name, value) { if (typeof SVGElement !== 'undefined' && elem instanceof SVGElement) { if (typeof value === 'undefined') { value = elem.getAttribute(name); } else if (value === null) { elem.removeAttribute(name); } else { elem.setAttribute(name, value + ""); } return value; } return jQuery._originalAttr(elem, name, value); } }); тест: <!DOCTYPE html> <html lang="en"> <head> <title>…</title> <meta charset="UTF-8"> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> </head> <body> <script> jQuery.extend({ _originalAttr: jQuery.attr, attr: function(elem, name, value) { if (typeof SVGElement !== 'undefined' && elem instanceof SVGElement) { if (typeof value === 'undefined') { value = elem.getAttribute(name); } else if (value === null) { elem.removeAttribute(name); } else { elem.setAttribute(name, value + ""); } return value; } return jQuery._originalAttr(elem, name, value); } }); var inlineSVG = '<svg baseProfile="full" WIDTH="300" HEIGHT="200"><polygon points="100,10 40,198 190,78 10,78 160,198" style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;" /></svg>', tmpContainer = document.createElement('div'), svgElement; tmpContainer.innerHTML = inlineSVG; document.body.appendChild(tmpContainer.firstChild); tmpContainer = null; svgElement = jQuery('svg'); alert([ 'baseprofile: ' + svgElement.attr('baseprofile'), 'baseProfile: ' + svgElement.attr('baseProfile'), 'width: ' + svgElement.attr('width'), 'height: ' + svgElement.attr('height') ].join('\n')); </script> </body> </html> |
То, что доктор прописал... Работает... Спасибо. :)
ЗЫ: У меня правда всплыли ещё проблемы, но это уже другая песня... |
Я вот, кстати, не пойму: как так получилось, что я ни разу не сталкивался с такой проблемой? Как эта проблема решается в svg-фреймворках?
|
Цитата:
|
;) Ето да...
Я тож раньше обходил тем что просто нативный js использовал... |
Часовой пояс GMT +3, время: 20:05. |