qtools_profiler-8.x-1.x-dev/modules/qtools_cache_profiler/js/renderviz/jquery.comments.js

modules/qtools_cache_profiler/js/renderviz/jquery.comments.js
;(function( $ ) {

  "use strict";

  // When invoked, the arguments can be defined in several ways:
  // --
  // .comments() - Gets all child comments.
  // .comments( true ) - Gets all comments (deep search).
  // .comments( value ) - Gets all child comments with the current value.
  // .comments( value, true ) - Gets all comments with the current value (deep search).
  // .comments( name, value ) - Gets all child comments with given name-value pair.
  // .comments( name, value, true ) - Gets all comments with given name-value pair (deep search).
  $.fn.comments = function() {

    var settings = normalizeArguments( arguments );

    var comments = [];

    // Search for comments in each of the current context nodes.
    for ( var i = 0, length = this.length ; i < length ; i++ ) {

      appendAll(
        comments,
        findComments( this[ i ], settings.deep, settings.name, settings.value )
      );

    }

    // If there is more than one comment, make sure the collection is unique.
    if ( comments.length > 1 ) {

      comments = $.unique( comments );

    }

    // Add the found comments to the stack of jQuery selector execution so that the
    // user can tranverse back up the stack when done.
    return( this.pushStack( comments, "comments", arguments ) );

  };


  // ---
  // PRIVATE METHODS.
  // ---


  // I add all items in the incoming collection to the end of the existing collection.
  // This performs an in-place append; meaning, the existing array is mutated directly.
  function appendAll( existing, incoming ) {

    for ( var i = 0, length = incoming.length ; i < length ; i++ ) {

      existing.push( incoming[ i ] );

    }

    return( existing );

  }


  // I collect the comment nodes contained within the given root node.
  function collectComments( rootNode, isDeepSearch ) {

    // Check for modern browser optimization.
    if ( isDeepSearch && document.createTreeWalker ) {

      return( collectCommentsWithTreeWalker( rootNode ) );

    }

    return( collectCommentsWithRecursion( rootNode, isDeepSearch ) );

  }


  // I collect the comment nodes contained within the given root node using the
  // universally supported node API. This method can handle both shallow and deep
  // searches using recursion.
  function collectCommentsWithRecursion( rootNode, isDeepSearch ) {

    var comments = [];

    var node = rootNode.firstChild;

    while ( node ) {

      // Is comment node.
      if ( node.nodeType === 8 ) {

        comments.push( node );

        // Is element node (and we want to recurse).
      } else if ( isDeepSearch && ( node.nodeType === 1 ) ) {

        appendAll( comments, collectCommentsWithRecursion( node, isDeepSearch ) );

      }

      node = node.nextSibling;

    }

    return( comments );

  }


  // I collect the comment nodes contained within the given root node using the newer
  // TreeWalker API. This method can only handle deep searches since the search cannot
  // be [easily] limited to a single level of the DOM.
  function collectCommentsWithTreeWalker( rootNode ) {

    var comments = [];

    // NOTE: Last two arguments use default values but are NOT optional in Internet
    // Explorer. As such, we have to use them here for broader support.
    var treeWalker = document.createTreeWalker( rootNode, NodeFilter.SHOW_COMMENT, null, false );

    while ( treeWalker.nextNode() ) {

      comments.push( treeWalker.currentNode );

    }

    return( comments );

  }


  // I determine if the given name-value pair is contained within the given text.
  function containsAttribute( text, name, value ) {

    if ( ! text ) {

      return( false );

    }

    // This is an attempt to quickly disqualify the comment value without having to
    // incur the overhead of parsing the comment value into name-value pairs.
    if ( value && ( text.indexOf( value ) === -1 ) ) {

      return( false );

    }

    // NOTE: Using "==" to allow some type coersion.
    if ( parseAttributes( text )[ name.toLowerCase() ] == value ) {

      return( true );

    }

    return( false );

  }


  // I filter the given comments collection based on the existing of a "pseudo"
  // attributes with the given name-value pair.
  function filterCommentsByAttribute( comments, name, value ) {

    var filteredComments = [];

    for ( var i = 0, length = comments.length ; i < length ; i++ ) {

      var comment = comments[ i ];

      if ( containsAttribute( comment.nodeValue, name, value ) ) {

        filteredComments.push( comment );

      }

    }

    return( filteredComments );

  }


  // I filter the given comments based on the full-text match of the given value.
  // --
  // NOTE: Leading and trailing white-space is trimmed from the node content before
  // being compared to the given value.
  function filterCommentsByText( comments, value ) {

    var filteredComments = [];

    var whitespace = /^\s+|\s+$/g;

    for ( var i = 0, length = comments.length ; i < length ; i++ ) {

      var comment = comments[ i ];
      var text = ( comment.nodeValue || "" ).replace( whitespace, "" );

      if ( text === value ) {

        filteredComments.push( comment );

      }

    }

    return( filteredComments );

  }



  // I find the comments in the given node using the given, normalized settings.
  function findComments( node, isDeepSearch, name, value ) {

    var comments = collectComments( node, isDeepSearch );

    if ( name ) {

      return( filterCommentsByAttribute( comments, name, value ) );

    } else if ( value ) {

      return( filterCommentsByText( comments, value ) );

    }

    return( comments );

  }


  // I convert the invocation arguments into a normalized settings hash that the search
  // algorithm can use with confidence.
  function normalizeArguments( argumentCollection ) {

    if ( argumentCollection.length > 3 ) {

      throw( new Error( "Unexpected number of arguments." ) );

    }

    if ( ! argumentCollection.length ) {

      return({
        deep: false,
        name: "",
        value: ""
      });

    }

    if ( argumentCollection.length === 3 ) {

      return({
        deep: !! argumentCollection[ 2 ],
        name: argumentCollection[ 0 ],
        value: argumentCollection[ 1 ]
      });

    }

    var lastValue = Array.prototype.pop.call( argumentCollection );

    if ( ( lastValue === true ) || ( lastValue === false ) ) {

      if ( ! argumentCollection.length ) {

        return({
          deep: lastValue,
          name: "",
          value: ""
        });

      }

      if ( argumentCollection.length === 1 ) {

        return({
          deep: lastValue,
          name: "",
          value: argumentCollection[ 0 ]
        });

      }

      if ( argumentCollection.length === 2 ) {

        return({
          deep: lastValue,
          name: argumentCollection[ 0 ],
          value: argumentCollection[ 1 ]
        });

      }

    }

    if ( ! argumentCollection.length ) {

      return({
        deep: false,
        name: "",
        value: lastValue
      });

    }

    if ( argumentCollection.length === 1 ) {

      return({
        deep: false,
        name: argumentCollection[ 0 ],
        value: lastValue
      });

    }

    if ( argumentCollection.length === 2 ) {

      return({
        deep: false,
        name: argumentCollection[ 1 ],
        value: lastValue
      });

    }

  }


  // I parse the given text value into a collection of name-value pairs.
  function parseAttributes( text ) {

    var attributes = {};

    var pairPattern = /([a-zA-Z][^=\s]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s]+)))?/gi;

    var matches = null;

    while ( matches = pairPattern.exec( text ) ) {

      attributes[ matches[ 1 ].toLowerCase() ] = ( matches[ 2 ] || matches[ 3 ] || matches[ 4 ] || "" );

    }

    return( attributes );

  }

})( jQuery );

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc