Скрипт, модифицирующий body.innerHTML из тела - иногда IE8 прерывается, иногда нет? - PullRequest
0 голосов
/ 27 декабря 2011

В связи с тем, что нашему клиенту нужен адаптивный (CSS) веб-сайт и требование работать на его чрезвычайно базовой платформе CMS, мы написали сценарий, который соответствовал бы стоимости пользовательского HTML на странице:

  1. сохраняет наш HTML в переменную,
  2. очищает все head и document,
  3. и затем добавляет наш пользовательский HTML обратно в document.body как единственный HTML-контент.

Это гарантирует, что в CMS не останется ненужных элементов HTML, <style> или <link>, которые мешают адаптивному макету. Наш собственный CSS требует, чтобы мы достигли всего до элемента body.

Тестовая страница с проблемой: https://www.eiseverywhere.com/ehome/index.php?eventid=31648&tabid=53961

Однако сценарий выполняется из вложенной таблицы в document, поскольку именно здесь CMS размещает наш контент (в пределах своего предварительно заданного шаблона страницы).

Кажется, что это работает гладко (хотя и в заметных «проходах») во всех современных браузерах, включая FF, Chrome, Safari, iOS и IE9.

И в IE8 каждый раз при перезагрузке страницы происходит несколько разных вещей:

  1. Страница загружается без ошибок, но виден только элемент HTML (черный фон). Все остальные элементы полностью невидимы, но есть (например, по ссылкам можно щелкнуть, если они найдены).

  2. Страница загружается черным и невидимым, как описано выше, но в строке состояния отображается ошибка 927917 .

  3. Страница начинает заметно загружать содержимое (фоновые изображения и т. Д.), Но прерывается всплывающим сообщением об ошибке «Операция прервана 927917», за которым следует перенаправление на пустую белую страницу «Не удалось загрузить страницу».

  4. Страница загружается все нормально, без ошибок.

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

С IE7 мы получаем аналогично противоречивые результаты, и известная ошибка 927917

Главный вопрос здесь, учитывая требования, код и контент, каков наилучший способ выполнить этот обмен / внедрение контента? Мы заинтересованы только в поддержке IE7 + и готовы отказаться от IE7 вместе, если это слишком хлопотно.

Мы попробовали некоторые из следующих предложений, но получили IE5 и IE8 смешанные результаты, ни одно из которых не решает полностью проблемы, перечисленные выше:

http://www.timvasil.com/blog14/post/2008/05/28/Fix-for-IEs-Operation-Aborted-error.aspx

http://blogs.msdn.com/b/ie/archive/2008/04/23/what-happened-to-operation-aborted.aspx

Вывод CMS до запуска нашего скрипта:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Title</title>

<!-- CMS included meta tags -->
<meta name="description" content="event title" />
<meta name="keywords" content="meta-tags" />

<!-- CMS included scripts -->
<script language="javascript" type="text/javascript" src="/include/scripts/scripts.js"></script>
<script language="javascript" type="text/javascript" src="/ehome/include/scripts.js"></script>

<style type="text/css"> /* CMS styles */ </style>

<!-- CMS JS Library inclusion - could possible use this to wait for DOM ready -->
<script type="text/javascript" src="/include/scripts/prototype.js">

</script>
</head>

<body>
<form>
<input type="hidden" id="module" value="ehome" /><input type="hidden" id="eventid" value="31648" />
</form>

<table id="shadow_table">
<tr>
<td></td>

<td>
<table id="outer_table">

<!-- Lots of CMS table HTML -->

