| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 // TODO(jacobr): use _Lists.dart to remove some of the duplicated | 7 // TODO(jacobr): use _Lists.dart to remove some of the duplicated |
| 8 // functionality. | 8 // functionality. |
| 9 class _ChildrenElementList implements List { | 9 class _ChildrenElementList implements List { |
| 10 // Raw Element. | 10 // Raw Element. |
| (...skipping 828 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 } | 839 } |
| 840 } | 840 } |
| 841 $else | 841 $else |
| 842 $endif | 842 $endif |
| 843 | 843 |
| 844 $!MEMBERS | 844 $!MEMBERS |
| 845 } | 845 } |
| 846 | 846 |
| 847 final _START_TAG_REGEXP = new RegExp('<(\\w+)'); | 847 final _START_TAG_REGEXP = new RegExp('<(\\w+)'); |
| 848 class _ElementFactoryProvider { | 848 class _ElementFactoryProvider { |
| 849 static final _CUSTOM_PARENT_TAG_MAP = const { | 849 static const _CUSTOM_PARENT_TAG_MAP = const { |
| 850 'body' : 'html', | 850 'body' : 'html', |
| 851 'head' : 'html', | 851 'head' : 'html', |
| 852 'caption' : 'table', | 852 'caption' : 'table', |
| 853 'td': 'tr', | 853 'td': 'tr', |
| 854 'th': 'tr', |
| 854 'colgroup': 'table', | 855 'colgroup': 'table', |
| 855 'col' : 'colgroup', | 856 'col' : 'colgroup', |
| 856 'tr' : 'tbody', | 857 'tr' : 'tbody', |
| 857 'tbody' : 'table', | 858 'tbody' : 'table', |
| 858 'tfoot' : 'table', | 859 'tfoot' : 'table', |
| 859 'thead' : 'table', | 860 'thead' : 'table', |
| 860 'track' : 'audio', | 861 'track' : 'audio', |
| 861 }; | 862 }; |
| 862 | 863 |
| 864 // TODO(jmesserly): const set would be better |
| 865 static const _TABLE_TAGS = const { |
| 866 'caption': null, |
| 867 'col': null, |
| 868 'colgroup': null, |
| 869 'tbody': null, |
| 870 'td': null, |
| 871 'tfoot': null, |
| 872 'th': null, |
| 873 'thead': null, |
| 874 'tr': null, |
| 875 }; |
| 876 |
| 863 /** @domName Document.createElement */ | 877 /** @domName Document.createElement */ |
| 864 static Element createElement_html(String html) { | 878 static Element createElement_html(String html) { |
| 865 // TODO(jacobr): this method can be made more robust and performant. | 879 // TODO(jacobr): this method can be made more robust and performant. |
| 866 // 1) Cache the dummy parent elements required to use innerHTML rather than | 880 // 1) Cache the dummy parent elements required to use innerHTML rather than |
| 867 // creating them every call. | 881 // creating them every call. |
| 868 // 2) Verify that the html does not contain leading or trailing text nodes. | 882 // 2) Verify that the html does not contain leading or trailing text nodes. |
| 869 // 3) Verify that the html does not contain both <head> and <body> tags. | 883 // 3) Verify that the html does not contain both <head> and <body> tags. |
| 870 // 4) Detatch the created element from its dummy parent. | 884 // 4) Detatch the created element from its dummy parent. |
| 871 String parentTag = 'div'; | 885 String parentTag = 'div'; |
| 872 String tag; | 886 String tag; |
| 873 final match = _START_TAG_REGEXP.firstMatch(html); | 887 final match = _START_TAG_REGEXP.firstMatch(html); |
| 874 if (match != null) { | 888 if (match != null) { |
| 875 tag = match.group(1).toLowerCase(); | 889 tag = match.group(1).toLowerCase(); |
| 876 if (_CUSTOM_PARENT_TAG_MAP.containsKey(tag)) { | 890 if (_Device.isIE && _TABLE_TAGS.containsKey(tag)) { |
| 877 parentTag = _CUSTOM_PARENT_TAG_MAP[tag]; | 891 return _createTableForIE(html, tag); |
| 878 } | 892 } |
| 893 parentTag = _CUSTOM_PARENT_TAG_MAP[tag]; |
| 894 if (parentTag == null) parentTag = 'div'; |
| 879 } | 895 } |
| 880 final Element temp = new Element.tag(parentTag); | 896 |
| 897 final temp = new Element.tag(parentTag); |
| 881 temp.innerHtml = html; | 898 temp.innerHtml = html; |
| 882 | 899 |
| 883 Element element; | 900 Element element; |
| 884 if (temp.children.length == 1) { | 901 if (temp.children.length == 1) { |
| 885 element = temp.children[0]; | 902 element = temp.children[0]; |
| 886 } else if (parentTag == 'html' && temp.children.length == 2) { | 903 } else if (parentTag == 'html' && temp.children.length == 2) { |
| 887 // Work around for edge case in WebKit and possibly other browsers where | 904 // In html5 the root <html> tag will always have a <body> and a <head>, |
| 888 // both body and head elements are created even though the inner html | 905 // even though the inner html only contains one of them. |
| 889 // only contains a head or body element. | |
| 890 element = temp.children[tag == 'head' ? 0 : 1]; | 906 element = temp.children[tag == 'head' ? 0 : 1]; |
| 891 } else { | 907 } else { |
| 892 throw new ArgumentError('HTML had ${temp.children.length} ' | 908 _singleNode(temp.children); |
| 893 'top level elements but 1 expected'); | |
| 894 } | 909 } |
| 895 element.remove(); | 910 element.remove(); |
| 896 return element; | 911 return element; |
| 897 } | 912 } |
| 898 | 913 |
| 914 /** |
| 915 * IE table elements don't support innerHTML (even in standards mode). |
| 916 * Instead we use a div and inject the table element in the innerHtml string. |
| 917 * This technique works on other browsers too, but it's probably slower, |
| 918 * so we only use it when running on IE. |
| 919 * |
| 920 * See also innerHTML: |
| 921 * <http://msdn.microsoft.com/en-us/library/ie/ms533897(v=vs.85).aspx> |
| 922 * and Building Tables Dynamically: |
| 923 * <http://msdn.microsoft.com/en-us/library/ie/ms532998(v=vs.85).aspx>. |
| 924 */ |
| 925 static Element _createTableForIE(String html, String tag) { |
| 926 var div = new Element.tag('div'); |
| 927 div.innerHtml = '<table>$html</table>'; |
| 928 var table = _singleNode(div.children); |
| 929 Element element; |
| 930 switch (tag) { |
| 931 case 'td': |
| 932 case 'th': |
| 933 element = _singleNode(_singleNode(table.rows).cells); |
| 934 break; |
| 935 case 'tr': |
| 936 element = _singleNode(table.rows); |
| 937 break; |
| 938 case 'tbody': |
| 939 element = _singleNode(table.tBodies); |
| 940 break; |
| 941 case 'thead': |
| 942 element = table.tHead; |
| 943 break; |
| 944 case 'tfoot': |
| 945 element = table.tFoot; |
| 946 break; |
| 947 case 'caption': |
| 948 element = table.caption; |
| 949 break; |
| 950 case 'colgroup': |
| 951 element = _getColgroup(table); |
| 952 break; |
| 953 case 'col': |
| 954 element = _singleNode(_getColgroup(table).children); |
| 955 break; |
| 956 } |
| 957 element.remove(); |
| 958 return element; |
| 959 } |
| 960 |
| 961 static TableColElement _getColgroup(TableElement table) { |
| 962 // TODO(jmesserly): is there a better way to do this? |
| 963 return _singleNode(table.children.where((n) => n.tagName == 'COLGROUP') |
| 964 .toList()); |
| 965 } |
| 966 |
| 967 static Node _singleNode(List<Node> list) { |
| 968 if (list.length == 1) return list[0]; |
| 969 throw new ArgumentError('HTML had ${list.length} ' |
| 970 'top level elements but 1 expected'); |
| 971 } |
| 972 |
| 899 /** @domName Document.createElement */ | 973 /** @domName Document.createElement */ |
| 900 $if DART2JS | 974 $if DART2JS |
| 901 // Optimization to improve performance until the dart2js compiler inlines this | 975 // Optimization to improve performance until the dart2js compiler inlines this |
| 902 // method. | 976 // method. |
| 903 static dynamic createElement_tag(String tag) => | 977 static dynamic createElement_tag(String tag) => |
| 904 JS('Element', 'document.createElement(#)', tag); | 978 JS('Element', 'document.createElement(#)', tag); |
| 905 $else | 979 $else |
| 906 static Element createElement_tag(String tag) => | 980 static Element createElement_tag(String tag) => |
| 907 document.$dom_createElement(tag); | 981 document.$dom_createElement(tag); |
| 908 $endif | 982 $endif |
| 909 } | 983 } |
| OLD | NEW |