function makeHtmlSanitizer(tagPolicy) {
    var stack;
    var ignoring;
    var emit = function (text, out) {
      if (!ignoring) { out.push(text); }
    };
    return makeSaxParser({
      startDoc: function(_) {
        stack = [];
        ignoring = false;
      },
      startTag: function(tagName, attribs, out) {
        if (ignoring) { return; }
        if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
        var eflags = html4.ELEMENTS[tagName];
        if (eflags & html4.eflags.FOLDABLE) {
          return;
        }
        attribs = tagPolicy(tagName, attribs);
        if (!attribs) {
          ignoring = !(eflags & html4.eflags.EMPTY);
          return;
        }
        // TODO(mikesamuel): relying on tagPolicy not to insert unsafe
        // attribute names.
        if (!(eflags & html4.eflags.EMPTY)) {
          stack.push(tagName);
        }

        out.push('<', tagName);
        for (var i = 0, n = attribs.length; i < n; i += 2) {
          var attribName = attribs[i],
              value = attribs[i + 1];
          if (value !== null && value !== void 0) {
            out.push(' ', attribName, '="', escapeAttrib(value), '"');
          }
        }
        out.push('>');
      },
      endTag: function(tagName, out) {
        if (ignoring) {
          ignoring = false;
          return;
        }
        if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
        var eflags = html4.ELEMENTS[tagName];
        if (!(eflags & (html4.eflags.EMPTY | html4.eflags.FOLDABLE))) {
          var index;
          if (eflags & html4.eflags.OPTIONAL_ENDTAG) {
            for (index = stack.length; --index >= 0;) {
              var stackEl = stack[index];
              if (stackEl === tagName) { break; }
              if (!(html4.ELEMENTS[stackEl] &
                    html4.eflags.OPTIONAL_ENDTAG)) {
                // Don't pop non optional end tags looking for a match.
                return;
              }
            }
          } else {
            for (index = stack.length; --index >= 0;) {
              if (stack[index] === tagName) { break; }
            }
          }
          if (index < 0) { return; }  // Not opened.
          for (var i = stack.length; --i > index;) {
            var stackEl = stack[i];
            if (!(html4.ELEMENTS[stackEl] &
                  html4.eflags.OPTIONAL_ENDTAG)) {
              out.push('<\/', stackEl, '>');
            }
          }
          stack.length = index;
          out.push('<\/', tagName, '>');
        }
      },
      pcdata: emit,
      rcdata: emit,
      cdata: emit,
      endDoc: function(out) {
        for (; stack.length; stack.length--) {
          out.push('<\/', stack[stack.length - 1], '>');
        }
      }
    });
  }
/**
   * Returns a function that strips unsafe tags and attributes from html.
   * @param {function(string, Array.<string>): ?Array.<string>} tagPolicy
   *     A function that takes (tagName, attribs[]), where tagName is a key in
   *     html4.ELEMENTS and attribs is an array of alternating attribute names
   *     and values.  It should return a sanitized attribute array, or null to
   *     delete the tag.  It's okay for tagPolicy to modify the attribs array,
   *     but the same array is reused, so it should not be held between calls.
   * @return {function(string, Array)} A function that sanitizes a string of
   *     HTML and appends result strings to the second argument, an array.
   */