<tr>
<td id="inner_content">
<div class="eh_outer_div">
<div id="main_section">
<div>
<div>

    <!-- BEGIN OUR CUSTOM CODE - intended to replace body contents -->

    <div id="wrap">
        <!--[if (gte IE 6)&(lte IE 8)]>
            <script src="https://www.eiseverywhere.com/docs/562/selectivizr.js"></script>
        <![endif]-->
        <!--[if lt IE 9]>
            <script src="https://www.eiseverywhere.com/docs/562/html5.js"></script>
            <script src="https://www.eiseverywhere.com/docs/562/iemq.js"></script>
        <![endif]-->

        <header>
            <!-- header content... -->
        </header>

        <div id="main">

            <ul>
                <li data-id="home"><a href="https://www.eiseverywhere.com/ehome/index.php?eventid=31648&tabid=50283">Home</a></li>
                <!-- Other nav items... --> 
            </ul>

            <h1>speakers</h1>

            <section id="content">
                <!-- Begin Main Content Section -->

                <article>
                    <h2>CITE <strong>2012 speakers</strong></h2>

                    <p><strong>Our speaker list is growing continuously, so check back often for updates. Our esteemed roster so far includes:</strong></p>

                    <!-- Misc main content - etc.. -->

                </article>
            </section>

        </div><!-- End Main -->

    </div><!-- End #wrap Wrapper -->

    <footer>
        <div>
            <ul>
                <li data-id="home"><a href="https://www.eiseverywhere.com/ehome/index.php?eventid=31648&tabid=50283">Home</a></li>
                <!-- Other nav items... --> 
            </ul>

            <!-- Misc footer content... -->
        </div>
    </footer> <!-- End Footer -->

    <!-- Cleaning Code -->
    <!-- THIS IS WHERE THE REPLACEMENT SCRIPTING IS (<SCRIPT>) -->

    <!-- END CUSTOM CONTENT -->

</div>
</div>
</div>
</div>
</td>
</tr>

<!-- LOTS OF OTHER UNNECESSARY CMS TABLE MARKUP... -->

</table>

<!-- Garbage DIVs from CMS scripts -->
<div id="overlay"></div>
<div id="home_od"></div>

</body>
</html>

ОБНОВЛЕНО: наш пользовательский скрипт замены / внедрения с DOM ready ():

<script type="text/javascript">
/* Clean.js /// Switches out host HTML and replaces with clean custom HTML */

