* collapseWhitespace(options) removes extraneous whitespace from an the given element. * * @param {Object} options
(options)
| 401 | * @param {Object} options |
| 402 | */ |
| 403 | function collapseWhitespace (options) { |
| 404 | var element = options.element; |
| 405 | var isBlock = options.isBlock; |
| 406 | var isVoid = options.isVoid; |
| 407 | var isPre = options.isPre || function (node) { |
| 408 | return node.nodeName === 'PRE' |
| 409 | }; |
| 410 | |
| 411 | if (!element.firstChild || isPre(element)) return |
| 412 | |
| 413 | var prevText = null; |
| 414 | var prevVoid = false; |
| 415 | |
| 416 | var prev = null; |
| 417 | var node = next(prev, element, isPre); |
| 418 | |
| 419 | while (node !== element) { |
| 420 | if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE |
| 421 | var text = node.data.replace(/[ \r\n\t]+/g, ' '); |
| 422 | |
| 423 | if ((!prevText || / $/.test(prevText.data)) && |
| 424 | !prevVoid && text[0] === ' ') { |
| 425 | text = text.substr(1); |
| 426 | } |
| 427 | |
| 428 | // `text` might be empty at this point. |
| 429 | if (!text) { |
| 430 | node = remove(node); |
| 431 | continue |
| 432 | } |
| 433 | |
| 434 | node.data = text; |
| 435 | |
| 436 | prevText = node; |
| 437 | } else if (node.nodeType === 1) { // Node.ELEMENT_NODE |
| 438 | if (isBlock(node) || node.nodeName === 'BR') { |
| 439 | if (prevText) { |
| 440 | prevText.data = prevText.data.replace(/ $/, ''); |
| 441 | } |
| 442 | |
| 443 | prevText = null; |
| 444 | prevVoid = false; |
| 445 | } else if (isVoid(node)) { |
| 446 | // Avoid trimming space around non-block, non-BR void elements. |
| 447 | prevText = null; |
| 448 | prevVoid = true; |
| 449 | } |
| 450 | } else { |
| 451 | node = remove(node); |
| 452 | continue |
| 453 | } |
| 454 | |
| 455 | var nextNode = next(prev, node, isPre); |
| 456 | prev = node; |
| 457 | node = nextNode; |
| 458 | } |
| 459 | |
| 460 | if (prevText) { |