Firefox empties documentFragment on clone

261 Views Asked by At

I've found this strange scenario where Firefox seems to loose the content of a documentFragment after cloning it (with the deep flag set to true). Is this a Firefox bug, or am I missing an implementation detail?

var n = ( function nScope(){
 'use strict';

 function isDom( x ){
  return x.nodeType > 0;
 }

 function notDom( x ){
  return !isDom( x );
 }

 return function n(){
  // Avoids conditional logic later by forcing a standard output.
  var args   = [].map.call( arguments, function wrapDom( x ){
   return isDom( x ) ? [ x ] : x;
  } );
  var dom    = [];
  var vdom   = [];
  // Render virtual DOM, then parse output.
  var view   = m.apply( void 0, args );
  var cfg    = view.attrs.config;

  if( view.children.forEach ){
   view.children.forEach( function divideChildren( x ){
    ( isDom( x ) ? dom : vdom ).push( x );
   } );
  }

  if( dom.length === 0 ){
   return view; 
  }

  view.attrs.config = function appendDom( el, init, context ){
   // Only perform DOM insertion logic at config time:
   // Saves unnecessary execution during strategy none redraws.
            if( !init ){
                dom.forEach( function appendNode( node, index ){
                    // If a virtual DOM element occurs after the real node in the children list, grab it and find its
                    // index in the list of virtual elements as a reference point for inserting the real node.
                    var insertAt = vdom.indexOf( view.children.slice( view.children.indexOf( node ) ).filter( notDom )[ 0 ] );
                    // When a documentFragment is inserted into the document, the reference becomes empty.
                    // Therefore we need to insert clones of the original reference.
                    // Because this happens on every redraw, this means DOM nodes cannot be modified by prior reference
                    // between redraw cycles :(
                    console.log( 'Original node:', node );

                    var clone   = node.cloneNode( true );

                    console.log( 'Cloned node:', clone );

                    
                    if( insertAt ){
                        el.insertBefore( clone, el.childNodes[ insertAt ] );
                    }
                    else {
                        el.appendChild( clone );
                    }
                } );
            }

   if( cfg ){
    return cfg( el, init, context );
   }
  };

  // Make sure only the virtual elements are parsed by m.render.
  view.children = vdom;

  return view;
 };
}() );

// To stop jsfiddle breaking
m.route.mode = 'hash';

var links = document.createDocumentFragment();
var array = [ 1, 2 ];

array.forEach( function appendLink( index ){
    var a  = document.createElement( 'a' );
    
    a.innerText = 'Page ' + index;
    a.href      = '/route' + index;
    
    m.route( a );
    
    links.appendChild( a );
    links.appendChild( document.createTextNode( ' ' ) );
} );

var modules = array.map( function makeModule( index ){
    return {
        controller : function(){},
        view       : function(){
            return n(
                '.module',
                [
                    n( 'h1', {
                        onclick : function(){
                            alert( 'Redraw incoming...' );
                        }
                    }, 'Page ' + index ),
                    links 
                ]
            );
        }
    };
} );

m.route( document.body, '/route1', {
    '/route1' : modules[ 0 ],
    '/route2' : modules[ 1 ]
} );
<script src="https://rawgit.com/lhorie/mithril.js/master/mithril.js"></script>

1

There are 1 best solutions below

3
On BEST ANSWER

You're using innerText, which is not supported by Firefox: 'innerText' works in IE, but not in Firefox

You could use textContent or innerHTML instead

array.forEach( function appendLink( index ){
    var a  = document.createElement( 'a' );

    a.textContent = 'Page ' + index; // <-- here
    a.href      = '/route' + index;

    m.route( a );

    links.appendChild( a );
    links.appendChild( document.createTextNode( ' ' ) );
} );