document.observe('dom:loaded', function() { // Prototype.js listener: http://www.prototypejs.org/api/document/observe


    /* PAGE VARIABLES */

    var pre = '<!--[if lt IE 7 ]><div id="wrap" class="ie pre9 ie6"><![endif]--><!--[if IE 7 ]><div id="wrap" class="ie pre9 ie7"><![endif]--><!--[if IE 8 ]><div id="wrap" class="ie pre9 ie8"> <![endif]--><!--[if IE 9 ]><div id="wrap" class="ie ie9"> <![endif]--><!--[if (gt IE 9)|!(IE)]><!--><div id="wrap"><!--<![endif]-->';

        var wrap = document.getElementById('wrap');
        var title = wrap.getElementsByTagName('h1')[0].innerHTML;
        var pgid = title.replace(/[^a-zA-Z 0-9]+/g,'-').toLowerCase().replace(/[ ]/g, '-'); // clean H1 text and use as page id
        var footer = "<footer>" + document.getElementsByTagName('footer')[0].innerHTML + "</footer>";
        var content = pre + wrap.innerHTML + footer;

    var post = '</div>';


    /* HOUSE CLEANING */

    // Clean out <HEAD>
    emptyHead(); //remove all style blocks from head
    removeLinks("js"); //remove all occurences of "somescript.js" on page
    removeLinks("css"); //remove all occurences "somestyle.css" on page

    // Stage <BODY> 
    document.body.setAttribute("id", pgid);
    document.body.setAttribute("onload", "finished('"+pgid+"')");
    document.title = "CITE Expo + Conference: March 4-6, 2012 | " + title;
    document.body.innerHTML = content + post;

//  document.body.insertAdjacentElement('afterBegin', document.getElementsByTagName('footer')[0]);
//  document.body.insertAdjacentElement('afterBegin', wrap);
//  document.body.removeChild(document.getElementById('shadow_table'));

    // Add meta tags
    addMetatag('viewport', 'head');

    // Add stylesheets
    addStylesheet('https://www.eiseverywhere.com/file_uploads/d1d7aeedb561585d601535bb14aa6910_cite.css', 'head');
    addStylesheet('https://www.eiseverywhere.com/file_uploads/cead2f725f0acc8b4ada117d22b2e872_type.css', 'head');
    addStylesheet('https://www.eiseverywhere.com/file_uploads/41062e7af46018760d01e8d9f7a7b9a9_flex.css', 'head');
    addStylesheet('https://www.eiseverywhere.com/file_uploads/fff3d12e98686a02eb8e8f2ac45f7bf8_anm8.css', 'head');
    addStylesheet('https://www.eiseverywhere.com/file_uploads/64388fdb8762f9232b2330f9e196f996_benton-gothic-cite.css', 'head');
    addStylesheet('https://www.eiseverywhere.com/file_uploads/f92ea468d4be1013b77010d2c42fdc6f_stag-cite.css', 'head');

    // Add javascript
/*  addJavascript('https://www.eiseverywhere.com/file_uploads/3df3d4e3b7e57d447396fe2608c96664_jump.js', 'body'); // Not working well - need to inject a new element */
    addJavascript('https://www.eiseverywhere.com/file_uploads/b8601cc668024431aae05a886084fc37_android21.js', 'body');


    /* FUNCTIONS */

    function emptyHead()
    {
        var head = document.getElementsByTagName('head')[0];
        var s = head.getElementsByTagName('style');
        if(s)
            while(s.length >= 1)
                head.removeChild(s[0]);
    }

    function emptyBody()
    {
    //  document.body.removeChild(document.getElementById("overlay"));
    //  document.body.removeChild(document.getElementById("home_od"));
    }

    function addJavascript(jsname, pos)
    {
        var th = document.getElementsByTagName(pos)[0];
        var s = document.createElement('script');
        s.setAttribute('type', 'text/javascript');
        s.setAttribute('src', jsname);
        th.appendChild(s);
    }

    function addStylesheet(cssname, pos2)
    {
        var th2 = document.getElementsByTagName(pos2)[0];
        var s2 = document.createElement('link');
        s2.setAttribute('type', 'text/css');
        s2.setAttribute('href', cssname);
        s2.setAttribute('media', 'screen');
        s2.setAttribute('rel', 'stylesheet');
        th2.appendChild(s2);
    }

    function addMetatag(meta, pos3)
    {
        var th3 = document.getElementsByTagName(pos3)[0];
        var s3 = document.createElement('meta');
        s3.setAttribute('name', meta);
        s3.setAttribute('content', 'width=device-width, minimum-scale=1.0, maximum-scale=1.0');
        th3.appendChild(s3);
    }

    function removeLinks(filetype)
    {
        var targetelement = (filetype == "js") ? "script" : (filetype == "css") ? "link" : "none" //determine element type to create nodelist from
        var targetattr = (filetype == "js") ? "src" : (filetype == "css") ? "href" : "none" //determine corresponding attribute to test for
        var allsuspects = document.getElementsByTagName(targetelement)
        for (var i = allsuspects.length; i >= 0; i--) //search backwards within nodelist for matching elements to remove
            if (allsuspects[i] && allsuspects[i].getAttribute(targetattr) != null)
                allsuspects[i].parentNode.removeChild(allsuspects[i]) //remove element by calling parentNode.removeChild()
    }

    document.stopObserving("dom:loaded")

});

