| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of html; | 5 part of html; |
| 6 | 6 |
| 7 // This code is a port of Model-Driven-Views: | 7 // This code is a port of Model-Driven-Views: |
| 8 // https://github.com/polymer-project/mdv | 8 // https://github.com/polymer-project/mdv |
| 9 // The code mostly comes from src/template_element.js | 9 // The code mostly comes from src/template_element.js |
| 10 | 10 |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 | 364 |
| 365 static Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) { | 365 static Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) { |
| 366 var clone = node.clone(false); // Shallow clone. | 366 var clone = node.clone(false); // Shallow clone. |
| 367 if (clone is Element && clone.isTemplate) { | 367 if (clone is Element && clone.isTemplate) { |
| 368 TemplateElement.decorate(clone, node); | 368 TemplateElement.decorate(clone, node); |
| 369 if (syntax != null) { | 369 if (syntax != null) { |
| 370 clone.attributes.putIfAbsent('syntax', () => syntax); | 370 clone.attributes.putIfAbsent('syntax', () => syntax); |
| 371 } | 371 } |
| 372 } | 372 } |
| 373 | 373 |
| 374 for (var c = node.$dom_firstChild; c != null; c = c.nextNode) { | 374 for (var c = node.firstChild; c != null; c = c.nextNode) { |
| 375 clone.append(_createDeepCloneAndDecorateTemplates(c, syntax)); | 375 clone.append(_createDeepCloneAndDecorateTemplates(c, syntax)); |
| 376 } | 376 } |
| 377 return clone; | 377 return clone; |
| 378 } | 378 } |
| 379 | 379 |
| 380 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#
dfn-template-contents-owner | 380 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#
dfn-template-contents-owner |
| 381 static Document _getTemplateContentsOwner(HtmlDocument doc) { | 381 static Document _getTemplateContentsOwner(HtmlDocument doc) { |
| 382 if (doc.window == null) { | 382 if (doc.window == null) { |
| 383 return doc; | 383 return doc; |
| 384 } | 384 } |
| 385 var d = doc._templateContentsOwner; | 385 var d = doc._templateContentsOwner; |
| 386 if (d == null) { | 386 if (d == null) { |
| 387 // TODO(arv): This should either be a Document or HTMLDocument depending | 387 // TODO(arv): This should either be a Document or HTMLDocument depending |
| 388 // on doc. | 388 // on doc. |
| 389 d = doc.implementation.createHtmlDocument(''); | 389 d = doc.implementation.createHtmlDocument(''); |
| 390 while (d.$dom_lastChild != null) { | 390 while (d.lastChild != null) { |
| 391 d.$dom_lastChild.remove(); | 391 d.lastChild.remove(); |
| 392 } | 392 } |
| 393 doc._templateContentsOwner = d; | 393 doc._templateContentsOwner = d; |
| 394 } | 394 } |
| 395 return d; | 395 return d; |
| 396 } | 396 } |
| 397 | 397 |
| 398 static Element _cloneAndSeperateAttributeTemplate(Element templateElement) { | 398 static Element _cloneAndSeperateAttributeTemplate(Element templateElement) { |
| 399 var clone = templateElement.clone(false); | 399 var clone = templateElement.clone(false); |
| 400 var attributes = templateElement.attributes; | 400 var attributes = templateElement.attributes; |
| 401 for (var name in attributes.keys.toList()) { | 401 for (var name in attributes.keys.toList()) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 413 } | 413 } |
| 414 | 414 |
| 415 return clone; | 415 return clone; |
| 416 } | 416 } |
| 417 | 417 |
| 418 static void _liftNonNativeChildrenIntoContent(Element templateElement) { | 418 static void _liftNonNativeChildrenIntoContent(Element templateElement) { |
| 419 var content = templateElement.content; | 419 var content = templateElement.content; |
| 420 | 420 |
| 421 if (!templateElement._isAttributeTemplate) { | 421 if (!templateElement._isAttributeTemplate) { |
| 422 var child; | 422 var child; |
| 423 while ((child = templateElement.$dom_firstChild) != null) { | 423 while ((child = templateElement.firstChild) != null) { |
| 424 content.append(child); | 424 content.append(child); |
| 425 } | 425 } |
| 426 return; | 426 return; |
| 427 } | 427 } |
| 428 | 428 |
| 429 // For attribute templates we copy the whole thing into the content and | 429 // For attribute templates we copy the whole thing into the content and |
| 430 // we move the non template attributes into the content. | 430 // we move the non template attributes into the content. |
| 431 // | 431 // |
| 432 // <tr foo template> | 432 // <tr foo template> |
| 433 // | 433 // |
| 434 // becomes | 434 // becomes |
| 435 // | 435 // |
| 436 // <tr template> | 436 // <tr template> |
| 437 // + #document-fragment | 437 // + #document-fragment |
| 438 // + <tr foo> | 438 // + <tr foo> |
| 439 // | 439 // |
| 440 var newRoot = _cloneAndSeperateAttributeTemplate(templateElement); | 440 var newRoot = _cloneAndSeperateAttributeTemplate(templateElement); |
| 441 var child; | 441 var child; |
| 442 while ((child = templateElement.$dom_firstChild) != null) { | 442 while ((child = templateElement.firstChild) != null) { |
| 443 newRoot.append(child); | 443 newRoot.append(child); |
| 444 } | 444 } |
| 445 content.append(newRoot); | 445 content.append(newRoot); |
| 446 } | 446 } |
| 447 | 447 |
| 448 static void _bootstrapTemplatesRecursivelyFrom(Node node) { | 448 static void _bootstrapTemplatesRecursivelyFrom(Node node) { |
| 449 void bootstrap(template) { | 449 void bootstrap(template) { |
| 450 if (!TemplateElement.decorate(template)) { | 450 if (!TemplateElement.decorate(template)) { |
| 451 _bootstrapTemplatesRecursivelyFrom(template.content); | 451 _bootstrapTemplatesRecursivelyFrom(template.content); |
| 452 } | 452 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 464 static final String _allTemplatesSelectors = 'template, option[template], ' + | 464 static final String _allTemplatesSelectors = 'template, option[template], ' + |
| 465 Element._TABLE_TAGS.keys.map((k) => "$k[template]").join(", "); | 465 Element._TABLE_TAGS.keys.map((k) => "$k[template]").join(", "); |
| 466 | 466 |
| 467 static void _addBindings(Node node, model, [CustomBindingSyntax syntax]) { | 467 static void _addBindings(Node node, model, [CustomBindingSyntax syntax]) { |
| 468 if (node is Element) { | 468 if (node is Element) { |
| 469 _addAttributeBindings(node, model, syntax); | 469 _addAttributeBindings(node, model, syntax); |
| 470 } else if (node is Text) { | 470 } else if (node is Text) { |
| 471 _parseAndBind(node, 'text', node.text, model, syntax); | 471 _parseAndBind(node, 'text', node.text, model, syntax); |
| 472 } | 472 } |
| 473 | 473 |
| 474 for (var c = node.$dom_firstChild; c != null; c = c.nextNode) { | 474 for (var c = node.firstChild; c != null; c = c.nextNode) { |
| 475 _addBindings(c, model, syntax); | 475 _addBindings(c, model, syntax); |
| 476 } | 476 } |
| 477 } | 477 } |
| 478 | 478 |
| 479 static void _addAttributeBindings(Element element, model, syntax) { | 479 static void _addAttributeBindings(Element element, model, syntax) { |
| 480 element.attributes.forEach((name, value) { | 480 element.attributes.forEach((name, value) { |
| 481 if (value == '' && (name == 'bind' || name == 'repeat')) { | 481 if (value == '' && (name == 'bind' || name == 'repeat')) { |
| 482 value = '{{}}'; | 482 value = '{{}}'; |
| 483 } | 483 } |
| 484 _parseAndBind(element, name, value, model, syntax); | 484 _parseAndBind(element, name, value, model, syntax); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 | 580 |
| 581 var value = s.substring(lastIndex, index).trim(); | 581 var value = s.substring(lastIndex, index).trim(); |
| 582 result.add(new _BindingToken(value, isBinding: true)); | 582 result.add(new _BindingToken(value, isBinding: true)); |
| 583 lastIndex = index + 2; | 583 lastIndex = index + 2; |
| 584 } | 584 } |
| 585 } | 585 } |
| 586 return result; | 586 return result; |
| 587 } | 587 } |
| 588 | 588 |
| 589 static void _addTemplateInstanceRecord(fragment, model) { | 589 static void _addTemplateInstanceRecord(fragment, model) { |
| 590 if (fragment.$dom_firstChild == null) { | 590 if (fragment.firstChild == null) { |
| 591 return; | 591 return; |
| 592 } | 592 } |
| 593 | 593 |
| 594 var instanceRecord = new TemplateInstance( | 594 var instanceRecord = new TemplateInstance( |
| 595 fragment.$dom_firstChild, fragment.$dom_lastChild, model); | 595 fragment.firstChild, fragment.lastChild, model); |
| 596 | 596 |
| 597 var node = instanceRecord.firstNode; | 597 var node = instanceRecord.firstNode; |
| 598 while (node != null) { | 598 while (node != null) { |
| 599 node._templateInstance = instanceRecord; | 599 node._templateInstance = instanceRecord; |
| 600 node = node.nextNode; | 600 node = node.nextNode; |
| 601 } | 601 } |
| 602 } | 602 } |
| 603 | 603 |
| 604 static void _removeAllBindingsRecursively(Node node) { | 604 static void _removeAllBindingsRecursively(Node node) { |
| 605 _nodeOrCustom(node).unbindAll(); | 605 _nodeOrCustom(node).unbindAll(); |
| 606 for (var c = node.$dom_firstChild; c != null; c = c.nextNode) { | 606 for (var c = node.firstChild; c != null; c = c.nextNode) { |
| 607 _removeAllBindingsRecursively(c); | 607 _removeAllBindingsRecursively(c); |
| 608 } | 608 } |
| 609 } | 609 } |
| 610 | 610 |
| 611 static void _removeChild(Node parent, Node child) { | 611 static void _removeChild(Node parent, Node child) { |
| 612 child._templateInstance = null; | 612 child._templateInstance = null; |
| 613 if (child is Element && (child as Element).isTemplate) { | 613 if (child is Element && (child as Element).isTemplate) { |
| 614 Element childElement = child; | 614 Element childElement = child; |
| 615 // Make sure we stop observing when we remove an element. | 615 // Make sure we stop observing when we remove an element. |
| 616 var templateIterator = childElement._templateIterator; | 616 var templateIterator = childElement._templateIterator; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 686 if (terminator is! Element) return terminator; | 686 if (terminator is! Element) return terminator; |
| 687 | 687 |
| 688 var subIterator = terminator._templateIterator; | 688 var subIterator = terminator._templateIterator; |
| 689 if (subIterator == null) return terminator; | 689 if (subIterator == null) return terminator; |
| 690 | 690 |
| 691 return subIterator.getTerminatorAt(subIterator.terminators.length - 1); | 691 return subIterator.getTerminatorAt(subIterator.terminators.length - 1); |
| 692 } | 692 } |
| 693 | 693 |
| 694 void insertInstanceAt(int index, Node fragment) { | 694 void insertInstanceAt(int index, Node fragment) { |
| 695 var previousTerminator = getTerminatorAt(index - 1); | 695 var previousTerminator = getTerminatorAt(index - 1); |
| 696 var terminator = fragment.$dom_lastChild; | 696 var terminator = fragment.lastChild; |
| 697 if (terminator == null) terminator = previousTerminator; | 697 if (terminator == null) terminator = previousTerminator; |
| 698 | 698 |
| 699 terminators.insert(index, terminator); | 699 terminators.insert(index, terminator); |
| 700 var parent = _templateElement.parentNode; | 700 var parent = _templateElement.parentNode; |
| 701 parent.insertBefore(fragment, previousTerminator.nextNode); | 701 parent.insertBefore(fragment, previousTerminator.nextNode); |
| 702 } | 702 } |
| 703 | 703 |
| 704 void removeInstanceAt(int index) { | 704 void removeInstanceAt(int index) { |
| 705 var previousTerminator = getTerminatorAt(index - 1); | 705 var previousTerminator = getTerminatorAt(index - 1); |
| 706 var terminator = getTerminatorAt(index); | 706 var terminator = getTerminatorAt(index); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 780 _sub.cancel(); | 780 _sub.cancel(); |
| 781 _sub = null; | 781 _sub = null; |
| 782 } | 782 } |
| 783 | 783 |
| 784 void abandon() { | 784 void abandon() { |
| 785 unobserve(); | 785 unobserve(); |
| 786 _valueBinding.cancel(); | 786 _valueBinding.cancel(); |
| 787 inputs.dispose(); | 787 inputs.dispose(); |
| 788 } | 788 } |
| 789 } | 789 } |
| OLD | NEW |