* Enter a tag, opening a scope for child tags. Entering a tag can close the * previous tag or enter other tags (such as opening a tag when * encountering a tag not allowed outside the body. * @param {!parserInterface.ParsedHtmlTag} tag
(tag)
| 225 | * @param {!parserInterface.ParsedHtmlTag} tag |
| 226 | */ |
| 227 | startTag(tag) { |
| 228 | // We only report the first body for each document - either |
| 229 | // a manufactured one, or the first one encountered. However, |
| 230 | // we collect all attributes in this.effectiveBodyAttribs_. |
| 231 | if (tag.upperName() === 'BODY') { |
| 232 | this.effectiveBodyAttribs_ = |
| 233 | this.effectiveBodyAttribs_.concat(tag.attrs().slice()); |
| 234 | } |
| 235 | |
| 236 | // This section deals with manufacturing <head>, </head>, and <body> tags |
| 237 | // if the document has left them out or placed them in the wrong location. |
| 238 | switch (this.region_) { |
| 239 | case TagRegion.PRE_DOCTYPE: |
| 240 | if (tag.upperName() === '!DOCTYPE') { |
| 241 | this.region_ = TagRegion.PRE_HTML; |
| 242 | } else if (tag.upperName() === 'HTML') { |
| 243 | this.region_ = TagRegion.PRE_HEAD; |
| 244 | } else if (tag.upperName() === 'HEAD') { |
| 245 | this.region_ = TagRegion.IN_HEAD; |
| 246 | } else if (tag.upperName() === 'BODY') { |
| 247 | this.region_ = TagRegion.IN_BODY; |
| 248 | } else if (!HtmlStructureElements.hasOwnProperty(tag.upperName())) { |
| 249 | if (HeadElements.hasOwnProperty(tag.upperName())) { |
| 250 | this.startTag(new parserInterface.ParsedHtmlTag('HEAD')); |
| 251 | } else { |
| 252 | if (this.handler_.markManufacturedBody) { |
| 253 | this.handler_.markManufacturedBody(); |
| 254 | } |
| 255 | this.startTag(new parserInterface.ParsedHtmlTag('BODY')); |
| 256 | } |
| 257 | } |
| 258 | break; |
| 259 | case TagRegion.PRE_HTML: |
| 260 | // Stray DOCTYPE/HTML tags are ignored, not emitted twice. |
| 261 | if (tag.upperName() === '!DOCTYPE') { |
| 262 | return; |
| 263 | } else if (tag.upperName() === 'HTML') { |
| 264 | this.region_ = TagRegion.PRE_HEAD; |
| 265 | } else if (tag.upperName() === 'HEAD') { |
| 266 | this.region_ = TagRegion.IN_HEAD; |
| 267 | } else if (tag.upperName() === 'BODY') { |
| 268 | this.region_ = TagRegion.IN_BODY; |
| 269 | } else if (!HtmlStructureElements.hasOwnProperty(tag.upperName())) { |
| 270 | if (HeadElements.hasOwnProperty(tag.upperName())) { |
| 271 | this.startTag(new parserInterface.ParsedHtmlTag('HEAD')); |
| 272 | } else { |
| 273 | if (this.handler_.markManufacturedBody) { |
| 274 | this.handler_.markManufacturedBody(); |
| 275 | } |
| 276 | this.startTag(new parserInterface.ParsedHtmlTag('BODY')); |
| 277 | } |
| 278 | } |
| 279 | break; |
| 280 | case TagRegion.PRE_HEAD: |
| 281 | // Stray DOCTYPE/HTML tags are ignored, not emitted twice. |
| 282 | if (tag.upperName() === '!DOCTYPE' || tag.upperName() === 'HTML') { |
| 283 | return; |
| 284 | } else if (tag.upperName() === 'HEAD') { |