Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > JavaScript: Общие вопросы > Добавление правил в таблицу стилей в FF


Автор: Ciber SLasH 17.4.2014, 17:01
Приветствую всех!
Давно написал ф. для добавления правила в таблицу стилей и ф. работала. Но с какой-то версии FireFox перестала работать ф. и меню не отрабатывает.
Подскажите пожалуйста, где ошибка в коде:
Код

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content='text/html; charset=windows-1251'>
<link rel="stylesheet" type='text/css' href='./main.css'>
<script type='text/javascript'>
/*** Для добавления правил в таблицу стилей ***/
function changeStyle(css, ssNum) {
var styleObj = document.getElementsByTagName('STYLE')[0];
    if (!styleObj) {    // если нет тэга STYLE в документе
        styleObj = document.createElement('STYLE');
        styleObj.type = 'text/css';
        document.getElementsByTagName('HEAD')[0].appendChild(styleObj);
    }
    if (document.styleSheets) {
        if (document.styleSheets[ssNum].addRule) {    // for IE
            var sList = css.split('\n');
            for (var i = 0; i < sList.length; i++) {
                var selector = sList[i].substr(0, sList[i].search(/\s\{/));
                var rule = (
                    sList[i].substring( sList[i].indexOf('{')+1, sList[i].lastIndexOf('}') )
                ).replace(/[\t\r\n]/g, '');
                document.styleSheets[ssNum].addRule(selector, rule);
            }
        }
        else if (document.styleSheets[ssNum].insertRule) {    // for FF
            document.styleSheets[ssNum].insertRule(css, document.styleSheets[ssNum].cssRules.length);
        }
    }
    else if (!window.opera) {    // for NOT Opera
        var rule = document.createTextNode(css);
        styleObj.appendChild(rule);
    }
}
onload = function () {
//==[ Fix stylesheets ]=========================================================
// Fix UL margin-left в FF в добавление border-collapse во всех браузерах, кроме Оперы
var cssFF = 'ul {margin-left: -20px}\n';
var css =
    'table {table-layout: fixed; border-collapse: collapse}';
    //'td {border: 3px double #269CF7}';
    if (document.body.textContent) {    // if FF
        //document.styleSheets[1].insertRule(cssFF+css, document.styleSheets[1].cssRules.length);
        changeStyle(cssFF+css, 1);
    } else {
        changeStyle(css, 1);
    }
//==[ Add event to menu ]=======================================================
menuElem = document.getElementById("menu");
    for (var i = 0; i < menuElem.childNodes.length; i++) {
        var curNode = menuElem.childNodes[i];
        if (curNode.nodeName == "LI") {
            curNode.onmouseover = function () {this.className = "enter"}
            curNode.onmouseout = function () {this.className = ""}
            if (curNode.lastChild.nodeName == "UL"    // IE
                ||
                curNode.lastChild.previousSibling.nodeName == "UL"    // Gecko
            )
                curNode.firstChild.className = "subMenu";
        }
    }
}
</script>
<style type='text/css'>
@import url("./menu.css");
body {overflow-x: hidden}
ul {margin-left: 20px}
td {border: 1px solid #269CF7}    /* for Opera */
</style>
</head>

<body>
<div class='menu' onMouseOver='menuElem.style.display = "block"' onMouseOut='menuElem.style.display = "none"'>
<span id='menuText'>МЕНЮ</span>
<ul id='menu' onClick='menuElem.style.display = "none"'>
    <li><a href='#JS_sprav'>Справочник по JavaScript</a>
        <ul>
            <li><a href='#stand_comp'>Стандарты и совместимость</a></li>
            <li><a href='#object_model'>Объектная модель JavaScript</a></li>
            <li><a href='#model_event'>Модели событий JavaScript</a></li>
        </ul>
    </li>
</ul>
</div>
</body>
</html>

FF ругается в консоль так:
Цитата
Ошибка: SyntaxError: An invalid or illegal string was specified
Источник: test.htm
Строка: 27

Автор: Aliance 25.4.2014, 14:27
Использовать глобальную переменную menuElem в атрибутах обработчиков событий - не гуд. У меня на jsfiddle выдает как минимум эту ошибку.

Автор: Ciber SLasH 27.4.2014, 00:11
Заменил в обработчиках событий глобальную переменную на document.getElementById("menu") и заработало, но в консоли всё равно ругается на 27 строку:
Цитата
Ошибка: SyntaxError: An invalid or illegal string was specified
Строка: 27

Хотя раньше и так работало. Видимо в новых версиях FF обработчики событий больше не видят глобальных переменных.

Автор: Aliance 28.4.2014, 10:02
Не то, чтобы это не правильно, но лично мне кажется нелогичным. Я бы посоветовал делать так:
в обработчики событий вешать функции (при чем лучше делать это именно inline, чтобы было сразу понятно что должно вызываться и когда), а в функции обращаться к единой переменной, которая просчитана один раз в закеширована (это может быть и глобальная, конечно, но лучше в качестве неймспейса завести некий объект и переменную хранить как его свойство).

Выложи обновленный код на jsfiddle и посмотрим, что там за ошибка.

Автор: Ciber SLasH 28.4.2014, 22:57
Попробовал создать объект, на обработчики навесить функции - вообще перестало работать в FF 28.0
http://jsfiddle.net/YRNF9/2/

Автор: Aliance 29.4.2014, 10:36
Ну а теперь открываем консоль по ссылке и видим ошибки:
Цитата

Uncaught ReferenceError: menuHide is not defined
Uncaught ReferenceError: menuShow is not defined 


Это потому, что в левом верхнем селекте нужно выбрать было не onload, а no wrap (лучше в body, но для примера все равно).

После этого вроде как пример работает нормально, без ошибок. Только я бы посоветовал не извращаться и писать все атрибуты html в нижнем регистре, onClick выглядит ужасно. Но это лишь мое мнение smile

Автор: Ciber SLasH 29.4.2014, 11:13
Выбрал no wrap, изменил атрибуты в нижний регистр. В текущем состоянии:
Цитата
Метка времени: 29.04.2014 12:15:37
Ошибка: TypeError: menuObj.menu is undefined
Источник: http://fiddle.jshell.net/YRNF9/7/show/
Строка: 194

Автор: Aliance 29.4.2014, 16:36
Какой браузер-то? В Хроме все окей. Видимо проблема в Лисе? Вообще, 194 строчка - это первая строчка в функции changeStyle. Может быть идет наведение мышкой ДО события onload? Тогда еще объект не успевает заинититься, и такая ошибка может возникнуть. Но это нормально. Не нормально то, что такая ситуация не обрабатывается внутри методов, навешанных на события.

А зачем вообще нужна функция changeStyle? Она, честно говоря, похода на огромный костыль. Что мешает просто написать нужные стили сразу и просто менять класс у элемента при взаимодействии с ним? Ну или второй вариант менять стили (elem.style.STYLE = 'VALUE')?

И еще, я бы вот таких проверок не делал бы (curNode.nodeName == "LI"), ибо регистрозависимость есть зло. Лучше привести в нижний регистр и сравнивать с li.

Кстати, чтобы работало \n - нужно его заключать в двойные кавычки.

Автор: Ciber SLasH 29.4.2014, 17:10
Браузер уже писал - FF 28.0
Остальное позже поковыряю...

Автор: Ciber SLasH 1.5.2014, 19:06
Внутри методов повесил проверку: typeof(menuObj.menu) == "undefined"
Функция действительно костыль. Она и была написана, как костыль для разных браузеров.
А по поводу \n ошибаешся - оно работает и в одинарных и в двойных кавычках в JS. Это у PHP в одинарных кавычках строка не вычисляется.
А ошибка:
Цитата
Ошибка: SyntaxError: An invalid or illegal string was specified
Источник: test.htm
Строка: 27

как выяснилось, означает, что insertRule не поддерживает мультистроки. Поэтому пршлось мультистроку css-правил разбивать на части:
Код
var ruleList = css.split("\n");
for (var i = 0; i < ruleList.length; i++) {
    SS.insertRule(ruleList[i], SS.cssRules.length);
}

Код по http://jsfiddle.net/YRNF9/10/ исправил.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)