function finished(pid) // DOM is [natively] ready
{
    setMenu(pid); // set the active class on li elements that contain a link to the current page
//  emptyBody(); // remove junk divs from bottom of page
    setLayout(); // if <aside> is missing, set #main to .single-column class

    if(pid == "home") {
        var anm8 = '<object type="application/x-shockwave-flash" data="http://client.clevelanddesign.com/CD/IDG/CITE/content/intro.swf"><!-- By default, play flash video --><param name="movie" value="http://client.clevelanddesign.com/CD/IDG/CITE/content/intro.swf" /><param name="wmode" value="transparent" /><param name="scale" value="default" /><!-- Show iPad/iPhone/iPod visitors the HTML5 video --><video autoplay poster="https://www.eiseverywhere.com/file_uploads/e82b83f31bb069e818fe691ebc824cf1_mtng-locked.png"><source src="https://www.eiseverywhere.com/docs/562/intro-compressed.mp4" type="video/mp4"></source></video><!-- Backup image if all else fails --><img src="https://www.eiseverywhere.com/file_uploads/e82b83f31bb069e818fe691ebc824cf1_mtng-locked.png" alt="Meet the next generation of business" /></object>';
        document.getElementById('hero').innerHTML = anm8; // if home page, add animation after page is loaded
    }
    window.scrollTo(0, 1); // scroll mobile address bars out of sight (iPhone, Android) - gives us more screen space
}

function setMenu(p) // compare cleaned H1 text to link IDs // requires consistent naming between H1 and li.data-id // update topnav + footer HTML snippets in eTouches to match
{
    var mitems = document.getElementsByTagName('li');
    for(i = 0; i < mitems.length; i++) {
        if(mitems[i].getAttribute('data-id'))
            if(mitems[i].getAttribute('data-id') == p)
                mitems[i].setAttribute("class", "active");
    }
}

function setLayout()
{
    if(!document.getElementsByTagName('aside').length)
        document.getElementById("main").setAttribute("class", "single-column");
}

</script>

<!--[if IE 7 ]>
<script type="text/javascript">
//  alert('Please upgrade to a modern browser to enjoy this website properly.');
</script>
<![endif]-->

Ответы [ 2 ]

1 голос
/ 27 декабря 2011

Во всех браузерах (и в частности IE) вы не можете / не должны изменять элементы, которые все еще находятся в процессе загрузки.Таким образом, вы не можете изменять содержимое элемента <body> из кода внутри элемента <body>.IE, в частности, может / будет аварийно завершать работу.Не просто сбой на уровне страницы, а иногда и весь сбой браузера.

Типичное решение - убедиться, что ВСЕ сценарии, которые изменяют страницу, должны ждать, пока она не станет безопасной для изменения страницы.Типичные веб-фреймворки, такие как YUI и jQuery, имеют встроенные методы для ожидания безопасной загрузки всей страницы (таким образом, готовой к манипулированию) или для безопасной модификации даже части DOM.Если вы не используете какой-либо веб-фреймворк, в который встроена эта возможность, то вы можете найти фрагменты кода с поиском, которые позволят вам создать собственную небольшую функцию для этого.Логика варьируется в зависимости от браузера и версии браузера.

Абсолютно простейшая версия безопасной модификации DOM состоит в том, чтобы инициировать модификацию DOM из вызова функции javascript, который размещается в самом конце <body>.Если у вас нет доступной платформы, в которой есть код, который сделает это за вас, вы можете добавить свою собственную кросс-браузерную функцию DOMReady, как показано в этой ссылке , и прокрутить вниз, где говорится «Обработка перекрестного браузера DOMContentLoadedкод».

0 голосов
/ 28 декабря 2011

Как удаление атрибута "defer", так и вложение кода манипуляции внутри события готовности документа ( a la Prototype.js ) решили проблемы, описанные в исходном вопросе.IE 7/8 больше не может загружаться или загружаться непоследовательно.

Спасибо обоим @ jfriend00 и @Alfabravo за их советы.

У меня все еще есть проблемы с (всеми браузерами) родного onLoadсобытие body и его функция не запускаются, а также тот факт, что IE 7/8 случайным образом сбрасывает таблицы стилей, но я считаю, что это отдельная проблема.

...