diff --git a/README.md b/README.md index 5f655a097..1d54e525a 100644 --- a/README.md +++ b/README.md @@ -382,7 +382,8 @@ HTML Beautifier Options: -M, --wrap-attributes-min-attrs Minimum number of html tag attributes for force wrap attribute options [2] -i, --wrap-attributes-indent-size Indent wrapped attributes to after N characters [indent-size] (ignored if wrap-attributes is "aligned") -d, --inline List of tags to be considered inline tags - --inline_custom_elements Inline custom elements [true] + --inline_custom_elements Inline custom elements [false] + --preserve_self_closing_tags Preserve the no-space form of self-closing tags [false] -U, --unformatted List of tags (defaults to inline) that should not be reformatted -T, --content_unformatted List of tags (defaults to pre) whose content should not be reformatted -E, --extra_liners List of tags (defaults to [head,body,/html] that should have an extra newline before them. diff --git a/js/src/cli.js b/js/src/cli.js index d6ec9e93e..71a88ca58 100755 --- a/js/src/cli.js +++ b/js/src/cli.js @@ -120,6 +120,7 @@ var path = require('path'), "max_char": Number, // obsolete since 1.3.5 "inline": [String, Array], "inline_custom_elements": [Boolean], + "preserve_self_closing_tags": [Boolean], "unformatted": [String, Array], "content_unformatted": [String, Array], "indent_inner_html": [Boolean], @@ -173,6 +174,7 @@ var path = require('path'), "W": ["--max_char"], // obsolete since 1.3.5 "d": ["--inline"], // no shorthand for "inline_custom_elements" + // no shorthand for "preserve_self_closing_tags" "U": ["--unformatted"], "T": ["--content_unformatted"], "I": ["--indent_inner_html"], @@ -710,4 +712,4 @@ function logToStdout(str, config) { if (typeof config.quiet === "undefined" || !config.quiet) { console.log(str); } -} \ No newline at end of file +} diff --git a/js/src/html/beautifier.js b/js/src/html/beautifier.js index e32940fb7..48ace1ac7 100644 --- a/js/src/html/beautifier.js +++ b/js/src/html/beautifier.js @@ -375,7 +375,7 @@ Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_t printer.add_raw_token(raw_token); } else { if (last_tag_token.tag_start_char === '<') { - printer.set_space_before_token(raw_token.text[0] === '/', true); // space before />, no space before > + printer.set_space_before_token(raw_token.text[0] === '/' && !this._options.preserve_self_closing_tags, true); // space before />, no space before > when preserving self-closing tags if (this._is_wrap_attributes_force_expand_multiline && last_tag_token.has_wrapped_attrs) { printer.print_newline(false); } @@ -818,92 +818,93 @@ Beautifier.prototype._do_optional_end_element = function(parser_token) { // https://www.w3.org/TR/html5/syntax.html#optional-tags if (parser_token.is_empty_element || !parser_token.is_start_tag || !parser_token.parent) { return; - } - if (parser_token.tag_name === 'body') { - // A head element’s end tag may be omitted if the head element is not immediately followed by a space character or a comment. - result = result || this._tag_stack.try_pop('head'); + if (parser_token.tag_start_char === '<') { + if (parser_token.tag_name === 'body') { + // A head element’s end tag may be omitted if the head element is not immediately followed by a space character or a comment. + result = result || this._tag_stack.try_pop('head'); - //} else if (parser_token.tag_name === 'body') { - // DONE: A body element’s end tag may be omitted if the body element is not immediately followed by a comment. + //} else if (parser_token.tag_name === 'body') { + // DONE: A body element’s end tag may be omitted if the body element is not immediately followed by a comment. - } else if (parser_token.tag_name === 'li') { - // An li element’s end tag may be omitted if the li element is immediately followed by another li element or if there is no more content in the parent element. - result = result || this._tag_stack.try_pop('li', ['ol', 'ul', 'menu']); + } else if (parser_token.tag_name === 'li') { + // An li element’s end tag may be omitted if the li element is immediately followed by another li element or if there is no more content in the parent element. + result = result || this._tag_stack.try_pop('li', ['ol', 'ul', 'menu']); - } else if (parser_token.tag_name === 'dd' || parser_token.tag_name === 'dt') { - // A dd element’s end tag may be omitted if the dd element is immediately followed by another dd element or a dt element, or if there is no more content in the parent element. - // A dt element’s end tag may be omitted if the dt element is immediately followed by another dt element or a dd element. - result = result || this._tag_stack.try_pop('dt', ['dl']); - result = result || this._tag_stack.try_pop('dd', ['dl']); + } else if (parser_token.tag_name === 'dd' || parser_token.tag_name === 'dt') { + // A dd element’s end tag may be omitted if the dd element is immediately followed by another dd element or a dt element, or if there is no more content in the parent element. + // A dt element’s end tag may be omitted if the dt element is immediately followed by another dt element or a dd element. + result = result || this._tag_stack.try_pop('dt', ['dl']); + result = result || this._tag_stack.try_pop('dd', ['dl']); - } else if (parser_token.parent.tag_name === 'p' && p_closers.indexOf(parser_token.tag_name) !== -1) { - // IMPORTANT: this else-if works because p_closers has no overlap with any other element we look for in this method - // check for the parent element is an HTML element that is not an ,