Returns a function that strips unsafe tags and attributes from html.
@param {function(string, Array.): ?Array.} tagPolicy
A function that takes (tagName, attribs[]), where tagName is a key in
html4.ELEMENTS and attribs is an array of alternating attribute names
and values.  It should return a sanitized attribute array, or null to
delete the tag.  It's okay for tagPolicy to modify the attribs array,
but the same array is reused, so it should not be held between calls.
@return {function(string, Array)} A function that sanitizes a string of
HTML and appends result strings to the second argument, an array.
Returns a function that strips unsafe tags and attributes from html . @param { function ( string Array . ) : ?Array . } tagPolicy A function that takes ( tagName attribs [] ) where tagName is a key in html4 . ELEMENTS and attribs is an array of alternating attribute names and values . It should return a sanitized attribute array or null to delete the tag . It ' s okay for tagPolicy to modify the attribs array but the same array is reused so it should not be held between calls . @return { function ( string Array ) } A function that sanitizes a string of HTML and appends result strings to the second argument an array .
function makeHtmlSanitizer(tagPolicy) {
    var stack;
    var ignoring;
    var emit = function (text, out) {
      if (!ignoring) { out.push(text); }
    };
    return makeSaxParser({
      startDoc: function(_) {
        stack = [];
        ignoring = false;
      },
      startTag: function(tagName, attribs, out) {
        if (ignoring) { return; }
        if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
        var eflags = html4.ELEMENTS[tagName];
        if (eflags & html4.eflags.FOLDABLE) {
          return;
        }
        attribs = tagPolicy(tagName, attribs);
        if (!attribs) {
          ignoring = !(eflags & html4.eflags.EMPTY);
          return;
        }
        if (!(eflags & html4.eflags.EMPTY)) {
          stack.push(tagName);
        }
        out.push('<', tagName);
        for (var i = 0, n = attribs.length; i < n; i += 2) {
          var attribName = attribs[i],
              value = attribs[i + 1];
          if (value !== null && value !== void 0) {
            out.push(' ', attribName, '="', escapeAttrib(value), '"');
          }
        }
        out.push('>');
      },
      endTag: function(tagName, out) {
        if (ignoring) {
          ignoring = false;
          return;
        }
        if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
        var eflags = html4.ELEMENTS[tagName];
        if (!(eflags & (html4.eflags.EMPTY | html4.eflags.FOLDABLE))) {
          var index;
          if (eflags & html4.eflags.OPTIONAL_ENDTAG) {
            for (index = stack.length; --index >= 0;) {
              var stackEl = stack[index];
              if (stackEl === tagName) { break; }
              if (!(html4.ELEMENTS[stackEl] &
                    html4.eflags.OPTIONAL_ENDTAG)) {
                return;
              }
            }
          } else {
            for (index = stack.length; --index >= 0;) {
              if (stack[index] === tagName) { break; }
            }
          }
          if (index < 0) { return; }  
          for (var i = stack.length; --i > index;) {
            var stackEl = stack[i];
            if (!(html4.ELEMENTS[stackEl] &
                  html4.eflags.OPTIONAL_ENDTAG)) {
              out.push('<\/', stackEl, '>');
            }
          }
          stack.length = index;
          out.push('<\/', tagName, '>');
        }
      },
      pcdata: emit,
      rcdata: emit,
      cdata: emit,
      endDoc: function(out) {
        for (; stack.length; stack.length--) {
          out.push('<\/', stack[stack.length - 1], '>');
        }
      }
    });
  }
function makeHtmlSanitizer ( tagPolicy ) { var stack ; var ignoring ; var emit = function ( text , out ) { if ( ! ignoring ) { out . push ( text ) ; } } ; return makeSaxParser ( { startDoc : function ( _ ) { stack = [ ] ; ignoring = false ; } , startTag : function ( tagName , attribs , out ) { if ( ignoring ) { return ; } if ( ! html4 . ELEMENTS . hasOwnProperty ( tagName ) ) { return ; } var eflags = html4 . ELEMENTS [ tagName ] ; if ( eflags & html4 . eflags . FOLDABLE ) { return ; } attribs = tagPolicy ( tagName , attribs ) ; if ( ! attribs ) { ignoring = ! ( eflags & html4 . eflags . EMPTY ) ; return ; } if ( ! ( eflags & html4 . eflags . EMPTY ) ) { stack . push ( tagName ) ; } out . push ( '<' , tagName ) ; for ( var i = 0 , n = attribs . length ; i < n ; i += 2 ) { var attribName = attribs [ i ] , value = attribs [ i + 1 ] ; if ( value !== null && value !== void 0 ) { out . push ( ' ' , attribName , '="' , escapeAttrib ( value ) , '"' ) ; } } out . push ( '>' ) ; } , endTag : function ( tagName , out ) { if ( ignoring ) { ignoring = false ; return ; } if ( ! html4 . ELEMENTS . hasOwnProperty ( tagName ) ) { return ; } var eflags = html4 . ELEMENTS [ tagName ] ; if ( ! ( eflags & ( html4 . eflags . EMPTY | html4 . eflags . FOLDABLE ) ) ) { var index ; if ( eflags & html4 . eflags . OPTIONAL_ENDTAG ) { for ( index = stack . length ; -- index >= 0 ; ) { var stackEl = stack [ index ] ; if ( stackEl === tagName ) { break ; } if ( ! ( html4 . ELEMENTS [ stackEl ] & html4 . eflags . OPTIONAL_ENDTAG ) ) { return ; } } } else { for ( index = stack . length ; -- index >= 0 ; ) { if ( stack [ index ] === tagName ) { break ; } } } if ( index < 0 ) { return ; } for ( var i = stack . length ; -- i > index ; ) { var stackEl = stack [ i ] ; if ( ! ( html4 . ELEMENTS [ stackEl ] & html4 . eflags . OPTIONAL_ENDTAG ) ) { out . push ( '<\/' , stackEl , '>' ) ; } } stack . length = index ; out . push ( '<\/' , tagName , '>' ) ; } } , pcdata : emit , rcdata : emit , cdata : emit , endDoc : function ( out ) { for ( ; stack . length ; stack . length -- ) { out . push ( '<\/' , stack [ stack . length - 1 ] , '>' ) ; } } } ) ; }
Returns a function that strips unsafe tags and attributes from html.
Returns a function that strips unsafe tags and attributes from html .
// TODO(mikesamuel): relying on tagPolicy not to insert unsafe // attribute names. // Don't pop non optional end tags looking for a match. // Not opened.