@ui5/webcomponents-base 0.34.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/.eslintignore +3 -1
  2. package/CHANGELOG.md +52 -0
  3. package/README.md +26 -2
  4. package/bundle.esm.js +6 -2
  5. package/dist/CSP.js +59 -0
  6. package/dist/Device.js +7 -0
  7. package/dist/EventProvider.js +19 -25
  8. package/dist/FontFace.js +7 -95
  9. package/dist/InitialConfiguration.js +31 -14
  10. package/dist/Keys.js +15 -0
  11. package/dist/ManagedStyles.js +83 -0
  12. package/dist/Render.js +3 -1
  13. package/dist/StaticAreaItem.js +11 -9
  14. package/dist/SystemCSSVars.js +4 -25
  15. package/dist/UI5Element.js +46 -60
  16. package/dist/UI5ElementMetadata.js +9 -1
  17. package/dist/asset-registries/Icons.js +29 -8
  18. package/dist/asset-registries/Illustrations.js +30 -0
  19. package/dist/asset-registries/LocaleData.js +11 -2
  20. package/dist/assets-meta/IconCollectionsAlias.js +18 -0
  21. package/dist/config/Theme.js +14 -0
  22. package/dist/css/FontFace.css +45 -0
  23. package/dist/css/OverrideFontFace.css +32 -0
  24. package/dist/css/SystemCSSVars.css +17 -0
  25. package/dist/delegate/ItemNavigation.js +66 -0
  26. package/dist/delegate/ScrollEnablement.js +7 -1
  27. package/dist/generated/AssetParameters.js +1 -1
  28. package/dist/generated/css/FontFace.css.js +5 -0
  29. package/dist/generated/css/OverrideFontFace.css.js +5 -0
  30. package/dist/generated/css/SystemCSSVars.css.js +5 -0
  31. package/dist/i18nBundle.js +33 -2
  32. package/dist/renderer/LitRenderer.js +24 -21
  33. package/dist/renderer/directives/style-map.js +72 -0
  34. package/dist/resources/bundle.esm.js +17 -101
  35. package/dist/resources/bundle.esm.js.map +1 -1
  36. package/dist/sap/base/Log.js +241 -0
  37. package/dist/sap/base/assert.js +8 -0
  38. package/dist/sap/base/security/URLListValidator.js +148 -0
  39. package/dist/sap/base/security/sanitizeHTML.js +16 -0
  40. package/dist/sap/base/util/now.js +7 -0
  41. package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +3585 -0
  42. package/dist/test-resources/elements/WithStaticArea.js +2 -1
  43. package/dist/test-resources/pages/AllTestElements.html +3 -0
  44. package/dist/test-resources/pages/i18n.html +1 -3
  45. package/dist/test-resources/specs/ConfigurationChange.spec.js +9 -9
  46. package/dist/test-resources/specs/ConfigurationScript.spec.js +24 -24
  47. package/dist/test-resources/specs/ConfigurationURL.spec.js +64 -18
  48. package/dist/test-resources/specs/CustomTheme.spec.js +7 -7
  49. package/dist/test-resources/specs/EventProvider.spec.js +63 -0
  50. package/dist/test-resources/specs/StaticArea.spec.js +55 -13
  51. package/dist/test-resources/specs/Theming.spec.js +11 -11
  52. package/dist/test-resources/specs/UI5ElementInvalidation.js +29 -29
  53. package/dist/test-resources/specs/UI5ElementLifecycle.js +11 -11
  54. package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +11 -11
  55. package/dist/test-resources/specs/UI5ElementMetadataExt.js +8 -8
  56. package/dist/test-resources/specs/UI5ElementPropertyValidation.js +6 -6
  57. package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +36 -36
  58. package/dist/test-resources/specs/UI5ElementShadowDOM.js +9 -9
  59. package/dist/test-resources/specs/UI5ElementSlots.js +9 -9
  60. package/dist/theming/CustomStyle.js +23 -3
  61. package/dist/theming/applyTheme.js +5 -8
  62. package/dist/theming/getEffectiveLinksHrefs.js +20 -0
  63. package/dist/theming/getStylesString.js +4 -2
  64. package/dist/theming/getThemeDesignerTheme.js +2 -1
  65. package/dist/theming/preloadLinks.js +23 -0
  66. package/dist/types/DataType.js +12 -0
  67. package/dist/types/Float.js +4 -0
  68. package/dist/types/Integer.js +4 -0
  69. package/dist/types/InvisibleMessageMode.js +30 -0
  70. package/dist/updateShadowRoot.js +8 -4
  71. package/dist/util/AriaLabelHelper.js +4 -4
  72. package/dist/util/FocusableElements.js +5 -1
  73. package/dist/util/HTMLSanitizer.js +7 -0
  74. package/dist/util/InvisibleMessage.js +58 -0
  75. package/dist/util/PopupUtils.js +1 -1
  76. package/dist/util/TabbableElements.js +1 -1
  77. package/dist/util/createLinkInHead.js +19 -0
  78. package/dist/util/encodeXML.js +35 -0
  79. package/dist/util/escapeRegex.js +10 -0
  80. package/dist/util/generateHighlightedMarkup.js +42 -0
  81. package/dist/util/getClassCopy.js +7 -2
  82. package/dist/util/isNodeTabbable.js +4 -4
  83. package/hash.txt +1 -1
  84. package/index.js +1 -1
  85. package/lib/generate-asset-parameters/index.js +0 -1
  86. package/lib/generate-styles/index.js +18 -0
  87. package/package-scripts.js +25 -3
  88. package/package.json +17 -9
  89. package/src/CSP.js +59 -0
  90. package/src/Device.js +7 -0
  91. package/src/EventProvider.js +19 -25
  92. package/src/FontFace.js +7 -95
  93. package/src/InitialConfiguration.js +31 -14
  94. package/src/Keys.js +15 -0
  95. package/src/ManagedStyles.js +83 -0
  96. package/src/Render.js +3 -1
  97. package/src/StaticAreaItem.js +11 -9
  98. package/src/SystemCSSVars.js +4 -25
  99. package/src/UI5Element.js +46 -60
  100. package/src/UI5ElementMetadata.js +9 -1
  101. package/src/asset-registries/Icons.js +29 -8
  102. package/src/asset-registries/Illustrations.js +30 -0
  103. package/src/asset-registries/LocaleData.js +11 -2
  104. package/src/assets-meta/IconCollectionsAlias.js +18 -0
  105. package/src/config/Theme.js +14 -0
  106. package/src/css/FontFace.css +45 -0
  107. package/src/css/OverrideFontFace.css +32 -0
  108. package/src/css/SystemCSSVars.css +17 -0
  109. package/src/delegate/ItemNavigation.js +66 -0
  110. package/src/delegate/ScrollEnablement.js +7 -1
  111. package/src/i18nBundle.js +33 -2
  112. package/src/renderer/LitRenderer.js +24 -21
  113. package/src/renderer/directives/style-map.js +72 -0
  114. package/src/theming/CustomStyle.js +23 -3
  115. package/src/theming/applyTheme.js +5 -8
  116. package/src/theming/getEffectiveLinksHrefs.js +20 -0
  117. package/src/theming/getStylesString.js +4 -2
  118. package/src/theming/getThemeDesignerTheme.js +2 -1
  119. package/src/theming/preloadLinks.js +23 -0
  120. package/src/types/DataType.js +12 -0
  121. package/src/types/Float.js +4 -0
  122. package/src/types/Integer.js +4 -0
  123. package/src/types/InvisibleMessageMode.js +30 -0
  124. package/src/updateShadowRoot.js +8 -4
  125. package/src/util/AriaLabelHelper.js +4 -4
  126. package/src/util/FocusableElements.js +5 -1
  127. package/src/util/HTMLSanitizer.js +7 -0
  128. package/src/util/InvisibleMessage.js +58 -0
  129. package/src/util/PopupUtils.js +1 -1
  130. package/src/util/TabbableElements.js +1 -1
  131. package/src/util/createLinkInHead.js +19 -0
  132. package/src/util/encodeXML.js +35 -0
  133. package/src/util/escapeRegex.js +10 -0
  134. package/src/util/generateHighlightedMarkup.js +42 -0
  135. package/src/util/getClassCopy.js +7 -2
  136. package/src/util/isNodeTabbable.js +4 -4
  137. package/used-modules.txt +7 -0
  138. package/dist/config/AssetsPath.js +0 -17
  139. package/dist/renderer/ifDefined.js +0 -21
  140. package/dist/renderer/scopeHTML.js +0 -32
  141. package/dist/theming/createThemePropertiesStyleTag.js +0 -20
  142. package/src/config/AssetsPath.js +0 -17
  143. package/src/renderer/ifDefined.js +0 -21
  144. package/src/renderer/scopeHTML.js +0 -32
  145. package/src/theming/createThemePropertiesStyleTag.js +0 -20
@@ -0,0 +1,3585 @@
1
+ (function() {
2
+ /* Copyright Google Inc.
3
+ * Licensed under the Apache Licence Version 2.0
4
+ * Autogenerated at Tue May 22 10:18:21 PDT 2012
5
+ * \@overrides window
6
+ * \@provides cssSchema, CSS_PROP_BIT_QUANTITY, CSS_PROP_BIT_HASH_VALUE, CSS_PROP_BIT_NEGATIVE_QUANTITY, CSS_PROP_BIT_QSTRING_CONTENT, CSS_PROP_BIT_QSTRING_URL, CSS_PROP_BIT_HISTORY_INSENSITIVE, CSS_PROP_BIT_Z_INDEX, CSS_PROP_BIT_ALLOWED_IN_LINK */
7
+ /**
8
+ * @const
9
+ * @type {number}
10
+ */
11
+ var CSS_PROP_BIT_QUANTITY = 1;
12
+ /**
13
+ * @const
14
+ * @type {number}
15
+ */
16
+ var CSS_PROP_BIT_HASH_VALUE = 2;
17
+ /**
18
+ * @const
19
+ * @type {number}
20
+ */
21
+ var CSS_PROP_BIT_NEGATIVE_QUANTITY = 4;
22
+ /**
23
+ * @const
24
+ * @type {number}
25
+ */
26
+ var CSS_PROP_BIT_QSTRING_CONTENT = 8;
27
+ /**
28
+ * @const
29
+ * @type {number}
30
+ */
31
+ var CSS_PROP_BIT_QSTRING_URL = 16;
32
+ /**
33
+ * @const
34
+ * @type {number}
35
+ */
36
+ var CSS_PROP_BIT_HISTORY_INSENSITIVE = 32;
37
+ /**
38
+ * @const
39
+ * @type {number}
40
+ */
41
+ var CSS_PROP_BIT_Z_INDEX = 64;
42
+ /**
43
+ * @const
44
+ * @type {number}
45
+ */
46
+ var CSS_PROP_BIT_ALLOWED_IN_LINK = 128;
47
+ var cssSchema = (function () {
48
+ var s = [
49
+ 'rgb(?:\\(\\s*(?:\\d+|0|\\d+(?:\\.\\d+)?%)\\s*,\\s*(?:\\d+|0|\\d+(?:\\.\\d+)?%)\\s*,\\s*(?:\\d+|0|\\d+(?:\\.\\d+)?%)|a\\(\\s*(?:\\d+|0|\\d+(?:\\.\\d+)?%)\\s*,\\s*(?:\\d+|0|\\d+(?:\\.\\d+)?%)\\s*,\\s*(?:\\d+|0|\\d+(?:\\.\\d+)?%)\\s*,\\s*(?:\\d+|0(?:\\.\\d+)?|\\.\\d+|1(?:\\.0+)?|0|\\d+(?:\\.\\d+)?%)) *\\)'
50
+ ], c = [ /^ *$/i, RegExp('^ *(?:\\s*' + s[ 0 ] + '|(?:\\s*' + s[ 0 ] +
51
+ ')?)+ *$', 'i'), RegExp('^ *\\s*' + s[ 0 ] + ' *$', 'i'),
52
+ RegExp('^ *\\s*' + s[ 0 ] + '\\s*' + s[ 0 ] + ' *$', 'i') ], L = [ [
53
+ 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige',
54
+ 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown',
55
+ 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral',
56
+ 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue',
57
+ 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkkhaki',
58
+ 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred',
59
+ 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray',
60
+ 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray',
61
+ 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia',
62
+ 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'green',
63
+ 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory',
64
+ 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon',
65
+ 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow',
66
+ 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen',
67
+ 'lightskyblue', 'lightslategray', 'lightsteelblue', 'lightyellow',
68
+ 'lime', 'limegreen', 'linen', 'magenta', 'maroon', 'mediumaquamarine',
69
+ 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen',
70
+ 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise',
71
+ 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose',
72
+ 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab',
73
+ 'orange', 'orangered', 'orchid', 'palegoldenrod', 'palegreen',
74
+ 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru',
75
+ 'pink', 'plum', 'powderblue', 'purple', 'red', 'rosybrown',
76
+ 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen',
77
+ 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 'slategray',
78
+ 'snow', 'springgreen', 'steelblue', 'tan', 'teal', 'thistle', 'tomato',
79
+ 'turquoise', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow',
80
+ 'yellowgreen' ], [ 'all-scroll', 'col-resize', 'crosshair', 'default',
81
+ 'e-resize', 'hand', 'help', 'move', 'n-resize', 'ne-resize', 'no-drop',
82
+ 'not-allowed', 'nw-resize', 'pointer', 'progress', 'row-resize',
83
+ 's-resize', 'se-resize', 'sw-resize', 'text', 'vertical-text',
84
+ 'w-resize', 'wait' ], [ '-moz-inline-box', '-moz-inline-stack',
85
+ 'block', 'inline', 'inline-block', 'inline-table', 'list-item',
86
+ 'run-in', 'table', 'table-caption', 'table-cell', 'table-column',
87
+ 'table-column-group', 'table-footer-group', 'table-header-group',
88
+ 'table-row', 'table-row-group' ], [ 'armenian', 'circle', 'decimal',
89
+ 'decimal-leading-zero', 'disc', 'georgian', 'lower-alpha',
90
+ 'lower-greek', 'lower-latin', 'lower-roman', 'square', 'upper-alpha',
91
+ 'upper-latin', 'upper-roman' ], [ '100', '200', '300', '400', '500',
92
+ '600', '700', '800', '900', 'bold', 'bolder', 'lighter' ], [
93
+ 'condensed', 'expanded', 'extra-condensed', 'extra-expanded',
94
+ 'narrower', 'semi-condensed', 'semi-expanded', 'ultra-condensed',
95
+ 'ultra-expanded', 'wider' ], [ 'behind', 'center-left', 'center-right',
96
+ 'far-left', 'far-right', 'left-side', 'leftwards', 'right-side',
97
+ 'rightwards' ], [ 'large', 'larger', 'small', 'smaller', 'x-large',
98
+ 'x-small', 'xx-large', 'xx-small' ], [ '-moz-pre-wrap', '-o-pre-wrap',
99
+ '-pre-wrap', 'nowrap', 'pre', 'pre-line', 'pre-wrap' ], [ 'dashed',
100
+ 'dotted', 'double', 'groove', 'outset', 'ridge', 'solid' ], [
101
+ 'baseline', 'middle', 'sub', 'super', 'text-bottom', 'text-top' ], [
102
+ 'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar'
103
+ ], [ 'fast', 'faster', 'slow', 'slower', 'x-fast', 'x-slow' ], [ 'above',
104
+ 'below', 'higher', 'level', 'lower' ], [ 'border-box', 'contain',
105
+ 'content-box', 'cover', 'padding-box' ], [ 'cursive', 'fantasy',
106
+ 'monospace', 'sans-serif', 'serif' ], [ 'loud', 'silent', 'soft',
107
+ 'x-loud', 'x-soft' ], [ 'no-repeat', 'repeat-x', 'repeat-y', 'round',
108
+ 'space' ], [ 'blink', 'line-through', 'overline', 'underline' ], [
109
+ 'high', 'low', 'x-high', 'x-low' ], [ 'absolute', 'relative', 'static'
110
+ ], [ 'capitalize', 'lowercase', 'uppercase' ], [ 'child', 'female',
111
+ 'male' ], [ 'bidi-override', 'embed' ], [ 'bottom', 'top' ], [ 'clip',
112
+ 'ellipsis' ], [ 'continuous', 'digits' ], [ 'hide', 'show' ], [
113
+ 'inside', 'outside' ], [ 'italic', 'oblique' ], [ 'left', 'right' ], [
114
+ 'ltr', 'rtl' ], [ 'no-content', 'no-display' ], [ 'suppress',
115
+ 'unrestricted' ], [ 'thick', 'thin' ], [ ',' ], [ '/' ], [ 'always' ],
116
+ [ 'auto' ], [ 'avoid' ], [ 'both' ], [ 'break-word' ], [ 'center' ], [
117
+ 'code' ], [ 'collapse' ], [ 'fixed' ], [ 'hidden' ], [ 'inherit' ], [
118
+ 'inset' ], [ 'invert' ], [ 'justify' ], [ 'local' ], [ 'medium' ], [
119
+ 'mix' ], [ 'none' ], [ 'normal' ], [ 'once' ], [ 'repeat' ], [ 'scroll'
120
+ ], [ 'separate' ], [ 'small-caps' ], [ 'spell-out' ], [ 'transparent' ],
121
+ [ 'visible' ] ];
122
+ return {
123
+ '-moz-border-radius': {
124
+ 'cssExtra': c[ 0 ],
125
+ 'cssPropBits': 5,
126
+ 'cssLitGroup': [ L[ 36 ] ]
127
+ },
128
+ '-moz-border-radius-bottomleft': {
129
+ 'cssExtra': c[ 0 ],
130
+ 'cssPropBits': 5
131
+ },
132
+ '-moz-border-radius-bottomright': {
133
+ 'cssExtra': c[ 0 ],
134
+ 'cssPropBits': 5
135
+ },
136
+ '-moz-border-radius-topleft': {
137
+ 'cssExtra': c[ 0 ],
138
+ 'cssPropBits': 5
139
+ },
140
+ '-moz-border-radius-topright': {
141
+ 'cssExtra': c[ 0 ],
142
+ 'cssPropBits': 5
143
+ },
144
+ '-moz-box-shadow': {
145
+ 'cssExtra': c[ 1 ],
146
+ 'cssAlternates': [ 'boxShadow' ],
147
+ 'cssPropBits': 7,
148
+ 'cssLitGroup': [ L[ 0 ], L[ 35 ], L[ 48 ], L[ 54 ] ]
149
+ },
150
+ '-moz-opacity': {
151
+ 'cssPropBits': 1,
152
+ 'cssLitGroup': [ L[ 47 ] ]
153
+ },
154
+ '-moz-outline': {
155
+ 'cssExtra': c[ 3 ],
156
+ 'cssPropBits': 7,
157
+ 'cssLitGroup': [ L[ 0 ], L[ 9 ], L[ 34 ], L[ 46 ], L[ 47 ], L[ 48 ], L[
158
+ 49 ], L[ 52 ], L[ 54 ] ]
159
+ },
160
+ '-moz-outline-color': {
161
+ 'cssExtra': c[ 2 ],
162
+ 'cssPropBits': 2,
163
+ 'cssLitGroup': [ L[ 0 ], L[ 47 ], L[ 49 ] ]
164
+ },
165
+ '-moz-outline-style': {
166
+ 'cssPropBits': 0,
167
+ 'cssLitGroup': [ L[ 9 ], L[ 46 ], L[ 47 ], L[ 48 ], L[ 54 ] ]
168
+ },
169
+ '-moz-outline-width': {
170
+ 'cssPropBits': 5,
171
+ 'cssLitGroup': [ L[ 34 ], L[ 47 ], L[ 52 ] ]
172
+ },
173
+ '-o-text-overflow': {
174
+ 'cssPropBits': 0,
175
+ 'cssLitGroup': [ L[ 25 ] ]
176
+ },
177
+ '-webkit-border-bottom-left-radius': {
178
+ 'cssExtra': c[ 0 ],
179
+ 'cssPropBits': 5
180
+ },
181
+ '-webkit-border-bottom-right-radius': {
182
+ 'cssExtra': c[ 0 ],
183
+ 'cssPropBits': 5
184
+ },
185
+ '-webkit-border-radius': {
186
+ 'cssExtra': c[ 0 ],
187
+ 'cssPropBits': 5,
188
+ 'cssLitGroup': [ L[ 36 ] ]
189
+ },
190
+ '-webkit-border-radius-bottom-left': {
191
+ 'cssExtra': c[ 0 ],
192
+ 'cssPropBits': 5
193
+ },
194
+ '-webkit-border-radius-bottom-right': {
195
+ 'cssExtra': c[ 0 ],
196
+ 'cssPropBits': 5
197
+ },
198
+ '-webkit-border-radius-top-left': {
199
+ 'cssExtra': c[ 0 ],
200
+ 'cssPropBits': 5
201
+ },
202
+ '-webkit-border-radius-top-right': {
203
+ 'cssExtra': c[ 0 ],
204
+ 'cssPropBits': 5
205
+ },
206
+ '-webkit-border-top-left-radius': {
207
+ 'cssExtra': c[ 0 ],
208
+ 'cssPropBits': 5
209
+ },
210
+ '-webkit-border-top-right-radius': {
211
+ 'cssExtra': c[ 0 ],
212
+ 'cssPropBits': 5
213
+ },
214
+ '-webkit-box-shadow': {
215
+ 'cssExtra': c[ 1 ],
216
+ 'cssAlternates': [ 'boxShadow' ],
217
+ 'cssPropBits': 7,
218
+ 'cssLitGroup': [ L[ 0 ], L[ 35 ], L[ 48 ], L[ 54 ] ]
219
+ },
220
+ 'azimuth': {
221
+ 'cssPropBits': 5,
222
+ 'cssLitGroup': [ L[ 6 ], L[ 30 ], L[ 42 ], L[ 47 ] ]
223
+ },
224
+ 'background': {
225
+ 'cssExtra': RegExp('^ *(?:\\s*' + s[ 0 ] + '){0,2} *$', 'i'),
226
+ 'cssPropBits': 23,
227
+ 'cssLitGroup': [ L[ 0 ], L[ 14 ], L[ 17 ], L[ 24 ], L[ 30 ], L[ 35 ],
228
+ L[ 36 ], L[ 38 ], L[ 42 ], L[ 45 ], L[ 47 ], L[ 51 ], L[ 54 ], L[ 57
229
+ ], L[ 58 ], L[ 62 ] ]
230
+ },
231
+ 'background-attachment': {
232
+ 'cssExtra': c[ 0 ],
233
+ 'cssPropBits': 0,
234
+ 'cssLitGroup': [ L[ 35 ], L[ 45 ], L[ 51 ], L[ 58 ] ]
235
+ },
236
+ 'background-color': {
237
+ 'cssExtra': c[ 2 ],
238
+ 'cssPropBits': 130,
239
+ 'cssLitGroup': [ L[ 0 ], L[ 47 ], L[ 62 ] ]
240
+ },
241
+ 'background-image': {
242
+ 'cssExtra': c[ 0 ],
243
+ 'cssPropBits': 16,
244
+ 'cssLitGroup': [ L[ 35 ], L[ 54 ] ]
245
+ },
246
+ 'background-position': {
247
+ 'cssExtra': c[ 0 ],
248
+ 'cssPropBits': 5,
249
+ 'cssLitGroup': [ L[ 24 ], L[ 30 ], L[ 35 ], L[ 42 ] ]
250
+ },
251
+ 'background-repeat': {
252
+ 'cssExtra': c[ 0 ],
253
+ 'cssPropBits': 0,
254
+ 'cssLitGroup': [ L[ 17 ], L[ 35 ], L[ 57 ] ]
255
+ },
256
+ 'border': {
257
+ 'cssExtra': c[ 3 ],
258
+ 'cssPropBits': 7,
259
+ 'cssLitGroup': [ L[ 0 ], L[ 9 ], L[ 34 ], L[ 46 ], L[ 47 ], L[ 48 ], L[
260
+ 52 ], L[ 54 ], L[ 62 ] ]
261
+ },
262
+ 'border-bottom': {
263
+ 'cssExtra': c[ 3 ],
264
+ 'cssPropBits': 7,
265
+ 'cssLitGroup': [ L[ 0 ], L[ 9 ], L[ 34 ], L[ 46 ], L[ 47 ], L[ 48 ], L[
266
+ 52 ], L[ 54 ], L[ 62 ] ]
267
+ },
268
+ 'border-bottom-color': {
269
+ 'cssExtra': c[ 2 ],
270
+ 'cssPropBits': 2,
271
+ 'cssLitGroup': [ L[ 0 ], L[ 47 ], L[ 62 ] ]
272
+ },
273
+ 'border-bottom-left-radius': {
274
+ 'cssExtra': c[ 0 ],
275
+ 'cssPropBits': 5
276
+ },
277
+ 'border-bottom-right-radius': {
278
+ 'cssExtra': c[ 0 ],
279
+ 'cssPropBits': 5
280
+ },
281
+ 'border-bottom-style': {
282
+ 'cssPropBits': 0,
283
+ 'cssLitGroup': [ L[ 9 ], L[ 46 ], L[ 47 ], L[ 48 ], L[ 54 ] ]
284
+ },
285
+ 'border-bottom-width': {
286
+ 'cssPropBits': 5,
287
+ 'cssLitGroup': [ L[ 34 ], L[ 47 ], L[ 52 ] ]
288
+ },
289
+ 'border-collapse': {
290
+ 'cssPropBits': 0,
291
+ 'cssLitGroup': [ L[ 44 ], L[ 47 ], L[ 59 ] ]
292
+ },
293
+ 'border-color': {
294
+ 'cssExtra': RegExp('^ *(?:\\s*' + s[ 0 ] + '){1,4} *$', 'i'),
295
+ 'cssPropBits': 2,
296
+ 'cssLitGroup': [ L[ 0 ], L[ 47 ], L[ 62 ] ]
297
+ },
298
+ 'border-left': {
299
+ 'cssExtra': c[ 3 ],
300
+ 'cssPropBits': 7,
301
+ 'cssLitGroup': [ L[ 0 ], L[ 9 ], L[ 34 ], L[ 46 ], L[ 47 ], L[ 48 ], L[
302
+ 52 ], L[ 54 ], L[ 62 ] ]
303
+ },
304
+ 'border-left-color': {
305
+ 'cssExtra': c[ 2 ],
306
+ 'cssPropBits': 2,
307
+ 'cssLitGroup': [ L[ 0 ], L[ 47 ], L[ 62 ] ]
308
+ },
309
+ 'border-left-style': {
310
+ 'cssPropBits': 0,
311
+ 'cssLitGroup': [ L[ 9 ], L[ 46 ], L[ 47 ], L[ 48 ], L[ 54 ] ]
312
+ },
313
+ 'border-left-width': {
314
+ 'cssPropBits': 5,
315
+ 'cssLitGroup': [ L[ 34 ], L[ 47 ], L[ 52 ] ]
316
+ },
317
+ 'border-radius': {
318
+ 'cssExtra': c[ 0 ],
319
+ 'cssPropBits': 5,
320
+ 'cssLitGroup': [ L[ 36 ] ]
321
+ },
322
+ 'border-right': {
323
+ 'cssExtra': c[ 3 ],
324
+ 'cssPropBits': 7,
325
+ 'cssLitGroup': [ L[ 0 ], L[ 9 ], L[ 34 ], L[ 46 ], L[ 47 ], L[ 48 ], L[
326
+ 52 ], L[ 54 ], L[ 62 ] ]
327
+ },
328
+ 'border-right-color': {
329
+ 'cssExtra': c[ 2 ],
330
+ 'cssPropBits': 2,
331
+ 'cssLitGroup': [ L[ 0 ], L[ 47 ], L[ 62 ] ]
332
+ },
333
+ 'border-right-style': {
334
+ 'cssPropBits': 0,
335
+ 'cssLitGroup': [ L[ 9 ], L[ 46 ], L[ 47 ], L[ 48 ], L[ 54 ] ]
336
+ },
337
+ 'border-right-width': {
338
+ 'cssPropBits': 5,
339
+ 'cssLitGroup': [ L[ 34 ], L[ 47 ], L[ 52 ] ]
340
+ },
341
+ 'border-spacing': {
342
+ 'cssExtra': c[ 0 ],
343
+ 'cssPropBits': 5,
344
+ 'cssLitGroup': [ L[ 47 ] ]
345
+ },
346
+ 'border-style': {
347
+ 'cssPropBits': 0,
348
+ 'cssLitGroup': [ L[ 9 ], L[ 46 ], L[ 47 ], L[ 48 ], L[ 54 ] ]
349
+ },
350
+ 'border-top': {
351
+ 'cssExtra': c[ 3 ],
352
+ 'cssPropBits': 7,
353
+ 'cssLitGroup': [ L[ 0 ], L[ 9 ], L[ 34 ], L[ 46 ], L[ 47 ], L[ 48 ], L[
354
+ 52 ], L[ 54 ], L[ 62 ] ]
355
+ },
356
+ 'border-top-color': {
357
+ 'cssExtra': c[ 2 ],
358
+ 'cssPropBits': 2,
359
+ 'cssLitGroup': [ L[ 0 ], L[ 47 ], L[ 62 ] ]
360
+ },
361
+ 'border-top-left-radius': {
362
+ 'cssExtra': c[ 0 ],
363
+ 'cssPropBits': 5
364
+ },
365
+ 'border-top-right-radius': {
366
+ 'cssExtra': c[ 0 ],
367
+ 'cssPropBits': 5
368
+ },
369
+ 'border-top-style': {
370
+ 'cssPropBits': 0,
371
+ 'cssLitGroup': [ L[ 9 ], L[ 46 ], L[ 47 ], L[ 48 ], L[ 54 ] ]
372
+ },
373
+ 'border-top-width': {
374
+ 'cssPropBits': 5,
375
+ 'cssLitGroup': [ L[ 34 ], L[ 47 ], L[ 52 ] ]
376
+ },
377
+ 'border-width': {
378
+ 'cssPropBits': 5,
379
+ 'cssLitGroup': [ L[ 34 ], L[ 47 ], L[ 52 ] ]
380
+ },
381
+ 'bottom': {
382
+ 'cssPropBits': 5,
383
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
384
+ },
385
+ 'box-shadow': {
386
+ 'cssExtra': c[ 1 ],
387
+ 'cssPropBits': 7,
388
+ 'cssLitGroup': [ L[ 0 ], L[ 35 ], L[ 48 ], L[ 54 ] ]
389
+ },
390
+ 'caption-side': {
391
+ 'cssPropBits': 0,
392
+ 'cssLitGroup': [ L[ 24 ], L[ 47 ] ]
393
+ },
394
+ 'clear': {
395
+ 'cssPropBits': 0,
396
+ 'cssLitGroup': [ L[ 30 ], L[ 40 ], L[ 47 ], L[ 54 ] ]
397
+ },
398
+ 'clip': {
399
+ 'cssExtra':
400
+ /^ *\s*rect\(\s*(?:0|[+\-]?\d+(?:\.\d+)?(?:[cem]m|ex|in|p[ctx])|auto)\s*,\s*(?:0|[+\-]?\d+(?:\.\d+)?(?:[cem]m|ex|in|p[ctx])|auto)\s*,\s*(?:0|[+\-]?\d+(?:\.\d+)?(?:[cem]m|ex|in|p[ctx])|auto)\s*,\s*(?:0|[+\-]?\d+(?:\.\d+)?(?:[cem]m|ex|in|p[ctx])|auto) *\) *$/i,
401
+ 'cssPropBits': 0,
402
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
403
+ },
404
+ 'color': {
405
+ 'cssExtra': c[ 2 ],
406
+ 'cssPropBits': 130,
407
+ 'cssLitGroup': [ L[ 0 ], L[ 47 ] ]
408
+ },
409
+ 'content': { 'cssPropBits': 0 },
410
+ 'counter-increment': {
411
+ 'cssExtra': c[ 0 ],
412
+ 'cssPropBits': 5,
413
+ 'cssLitGroup': [ L[ 47 ], L[ 54 ] ]
414
+ },
415
+ 'counter-reset': {
416
+ 'cssExtra': c[ 0 ],
417
+ 'cssPropBits': 5,
418
+ 'cssLitGroup': [ L[ 47 ], L[ 54 ] ]
419
+ },
420
+ 'cue': {
421
+ 'cssPropBits': 16,
422
+ 'cssLitGroup': [ L[ 47 ], L[ 54 ] ]
423
+ },
424
+ 'cue-after': {
425
+ 'cssPropBits': 16,
426
+ 'cssLitGroup': [ L[ 47 ], L[ 54 ] ]
427
+ },
428
+ 'cue-before': {
429
+ 'cssPropBits': 16,
430
+ 'cssLitGroup': [ L[ 47 ], L[ 54 ] ]
431
+ },
432
+ 'cursor': {
433
+ 'cssExtra': c[ 0 ],
434
+ 'cssPropBits': 144,
435
+ 'cssLitGroup': [ L[ 1 ], L[ 35 ], L[ 38 ], L[ 47 ] ]
436
+ },
437
+ 'direction': {
438
+ 'cssPropBits': 0,
439
+ 'cssLitGroup': [ L[ 31 ], L[ 47 ] ]
440
+ },
441
+ 'display': {
442
+ 'cssPropBits': 32,
443
+ 'cssLitGroup': [ L[ 2 ], L[ 47 ], L[ 54 ] ]
444
+ },
445
+ 'elevation': {
446
+ 'cssPropBits': 5,
447
+ 'cssLitGroup': [ L[ 13 ], L[ 47 ] ]
448
+ },
449
+ 'empty-cells': {
450
+ 'cssPropBits': 0,
451
+ 'cssLitGroup': [ L[ 27 ], L[ 47 ] ]
452
+ },
453
+ 'filter': {
454
+ 'cssExtra':
455
+ /^ *(?:\s*alpha\(\s*opacity\s*=\s*(?:0|\d+(?:\.\d+)?%|[+\-]?\d+(?:\.\d+)?) *\))+ *$/i,
456
+ 'cssPropBits': 32
457
+ },
458
+ 'float': {
459
+ 'cssAlternates': [ 'cssFloat', 'styleFloat' ],
460
+ 'cssPropBits': 32,
461
+ 'cssLitGroup': [ L[ 30 ], L[ 47 ], L[ 54 ] ]
462
+ },
463
+ 'font': {
464
+ 'cssExtra': c[ 0 ],
465
+ 'cssPropBits': 9,
466
+ 'cssLitGroup': [ L[ 4 ], L[ 7 ], L[ 11 ], L[ 15 ], L[ 29 ], L[ 35 ], L[
467
+ 36 ], L[ 47 ], L[ 52 ], L[ 55 ], L[ 60 ] ]
468
+ },
469
+ 'font-family': {
470
+ 'cssExtra': c[ 0 ],
471
+ 'cssPropBits': 8,
472
+ 'cssLitGroup': [ L[ 15 ], L[ 35 ], L[ 47 ] ]
473
+ },
474
+ 'font-size': {
475
+ 'cssPropBits': 1,
476
+ 'cssLitGroup': [ L[ 7 ], L[ 47 ], L[ 52 ] ]
477
+ },
478
+ 'font-stretch': {
479
+ 'cssPropBits': 0,
480
+ 'cssLitGroup': [ L[ 5 ], L[ 55 ] ]
481
+ },
482
+ 'font-style': {
483
+ 'cssPropBits': 0,
484
+ 'cssLitGroup': [ L[ 29 ], L[ 47 ], L[ 55 ] ]
485
+ },
486
+ 'font-variant': {
487
+ 'cssPropBits': 0,
488
+ 'cssLitGroup': [ L[ 47 ], L[ 55 ], L[ 60 ] ]
489
+ },
490
+ 'font-weight': {
491
+ 'cssPropBits': 0,
492
+ 'cssLitGroup': [ L[ 4 ], L[ 47 ], L[ 55 ] ]
493
+ },
494
+ 'height': {
495
+ 'cssPropBits': 37,
496
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
497
+ },
498
+ 'left': {
499
+ 'cssPropBits': 37,
500
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
501
+ },
502
+ 'letter-spacing': {
503
+ 'cssPropBits': 5,
504
+ 'cssLitGroup': [ L[ 47 ], L[ 55 ] ]
505
+ },
506
+ 'line-height': {
507
+ 'cssPropBits': 1,
508
+ 'cssLitGroup': [ L[ 47 ], L[ 55 ] ]
509
+ },
510
+ 'list-style': {
511
+ 'cssPropBits': 16,
512
+ 'cssLitGroup': [ L[ 3 ], L[ 28 ], L[ 47 ], L[ 54 ] ]
513
+ },
514
+ 'list-style-image': {
515
+ 'cssPropBits': 16,
516
+ 'cssLitGroup': [ L[ 47 ], L[ 54 ] ]
517
+ },
518
+ 'list-style-position': {
519
+ 'cssPropBits': 0,
520
+ 'cssLitGroup': [ L[ 28 ], L[ 47 ] ]
521
+ },
522
+ 'list-style-type': {
523
+ 'cssPropBits': 0,
524
+ 'cssLitGroup': [ L[ 3 ], L[ 47 ], L[ 54 ] ]
525
+ },
526
+ 'margin': {
527
+ 'cssPropBits': 5,
528
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
529
+ },
530
+ 'margin-bottom': {
531
+ 'cssPropBits': 5,
532
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
533
+ },
534
+ 'margin-left': {
535
+ 'cssPropBits': 5,
536
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
537
+ },
538
+ 'margin-right': {
539
+ 'cssPropBits': 5,
540
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
541
+ },
542
+ 'margin-top': {
543
+ 'cssPropBits': 5,
544
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
545
+ },
546
+ 'max-height': {
547
+ 'cssPropBits': 1,
548
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ], L[ 54 ] ]
549
+ },
550
+ 'max-width': {
551
+ 'cssPropBits': 1,
552
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ], L[ 54 ] ]
553
+ },
554
+ 'min-height': {
555
+ 'cssPropBits': 1,
556
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
557
+ },
558
+ 'min-width': {
559
+ 'cssPropBits': 1,
560
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
561
+ },
562
+ 'opacity': {
563
+ 'cssPropBits': 33,
564
+ 'cssLitGroup': [ L[ 47 ] ]
565
+ },
566
+ 'outline': {
567
+ 'cssExtra': c[ 3 ],
568
+ 'cssPropBits': 7,
569
+ 'cssLitGroup': [ L[ 0 ], L[ 9 ], L[ 34 ], L[ 46 ], L[ 47 ], L[ 48 ], L[
570
+ 49 ], L[ 52 ], L[ 54 ] ]
571
+ },
572
+ 'outline-color': {
573
+ 'cssExtra': c[ 2 ],
574
+ 'cssPropBits': 2,
575
+ 'cssLitGroup': [ L[ 0 ], L[ 47 ], L[ 49 ] ]
576
+ },
577
+ 'outline-style': {
578
+ 'cssPropBits': 0,
579
+ 'cssLitGroup': [ L[ 9 ], L[ 46 ], L[ 47 ], L[ 48 ], L[ 54 ] ]
580
+ },
581
+ 'outline-width': {
582
+ 'cssPropBits': 5,
583
+ 'cssLitGroup': [ L[ 34 ], L[ 47 ], L[ 52 ] ]
584
+ },
585
+ 'overflow': {
586
+ 'cssPropBits': 32,
587
+ 'cssLitGroup': [ L[ 38 ], L[ 46 ], L[ 47 ], L[ 58 ], L[ 63 ] ]
588
+ },
589
+ 'overflow-x': {
590
+ 'cssPropBits': 0,
591
+ 'cssLitGroup': [ L[ 32 ], L[ 38 ], L[ 46 ], L[ 58 ], L[ 63 ] ]
592
+ },
593
+ 'overflow-y': {
594
+ 'cssPropBits': 0,
595
+ 'cssLitGroup': [ L[ 32 ], L[ 38 ], L[ 46 ], L[ 58 ], L[ 63 ] ]
596
+ },
597
+ 'padding': {
598
+ 'cssPropBits': 1,
599
+ 'cssLitGroup': [ L[ 47 ] ]
600
+ },
601
+ 'padding-bottom': {
602
+ 'cssPropBits': 33,
603
+ 'cssLitGroup': [ L[ 47 ] ]
604
+ },
605
+ 'padding-left': {
606
+ 'cssPropBits': 33,
607
+ 'cssLitGroup': [ L[ 47 ] ]
608
+ },
609
+ 'padding-right': {
610
+ 'cssPropBits': 33,
611
+ 'cssLitGroup': [ L[ 47 ] ]
612
+ },
613
+ 'padding-top': {
614
+ 'cssPropBits': 33,
615
+ 'cssLitGroup': [ L[ 47 ] ]
616
+ },
617
+ 'page-break-after': {
618
+ 'cssPropBits': 0,
619
+ 'cssLitGroup': [ L[ 30 ], L[ 37 ], L[ 38 ], L[ 39 ], L[ 47 ] ]
620
+ },
621
+ 'page-break-before': {
622
+ 'cssPropBits': 0,
623
+ 'cssLitGroup': [ L[ 30 ], L[ 37 ], L[ 38 ], L[ 39 ], L[ 47 ] ]
624
+ },
625
+ 'page-break-inside': {
626
+ 'cssPropBits': 0,
627
+ 'cssLitGroup': [ L[ 38 ], L[ 39 ], L[ 47 ] ]
628
+ },
629
+ 'pause': {
630
+ 'cssPropBits': 5,
631
+ 'cssLitGroup': [ L[ 47 ] ]
632
+ },
633
+ 'pause-after': {
634
+ 'cssPropBits': 5,
635
+ 'cssLitGroup': [ L[ 47 ] ]
636
+ },
637
+ 'pause-before': {
638
+ 'cssPropBits': 5,
639
+ 'cssLitGroup': [ L[ 47 ] ]
640
+ },
641
+ 'pitch': {
642
+ 'cssPropBits': 5,
643
+ 'cssLitGroup': [ L[ 19 ], L[ 47 ], L[ 52 ] ]
644
+ },
645
+ 'pitch-range': {
646
+ 'cssPropBits': 5,
647
+ 'cssLitGroup': [ L[ 47 ] ]
648
+ },
649
+ 'play-during': {
650
+ 'cssExtra': c[ 0 ],
651
+ 'cssPropBits': 16,
652
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ], L[ 53 ], L[ 54 ], L[ 57 ] ]
653
+ },
654
+ 'position': {
655
+ 'cssPropBits': 32,
656
+ 'cssLitGroup': [ L[ 20 ], L[ 47 ] ]
657
+ },
658
+ 'quotes': {
659
+ 'cssExtra': c[ 0 ],
660
+ 'cssPropBits': 0,
661
+ 'cssLitGroup': [ L[ 47 ], L[ 54 ] ]
662
+ },
663
+ 'richness': {
664
+ 'cssPropBits': 5,
665
+ 'cssLitGroup': [ L[ 47 ] ]
666
+ },
667
+ 'right': {
668
+ 'cssPropBits': 37,
669
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
670
+ },
671
+ 'speak': {
672
+ 'cssPropBits': 0,
673
+ 'cssLitGroup': [ L[ 47 ], L[ 54 ], L[ 55 ], L[ 61 ] ]
674
+ },
675
+ 'speak-header': {
676
+ 'cssPropBits': 0,
677
+ 'cssLitGroup': [ L[ 37 ], L[ 47 ], L[ 56 ] ]
678
+ },
679
+ 'speak-numeral': {
680
+ 'cssPropBits': 0,
681
+ 'cssLitGroup': [ L[ 26 ], L[ 47 ] ]
682
+ },
683
+ 'speak-punctuation': {
684
+ 'cssPropBits': 0,
685
+ 'cssLitGroup': [ L[ 43 ], L[ 47 ], L[ 54 ] ]
686
+ },
687
+ 'speech-rate': {
688
+ 'cssPropBits': 5,
689
+ 'cssLitGroup': [ L[ 12 ], L[ 47 ], L[ 52 ] ]
690
+ },
691
+ 'stress': {
692
+ 'cssPropBits': 5,
693
+ 'cssLitGroup': [ L[ 47 ] ]
694
+ },
695
+ 'table-layout': {
696
+ 'cssPropBits': 0,
697
+ 'cssLitGroup': [ L[ 38 ], L[ 45 ], L[ 47 ] ]
698
+ },
699
+ 'text-align': {
700
+ 'cssPropBits': 0,
701
+ 'cssLitGroup': [ L[ 30 ], L[ 42 ], L[ 47 ], L[ 50 ] ]
702
+ },
703
+ 'text-decoration': {
704
+ 'cssPropBits': 0,
705
+ 'cssLitGroup': [ L[ 18 ], L[ 47 ], L[ 54 ] ]
706
+ },
707
+ 'text-indent': {
708
+ 'cssPropBits': 5,
709
+ 'cssLitGroup': [ L[ 47 ] ]
710
+ },
711
+ 'text-overflow': {
712
+ 'cssPropBits': 0,
713
+ 'cssLitGroup': [ L[ 25 ] ]
714
+ },
715
+ 'text-shadow': {
716
+ 'cssExtra': c[ 1 ],
717
+ 'cssPropBits': 7,
718
+ 'cssLitGroup': [ L[ 0 ], L[ 35 ], L[ 48 ], L[ 54 ] ]
719
+ },
720
+ 'text-transform': {
721
+ 'cssPropBits': 0,
722
+ 'cssLitGroup': [ L[ 21 ], L[ 47 ], L[ 54 ] ]
723
+ },
724
+ 'text-wrap': {
725
+ 'cssPropBits': 0,
726
+ 'cssLitGroup': [ L[ 33 ], L[ 54 ], L[ 55 ] ]
727
+ },
728
+ 'top': {
729
+ 'cssPropBits': 37,
730
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
731
+ },
732
+ 'unicode-bidi': {
733
+ 'cssPropBits': 0,
734
+ 'cssLitGroup': [ L[ 23 ], L[ 47 ], L[ 55 ] ]
735
+ },
736
+ 'vertical-align': {
737
+ 'cssPropBits': 5,
738
+ 'cssLitGroup': [ L[ 10 ], L[ 24 ], L[ 47 ] ]
739
+ },
740
+ 'visibility': {
741
+ 'cssPropBits': 32,
742
+ 'cssLitGroup': [ L[ 44 ], L[ 46 ], L[ 47 ], L[ 63 ] ]
743
+ },
744
+ 'voice-family': {
745
+ 'cssExtra': c[ 0 ],
746
+ 'cssPropBits': 8,
747
+ 'cssLitGroup': [ L[ 22 ], L[ 35 ], L[ 47 ] ]
748
+ },
749
+ 'volume': {
750
+ 'cssPropBits': 1,
751
+ 'cssLitGroup': [ L[ 16 ], L[ 47 ], L[ 52 ] ]
752
+ },
753
+ 'white-space': {
754
+ 'cssPropBits': 0,
755
+ 'cssLitGroup': [ L[ 8 ], L[ 47 ], L[ 55 ] ]
756
+ },
757
+ 'width': {
758
+ 'cssPropBits': 33,
759
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
760
+ },
761
+ 'word-spacing': {
762
+ 'cssPropBits': 5,
763
+ 'cssLitGroup': [ L[ 47 ], L[ 55 ] ]
764
+ },
765
+ 'word-wrap': {
766
+ 'cssPropBits': 0,
767
+ 'cssLitGroup': [ L[ 41 ], L[ 55 ] ]
768
+ },
769
+ 'z-index': {
770
+ 'cssPropBits': 69,
771
+ 'cssLitGroup': [ L[ 38 ], L[ 47 ] ]
772
+ },
773
+ 'zoom': {
774
+ 'cssPropBits': 1,
775
+ 'cssLitGroup': [ L[ 55 ] ]
776
+ }
777
+ };
778
+ })();
779
+ if (typeof window !== 'undefined') {
780
+ window['cssSchema'] = cssSchema;
781
+ }
782
+ // Copyright (C) 2011 Google Inc.
783
+ //
784
+ // Licensed under the Apache License, Version 2.0 (the "License");
785
+ // you may not use this file except in compliance with the License.
786
+ // You may obtain a copy of the License at
787
+ //
788
+ // http://www.apache.org/licenses/LICENSE-2.0
789
+ //
790
+ // Unless required by applicable law or agreed to in writing, software
791
+ // distributed under the License is distributed on an "AS IS" BASIS,
792
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
793
+ // See the License for the specific language governing permissions and
794
+ // limitations under the License.
795
+
796
+ /**
797
+ * A lexical scannar for CSS3 as defined at http://www.w3.org/TR/css3-syntax .
798
+ *
799
+ * @author Mike Samuel <mikesamuel@gmail.com>
800
+ * \@provides lexCss, decodeCss
801
+ * \@overrides window
802
+ */
803
+
804
+ var lexCss;
805
+ var decodeCss;
806
+
807
+ (function () {
808
+
809
+ /**
810
+ * Decodes an escape sequence as specified in CSS3 section 4.1.
811
+ * http://www.w3.org/TR/css3-syntax/#characters
812
+ * @private
813
+ */
814
+ function decodeCssEscape(s) {
815
+ var i = parseInt(s.substring(1), 16);
816
+ // If parseInt didn't find a hex diigt, it returns NaN so return the
817
+ // escaped character.
818
+ // Otherwise, parseInt will stop at the first non-hex digit so there's no
819
+ // need to worry about trailing whitespace.
820
+ if (i > 0xffff) {
821
+ // A supplemental codepoint.
822
+ return i -= 0x10000,
823
+ String.fromCharCode(
824
+ 0xd800 + (i >> 10),
825
+ 0xdc00 + (i & 0x3FF));
826
+ } else if (i == i) {
827
+ return String.fromCharCode(i);
828
+ } else if (s[1] < ' ') {
829
+ // "a backslash followed by a newline is ignored".
830
+ return '';
831
+ } else {
832
+ return s[1];
833
+ }
834
+ }
835
+
836
+ /**
837
+ * Returns an equivalent CSS string literal given plain text: foo -> "foo".
838
+ * @private
839
+ */
840
+ function escapeCssString(s, replacer) {
841
+ return '"' + s.replace(/[\u0000-\u001f\\\"<>]/g, replacer) + '"';
842
+ }
843
+
844
+ /**
845
+ * Maps chars to CSS escaped equivalents: "\n" -> "\\a ".
846
+ * @private
847
+ */
848
+ function escapeCssStrChar(ch) {
849
+ return cssStrChars[ch]
850
+ || (cssStrChars[ch] = '\\' + ch.charCodeAt(0).toString(16) + ' ');
851
+ }
852
+
853
+ /**
854
+ * Maps chars to URI escaped equivalents: "\n" -> "%0a".
855
+ * @private
856
+ */
857
+ function escapeCssUrlChar(ch) {
858
+ return cssUrlChars[ch]
859
+ || (cssUrlChars[ch] = (ch < '\x10' ? '%0' : '%')
860
+ + ch.charCodeAt(0).toString(16));
861
+ }
862
+
863
+ /**
864
+ * Mapping of CSS special characters to escaped equivalents.
865
+ * @private
866
+ */
867
+ var cssStrChars = {
868
+ '\\': '\\\\'
869
+ };
870
+
871
+ /**
872
+ * Mapping of CSS special characters to URL-escaped equivalents.
873
+ * @private
874
+ */
875
+ var cssUrlChars = {
876
+ '\\': '%5c'
877
+ };
878
+
879
+ // The comments below are copied from the CSS3 module syntax at
880
+ // http://www.w3.org/TR/css3-syntax .
881
+ // These string constants minify out when this is run-through closure
882
+ // compiler.
883
+ // Rules that have been adapted have comments prefixed with "Diff:", and
884
+ // where rules have been combined to avoid back-tracking in the regex engine
885
+ // or to work around limitations, there is a comment prefixed with
886
+ // "NewRule:".
887
+
888
+ // In the below, we assume CRLF and CR have been normalize to CR.
889
+
890
+ // wc ::= #x9 | #xA | #xC | #xD | #x20
891
+ var WC = '[\\t\\n\\f ]';
892
+ // w ::= wc*
893
+ var W = WC + '*';
894
+ // nl ::= #xA | #xD #xA | #xD | #xC
895
+ var NL = '[\\n\\f]';
896
+ // nonascii ::= [#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]
897
+ // NewRule: Supplemental codepoints are represented as surrogate pairs in JS.
898
+ var SURROGATE_PAIR = '[\\ud800-\\udbff][\\udc00-\\udfff]';
899
+ var NONASCII = '[\\u0080-\\ud7ff\\ue000-\\ufffd]|' + SURROGATE_PAIR;
900
+ // unicode ::= '\' [0-9a-fA-F]{1,6} wc?
901
+ // NewRule: No point in having ESCAPE do (\\x|\\y)
902
+ var UNICODE_TAIL = '[0-9a-fA-F]{1,6}' + WC + '?';
903
+ var UNICODE = '\\\\' + UNICODE_TAIL;
904
+ // escape ::= unicode
905
+ // | '\' [#x20-#x7E#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]
906
+ // NewRule: Below we use escape tail to efficiently match an escape or a
907
+ // line continuation so we can decode string content.
908
+ var ESCAPE_TAIL = '(?:' + UNICODE_TAIL
909
+ + '|[\\u0020-\\u007e\\u0080-\\ud7ff\\ue000\\ufffd]|'
910
+ + SURROGATE_PAIR + ')';
911
+ var ESCAPE = '\\\\' + ESCAPE_TAIL;
912
+ // urlchar ::= [#x9#x21#x23-#x26#x28-#x7E] | nonascii | escape
913
+ var URLCHAR = '(?:[\\t\\x21\\x23-\\x26\\x28-\\x5b\\x5d-\\x7e]|'
914
+ + NONASCII + '|' + ESCAPE + ')';
915
+ // stringchar ::= urlchar | #x20 | '\' nl
916
+ // We ignore mismatched surrogate pairs inside strings, so stringchar
917
+ // simplifies to a non-(quote|newline|backslash) or backslash any.
918
+ // Since we normalize CRLF to a single code-unit, there is no special
919
+ // handling needed for '\\' + CRLF.
920
+ var STRINGCHAR = '[^\'"\\n\\f\\\\]|\\\\[\\s\\S]';
921
+ // string ::= '"' (stringchar | "'")* '"' | "'" (stringchar | '"')* "'"
922
+ var STRING = '"(?:\'|' + STRINGCHAR + ')*"'
923
+ + '|\'(?:\"|' + STRINGCHAR + ')*\'';
924
+ // num ::= [0-9]+ | [0-9]* '.' [0-9]+
925
+ // Diff: We attach signs to num tokens.
926
+ var NUM = '[-+]?(?:[0-9]+(?:[.][0-9]+)?|[.][0-9]+)';
927
+ // nmstart ::= [a-zA-Z] | '_' | nonascii | escape
928
+ var NMSTART = '(?:[a-zA-Z_]|' + NONASCII + '|' + ESCAPE + ')';
929
+ // nmchar ::= [a-zA-Z0-9] | '-' | '_' | nonascii | escape
930
+ var NMCHAR = '(?:[a-zA-Z0-9_-]|' + NONASCII + '|' + ESCAPE + ')';
931
+ // name ::= nmchar+
932
+ var NAME = NMCHAR + '+';
933
+ // ident ::= '-'? nmstart nmchar*
934
+ var IDENT = '-?' + NMSTART + NMCHAR + '*';
935
+
936
+ // ATKEYWORD ::= '@' ident
937
+ var ATKEYWORD = '@' + IDENT;
938
+ // HASH ::= '#' name
939
+ var HASH = '#' + NAME;
940
+ // NUMBER ::= num
941
+ var NUMBER = NUM;
942
+
943
+ // NewRule: union of IDENT, ATKEYWORD, HASH, but excluding #[0-9].
944
+ var WORD_TERM = '(?:@?-?' + NMSTART + '|#)' + NMCHAR + '*';
945
+
946
+ // PERCENTAGE ::= num '%'
947
+ var PERCENTAGE = NUM + '%';
948
+ // DIMENSION ::= num ident
949
+ var DIMENSION = NUM + IDENT;
950
+ var NUMERIC_VALUE = NUM + '(?:%|' + IDENT + ')?';
951
+ // URI ::= "url(" w (string | urlchar* ) w ")"
952
+ var URI = 'url[(]' + W + '(?:' + STRING + '|' + URLCHAR + '*)' + W + '[)]';
953
+ // UNICODE-RANGE ::= "U+" [0-9A-F?]{1,6} ('-' [0-9A-F]{1,6})?
954
+ var UNICODE_RANGE = 'U[+][0-9A-F?]{1,6}(?:-[0-9A-F]{1,6})?';
955
+ // CDO ::= "<\!--"
956
+ var CDO = '<\!--';
957
+ // CDC ::= "-->"
958
+ var CDC = '-->';
959
+ // S ::= wc+
960
+ var S = WC + '+';
961
+ // COMMENT ::= "/*" [^*]* '*'+ ([^/] [^*]* '*'+)* "/"
962
+ // Diff: recognizes // comments.
963
+ var COMMENT = '/(?:[*][^*]*[*]+(?:[^/][^*]*[*]+)*/|/[^\\n\\f]*)';
964
+ // FUNCTION ::= ident '('
965
+ // Diff: We exclude url explicitly.
966
+ // TODO: should we be tolerant of "fn ("?
967
+ // ##### BEGIN: MODIFIED BY SAP
968
+ // Avoid risk of 'catastrophic backtracking' when unicode escapes are used
969
+ // var FUNCTION = '(?!url[(])' + IDENT + '[(]';
970
+ var FUNCTION = '(?!url[(])(?=(' + IDENT + '))\\1[(]';
971
+ // ##### END: MODIFIED BY SAP
972
+ // INCLUDES ::= "~="
973
+ var INCLUDES = '~=';
974
+ // DASHMATCH ::= "|="
975
+ var DASHMATCH = '[|]=';
976
+ // PREFIXMATCH ::= "^="
977
+ var PREFIXMATCH = '[^]=';
978
+ // SUFFIXMATCH ::= "$="
979
+ var SUFFIXMATCH = '[$]=';
980
+ // SUBSTRINGMATCH ::= "*="
981
+ var SUBSTRINGMATCH = '[*]=';
982
+ // NewRule: one rule for all the comparison operators.
983
+ var CMP_OPS = '[~|^$*]=';
984
+ // CHAR ::= any character not matched by the above rules, except for " or '
985
+ // Diff: We exclude / and \ since they are handled above to prevent
986
+ // /* without a following */ from combining when comments are concatenated.
987
+ var CHAR = '[^"\'\\\\/]|/(?![/*])';
988
+ // BOM ::= #xFEFF
989
+ var BOM = '\\uFEFF';
990
+
991
+ var CSS_TOKEN = new RegExp([
992
+ BOM, UNICODE_RANGE, URI, FUNCTION, WORD_TERM, STRING, NUMERIC_VALUE,
993
+ CDO, CDC, S, COMMENT, CMP_OPS, CHAR].join("|"), 'gi');
994
+
995
+ /**
996
+ * Decodes CSS escape sequences in a CSS string body.
997
+ */
998
+ decodeCss = function (css) {
999
+ return css.replace(
1000
+ new RegExp('\\\\(?:' + ESCAPE_TAIL + '|' + NL + ')', 'g'),
1001
+ decodeCssEscape);
1002
+ };
1003
+
1004
+ /**
1005
+ * Given CSS Text, returns an array of normalized tokens.
1006
+ * @param {string} cssText
1007
+ * @return {Array.<string>} tokens where all ignorable token sequences have
1008
+ * been reduced to a single {@code " "} and all strings and
1009
+ * {@code url(...)} tokens have been normalized to use double quotes as
1010
+ * delimiters and to not otherwise contain double quotes.
1011
+ */
1012
+ lexCss = function (cssText) {
1013
+ cssText = '' + cssText;
1014
+ var tokens = cssText.replace(/\r\n?/g, '\n') // Normalize CRLF & CR to LF.
1015
+ .match(CSS_TOKEN) || [];
1016
+ var j = 0;
1017
+ var last = ' ';
1018
+ for (var i = 0, n = tokens.length; i < n; ++i) {
1019
+ // Normalize all escape sequences. We will have to re-escape some
1020
+ // codepoints in string and url(...) bodies but we already know the
1021
+ // boundaries.
1022
+ // We might mistakenly treat a malformed identifier like \22\20\22 as a
1023
+ // string, but that will not break any valid stylesheets since we requote
1024
+ // and re-escape in string below.
1025
+ var tok = decodeCss(tokens[i]);
1026
+ var len = tok.length;
1027
+ var cc = tok.charCodeAt(0);
1028
+ tok =
1029
+ // All strings should be double quoted, and the body should never
1030
+ // contain a double quote.
1031
+ (cc == '"'.charCodeAt(0) || cc == '\''.charCodeAt(0))
1032
+ ? escapeCssString(tok.substring(1, len - 1), escapeCssStrChar)
1033
+ // A breaking ignorable token should is replaced with a single space.
1034
+ : (cc == '/'.charCodeAt(0) && len > 1 // Comment.
1035
+ || tok == '\\' || tok == CDC || tok == CDO || tok == '\ufeff'
1036
+ // Characters in W.
1037
+ || cc <= ' '.charCodeAt(0))
1038
+ ? ' '
1039
+ // Make sure that all url(...)s are double quoted.
1040
+ : /url\(/i.test(tok)
1041
+ ? 'url(' + escapeCssString(
1042
+ tok.replace(
1043
+ new RegExp('^url\\(' + W + '["\']?|["\']?' + W + '\\)$', 'gi'),
1044
+ ''),
1045
+ escapeCssUrlChar)
1046
+ + ')'
1047
+ // Escapes in identifier like tokens will have been normalized above.
1048
+ : tok;
1049
+ // Merge adjacent space tokens.
1050
+ if (last != tok || tok != ' ') {
1051
+ tokens[j++] = last = tok;
1052
+ }
1053
+ }
1054
+ tokens.length = j;
1055
+ return tokens;
1056
+ };
1057
+ })();
1058
+
1059
+ // Exports for closure compiler.
1060
+ if (typeof window !== 'undefined') {
1061
+ window['lexCss'] = lexCss;
1062
+ window['decodeCss'] = decodeCss;
1063
+ }
1064
+ // Copyright (C) 2011 Google Inc.
1065
+ //
1066
+ // Licensed under the Apache License, Version 2.0 (the "License");
1067
+ // you may not use this file except in compliance with the License.
1068
+ // You may obtain a copy of the License at
1069
+ //
1070
+ // http://www.apache.org/licenses/LICENSE-2.0
1071
+ //
1072
+ // Unless required by applicable law or agreed to in writing, software
1073
+ // distributed under the License is distributed on an "AS IS" BASIS,
1074
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1075
+ // See the License for the specific language governing permissions and
1076
+ // limitations under the License.
1077
+
1078
+ /**
1079
+ * @fileoverview
1080
+ * JavaScript support for client-side CSS sanitization.
1081
+ * The CSS property schema API is defined in CssPropertyPatterns.java which
1082
+ * is used to generate css-defs.js.
1083
+ *
1084
+ * @author mikesamuel@gmail.com
1085
+ * \@requires CSS_PROP_BIT_ALLOWED_IN_LINK
1086
+ * \@requires CSS_PROP_BIT_HASH_VALUE
1087
+ * \@requires CSS_PROP_BIT_NEGATIVE_QUANTITY
1088
+ * \@requires CSS_PROP_BIT_QSTRING_CONTENT
1089
+ * \@requires CSS_PROP_BIT_QSTRING_URL
1090
+ * \@requires CSS_PROP_BIT_QUANTITY
1091
+ * \@requires CSS_PROP_BIT_Z_INDEX
1092
+ * \@requires cssSchema
1093
+ * \@requires decodeCss
1094
+ * \@requires html4
1095
+ * \@overrides window
1096
+ * \@requires parseCssStylesheet
1097
+ * \@provides sanitizeCssProperty
1098
+ * \@provides sanitizeCssSelectors
1099
+ * \@provides sanitizeStylesheet
1100
+ */
1101
+
1102
+ /**
1103
+ * Given a series of normalized CSS tokens, applies a property schema, as
1104
+ * defined in CssPropertyPatterns.java, and sanitizes the tokens in place.
1105
+ * @param property a property name.
1106
+ * @param propertySchema a property of cssSchema as defined by
1107
+ * CssPropertyPatterns.java
1108
+ * @param tokens as parsed by lexCss. Modified in place.
1109
+ * @param opt_naiveUriRewriter a URI rewriter; an object with a "rewrite"
1110
+ * function that takes a URL and returns a safe URL.
1111
+ */
1112
+ var sanitizeCssProperty = (function () {
1113
+ var NOEFFECT_URL = 'url("about:blank")';
1114
+ /**
1115
+ * The set of characters that need to be normalized inside url("...").
1116
+ * We normalize newlines because they are not allowed inside quoted strings,
1117
+ * normalize quote characters, angle-brackets, and asterisks because they
1118
+ * could be used to break out of the URL or introduce targets for CSS
1119
+ * error recovery. We normalize parentheses since they delimit unquoted
1120
+ * URLs and calls and could be a target for error recovery.
1121
+ */
1122
+ var NORM_URL_REGEXP = /[\n\f\r\"\'()*<>]/g;
1123
+ /** The replacements for NORM_URL_REGEXP. */
1124
+ var NORM_URL_REPLACEMENTS = {
1125
+ '\n': '%0a',
1126
+ '\f': '%0c',
1127
+ '\r': '%0d',
1128
+ '"': '%22',
1129
+ '\'': '%27',
1130
+ '(': '%28',
1131
+ ')': '%29',
1132
+ '*': '%2a',
1133
+ '<': '%3c',
1134
+ '>': '%3e'
1135
+ };
1136
+
1137
+
1138
+ function normalizeUrl(s) {
1139
+ if ('string' === typeof s) {
1140
+ return 'url("' + s.replace(NORM_URL_REGEXP, normalizeUrlChar) + '")';
1141
+ } else {
1142
+ return NOEFFECT_URL;
1143
+ }
1144
+ }
1145
+ function normalizeUrlChar(ch) {
1146
+ return NORM_URL_REPLACEMENTS[ch];
1147
+ }
1148
+
1149
+ // From RFC3986
1150
+ var URI_SCHEME_RE = new RegExp(
1151
+ '^' +
1152
+ '(?:' +
1153
+ '([^:\/?# ]+)' + // scheme
1154
+ ':)?'
1155
+ );
1156
+
1157
+ var ALLOWED_URI_SCHEMES = /^(?:https?|mailto)$/i;
1158
+
1159
+ function safeUri(uri, prop, naiveUriRewriter) {
1160
+ if (!naiveUriRewriter) { return null; }
1161
+ var parsed = ('' + uri).match(URI_SCHEME_RE);
1162
+ if (parsed && (!parsed[1] || ALLOWED_URI_SCHEMES.test(parsed[1]))) {
1163
+ return naiveUriRewriter(uri, prop);
1164
+ } else {
1165
+ return null;
1166
+ }
1167
+ }
1168
+
1169
+ function unionArrays(arrs) {
1170
+ var map = {};
1171
+ for (var i = arrs.length; --i >= 0;) {
1172
+ var arr = arrs[i];
1173
+ for (var j = arr.length; --j >= 0;) {
1174
+ map[arr[j]] = ALLOWED_LITERAL;
1175
+ }
1176
+ }
1177
+ return map;
1178
+ }
1179
+
1180
+ /**
1181
+ * Normalize tokens within a function call they can match against
1182
+ * cssSchema[propName].cssExtra.
1183
+ * @return the exclusive end in tokens of the function call.
1184
+ */
1185
+ function normalizeFunctionCall(tokens, start) {
1186
+ var parenDepth = 1, end = start + 1, n = tokens.length;
1187
+ while (end < n && parenDepth) {
1188
+ // TODO: Can URLs appear in functions?
1189
+ var token = tokens[end++];
1190
+ parenDepth += (token === '(' ? 1 : token === ')' ? -1 : 0);
1191
+ }
1192
+ return end;
1193
+ }
1194
+
1195
+ // Used as map value to avoid hasOwnProperty checks.
1196
+ var ALLOWED_LITERAL = {};
1197
+
1198
+ return function (property, propertySchema, tokens, opt_naiveUriRewriter) {
1199
+ var propBits = propertySchema.cssPropBits;
1200
+ // Used to determine whether to treat quoted strings as URLs or
1201
+ // plain text content, and whether unrecognized keywords can be quoted
1202
+ // to treate ['Arial', 'Black'] equivalently to ['"Arial Black"'].
1203
+ var qstringBits = propBits & (
1204
+ CSS_PROP_BIT_QSTRING_CONTENT | CSS_PROP_BIT_QSTRING_URL);
1205
+ // TODO(mikesamuel): Figure out what to do with props like
1206
+ // content that admit both URLs and strings.
1207
+
1208
+ // Used to join unquoted keywords into a single quoted string.
1209
+ var lastQuoted = NaN;
1210
+ var i = 0, k = 0;
1211
+ for (;i < tokens.length; ++i) {
1212
+ // Has the effect of normalizing hex digits, keywords,
1213
+ // and function names.
1214
+ var token = tokens[i].toLowerCase();
1215
+ var cc = token.charCodeAt(0), cc1, cc2, isnum1, isnum2, end;
1216
+ var litGroup, litMap;
1217
+ token = (
1218
+ // Strip out spaces. Normally cssparser.js dumps these, but we
1219
+ // strip them out in case the content doesn't come via cssparser.js.
1220
+ (cc === ' '.charCodeAt(0)) ? ''
1221
+ : (cc === '"'.charCodeAt(0)) ? ( // Quoted string.
1222
+ (qstringBits === CSS_PROP_BIT_QSTRING_URL && opt_naiveUriRewriter)
1223
+ // Sanitize and convert to url("...") syntax.
1224
+ // Treat url content as case-sensitive.
1225
+ ? (normalizeUrl(safeUri(
1226
+ decodeCss(tokens[i].substring(1, token.length - 1)),
1227
+ property,
1228
+ opt_naiveUriRewriter)))
1229
+ // Drop if plain text content strings not allowed.
1230
+ : (qstringBits === CSS_PROP_BIT_QSTRING_CONTENT) ? token : '')
1231
+ // Preserve hash color literals if allowed.
1232
+ : (cc === '#'.charCodeAt(0) && /^#(?:[0-9a-f]{3}){1,2}$/.test(token))
1233
+ ? (propBits & CSS_PROP_BIT_HASH_VALUE ? token : '')
1234
+ : ('0'.charCodeAt(0) <= cc && cc <= '9'.charCodeAt(0))
1235
+ // A number starting with a digit.
1236
+ ? ((propBits & CSS_PROP_BIT_QUANTITY)
1237
+ ? ((propBits & CSS_PROP_BIT_Z_INDEX)
1238
+ ? (token.match(/^\d{1,7}$/) ? token : '')
1239
+ : token)
1240
+ : '')
1241
+ // Normalize quantities so they don't start with a '.' or '+' sign and
1242
+ // make sure they all have an integer component so can't be confused
1243
+ // with a dotted identifier.
1244
+ // This can't be done in the lexer since ".4" is a valid rule part.
1245
+ : (cc1 = token.charCodeAt(1),
1246
+ cc2 = token.charCodeAt(2),
1247
+ isnum1 = '0'.charCodeAt(0) <= cc1 && cc1 <= '9'.charCodeAt(0),
1248
+ isnum2 = '0'.charCodeAt(0) <= cc2 && cc2 <= '9'.charCodeAt(0),
1249
+ // +.5 -> 0.5 if allowed.
1250
+ (cc === '+'.charCodeAt(0)
1251
+ && (isnum1 || (cc1 === '.'.charCodeAt(0) && isnum2))))
1252
+ ? ((propBits & CSS_PROP_BIT_QUANTITY)
1253
+ ? ((propBits & CSS_PROP_BIT_Z_INDEX)
1254
+ ? (token.match(/^\+\d{1,7}$/) ? token : '')
1255
+ : ((isnum1 ? '' : '0') + token.substring(1)))
1256
+ : '')
1257
+ // -.5 -> -0.5 if allowed otherwise -> 0 if quantities allowed.
1258
+ : (cc === '-'.charCodeAt(0)
1259
+ && (isnum1 || (cc1 === '.'.charCodeAt(0) && isnum2)))
1260
+ ? ((propBits & CSS_PROP_BIT_NEGATIVE_QUANTITY)
1261
+ ? ((propBits & CSS_PROP_BIT_Z_INDEX)
1262
+ ? (token.match(/^\-\d{1,7}$/) ? token : '')
1263
+ : ((isnum1 ? '-' : '-0') + token.substring(1)))
1264
+ : ((propBits & CSS_PROP_BIT_QUANTITY) ? '0' : ''))
1265
+ // .5 -> 0.5 if allowed.
1266
+ : (cc === '.'.charCodeAt(0) && isnum1)
1267
+ ? ((propBits & CSS_PROP_BIT_QUANTITY) ? '0' + token : '')
1268
+ // Handle url("...") by rewriting the body.
1269
+ : ('url(' === token.substring(0, 4))
1270
+ ? ((opt_naiveUriRewriter && (qstringBits & CSS_PROP_BIT_QSTRING_URL))
1271
+ ? normalizeUrl(safeUri(
1272
+ tokens[i].substring(5, token.length - 2),
1273
+ property,
1274
+ opt_naiveUriRewriter))
1275
+ : '')
1276
+ // Handle func(...) and literal tokens
1277
+ // such as keywords and punctuation.
1278
+ : (
1279
+ // Step 1. Combine func(...) into something that can be compared
1280
+ // against propertySchema.cssExtra.
1281
+ (token.charAt(token.length-1) === '(')
1282
+ && (end = normalizeFunctionCall(tokens, i),
1283
+ // When tokens is
1284
+ // ['x', ' ', 'rgb(', '255', ',', '0', ',', '0', ')', ' ', 'y']
1285
+ // and i is the index of 'rgb(' and end is the index of ')'
1286
+ // splices tokens to where i now is the index of the whole call:
1287
+ // ['x', ' ', 'rgb( 255 , 0 , 0 )', ' ', 'y']
1288
+ tokens.splice(i, end - i,
1289
+ token = tokens.slice(i, end).join(' '))),
1290
+ litGroup = propertySchema.cssLitGroup,
1291
+ litMap = (litGroup
1292
+ ? (propertySchema.cssLitMap
1293
+ // Lazily compute the union from litGroup.
1294
+ || (propertySchema.cssLitMap = unionArrays(litGroup)))
1295
+ : ALLOWED_LITERAL), // A convenient empty object.
1296
+ (litMap[token] === ALLOWED_LITERAL
1297
+ || propertySchema.cssExtra && propertySchema.cssExtra.test(token)))
1298
+ // Token is in the literal map or matches extra.
1299
+ ? token
1300
+ : (/^\w+$/.test(token)
1301
+ && (qstringBits === CSS_PROP_BIT_QSTRING_CONTENT))
1302
+ // Quote unrecognized keywords so font names like
1303
+ // Arial Bold
1304
+ // ->
1305
+ // "Arial Bold"
1306
+ ? (lastQuoted+1 === k
1307
+ // If the last token was also a keyword that was quoted, then
1308
+ // combine this token into that.
1309
+ ? (tokens[lastQuoted] = tokens[lastQuoted]
1310
+ .substring(0, tokens[lastQuoted].length-1) + ' ' + token + '"',
1311
+ token = '')
1312
+ : (lastQuoted = k, '"' + token + '"'))
1313
+ // Disallowed.
1314
+ : '');
1315
+ if (token) {
1316
+ tokens[k++] = token;
1317
+ }
1318
+ }
1319
+ // For single URL properties, if the URL failed to pass the sanitizer,
1320
+ // then just drop it.
1321
+ if (k === 1 && tokens[0] === NOEFFECT_URL) { k = 0; }
1322
+ tokens.length = k;
1323
+ };
1324
+ })();
1325
+
1326
+ /**
1327
+ * Given a series of tokens, returns two lists of sanitized selectors.
1328
+ * @param {Array.<string>} selectors In the form produces by csslexer.js.
1329
+ * @param {string} suffix a suffix that is added to all IDs and which is
1330
+ * used as a CLASS names so that the returned selectors will only match
1331
+ * nodes under one with suffix as a class name.
1332
+ * If suffix is {@code "sfx"}, the selector
1333
+ * {@code ["a", "#foo", " ", "b", ".bar"]} will be namespaced to
1334
+ * {@code [".sfx", " ", "a", "#foo-sfx", " ", "b", ".bar"]}.
1335
+ * @return {Array.<Array.<string>>} an array of length 2 where the zeroeth
1336
+ * element contains history-insensitive selectors and the first element
1337
+ * contains history-sensitive selectors.
1338
+ */
1339
+ function sanitizeCssSelectors(selectors, suffix) {
1340
+ // Produce two distinct lists of selectors to sequester selectors that are
1341
+ // history sensitive (:visited), so that we can disallow properties in the
1342
+ // property groups for the history sensitive ones.
1343
+ var historySensitiveSelectors = [];
1344
+ var historyInsensitiveSelectors = [];
1345
+
1346
+ // Remove any spaces that are not operators.
1347
+ var k = 0, i;
1348
+ for (i = 0; i < selectors.length; ++i) {
1349
+ if (!(selectors[i] == ' '
1350
+ && (selectors[i-1] == '>' || selectors[i+1] == '>'))) {
1351
+ selectors[k++] = selectors[i];
1352
+ }
1353
+ }
1354
+ selectors.length = k;
1355
+
1356
+ // Split around commas. If there is an error in one of the comma separated
1357
+ // bits, we throw the whole away, but the failure of one selector does not
1358
+ // affect others.
1359
+ var n = selectors.length, start = 0;
1360
+ for (i = 0; i < n; ++i) {
1361
+ if (selectors[i] == ',') {
1362
+ processSelector(start, i);
1363
+ start = i+1;
1364
+ }
1365
+ }
1366
+ processSelector(start, n);
1367
+
1368
+
1369
+ function processSelector(start, end) {
1370
+ var historySensitive = false;
1371
+
1372
+ // Space around commas is not an operator.
1373
+ if (selectors[start] === ' ') { ++start; }
1374
+ if (end-1 !== start && selectors[end] === ' ') { --end; }
1375
+
1376
+ // Split the selector into element selectors, content around
1377
+ // space (ancestor operator) and '>' (descendant operator).
1378
+ var out = [];
1379
+ var lastOperator = start;
1380
+ var elSelector = '';
1381
+ for (var i = start; i < end; ++i) {
1382
+ var tok = selectors[i];
1383
+ var isChild = (tok === '>');
1384
+ if (isChild || tok === ' ') {
1385
+ // We've found the end of a single link in the selector chain.
1386
+ // We disallow absolute positions relative to html.
1387
+ elSelector = processElementSelector(lastOperator, i, false);
1388
+ if (!elSelector || (isChild && /^html/i.test(elSelector))) {
1389
+ return;
1390
+ }
1391
+ lastOperator = i+1;
1392
+ out.push(elSelector, isChild ? ' > ' : ' ');
1393
+ }
1394
+ }
1395
+ elSelector = processElementSelector(lastOperator, end, true);
1396
+ if (!elSelector) { return; }
1397
+ out.push(elSelector);
1398
+
1399
+ function processElementSelector(start, end, last) {
1400
+ var debugStart = start, debugEnd = end;
1401
+
1402
+ // Split the element selector into three parts.
1403
+ // DIV.foo#bar:hover
1404
+ // ^ ^
1405
+ // el classes pseudo
1406
+ var element, classId, pseudoSelector, tok, elType;
1407
+ element = '';
1408
+ if (start < end) {
1409
+ tok = selectors[start].toLowerCase();
1410
+ if (tok === '*'
1411
+ || (tok === 'body' && start+1 !== end && !last)
1412
+ || ('number' === typeof (elType = html4.ELEMENTS[tok])
1413
+ && !(elType & html4.eflags.UNSAFE))) {
1414
+ ++start;
1415
+ element = tok;
1416
+ }
1417
+ }
1418
+ classId = '';
1419
+ while (start < end) {
1420
+ tok = selectors[start];
1421
+ if (tok.charAt(0) === '#') {
1422
+ if (/^#_|__$|[^#0-9A-Za-z:_\-]/.test(tok)) { return null; }
1423
+ // Rewrite ID elements to include the suffix.
1424
+ classId += tok + '-' + suffix;
1425
+ } else if (tok === '.') {
1426
+ if (++start < end
1427
+ && /^[0-9A-Za-z:_\-]+$/.test(tok = selectors[start])
1428
+ && !/^_|__$/.test(tok)) {
1429
+ classId += '.' + tok;
1430
+ } else {
1431
+ return null;
1432
+ }
1433
+ } else {
1434
+ break;
1435
+ }
1436
+ ++start;
1437
+ }
1438
+ pseudoSelector = '';
1439
+ if (start < end && selectors[start] === ':') {
1440
+ tok = selectors[++start];
1441
+ if (tok === 'visited' || tok === 'link') {
1442
+ if (!/^[a*]?$/.test(element)) {
1443
+ return null;
1444
+ }
1445
+ historySensitive = true;
1446
+ pseudoSelector = ':' + tok;
1447
+ element = 'a';
1448
+ ++start;
1449
+ }
1450
+ }
1451
+ if (start === end) {
1452
+ return element + classId + pseudoSelector;
1453
+ }
1454
+ return null;
1455
+ }
1456
+
1457
+
1458
+ var safeSelector = out.join('');
1459
+ if (/^body\b/.test(safeSelector)) {
1460
+ // Substitute the class that is attached to pseudo body elements for
1461
+ // the body element.
1462
+ safeSelector = '.vdoc-body___.' + suffix + safeSelector.substring(4);
1463
+ } else {
1464
+ // Namespace the selector so that it only matches under
1465
+ // a node with suffix in its CLASS attribute.
1466
+ safeSelector = '.' + suffix + ' ' + safeSelector;
1467
+ }
1468
+
1469
+ (historySensitive
1470
+ ? historySensitiveSelectors
1471
+ : historyInsensitiveSelectors).push(safeSelector);
1472
+ }
1473
+
1474
+ return [historyInsensitiveSelectors, historySensitiveSelectors];
1475
+ }
1476
+
1477
+ var sanitizeStylesheet = (function () {
1478
+ var allowed = {};
1479
+ var cssMediaTypeWhitelist = {
1480
+ 'braille': allowed,
1481
+ 'embossed': allowed,
1482
+ 'handheld': allowed,
1483
+ 'print': allowed,
1484
+ 'projection': allowed,
1485
+ 'screen': allowed,
1486
+ 'speech': allowed,
1487
+ 'tty': allowed,
1488
+ 'tv': allowed
1489
+ };
1490
+
1491
+ /**
1492
+ * Given a series of sanitized tokens, removes any properties that would
1493
+ * leak user history if allowed to style links differently depending on
1494
+ * whether the linked URL is in the user's browser history.
1495
+ * @param {Array.<string>} blockOfProperties
1496
+ */
1497
+ function sanitizeHistorySensitive(blockOfProperties) {
1498
+ var elide = false;
1499
+ for (var i = 0, n = blockOfProperties.length; i < n-1; ++i) {
1500
+ var token = blockOfProperties[i];
1501
+ if (':' === blockOfProperties[i+1]) {
1502
+ elide = !(cssSchema[token].cssPropBits & CSS_PROP_BIT_ALLOWED_IN_LINK);
1503
+ }
1504
+ if (elide) { blockOfProperties[i] = ''; }
1505
+ if (';' === token) { elide = false; }
1506
+ }
1507
+ return blockOfProperties.join('');
1508
+ }
1509
+
1510
+ /**
1511
+ * @param {string} cssText a string containing a CSS stylesheet.
1512
+ * @param {string} suffix a suffix that is added to all IDs and which is
1513
+ * used as a CLASS names so that the returned selectors will only match
1514
+ * nodes under one with suffix as a class name.
1515
+ * If suffix is {@code "sfx"}, the selector
1516
+ * {@code ["a", "#foo", " ", "b", ".bar"]} will be namespaced to
1517
+ * {@code [".sfx", " ", "a", "#foo-sfx", " ", "b", ".bar"]}.
1518
+ * @param {function(string, string)} opt_naiveUriRewriter maps URLs of media
1519
+ * (images, sounds) that appear as CSS property values to sanitized
1520
+ * URLs or null if the URL should not be allowed as an external media
1521
+ * file in sanitized CSS.
1522
+ */
1523
+ return function /*sanitizeStylesheet*/(
1524
+ cssText, suffix, opt_naiveUriRewriter) {
1525
+ var safeCss = void 0;
1526
+ // A stack describing the { ... } regions.
1527
+ // Null elements indicate blocks that should not be emitted.
1528
+ var blockStack = [];
1529
+ // True when the content of the current block should be left off safeCss.
1530
+ var elide = false;
1531
+ parseCssStylesheet(
1532
+ cssText,
1533
+ {
1534
+ startStylesheet: function () {
1535
+ safeCss = [];
1536
+ },
1537
+ endStylesheet: function () {
1538
+ },
1539
+ startAtrule: function (atIdent, headerArray) {
1540
+ if (elide) {
1541
+ atIdent = null;
1542
+ } else if (atIdent === '@media') {
1543
+ headerArray = headerArray.filter(
1544
+ function (mediaType) {
1545
+ return cssMediaTypeWhitelist[mediaType] == allowed;
1546
+ });
1547
+ if (headerArray.length) {
1548
+ safeCss.push(atIdent, headerArray.join(','), '{');
1549
+ } else {
1550
+ atIdent = null;
1551
+ }
1552
+ } else {
1553
+ if (atIdent === '@import') {
1554
+ // TODO: Use a logger instead.
1555
+ if (window.console) {
1556
+ window.console.log(
1557
+ '@import ' + headerArray.join(' ') + ' elided');
1558
+ }
1559
+ }
1560
+ atIdent = null; // Elide the block.
1561
+ }
1562
+ elide = !atIdent;
1563
+ blockStack.push(atIdent);
1564
+ },
1565
+ endAtrule: function () {
1566
+ var atIdent = blockStack.pop();
1567
+ if (!elide) {
1568
+ safeCss.push(';');
1569
+ }
1570
+ checkElide();
1571
+ },
1572
+ startBlock: function () {
1573
+ // There are no bare blocks in CSS, so we do not change the
1574
+ // block stack here, but instead in the events that bracket
1575
+ // blocks.
1576
+ if (!elide) {
1577
+ safeCss.push('{');
1578
+ }
1579
+ },
1580
+ endBlock: function () {
1581
+ if (!elide) {
1582
+ safeCss.push('}');
1583
+ elide = true; // skip any semicolon from endAtRule.
1584
+ }
1585
+ },
1586
+ startRuleset: function (selectorArray) {
1587
+ var historySensitiveSelectors = void 0;
1588
+ var removeHistoryInsensitiveSelectors = false;
1589
+ if (!elide) {
1590
+ var selectors = sanitizeCssSelectors(selectorArray, suffix);
1591
+ var historyInsensitiveSelectors = selectors[0];
1592
+ historySensitiveSelectors = selectors[1];
1593
+ if (!historyInsensitiveSelectors.length
1594
+ && !historySensitiveSelectors.length) {
1595
+ elide = true;
1596
+ } else {
1597
+ var selector = historyInsensitiveSelectors.join(', ');
1598
+ if (!selector) {
1599
+ // If we have only history sensitive selectors,
1600
+ // use an impossible rule so that we can capture the content
1601
+ // for later processing by
1602
+ // history insenstive content for use below.
1603
+ selector = 'head > html';
1604
+ removeHistoryInsensitiveSelectors = true;
1605
+ }
1606
+ safeCss.push(selector, '{');
1607
+ }
1608
+ }
1609
+ blockStack.push(
1610
+ elide
1611
+ ? null
1612
+ // Sometimes a single list of selectors is split in two,
1613
+ // div, a:visited
1614
+ // because we want to allow some properties for DIV that
1615
+ // we don't want to allow for A:VISITED to avoid leaking
1616
+ // user history.
1617
+ // Store the history sensitive selectors and the position
1618
+ // where the block starts so we can later create a copy
1619
+ // of the permissive tokens, and filter it to handle the
1620
+ // history sensitive case.
1621
+ : {
1622
+ historySensitiveSelectors: historySensitiveSelectors,
1623
+ endOfSelectors: safeCss.length - 1, // 1 is open curly
1624
+ removeHistoryInsensitiveSelectors:
1625
+ removeHistoryInsensitiveSelectors
1626
+ });
1627
+ },
1628
+ endRuleset: function () {
1629
+ var rules = blockStack.pop();
1630
+ var propertiesEnd = safeCss.length;
1631
+ if (!elide) {
1632
+ safeCss.push('}');
1633
+ if (rules) {
1634
+ var extraSelectors = rules.historySensitiveSelectors;
1635
+ if (extraSelectors.length) {
1636
+ var propertyGroupTokens = safeCss.slice(rules.endOfSelectors);
1637
+ safeCss.push(extraSelectors.join(', '),
1638
+ sanitizeHistorySensitive(propertyGroupTokens));
1639
+ }
1640
+ }
1641
+ }
1642
+ if (rules && rules.removeHistoryInsensitiveSelectors) {
1643
+ safeCss.splice(
1644
+ // -1 and +1 account for curly braces.
1645
+ rules.endOfSelectors - 1, propertiesEnd + 1);
1646
+ }
1647
+ checkElide();
1648
+ },
1649
+ declaration: function (property, valueArray) {
1650
+ if (!elide) {
1651
+ var schema = cssSchema[property];
1652
+ if (schema) {
1653
+ sanitizeCssProperty(property, schema, valueArray, opt_naiveUriRewriter);
1654
+ if (valueArray.length) {
1655
+ safeCss.push(property, ':', valueArray.join(' '), ';');
1656
+ }
1657
+ }
1658
+ }
1659
+ }
1660
+ });
1661
+ function checkElide() {
1662
+ elide = blockStack.length !== 0
1663
+ && blockStack[blockStack.length-1] !== null;
1664
+ }
1665
+ return safeCss.join('');
1666
+ };
1667
+ })();
1668
+
1669
+ // Exports for closure compiler.
1670
+ if (typeof window !== 'undefined') {
1671
+ window['sanitizeCssProperty'] = sanitizeCssProperty;
1672
+ window['sanitizeCssSelectors'] = sanitizeCssSelectors;
1673
+ window['sanitizeStylesheet'] = sanitizeStylesheet;
1674
+ }
1675
+ // Copyright (C) 2010 Google Inc.
1676
+ //
1677
+ // Licensed under the Apache License, Version 2.0 (the "License");
1678
+ // you may not use this file except in compliance with the License.
1679
+ // You may obtain a copy of the License at
1680
+ //
1681
+ // http://www.apache.org/licenses/LICENSE-2.0
1682
+ //
1683
+ // Unless required by applicable law or agreed to in writing, software
1684
+ // distributed under the License is distributed on an "AS IS" BASIS,
1685
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1686
+ // See the License for the specific language governing permissions and
1687
+ // limitations under the License.
1688
+
1689
+ /**
1690
+ * @fileoverview
1691
+ * Utilities for dealing with CSS source code.
1692
+ *
1693
+ * @author mikesamuel@gmail.com
1694
+ * \@requires lexCss
1695
+ * \@overrides window
1696
+ * \@provides parseCssStylesheet, parseCssDeclarations
1697
+ */
1698
+
1699
+ /**
1700
+ * parseCssStylesheet takes a chunk of CSS text and a handler object with
1701
+ * methods that it calls as below:
1702
+ * <pre>
1703
+ * // At the beginning of a stylesheet.
1704
+ * handler.startStylesheet();
1705
+ *
1706
+ * // For an @foo rule ended by a semicolon: @import "foo.css";
1707
+ * handler.startAtrule('@import', ['"foo.css"']);
1708
+ * handler.endAtrule();
1709
+ *
1710
+ * // For an @foo rule ended with a block. @media print { ... }
1711
+ * handler.startAtrule('@media', ['print']);
1712
+ * handler.startBlock();
1713
+ * // Calls to contents elided. Probably selectors and declarations as below.
1714
+ * handler.endBlock();
1715
+ * handler.endAtrule();
1716
+ *
1717
+ * // For a ruleset: p.clazz q, s { color: blue; }
1718
+ * handler.startRuleset(['p', '.', 'clazz', ' ', 'q', ',', ' ', 's']);
1719
+ * handler.declaration('color', ['blue']);
1720
+ * handler.endRuleset();
1721
+ *
1722
+ * // At the end of a stylesheet.
1723
+ * handler.endStylesheet();
1724
+ * </pre>
1725
+ * When errors are encountered, the parser drops the useless tokens and
1726
+ * attempts to resume parsing.
1727
+ *
1728
+ * @param {string} cssText CSS3 content to parse as a stylesheet.
1729
+ * @param {Object} handler An object like <pre>{
1730
+ * startStylesheet: function () { ... },
1731
+ * endStylesheet: function () { ... },
1732
+ * startAtrule: function (atIdent, headerArray) { ... },
1733
+ * endAtrule: function () { ... },
1734
+ * startBlock: function () { ... },
1735
+ * endBlock: function () { ... },
1736
+ * startRuleset: function (selectorArray) { ... },
1737
+ * endRuleset: function () { ... },
1738
+ * declaration: function (property, valueArray) { ... },
1739
+ * }</pre>
1740
+ */
1741
+ var parseCssStylesheet;
1742
+
1743
+ /**
1744
+ * parseCssDeclarations parses a run of declaration productions as seen in the
1745
+ * body of the HTML5 {@code style} attribute.
1746
+ *
1747
+ * @param {string} cssText CSS3 content to parse as a run of declarations.
1748
+ * @param {Object} handler An object like <pre>{
1749
+ * declaration: function (property, valueArray) { ... },
1750
+ * }</pre>
1751
+ */
1752
+ var parseCssDeclarations;
1753
+
1754
+ (function () {
1755
+ // stylesheet : [ CDO | CDC | S | statement ]*;
1756
+ parseCssStylesheet = function(cssText, handler) {
1757
+ var toks = lexCss(cssText);
1758
+ if (handler.startStylesheet) { handler.startStylesheet(); }
1759
+ for (var i = 0, n = toks.length; i < n;) {
1760
+ // CDO and CDC ("<!--" and "-->") are converted to space by the lexer.
1761
+ i = toks[i] === ' ' ? i+1 : statement(toks, i, n, handler);
1762
+ }
1763
+ if (handler.endStylesheet) { handler.endStylesheet(); }
1764
+ };
1765
+
1766
+ // statement : ruleset | at-rule;
1767
+ function statement(toks, i, n, handler) {
1768
+ if (i < n) {
1769
+ var tok = toks[i];
1770
+ if (tok.charAt(0) === '@') {
1771
+ return atrule(toks, i, n, handler, true);
1772
+ } else {
1773
+ return ruleset(toks, i, n, handler);
1774
+ }
1775
+ } else {
1776
+ return i;
1777
+ }
1778
+ }
1779
+
1780
+ // at-rule : ATKEYWORD S* any* [ block | ';' S* ];
1781
+ function atrule(toks, i, n, handler, blockok) {
1782
+ var start = i++;
1783
+ while (i < n && toks[i] !== '{' && toks[i] !== ';') {
1784
+ ++i;
1785
+ }
1786
+ if (i < n && (blockok || toks[i] === ';')) {
1787
+ var s = start+1, e = i;
1788
+ if (s < n && toks[s] === ' ') { ++s; }
1789
+ if (e > s && toks[e-1] === ' ') { --e; }
1790
+ if (handler.startAtrule) {
1791
+ handler.startAtrule(toks[start].toLowerCase(), toks.slice(s, e));
1792
+ }
1793
+ i = (toks[i] === '{')
1794
+ ? block(toks, i, n, handler)
1795
+ : i+1; // Skip over ';'
1796
+ if (handler.endAtrule) {
1797
+ handler.endAtrule();
1798
+ }
1799
+ }
1800
+ // Else we reached end of input or are missing a semicolon.
1801
+ // Drop the rule on the floor.
1802
+ return i;
1803
+ }
1804
+
1805
+ // block : '{' S* [ any | block | ATKEYWORD S* | ';' S* ]* '}' S*;
1806
+ // Assumes the leading '{' has been verified by callers.
1807
+ function block(toks, i, n, handler) {
1808
+ ++i; // skip over '{'
1809
+ if (handler.startBlock) { handler.startBlock(); }
1810
+ while (i < n) {
1811
+ var ch = toks[i].charAt(0);
1812
+ if (ch == '}') {
1813
+ ++i;
1814
+ break;
1815
+ }
1816
+ if (ch === ' ' || ch === ';') {
1817
+ i = i+1;
1818
+ } else if (ch === '@') {
1819
+ i = atrule(toks, i, n, handler, false);
1820
+ } else if (ch === '{') {
1821
+ i = block(toks, i, n, handler);
1822
+ } else {
1823
+ // Instead of using (any* block) to subsume ruleset we allow either
1824
+ // blocks or rulesets with a non-blank selector.
1825
+ // This is more restrictive but does not require atrule specific
1826
+ // parse tree fixup to realize that the contents of the block in
1827
+ // @media print { ... }
1828
+ // is a ruleset. We just don't care about any block carrying at-rules
1829
+ // whose body content is not ruleset content.
1830
+ i = ruleset(toks, i, n, handler);
1831
+ }
1832
+ }
1833
+ if (handler.endBlock) { handler.endBlock(); }
1834
+ return i;
1835
+ }
1836
+
1837
+ // ruleset : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
1838
+ function ruleset(toks, i, n, handler) {
1839
+ // toks[s:e] are the selector tokens including internal whitespace.
1840
+ var s = i, e = selector(toks, i, n, true);
1841
+ if (e < 0) {
1842
+ // Skip malformed content per selector calling convention.
1843
+ e = ~e;
1844
+ // Make sure we skip at least one token.
1845
+ return i === e ? e+1 : e;
1846
+ }
1847
+ i = e;
1848
+ // Don't include any trailing space in the selector slice.
1849
+ if (e > s && toks[e-1] === ' ') { --e; }
1850
+ var tok = toks[i];
1851
+ ++i; // Skip over '{'
1852
+ if (tok !== '{') {
1853
+ // Skips past the '{' when there is a malformed input.
1854
+ return i;
1855
+ }
1856
+ if (handler.startRuleset) {
1857
+ handler.startRuleset(toks.slice(s, e));
1858
+ }
1859
+ while (i < n) {
1860
+ tok = toks[i];
1861
+ if (tok === '}') {
1862
+ ++i;
1863
+ break;
1864
+ }
1865
+ if (tok === ' ') {
1866
+ i = i+1;
1867
+ } else {
1868
+ i = declaration(toks, i, n, handler);
1869
+ }
1870
+ }
1871
+ if (handler.endRuleset) {
1872
+ handler.endRuleset();
1873
+ }
1874
+ return i < n ? i+1 : i;
1875
+ }
1876
+
1877
+ // selector : any+;
1878
+ // any : [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
1879
+ // | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
1880
+ // | FUNCTION S* any* ')' | DASHMATCH | '(' S* any* ')'
1881
+ // | '[' S* any* ']' ] S*;
1882
+ // A negative return value, rv, indicates the selector was malformed and
1883
+ // the index at which we stopped is ~rv.
1884
+ function selector(toks, i, n, allowSemi) {
1885
+ var s = i;
1886
+ // The definition of any above can be summed up as
1887
+ // "any run of token except ('[', ']', '(', ')', ':', ';', '{', '}')
1888
+ // or nested runs of parenthesized tokens or square bracketed tokens".
1889
+ // Spaces are significant in the selector.
1890
+ // Selector is used as (selector?) so the below looks for (any*) for
1891
+ // simplicity.
1892
+ var tok;
1893
+ // Keeping a stack pointer actually causes this to minify better since
1894
+ // ".length" and ".push" are a lo of chars.
1895
+ var brackets = [], stackLast = -1;
1896
+ for (;i < n; ++i) {
1897
+ tok = toks[i].charAt(0);
1898
+ if (tok === '[' || tok === '(') {
1899
+ brackets[++stackLast] = tok;
1900
+ } else if ((tok === ']' && brackets[stackLast] === '[') ||
1901
+ (tok === ')' && brackets[stackLast] === '(')) {
1902
+ --stackLast;
1903
+ } else if (tok === '{' || tok === '}' || tok === ';' || tok === '@'
1904
+ || (tok === ':' && !allowSemi)) {
1905
+ break;
1906
+ }
1907
+ }
1908
+ if (stackLast >= 0) {
1909
+ // Returns the bitwise inverse of i+1 to indicate an error in the
1910
+ // token stream so that clients can ignore it.
1911
+ i = ~(i+1);
1912
+ }
1913
+ return i;
1914
+ }
1915
+
1916
+ var ident = /^-?[a-z]/i;
1917
+
1918
+ // declaration : property ':' S* value;
1919
+ // property : IDENT S*;
1920
+ // value : [ any | block | ATKEYWORD S* ]+;
1921
+ function declaration(toks, i, n, handler) {
1922
+ var property = toks[i++];
1923
+ if (!ident.test(property)) {
1924
+ return i+1; // skip one token.
1925
+ }
1926
+ var tok;
1927
+ if (i < n && toks[i] === ' ') { ++i; }
1928
+ if (i == n || toks[i] !== ':') {
1929
+ // skip tokens to next semi or close bracket.
1930
+ while (i < n && (tok = toks[i]) !== ';' && tok !== '}') { ++i; }
1931
+ return i;
1932
+ }
1933
+ ++i;
1934
+ if (i < n && toks[i] === ' ') { ++i; }
1935
+
1936
+ // None of the rules we care about want atrules or blocks in value, so
1937
+ // we look for any+ but that is the same as selector but not zero-length.
1938
+ // This gets us the benefit of not emitting any value with mismatched
1939
+ // brackets.
1940
+ var s = i, e = selector(toks, i, n, false);
1941
+ if (e < 0) {
1942
+ // Skip malformed content per selector calling convention.
1943
+ e = ~e;
1944
+ } else {
1945
+ var value = [], valuelen = 0;
1946
+ for (var j = s; j < e; ++j) {
1947
+ tok = toks[j];
1948
+ if (tok !== ' ') {
1949
+ value[valuelen++] = tok;
1950
+ }
1951
+ }
1952
+ // One of the following is now true:
1953
+ // (1) e is flush with the end of the tokens as in <... style="x:y">.
1954
+ // (2) tok[e] points to a ';' in which case we need to consume the semi.
1955
+ // (3) tok[e] points to a '}' in which case we don't consume it.
1956
+ // (4) else there is bogus unparsed value content at toks[e:].
1957
+ // Allow declaration flush with end for style attr body.
1958
+ if (e < n) { // 2, 3, or 4
1959
+ do {
1960
+ tok = toks[e];
1961
+ if (tok === ';' || tok === '}') { break; }
1962
+ // Don't emit the property if there is questionable trailing content.
1963
+ valuelen = 0;
1964
+ } while (++e < n);
1965
+ if (tok === ';') {
1966
+ ++e;
1967
+ }
1968
+ }
1969
+ if (valuelen && handler.declaration) {
1970
+ // TODO: coerce non-keyword ident tokens to quoted strings.
1971
+ handler.declaration(property.toLowerCase(), value);
1972
+ }
1973
+ }
1974
+ return e;
1975
+ }
1976
+
1977
+ parseCssDeclarations = function(cssText, handler) {
1978
+ var toks = lexCss(cssText);
1979
+ for (var i = 0, n = toks.length; i < n;) {
1980
+ i = toks[i] !== ' ' ? declaration(toks, i, n, handler) : i+1;
1981
+ }
1982
+ };
1983
+ })();
1984
+
1985
+ // Exports for closure compiler.
1986
+ if (typeof window !== 'undefined') {
1987
+ window['parseCssStylesheet'] = parseCssStylesheet;
1988
+ window['parseCssDeclarations'] = parseCssDeclarations;
1989
+ }
1990
+ /*!
1991
+ * OpenUI5
1992
+ * (c) Copyright 2009-2021 SAP SE or an SAP affiliate company.
1993
+ * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
1994
+ */
1995
+ // Based on coding from the HTML4 Sanitizer by Google Inc.
1996
+ // The HTML Attributes and ELements were reorganized according to the actual HTML5 specification
1997
+ // from the W3C. All types and flags were reviewed again as accurately as possible with HTML4 only
1998
+ // elements removed, you can still see them as comments. All rules which are new or changed from the
1999
+ // old HTML4 file are also marked "new" within the comment. The comments also state which attributes
2000
+ // and elements are assigned to respective types and flags. All rules which were not 100% clear were
2001
+ // analyzed in a way of similarity, so for example "audio" and "video" content behaves like images etc.
2002
+ // URIEFFECTS state if a URL is loaded inplace within a tag where the actual document is in control
2003
+ // of what type of content is loaded like "image" or if a new document is loaded like with "a href".
2004
+ // LOADERTYPES state if content is loaded as sandboxed which means it is loaded within a specific
2005
+ // surroundig player like with video content for example or if it is loaded freely without restrictions.
2006
+ // @overrides window
2007
+ // @provides html4
2008
+
2009
+ var html4 = {};
2010
+ html4.atype = {
2011
+ NONE: 0,
2012
+ URI: 1, //action, cite, data, href, icon, manifest, poster, src
2013
+ URI_FRAGMENT: 11, //usemap
2014
+ SCRIPT: 2, //all event handlers
2015
+ STYLE: 3, //style
2016
+ ID: 4, //id
2017
+ IDREF: 5, //for
2018
+ IDREFS: 6, //headers
2019
+ GLOBAL_NAME: 7, //name of form, iframe, img, map, meta
2020
+ LOCAL_NAME: 8, //name of button, fieldset, input, keygen, object, output, param, select, textarea
2021
+ CLASSES: 9, //class
2022
+ FRAME_TARGET: 10 //formtarget, srcdoc, target
2023
+ };
2024
+
2025
+ html4.ATTRIBS = {
2026
+ '*::accesskey': 0, //NONE
2027
+ '*::class': 9, //CLASSES
2028
+ '*::contenteditable': 0, //NONE new
2029
+ '*::contextmenu': 0, //NONE new
2030
+ '*::dir': 0, //NONE
2031
+ '*::draggable': 0, //NONE new
2032
+ '*::dropzone': 0, //NONE new
2033
+ '*::hidden': 0, //NONE new
2034
+ '*::id': 4, //ID
2035
+ '*::lang': 0, //NONE
2036
+ '*::onabort': 2, //SCRIPT new
2037
+ '*::onblur': 2, //SCRIPT new
2038
+ '*::oncanplay': 2, //SCRIPT new
2039
+ '*::oncanplaythrough': 2, //SCRIPT new
2040
+ '*::onchange': 2, //SCRIPT new
2041
+ '*::onclick': 2, //SCRIPT
2042
+ '*::oncontextmenu': 2, //SCRIPT new
2043
+ '*::oncuechange': 2, //SCRIPT new
2044
+ '*::ondblclick': 2, //SCRIPT
2045
+ '*::ondrag': 2, //SCRIPT new
2046
+ '*::ondragend': 2, //SCRIPT new
2047
+ '*::ondragenter': 2, //SCRIPT new
2048
+ '*::ondragleave': 2, //SCRIPT new
2049
+ '*::ondragover': 2, //SCRIPT new
2050
+ '*::ondragstart': 2, //SCRIPT new
2051
+ '*::ondrop': 2, //SCRIPT new
2052
+ '*::ondurationchange': 2, //SCRIPT new
2053
+ '*::onemptied': 2, //SCRIPT new
2054
+ '*::onended': 2, //SCRIPT new
2055
+ '*::onerror': 2, //SCRIPT new
2056
+ '*::onfocus': 2, //SCRIPT new
2057
+ '*::oninput': 2, //SCRIPT new
2058
+ '*::oninvalid': 2, //SCRIPT new
2059
+ '*::onkeydown': 2, //SCRIPT
2060
+ '*::onkeypress': 2, //SCRIPT
2061
+ '*::onkeyup': 2, //SCRIPT
2062
+ '*::onload': 2, //SCRIPT
2063
+ '*::onloadeddata': 2, //SCRIPT new
2064
+ '*::onloadedmetadata': 2, //SCRIPT new
2065
+ '*::onloadstart': 2, //SCRIPT new
2066
+ '*::onmousedown': 2, //SCRIPT
2067
+ '*::onmousemove': 2, //SCRIPT
2068
+ '*::onmouseout': 2, //SCRIPT
2069
+ '*::onmouseover': 2, //SCRIPT
2070
+ '*::onmouseup': 2, //SCRIPT
2071
+ '*::onmousewheel': 2, //SCRIPT new
2072
+ '*::onpause': 2, //SCRIPT new
2073
+ '*::onplay': 2, //SCRIPT new
2074
+ '*::onplaying': 2, //SCRIPT new
2075
+ '*::onprogress': 2, //SCRIPT new
2076
+ '*::onratechange': 2, //SCRIPT new
2077
+ '*::onreadystatechange': 2, //SCRIPT new
2078
+ '*::onreset': 2, //SCRIPT new
2079
+ '*::onscroll': 2, //SCRIPT new
2080
+ '*::onseeked': 2, //SCRIPT new
2081
+ '*::onseeking': 2, //SCRIPT new
2082
+ '*::onselect': 2, //SCRIPT new
2083
+ '*::onshow': 2, //SCRIPT new
2084
+ '*::onstalled': 2, //SCRIPT new
2085
+ '*::onsubmit': 2, //SCRIPT new
2086
+ '*::onsuspend': 2, //SCRIPT new
2087
+ '*::ontimeupdate': 2, //SCRIPT new
2088
+ '*::onvolumechange': 2, //SCRIPT new
2089
+ '*::onwaiting': 2, //SCRIPT new
2090
+ '*::spellcheck': 0, //NONE new
2091
+ '*::style': 3, //STYLE
2092
+ '*::tabindex': 0, //NONE
2093
+ '*::title': 0, //NONE
2094
+ //--------------------- 'a::accesskey': 0, moved to global
2095
+ //--------------------- 'a::coords': 0,
2096
+ 'a::href': 1, //URI
2097
+ 'a::hreflang': 0, //NONE
2098
+ 'a::media': 0, //NONE new
2099
+ //--------------------- 'a::name': 7,
2100
+ //--------------------- 'a::onblur': 2, moved to global
2101
+ //--------------------- 'a::onfocus': 2, moved to global
2102
+ 'a::rel': 0, //NONE
2103
+ //--------------------- 'a::rev': 0,
2104
+ //--------------------- 'a::shape': 0,
2105
+ //--------------------- 'a::tabindex': 0, moved to global
2106
+ 'a::target': 0, //changed to "0" because of CSN 1918585 2013, original value was 10 FRAME_TARGET but it seems uncritical
2107
+ 'a::type': 0, //NONE
2108
+ //--------------------- 'area::accesskey': 0, moved to global
2109
+ 'area::alt': 0, //NONE
2110
+ 'area::coords': 0, //NONE
2111
+ 'area::href': 1, //URI
2112
+ 'area::hreflang': 0, //NONE new
2113
+ 'area::media': 0, //NONE new
2114
+ //--------------------- 'area::nohref': 0,
2115
+ //--------------------- 'area::onblur': 2, moved to global
2116
+ //--------------------- 'area::onfocus': 2, moved to global
2117
+ 'area::rel': 0, //NONE new
2118
+ 'area::shape': 0, //NONE
2119
+ //--------------------- 'area::tabindex': 0, moved to global
2120
+ 'area::target': 10, //FRAME_TARGET
2121
+ 'area::type': 0, //NONE
2122
+ 'audio::autoplay': 0, //NONE new
2123
+ 'audio::controls': 0, //NONE new
2124
+ 'audio::loop': 0, //NONE new
2125
+ 'audio::mediagroup': 0, //NONE new
2126
+ 'audio::preload': 0, //NONE new
2127
+ 'audio::src': 1, //URI
2128
+ 'base::href': 1, //URI
2129
+ 'base::target': 10, //FRAME_TARGET
2130
+ //--------------------- 'bdo::dir': 0,
2131
+ 'blockquote::cite': 1, //URI
2132
+ 'body::onafterprint': 2, //SCRIPT new
2133
+ 'body::onbeforeprint': 2, //SCRIPT new
2134
+ 'body::onbeforeunload': 2, //SCRIPT new
2135
+ 'body::onblur': 2, //SCRIPT new
2136
+ 'body::onerror': 2, //SCRIPT new
2137
+ 'body::onfocus': 2, //SCRIPT new
2138
+ 'body::onhashchange': 2, //SCRIPT new
2139
+ 'body::onload': 2, //SCRIPT new
2140
+ 'body::onmessage': 2, //SCRIPT new
2141
+ 'body::onoffline': 2, //SCRIPT new
2142
+ 'body::ononline': 2, //SCRIPT new
2143
+ 'body::onpagehide': 2, //SCRIPT new
2144
+ 'body::onpageshow': 2, //SCRIPT new
2145
+ 'body::onpopstate': 2, //SCRIPT new
2146
+ 'body::onredo': 2, //SCRIPT new
2147
+ 'body::onresize': 2, //SCRIPT new
2148
+ 'body::onscroll': 2, //SCRIPT new
2149
+ 'body::onstorage': 2, //SCRIPT new
2150
+ 'body::onundo': 2, //SCRIPT new
2151
+ 'body::onunload': 2, //SCRIPT new
2152
+ //--------------------- 'br::clear': 0,
2153
+ //--------------------- 'button::accesskey': 0, moved to global
2154
+ 'button::autofocus': 0, //NONE new
2155
+ 'button::disabled': 0, //NONE
2156
+ 'button::form': 0, //NONE new
2157
+ 'button::formaction': 1, //URI new
2158
+ 'button::formenctype': 0, //NONE new
2159
+ 'button::formmethod': 0, //NONE new
2160
+ 'button::formnovalidate': 0, //NONE new
2161
+ 'button::formtarget': 10, //FRAME_TARGET new
2162
+ 'button::name': 8, //LOCAL_NAME
2163
+ //--------------------- 'button::onblur': 2,
2164
+ //--------------------- 'button::onfocus': 2,
2165
+ //--------------------- 'button::tabindex': 0, moved to global
2166
+ 'button::type': 0, //NONE
2167
+ 'button::value': 0, //NONE
2168
+ 'canvas::height': 0, //NONE
2169
+ 'canvas::width': 0, //NONE
2170
+ //--------------------- 'caption::align': 0,
2171
+ //--------------------- 'col::align': 0,
2172
+ //--------------------- 'col::char': 0,
2173
+ //--------------------- 'col::charoff': 0,
2174
+ 'col::span': 0, //NONE
2175
+ //--------------------- 'col::valign': 0,
2176
+ //--------------------- 'col::width': 0,
2177
+ //--------------------- 'colgroup::align': 0,
2178
+ //--------------------- 'colgroup::char': 0,
2179
+ //--------------------- 'colgroup::charoff': 0,
2180
+ 'colgroup::span': 0, //NONE
2181
+ //--------------------- 'colgroup::valign': 0,
2182
+ //--------------------- 'colgroup::width': 0,
2183
+ 'command::checked': 0, //NONE new
2184
+ 'command::disabled': 0, //NONE new
2185
+ 'command::icon': 1, //URI new
2186
+ 'command::label': 0, //NONE new
2187
+ 'command::radiogroup': 0, //NONE new
2188
+ 'command::type': 0, //NONE new
2189
+ 'del::cite': 1, //URI
2190
+ 'del::datetime': 0, //NONE
2191
+ 'details::open': 0, //NONE new
2192
+ //--------------------- 'dir::compact': 0,
2193
+ //--------------------- 'div::align': 0,
2194
+ //--------------------- 'dl::compact': 0,
2195
+ 'embed::height': 0, //NONE new
2196
+ 'embed::src': 1, //URI new
2197
+ 'embed::type': 0, //NONE new
2198
+ 'embed::width': 0, //NONE new
2199
+ 'fieldset::disabled': 0, //NONE new
2200
+ 'fieldset::form': 0, //NONE new
2201
+ 'fieldset::name': 8, //LOCAL_NAME new
2202
+ //--------------------- 'font::color': 0,
2203
+ //--------------------- 'font::face': 0,
2204
+ //--------------------- 'font::size': 0,
2205
+ //--------------------- 'form::accept': 0,
2206
+ 'form::accept-charset': 0, //NONE
2207
+ 'form::action': 1, //URI
2208
+ 'form::autocomplete': 0, //NONE
2209
+ 'form::enctype': 0, //NONE
2210
+ 'form::method': 0, //NONE
2211
+ 'form::name': 7, //GLOBAL_NAME
2212
+ 'form::novalidate': 0, //NONE new
2213
+ //--------------------- 'form::onreset': 2,
2214
+ //--------------------- 'form::onsubmit': 2,
2215
+ 'form::target': 10, //FRAME_TARGET
2216
+ //--------------------- 'h1::align': 0,
2217
+ //--------------------- 'h2::align': 0,
2218
+ //--------------------- 'h3::align': 0,
2219
+ //--------------------- 'h4::align': 0,
2220
+ //--------------------- 'h5::align': 0,
2221
+ //--------------------- 'h6::align': 0,
2222
+ //--------------------- 'hr::align': 0,
2223
+ //--------------------- 'hr::noshade': 0,
2224
+ //--------------------- 'hr::size': 0,
2225
+ //--------------------- 'hr::width': 0,
2226
+ 'html:: manifest': 1, //URI new
2227
+ //--------------------- 'iframe::align': 0,
2228
+ //--------------------- 'iframe::frameborder': 0,
2229
+ 'iframe::height': 0, //NONE
2230
+ //--------------------- 'iframe::marginheight': 0,
2231
+ //--------------------- 'iframe::marginwidth': 0,
2232
+ 'iframe::name': 7, //GLOBAL_NAME new
2233
+ 'iframe::sandbox': 0, //NONE new
2234
+ 'iframe::seamless': 0, //NONE new
2235
+ 'iframe::src': 1, //URI new
2236
+ 'iframe::srcdoc': 10, //FRAME_TARGET new
2237
+ 'iframe::width': 0, //NONE
2238
+ //--------------------- 'img::align': 0,
2239
+ 'img::alt': 0, //NONE
2240
+ //--------------------- 'img::border': 0,
2241
+ 'img::height': 0, //NONE
2242
+ //--------------------- 'img::hspace': 0,
2243
+ 'img::ismap': 0, //NONE
2244
+ 'img::name': 7, //GLOBAL_NAME
2245
+ 'img::src': 1, //URI
2246
+ 'img::usemap': 11, //URI_FRAGMENT
2247
+ //--------------------- 'img::vspace': 0,
2248
+ 'img::width': 0, //NONE
2249
+ 'input::accept': 0, //NONE
2250
+ //--------------------- 'input::accesskey': 0, moved to global
2251
+ //--------------------- 'input::align': 0,
2252
+ 'input::alt': 0, //NONE
2253
+ 'input::autocomplete': 0, //NONE
2254
+ 'input::autofocus': 0, //NONE new
2255
+ 'input::checked': 0, //NONE
2256
+ 'input::dirname': 0, //NONE new
2257
+ 'input::disabled': 0, //NONE
2258
+ 'input::form': 0, //NONE new
2259
+ 'input::formaction': 1, //URI new
2260
+ 'input::formenctype': 0, //NONE new
2261
+ 'input::formmethod': 0, //NONE new
2262
+ 'input::formnovalidate': 0, //NONE new
2263
+ 'input::formtarget': 10, //FRAME_TARGET new
2264
+ 'input::height': 0, //NONE new
2265
+ //--------------------- 'input::ismap': 0,
2266
+ 'input::list': 0, //NONE new
2267
+ 'input::max': 0, //NONE new
2268
+ 'input::maxlength': 0, //NONE
2269
+ 'input::min': 0, //NONE new
2270
+ 'input::multiple': 0, //NONE new
2271
+ 'input::name': 8, //LOCAL_NAME
2272
+ //--------------------- 'input::onblur': 2,
2273
+ //--------------------- 'input::onchange': 2,
2274
+ //--------------------- 'input::onfocus': 2,
2275
+ //--------------------- 'input::onselect': 2,
2276
+ 'input::pattern': 0, //NONE new
2277
+ 'input::placeholder': 0, //NONE new
2278
+ 'input::readonly': 0, //NONE
2279
+ 'input::required': 0, //NONE new
2280
+ 'input::step': 0, //NONE new
2281
+ 'input::size': 0, //NONE
2282
+ 'input::src': 1, //URI
2283
+ //--------------------- 'input::tabindex': 0, moved to global
2284
+ 'input::type': 0, //NONE
2285
+ //--------------------- 'input::usemap': 11,
2286
+ 'input::value': 0, //NONE
2287
+ 'input::width': 0, //NONE new
2288
+ 'ins::cite': 1, //URI
2289
+ 'ins::datetime': 0, //NONE
2290
+ //--------------------- 'label::accesskey': 0, moved to global
2291
+ 'keygen::autofocus': 0, //NONE new
2292
+ 'keygen::challenge': 0, //NONE new
2293
+ 'keygen::disabled': 0, //NONE new
2294
+ 'keygen::form': 0, //NONE new
2295
+ 'keygen::keytype': 0, //NONE new
2296
+ 'keygen::name': 8, //LOCAL_NAME new
2297
+ 'label::for': 5, //IDREF
2298
+ 'label::form': 0, //NONE new
2299
+ //--------------------- 'label::onblur': 2,
2300
+ //--------------------- 'label::onfocus': 2,
2301
+ //--------------------- 'legend::accesskey': 0, moved to global
2302
+ //--------------------- 'legend::align': 0,
2303
+ //--------------------- 'li::type': 0,
2304
+ 'link::href': 1, //URI new
2305
+ 'link::hreflang': 0, //NONE new
2306
+ 'link::media': 0, //NONE new
2307
+ 'link::rel': 0, //NONE new
2308
+ 'link::sizes': 0, //NONE new
2309
+ 'link::type': 0, //NONE new
2310
+ 'li::value': 0, //NONE new
2311
+ 'map::name': 7, //GLOBAL_NAME
2312
+ //--------------------- 'menu::compact': 0,
2313
+ 'menu::label': 0, //NONE new
2314
+ 'menu::type': 0, //NONE new
2315
+ 'meta::charset': 0, //NONE new
2316
+ 'meta::content': 0, //NONE new
2317
+ 'meta::http-equiv': 0, //NONE new
2318
+ 'meta::name': 7, //GLOBAL_NAME new
2319
+ 'meter::form': 0, //NONE new
2320
+ 'meter::high': 0, //NONE new
2321
+ 'meter::low': 0, //NONE new
2322
+ 'meter::max': 0, //NONE new
2323
+ 'meter::min': 0, //NONE new
2324
+ 'meter::optimum': 0, //NONE new
2325
+ 'meter::value': 0, //NONE new
2326
+ 'object::data': 1, //URI new
2327
+ 'object::form': 0, //NONE new
2328
+ 'object::height': 0, //NONE new
2329
+ 'object::name': 8, //LOCAL_NAME new
2330
+ 'object::type': 0, //NONE new
2331
+ 'object::usemap': 11, //URI_FRAGMENT new
2332
+ 'object::width': 0, //NONE new
2333
+ //--------------------- 'ol::compact': 0,
2334
+ 'ol::reversed': 0, //NONE new
2335
+ 'ol::start': 0, //NONE
2336
+ //--------------------- 'ol::type': 0,
2337
+ 'optgroup::disabled': 0, //NONE
2338
+ 'optgroup::label': 0, //NONE
2339
+ 'option::disabled': 0, //NONE
2340
+ 'option::label': 0, //NONE
2341
+ 'option::selected': 0, //NONE
2342
+ 'option::value': 0, //NONE
2343
+ 'output::for': 5, //IDREF new
2344
+ 'output::form': 0, //NONE new
2345
+ 'output::name': 8, //LOCAL_NAME new
2346
+ //--------------------- 'p::align': 0,
2347
+ 'param::name': 8, //LOCAL_NAME new
2348
+ 'param::value': 0, //NONE new
2349
+ 'progress::form': 0, //NONE new
2350
+ 'progress::max': 0, //NONE new
2351
+ 'progress::value': 0, //NONE new
2352
+ //--------------------- 'pre::width': 0,
2353
+ 'q::cite': 1, //URI
2354
+ 'script::async': 0, //NONE new
2355
+ 'script::charset': 0, //NONE new
2356
+ 'script::defer': 0, //NONE new
2357
+ 'script::src': 1, //URI new
2358
+ 'script::type': 0, //NONE new
2359
+ 'select::autofocus': 0, //NONE new
2360
+ 'select::disabled': 0, //NONE
2361
+ 'select::form': 0, //NONE new
2362
+ 'select::multiple': 0, //NONE
2363
+ 'select::name': 8, //LOCAL_NAME
2364
+ //--------------------- 'select::onblur': 2,
2365
+ //--------------------- 'select::onchange': 2,
2366
+ //--------------------- 'select::onfocus': 2,
2367
+ 'select::required': 0, //NONE new
2368
+ 'select::size': 0, //NONE
2369
+ //--------------------- 'select::tabindex': 0, moved to global
2370
+ 'source::media': 0, //NONE new
2371
+ 'source::src': 1, //URI new
2372
+ 'source::type': 0, //NONE new
2373
+ 'style::media': 0, //NONE new
2374
+ 'style::scoped': 0, //NONE new
2375
+ 'style::type': 0, //NONE new
2376
+ //--------------------- 'table::align': 0,
2377
+ //--------------------- 'table::bgcolor': 0,
2378
+ 'table::border': 0, //NONE
2379
+ //--------------------- 'table::cellpadding': 0,
2380
+ //--------------------- 'table::cellspacing': 0,
2381
+ //--------------------- 'table::frame': 0,
2382
+ //--------------------- 'table::rules': 0,
2383
+ //--------------------- 'table::summary': 0,
2384
+ //--------------------- 'table::width': 0,
2385
+ //--------------------- 'tbody::align': 0,
2386
+ //--------------------- 'tbody::char': 0,
2387
+ //--------------------- 'tbody::charoff': 0,
2388
+ //--------------------- 'tbody::valign': 0,
2389
+ //--------------------- 'td::abbr': 0,
2390
+ //--------------------- 'td::align': 0,
2391
+ //--------------------- 'td::axis': 0,
2392
+ //--------------------- 'td::bgcolor': 0,
2393
+ //--------------------- 'td::char': 0,
2394
+ //--------------------- 'td::charoff': 0,
2395
+ 'td::colspan': 0, //NONE
2396
+ 'td::headers': 6, //IDREFS
2397
+ //--------------------- 'td::height': 0,
2398
+ //--------------------- 'td::nowrap': 0,
2399
+ 'td::rowspan': 0, //NONE
2400
+ //--------------------- 'td::scope': 0,
2401
+ //--------------------- 'td::valign': 0,
2402
+ //--------------------- 'td::width': 0,
2403
+ //--------------------- 'textarea::accesskey': 0, moved to global
2404
+ 'textarea::autofocus': 0, //NONE new
2405
+ 'textarea::cols': 0, //NONE
2406
+ 'textarea::disabled': 0, //NONE
2407
+ 'textarea::form': 0, //NONE new
2408
+ 'textarea::maxlength': 0, //NONE new
2409
+ 'textarea::name': 8, //LOCAL_NAME
2410
+ //--------------------- 'textarea::onblur': 2,
2411
+ //--------------------- 'textarea::onchange': 2,
2412
+ //--------------------- 'textarea::onfocus': 2,
2413
+ //--------------------- 'textarea::onselect': 2,
2414
+ 'textarea::placeholder': 0, //NONE new
2415
+ 'textarea::readonly': 0, //NONE
2416
+ 'textarea::required': 0, //NONE new
2417
+ 'textarea::rows': 0, //NONE
2418
+ 'textarea::wrap': 0, //NONE new
2419
+ //--------------------- 'textarea::tabindex': 0, moved to global
2420
+ //--------------------- 'tfoot::align': 0,
2421
+ //--------------------- 'tfoot::char': 0,
2422
+ //--------------------- 'tfoot::charoff': 0,
2423
+ //--------------------- 'tfoot::valign': 0,
2424
+ //--------------------- 'th::abbr': 0,
2425
+ //--------------------- 'th::align': 0,
2426
+ //--------------------- 'th::axis': 0,
2427
+ //--------------------- 'th::bgcolor': 0,
2428
+ //--------------------- 'th::char': 0,
2429
+ //--------------------- 'th::charoff': 0,
2430
+ 'th::colspan': 0, //NONE
2431
+ 'th::headers': 6, //IDREFS
2432
+ //--------------------- 'th::height': 0,
2433
+ //--------------------- 'th::nowrap': 0,
2434
+ 'th::rowspan': 0, //NONE
2435
+ 'th::scope': 0, //NONE
2436
+ //--------------------- 'th::valign': 0,
2437
+ //--------------------- 'th::width': 0,
2438
+ //--------------------- 'thead::align': 0,
2439
+ //--------------------- 'thead::char': 0,
2440
+ //--------------------- 'thead::charoff': 0,
2441
+ //--------------------- 'thead::valign': 0,
2442
+ 'time::datetime': 0, //NONE new
2443
+ 'time::pubdate': 0, //NONE new
2444
+ //--------------------- 'tr::align': 0,
2445
+ //--------------------- 'tr::bgcolor': 0,
2446
+ //--------------------- 'tr::char': 0,
2447
+ //--------------------- 'tr::charoff': 0,
2448
+ //--------------------- 'tr::valign': 0,
2449
+ 'track::default': 0, //NONE new
2450
+ 'track::kind': 0, //NONE new
2451
+ 'track::label': 0, //NONE new
2452
+ 'track::src': 1, //URI new
2453
+ 'track::srclang': 0, //NONE new
2454
+ //--------------------- 'ul::compact': 0,
2455
+ //--------------------- 'ul::type': 0
2456
+ 'video::autoplay': 0, //NONE new
2457
+ 'video::controls': 0, //NONE new
2458
+ 'video::height': 0, //NONE new
2459
+ 'video::loop': 0, //NONE new
2460
+ 'video::mediagroup': 0, //NONE new
2461
+ 'video::poster': 1, //URI new
2462
+ 'video::preload': 0, //NONE new
2463
+ 'video::src': 1, //URI new
2464
+ 'video::width': 0 //NONE new
2465
+ };
2466
+ html4.eflags = {
2467
+ OPTIONAL_ENDTAG: 1,
2468
+ EMPTY: 2,
2469
+ CDATA: 4,
2470
+ RCDATA: 8,
2471
+ UNSAFE: 16,
2472
+ FOLDABLE: 32,
2473
+ SCRIPT: 64,
2474
+ STYLE: 128
2475
+ };
2476
+ html4.ELEMENTS = {
2477
+ 'a': 0,
2478
+ 'abbr': 0,
2479
+ //--------------------- 'acronym': 0,
2480
+ 'address': 0,
2481
+ //--------------------- 'applet': 16,
2482
+ 'area': 2, //EMPTY
2483
+ 'article': 0, //new
2484
+ 'aside': 0, //new
2485
+ 'audio': 0, //new
2486
+ 'b': 0,
2487
+ 'base': 18, //EMPTY, UNSAFE
2488
+ //--------------------- 'basefont': 18,
2489
+ 'bdi': 0, //new
2490
+ 'bdo': 0,
2491
+ //--------------------- 'big': 0,
2492
+ 'blockquote': 0,
2493
+ 'body': 49, //OPTIONAL_ENDTAG, UNSAFE, FOLDABLE
2494
+ 'br': 2, //EMPTY
2495
+ 'button': 0,
2496
+ 'canvas': 0,
2497
+ 'caption': 0,
2498
+ //--------------------- 'center': 0,
2499
+ 'cite': 0,
2500
+ 'code': 0,
2501
+ 'col': 2, //EMPTY
2502
+ 'colgroup': 1, //OPTIONAL_ENDTAG
2503
+ 'command': 2, //EMPTY new
2504
+ 'datalist': 0, //new
2505
+ 'dd': 1, //OPTIONAL_ENDTAG
2506
+ 'del': 0,
2507
+ 'details': 0, //new
2508
+ 'dfn': 0,
2509
+ //--------------------- 'dir': 0,
2510
+ 'div': 0,
2511
+ 'dl': 0,
2512
+ 'dt': 1, //OPTIONAL_ENDTAG
2513
+ 'em': 0,
2514
+ 'embed': 18, //EMPTY, UNSAFE new
2515
+ 'fieldset': 0,
2516
+ 'figcaption': 0, //new
2517
+ 'figure': 0, //new
2518
+ //--------------------- 'font': 0,
2519
+ 'footer': 0, //new
2520
+ 'form': 0,
2521
+ //--------------------- 'frame': 18,
2522
+ //--------------------- 'frameset': 16,
2523
+ 'h1': 0,
2524
+ 'h2': 0,
2525
+ 'h3': 0,
2526
+ 'h4': 0,
2527
+ 'h5': 0,
2528
+ 'h6': 0,
2529
+ 'head': 49, //OPTIONAL_ENDTAG, UNSAFE, FOLDABLE
2530
+ 'header': 0, //new
2531
+ 'hgroup': 0, //new
2532
+ 'hr': 2, //EMPTY
2533
+ 'html': 49, //OPTIONAL_ENDTAG, UNSAFE, FOLDABLE
2534
+ 'i': 0,
2535
+ 'iframe': 4, //CDATA
2536
+ 'img': 2,//EMPTY
2537
+ 'input': 2, //EMPTY
2538
+ 'ins': 0,
2539
+ //--------------------- 'isindex': 18,
2540
+ 'kbd': 0,
2541
+ 'keygen': 2, //EMPTY new
2542
+ 'label': 0,
2543
+ 'legend': 0,
2544
+ 'li': 1, //OPTIONAL_ENDTAG
2545
+ 'link': 18, //EMPTY, UNSAFE
2546
+ 'map': 0,
2547
+ 'mark': 0, //new
2548
+ 'menu': 0,
2549
+ 'meta': 18, //EMPTY, UNSAFE
2550
+ 'meter': 0, //new
2551
+ 'nav': 0,
2552
+ //--------------------- 'nobr': 0,
2553
+ //--------------------- 'noembed': 4,
2554
+ //--------------------- 'noframes': 20,
2555
+ 'noscript': 20, //CDATA, UNSAFE
2556
+ 'object': 16, //UNSAFE
2557
+ 'ol': 0,
2558
+ 'optgroup': 1, //OPTIONAL_ENDTAG new !!!!vorher 0
2559
+ 'option': 1, //OPTIONAL_ENDTAG
2560
+ 'output': 0, //new
2561
+ 'p': 1, //OPTIONAL_ENDTAG
2562
+ 'param': 18, //EMPTY, UNSAFE
2563
+ 'pre': 0,
2564
+ 'progress': 0, //new
2565
+ 'q': 0,
2566
+ 'rp': 1, //OPTIONAL_ENDTAG new
2567
+ 'rt': 1, //OPTIONAL_ENDTAG new
2568
+ 'ruby': 0, //new
2569
+ 's': 0,
2570
+ 'samp': 0,
2571
+ 'script': 84, //CDATA, UNSAFE, SCRIPT
2572
+ 'section': 0, //new
2573
+ 'select': 0,
2574
+ 'small': 0,
2575
+ 'source': 2, //EMPTY new
2576
+ 'span': 0,
2577
+ //--------------------- 'strike': 0,
2578
+ 'strong': 0,
2579
+ 'style': 148, //CDATA, UNSAFE, STYLE
2580
+ 'sub': 0,
2581
+ 'summary': 0, //new
2582
+ 'sup': 0,
2583
+ 'table': 0,
2584
+ 'tbody': 1, //OPTIONAL_ENDTAG
2585
+ 'td': 1, //OPTIONAL_ENDTAG
2586
+ 'textarea': 8, //RCDATA
2587
+ 'tfoot': 1, //OPTIONAL_ENDTAG
2588
+ 'th': 1, //OPTIONAL_ENDTAG
2589
+ 'thead': 1, //OPTIONAL_ENDTAG
2590
+ 'time': 0, //new
2591
+ 'title': 24, //RCDATA, UNSAFE
2592
+ 'tr': 1, //OPTIONAL_ENDTAG
2593
+ 'track': 2, //EMPTY new
2594
+ //--------------------- 'tt': 0,
2595
+ 'u': 0,
2596
+ 'ul': 0,
2597
+ 'var': 0,
2598
+ 'video': 0, //new
2599
+ 'wbr': 2 //EMPTY new
2600
+ };
2601
+ html4.ueffects = {
2602
+ NOT_LOADED: 0,
2603
+ SAME_DOCUMENT: 1,
2604
+ NEW_DOCUMENT: 2
2605
+ };
2606
+ html4.URIEFFECTS = {
2607
+ 'a::href': 2, //NEW_DOCUMENT
2608
+ 'area::href': 2, //NEW_DOCUMENT
2609
+ 'audio::src': 1, //SAME_DOCUMENT new
2610
+ 'base::href':2, //NEW_DOCUMENT new
2611
+ 'blockquote::cite': 0, //NOT_LOADED
2612
+ //--------------------- 'body::background': 1,
2613
+ 'button::formaction': 2, //NEW_DOCUMENT new
2614
+ 'command::icon': 1, //SAME_DOCUMENT new
2615
+ 'del::cite': 0, //NOT_LOADED
2616
+ 'embed::src': 1, //SAME_DOCUMENT new
2617
+ 'form::action': 2, //NEW_DOCUMENT
2618
+ 'html:: manifest': 1, //SAME_DOCUMENT new
2619
+ 'iframe::src': 1, //SAME_DOCUMENT new
2620
+ 'img::src': 1, //SAME_DOCUMENT
2621
+ 'input::formaction': 2, //NEW_DOCUMENT new
2622
+ 'input::src': 1, //SAME_DOCUMENT
2623
+ 'ins::cite': 0, //NOT_LOADED
2624
+ 'link::href': 2, //NEW_DOCUMENT new
2625
+ 'object::data': 1, //SAME_DOCUMENT new
2626
+ 'q::cite': 0, //NOT_LOADED
2627
+ 'script::src': 1, //SAME_DOCUMENT new
2628
+ 'source::src': 1, //SAME_DOCUMENT new
2629
+ 'track::src': 1, //SAME_DOCUMENT new
2630
+ 'video::poster': 1, //SAME_DOCUMENT new
2631
+ 'video::src': 1 //SAME_DOCUMENT new
2632
+ };
2633
+ html4.ltypes = {
2634
+ UNSANDBOXED: 2,
2635
+ SANDBOXED: 1,
2636
+ DATA: 0
2637
+ };
2638
+ html4.LOADERTYPES = {
2639
+ 'a::href': 2, //UNSANDBOXED
2640
+ 'area::href': 2, //UNSANDBOXED
2641
+ 'audio::src': 1, //SANDBOXED new
2642
+ 'base::href': 2, //UNSANDBOXED new
2643
+ 'blockquote::cite': 2, //UNSANDBOXED
2644
+ //--------------------- 'body::background': 1,
2645
+ 'button::formaction': 2, //UNSANDBOXED new
2646
+ 'command::icon': 1, //SANDBOXED new
2647
+ 'del::cite': 2, //UNSANDBOXED
2648
+ 'embed::src': 1, //SANDBOXED new
2649
+ 'form::action': 2, //UNSANDBOXED
2650
+ 'html:: manifest': 1, //SANDBOXED new
2651
+ 'iframe::src': 1, //SANDBOXED new
2652
+ 'img::src': 1, //SANDBOXED
2653
+ 'input::formaction': 2, //UNSANDBOXED new
2654
+ 'input::src': 1, //SANDBOXED
2655
+ 'ins::cite': 2, //UNSANDBOXED
2656
+ 'link::href': 2, //UNSANDBOXED new
2657
+ 'object::data': 0, //DATA new
2658
+ 'q::cite': 2, //UNSANDBOXED
2659
+ 'script::src': 1, //SANDBOXED new
2660
+ 'source::src': 1, //SANDBOXED new
2661
+ 'track::src': 1, //SANDBOXED new
2662
+ 'video::poster': 1, //SANDBOXED new
2663
+ 'video::src': 1 //SANDBOXED new
2664
+ };if (typeof window !== 'undefined') {
2665
+ window['html4'] = html4;
2666
+ }// Copyright (C) 2006 Google Inc.
2667
+ //
2668
+ // Licensed under the Apache License, Version 2.0 (the "License");
2669
+ // you may not use this file except in compliance with the License.
2670
+ // You may obtain a copy of the License at
2671
+ //
2672
+ // http://www.apache.org/licenses/LICENSE-2.0
2673
+ //
2674
+ // Unless required by applicable law or agreed to in writing, software
2675
+ // distributed under the License is distributed on an "AS IS" BASIS,
2676
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2677
+ // See the License for the specific language governing permissions and
2678
+ // limitations under the License.
2679
+
2680
+ /**
2681
+ * @fileoverview
2682
+ * An HTML sanitizer that can satisfy a variety of security policies.
2683
+ *
2684
+ * <p>
2685
+ * The HTML sanitizer is built around a SAX parser and HTML element and
2686
+ * attributes schemas.
2687
+ *
2688
+ * If the cssparser is loaded, inline styles are sanitized using the
2689
+ * css property and value schemas. Else they are remove during
2690
+ * sanitization.
2691
+ *
2692
+ * If it exists, uses parseCssDeclarations, sanitizeCssProperty, cssSchema
2693
+ *
2694
+ * @author mikesamuel@gmail.com
2695
+ * @author jasvir@gmail.com
2696
+ * \@requires html4
2697
+ * \@overrides window
2698
+ * \@provides html, html_sanitize
2699
+ */
2700
+
2701
+ /**
2702
+ * \@namespace
2703
+ */
2704
+ var html = (function(html4) {
2705
+
2706
+ // For closure compiler
2707
+ var parseCssDeclarations, sanitizeCssProperty, cssSchema;
2708
+ if ('undefined' !== typeof window) {
2709
+ parseCssDeclarations = window['parseCssDeclarations'];
2710
+ sanitizeCssProperty = window['sanitizeCssProperty'];
2711
+ cssSchema = window['cssSchema'];
2712
+ }
2713
+
2714
+ var lcase;
2715
+ // The below may not be true on browsers in the Turkish locale.
2716
+ if ('script' === 'SCRIPT'.toLowerCase()) {
2717
+ lcase = function(s) { return s.toLowerCase(); };
2718
+ } else {
2719
+ /**
2720
+ * {\@updoc
2721
+ * $ lcase('SCRIPT')
2722
+ * # 'script'
2723
+ * $ lcase('script')
2724
+ * # 'script'
2725
+ * }
2726
+ */
2727
+ lcase = function(s) {
2728
+ return s.replace(
2729
+ /[A-Z]/g,
2730
+ function(ch) {
2731
+ return String.fromCharCode(ch.charCodeAt(0) | 32);
2732
+ });
2733
+ };
2734
+ }
2735
+
2736
+ // The keys of this object must be 'quoted' or JSCompiler will mangle them!
2737
+ var ENTITIES = {
2738
+ 'lt': '<',
2739
+ 'gt': '>',
2740
+ 'amp': '&',
2741
+ 'nbsp': '\xA0',
2742
+ 'quot': '"',
2743
+ 'apos': '\''
2744
+ };
2745
+
2746
+ var decimalEscapeRe = /^#(\d+)$/;
2747
+ var hexEscapeRe = /^#x([0-9A-Fa-f]+)$/;
2748
+ /**
2749
+ * Decodes an HTML entity.
2750
+ *
2751
+ * {\@updoc
2752
+ * $ lookupEntity('lt')
2753
+ * # '<'
2754
+ * $ lookupEntity('GT')
2755
+ * # '>'
2756
+ * $ lookupEntity('amp')
2757
+ * # '&'
2758
+ * $ lookupEntity('nbsp')
2759
+ * # '\xA0'
2760
+ * $ lookupEntity('apos')
2761
+ * # "'"
2762
+ * $ lookupEntity('quot')
2763
+ * # '"'
2764
+ * $ lookupEntity('#xa')
2765
+ * # '\n'
2766
+ * $ lookupEntity('#10')
2767
+ * # '\n'
2768
+ * $ lookupEntity('#x0a')
2769
+ * # '\n'
2770
+ * $ lookupEntity('#010')
2771
+ * # '\n'
2772
+ * $ lookupEntity('#x00A')
2773
+ * # '\n'
2774
+ * $ lookupEntity('Pi') // Known failure
2775
+ * # '\u03A0'
2776
+ * $ lookupEntity('pi') // Known failure
2777
+ * # '\u03C0'
2778
+ * }
2779
+ *
2780
+ * @param {string} name the content between the '&' and the ';'.
2781
+ * @return {string} a single unicode code-point as a string.
2782
+ */
2783
+ function lookupEntity(name) {
2784
+ name = lcase(name); // TODO: &pi; is different from &Pi;
2785
+ if (ENTITIES.hasOwnProperty(name)) { return ENTITIES[name]; }
2786
+ var m = name.match(decimalEscapeRe);
2787
+ if (m) {
2788
+ return String.fromCharCode(parseInt(m[1], 10));
2789
+ } else if (!!(m = name.match(hexEscapeRe))) {
2790
+ return String.fromCharCode(parseInt(m[1], 16));
2791
+ }
2792
+ return '';
2793
+ }
2794
+
2795
+ function decodeOneEntity(_, name) {
2796
+ return lookupEntity(name);
2797
+ }
2798
+
2799
+ var nulRe = /\0/g;
2800
+ function stripNULs(s) {
2801
+ return s.replace(nulRe, '');
2802
+ }
2803
+
2804
+ var entityRe = /&(#\d+|#x[0-9A-Fa-f]+|\w+);/g;
2805
+ /**
2806
+ * The plain text of a chunk of HTML CDATA which possibly containing.
2807
+ *
2808
+ * {\@updoc
2809
+ * $ unescapeEntities('')
2810
+ * # ''
2811
+ * $ unescapeEntities('hello World!')
2812
+ * # 'hello World!'
2813
+ * $ unescapeEntities('1 &lt; 2 &amp;&AMP; 4 &gt; 3&#10;')
2814
+ * # '1 < 2 && 4 > 3\n'
2815
+ * $ unescapeEntities('&lt;&lt <- unfinished entity&gt;')
2816
+ * # '<&lt <- unfinished entity>'
2817
+ * $ unescapeEntities('/foo?bar=baz&copy=true') // & often unescaped in URLS
2818
+ * # '/foo?bar=baz&copy=true'
2819
+ * $ unescapeEntities('pi=&pi;&#x3c0;, Pi=&Pi;\u03A0') // FIXME: known failure
2820
+ * # 'pi=\u03C0\u03c0, Pi=\u03A0\u03A0'
2821
+ * }
2822
+ *
2823
+ * @param {string} s a chunk of HTML CDATA. It must not start or end inside
2824
+ * an HTML entity.
2825
+ */
2826
+ function unescapeEntities(s) {
2827
+ return s.replace(entityRe, decodeOneEntity);
2828
+ }
2829
+
2830
+ var ampRe = /&/g;
2831
+ var looseAmpRe = /&([^a-z#]|#(?:[^0-9x]|x(?:[^0-9a-f]|$)|$)|$)/gi;
2832
+ var ltRe = /[<]/g;
2833
+ var gtRe = />/g;
2834
+ var quotRe = /\"/g;
2835
+
2836
+ /**
2837
+ * Escapes HTML special characters in attribute values.
2838
+ *
2839
+ * {\@updoc
2840
+ * $ escapeAttrib('')
2841
+ * # ''
2842
+ * $ escapeAttrib('"<<&==&>>"') // Do not just escape the first occurrence.
2843
+ * # '&#34;&lt;&lt;&amp;&#61;&#61;&amp;&gt;&gt;&#34;'
2844
+ * $ escapeAttrib('Hello <World>!')
2845
+ * # 'Hello &lt;World&gt;!'
2846
+ * }
2847
+ */
2848
+ function escapeAttrib(s) {
2849
+ return ('' + s).replace(ampRe, '&amp;').replace(ltRe, '&lt;')
2850
+ .replace(gtRe, '&gt;').replace(quotRe, '&#34;');
2851
+ }
2852
+
2853
+ /**
2854
+ * Escape entities in RCDATA that can be escaped without changing the meaning.
2855
+ * {\@updoc
2856
+ * $ normalizeRCData('1 < 2 &&amp; 3 > 4 &amp;& 5 &lt; 7&8')
2857
+ * # '1 &lt; 2 &amp;&amp; 3 &gt; 4 &amp;&amp; 5 &lt; 7&amp;8'
2858
+ * }
2859
+ */
2860
+ function normalizeRCData(rcdata) {
2861
+ return rcdata
2862
+ .replace(looseAmpRe, '&amp;$1')
2863
+ .replace(ltRe, '&lt;')
2864
+ .replace(gtRe, '&gt;');
2865
+ }
2866
+
2867
+ // TODO(mikesamuel): validate sanitizer regexs against the HTML5 grammar at
2868
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html
2869
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html
2870
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
2871
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html
2872
+
2873
+ // We initially split input so that potentially meaningful characters
2874
+ // like '<' and '>' are separate tokens, using a fast dumb process that
2875
+ // ignores quoting. Then we walk that token stream, and when we see a
2876
+ // '<' that's the start of a tag, we use ATTR_RE to extract tag
2877
+ // attributes from the next token. That token will never have a '>'
2878
+ // character. However, it might have an unbalanced quote character, and
2879
+ // when we see that, we combine additional tokens to balance the quote.
2880
+
2881
+ var ATTR_RE = new RegExp(
2882
+ '^\\s*' +
2883
+ '([a-z][a-z-]*)' + // 1 = Attribute name
2884
+ '(?:' + (
2885
+ '\\s*(=)\\s*' + // 2 = Is there a value?
2886
+ '(' + ( // 3 = Attribute value
2887
+ // TODO(felix8a): maybe use backref to match quotes
2888
+ '(\")[^\"]*(\"|$)' + // 4, 5 = Double-quoted string
2889
+ '|' +
2890
+ '(\')[^\']*(\'|$)' + // 6, 7 = Single-quoted string
2891
+ '|' +
2892
+ // Positive lookahead to prevent interpretation of
2893
+ // <foo a= b=c> as <foo a='b=c'>
2894
+ // TODO(felix8a): might be able to drop this case
2895
+ '(?=[a-z][a-z-]*\\s*=)' +
2896
+ '|' +
2897
+ // Unquoted value that isn't an attribute name
2898
+ // (since we didn't match the positive lookahead above)
2899
+ '[^\"\'\\s]*' ) +
2900
+ ')' ) +
2901
+ ')?',
2902
+ 'i');
2903
+
2904
+ var ENTITY_RE = /^(#[0-9]+|#x[0-9a-f]+|\w+);/i;
2905
+
2906
+ // false on IE<=8, true on most other browsers
2907
+ var splitWillCapture = ('a,b'.split(/(,)/).length === 3);
2908
+
2909
+ // bitmask for tags with special parsing, like <script> and <textarea>
2910
+ var EFLAGS_TEXT = html4.eflags.CDATA | html4.eflags.RCDATA;
2911
+
2912
+ /**
2913
+ * Given a SAX-like event handler, produce a function that feeds those
2914
+ * events and a parameter to the event handler.
2915
+ *
2916
+ * The event handler has the form:{@code
2917
+ * {
2918
+ * // Name is an upper-case HTML tag name. Attribs is an array of
2919
+ * // alternating upper-case attribute names, and attribute values. The
2920
+ * // attribs array is reused by the parser. Param is the value passed to
2921
+ * // the saxParser.
2922
+ * startTag: function (name, attribs, param) { ... },
2923
+ * endTag: function (name, param) { ... },
2924
+ * pcdata: function (text, param) { ... },
2925
+ * rcdata: function (text, param) { ... },
2926
+ * cdata: function (text, param) { ... },
2927
+ * startDoc: function (param) { ... },
2928
+ * endDoc: function (param) { ... }
2929
+ * }}
2930
+ *
2931
+ * @param {Object} handler a record containing event handlers.
2932
+ * @return {function(string, Object)} A function that takes a chunk of HTML
2933
+ * and a parameter. The parameter is passed on to the handler methods.
2934
+ */
2935
+ function makeSaxParser(handler) {
2936
+ return function(htmlText, param) {
2937
+ return parse(htmlText, handler, param);
2938
+ };
2939
+ }
2940
+
2941
+ // Parsing strategy is to split input into parts that might be lexically
2942
+ // meaningful (every ">" becomes a separate part), and then recombine
2943
+ // parts if we discover they're in a different context.
2944
+
2945
+ // Note, html-sanitizer filters unknown tags here, even though they also
2946
+ // get filtered out by the sanitizer's handler. This is back-compat
2947
+ // behavior; makeSaxParser is public.
2948
+
2949
+ // TODO(felix8a): Significant performance regressions from -legacy,
2950
+ // tested on
2951
+ // Chrome 18.0
2952
+ // Firefox 11.0
2953
+ // IE 6, 7, 8, 9
2954
+ // Opera 11.61
2955
+ // Safari 5.1.3
2956
+ // Many of these are unusual patterns that are linearly slower and still
2957
+ // pretty fast (eg 1ms to 5ms), so not necessarily worth fixing.
2958
+
2959
+ // TODO(felix8a): "<script> && && && ... <\/script>" is slower on all
2960
+ // browsers. The hotspot is htmlSplit.
2961
+
2962
+ // TODO(felix8a): "<p title='>>>>...'><\/p>" is slower on all browsers.
2963
+ // This is partly htmlSplit, but the hotspot is parseTagAndAttrs.
2964
+
2965
+ // TODO(felix8a): "<a><\/a><a><\/a>..." is slower on IE9.
2966
+ // "<a>1<\/a><a>1<\/a>..." is faster, "<a><\/a>2<a><\/a>2..." is faster.
2967
+
2968
+ // TODO(felix8a): "<p<p<p..." is slower on IE[6-8]
2969
+
2970
+ var continuationMarker = {};
2971
+ function parse(htmlText, handler, param) {
2972
+ var h = handler;
2973
+ var m, p, tagName;
2974
+ var parts = htmlSplit(htmlText);
2975
+ var state = {
2976
+ noMoreGT: false,
2977
+ noMoreEndComments: false
2978
+ };
2979
+ parseCPS(handler, parts, 0, state, param);
2980
+ }
2981
+
2982
+ function continuationMaker(h, parts, initial, state, param) {
2983
+ return function () {
2984
+ parseCPS(h, parts, initial, state, param);
2985
+ };
2986
+ }
2987
+
2988
+ function parseCPS(h, parts, initial, state, param) {
2989
+ try {
2990
+ if (h.startDoc && initial == 0) { h.startDoc(param); }
2991
+ var m, p, tagName;
2992
+ for (var pos = initial, end = parts.length; pos < end;) {
2993
+ var current = parts[pos++];
2994
+ var next = parts[pos];
2995
+ switch (current) {
2996
+ case '&':
2997
+ if (ENTITY_RE.test(next)) {
2998
+ if (h.pcdata) {
2999
+ h.pcdata('&' + next, param, continuationMarker,
3000
+ continuationMaker(h, parts, pos, state, param));
3001
+ }
3002
+ pos++;
3003
+ } else {
3004
+ if (h.pcdata) { h.pcdata("&amp;", param, continuationMarker,
3005
+ continuationMaker(h, parts, pos, state, param));
3006
+ }
3007
+ }
3008
+ break;
3009
+ case '<\/':
3010
+ if (m = /^(\w+)[^\'\"]*/.exec(next)) {
3011
+ if (m[0].length === next.length && parts[pos + 1] === '>') {
3012
+ // fast case, no attribute parsing needed
3013
+ pos += 2;
3014
+ tagName = lcase(m[1]);
3015
+ if (html4.ELEMENTS.hasOwnProperty(tagName)) {
3016
+ if (h.endTag) {
3017
+ h.endTag(tagName, param, continuationMarker,
3018
+ continuationMaker(h, parts, pos, state, param));
3019
+ }
3020
+ }
3021
+ } else {
3022
+ // slow case, need to parse attributes
3023
+ // TODO(felix8a): do we really care about misparsing this?
3024
+ pos = parseEndTag(
3025
+ parts, pos, h, param, continuationMarker, state);
3026
+ }
3027
+ } else {
3028
+ if (h.pcdata) {
3029
+ h.pcdata('&lt;/', param, continuationMarker,
3030
+ continuationMaker(h, parts, pos, state, param));
3031
+ }
3032
+ }
3033
+ break;
3034
+ case '<':
3035
+ if (m = /^(\w+)\s*\/?/.exec(next)) {
3036
+ if (m[0].length === next.length && parts[pos + 1] === '>') {
3037
+ // fast case, no attribute parsing needed
3038
+ pos += 2;
3039
+ tagName = lcase(m[1]);
3040
+ if (html4.ELEMENTS.hasOwnProperty(tagName)) {
3041
+ if (h.startTag) {
3042
+ h.startTag(tagName, [], param, continuationMarker,
3043
+ continuationMaker(h, parts, pos, state, param));
3044
+ }
3045
+ // tags like <script> and <textarea> have special parsing
3046
+ var eflags = html4.ELEMENTS[tagName];
3047
+ if (eflags & EFLAGS_TEXT) {
3048
+ var tag = { name: tagName, next: pos, eflags: eflags };
3049
+ pos = parseText(
3050
+ parts, tag, h, param, continuationMarker, state);
3051
+ }
3052
+ }
3053
+ } else {
3054
+ // slow case, need to parse attributes
3055
+ pos = parseStartTag(
3056
+ parts, pos, h, param, continuationMarker, state);
3057
+ }
3058
+ } else {
3059
+ if (h.pcdata) {
3060
+ h.pcdata('&lt;', param, continuationMarker,
3061
+ continuationMaker(h, parts, pos, state, param));
3062
+ }
3063
+ }
3064
+ break;
3065
+ case '<\!--':
3066
+ // The pathological case is n copies of '<\!--' without '-->', and
3067
+ // repeated failure to find '-->' is quadratic. We avoid that by
3068
+ // remembering when search for '-->' fails.
3069
+ if (!state.noMoreEndComments) {
3070
+ // A comment <\!--x--> is split into three tokens:
3071
+ // '<\!--', 'x--', '>'
3072
+ // We want to find the next '>' token that has a preceding '--'.
3073
+ // pos is at the 'x--'.
3074
+ for (p = pos + 1; p < end; p++) {
3075
+ if (parts[p] === '>' && /--$/.test(parts[p - 1])) { break; }
3076
+ }
3077
+ if (p < end) {
3078
+ pos = p + 1;
3079
+ } else {
3080
+ state.noMoreEndComments = true;
3081
+ }
3082
+ }
3083
+ if (state.noMoreEndComments) {
3084
+ if (h.pcdata) {
3085
+ h.pcdata('&lt;!--', param, continuationMarker,
3086
+ continuationMaker(h, parts, pos, state, param));
3087
+ }
3088
+ }
3089
+ break;
3090
+ case '<\!':
3091
+ if (!/^\w/.test(next)) {
3092
+ if (h.pcdata) {
3093
+ h.pcdata('&lt;!', param, continuationMarker,
3094
+ continuationMaker(h, parts, pos, state, param));
3095
+ }
3096
+ } else {
3097
+ // similar to noMoreEndComment logic
3098
+ if (!state.noMoreGT) {
3099
+ for (p = pos + 1; p < end; p++) {
3100
+ if (parts[p] === '>') { break; }
3101
+ }
3102
+ if (p < end) {
3103
+ pos = p + 1;
3104
+ } else {
3105
+ state.noMoreGT = true;
3106
+ }
3107
+ }
3108
+ if (state.noMoreGT) {
3109
+ if (h.pcdata) {
3110
+ h.pcdata('&lt;!', param, continuationMarker,
3111
+ continuationMaker(h, parts, pos, state, param));
3112
+ }
3113
+ }
3114
+ }
3115
+ break;
3116
+ case '<?':
3117
+ // similar to noMoreEndComment logic
3118
+ if (!state.noMoreGT) {
3119
+ for (p = pos + 1; p < end; p++) {
3120
+ if (parts[p] === '>') { break; }
3121
+ }
3122
+ if (p < end) {
3123
+ pos = p + 1;
3124
+ } else {
3125
+ state.noMoreGT = true;
3126
+ }
3127
+ }
3128
+ if (state.noMoreGT) {
3129
+ if (h.pcdata) {
3130
+ h.pcdata('&lt;?', param, continuationMarker,
3131
+ continuationMaker(h, parts, pos, state, param));
3132
+ }
3133
+ }
3134
+ break;
3135
+ case '>':
3136
+ if (h.pcdata) {
3137
+ h.pcdata("&gt;", param, continuationMarker,
3138
+ continuationMaker(h, parts, pos, state, param));
3139
+ }
3140
+ break;
3141
+ case '':
3142
+ break;
3143
+ default:
3144
+ if (h.pcdata) {
3145
+ h.pcdata(current, param, continuationMarker,
3146
+ continuationMaker(h, parts, pos, state, param));
3147
+ }
3148
+ break;
3149
+ }
3150
+ }
3151
+ if (h.endDoc) { h.endDoc(param); }
3152
+ } catch (e) {
3153
+ if (e !== continuationMarker) { throw e; }
3154
+ }
3155
+ }
3156
+
3157
+ // Split str into parts for the html parser.
3158
+ function htmlSplit(str) {
3159
+ // can't hoist this out of the function because of the re.exec loop.
3160
+ var re = /(<\/|<\!--|<[!?]|[&<>])/g;
3161
+ str += '';
3162
+ if (splitWillCapture) {
3163
+ return str.split(re);
3164
+ } else {
3165
+ var parts = [];
3166
+ var lastPos = 0;
3167
+ var m;
3168
+ while ((m = re.exec(str)) !== null) {
3169
+ parts.push(str.substring(lastPos, m.index));
3170
+ parts.push(m[0]);
3171
+ lastPos = m.index + m[0].length;
3172
+ }
3173
+ parts.push(str.substring(lastPos));
3174
+ return parts;
3175
+ }
3176
+ }
3177
+
3178
+ function parseEndTag(parts, pos, h, param, continuationMarker, state) {
3179
+ var tag = parseTagAndAttrs(parts, pos);
3180
+ // drop unclosed tags
3181
+ if (!tag) { return parts.length; }
3182
+ if (tag.eflags !== void 0) {
3183
+ if (h.endTag) {
3184
+ h.endTag(tag.name, param, continuationMarker,
3185
+ continuationMaker(h, parts, pos, state, param));
3186
+ }
3187
+ }
3188
+ return tag.next;
3189
+ }
3190
+
3191
+ function parseStartTag(parts, pos, h, param, continuationMarker, state) {
3192
+ var tag = parseTagAndAttrs(parts, pos);
3193
+ // drop unclosed tags
3194
+ if (!tag) { return parts.length; }
3195
+ if (tag.eflags !== void 0) {
3196
+ if (h.startTag) {
3197
+ h.startTag(tag.name, tag.attrs, param, continuationMarker,
3198
+ continuationMaker(h, parts, tag.next, state, param));
3199
+ }
3200
+ // tags like <script> and <textarea> have special parsing
3201
+ if (tag.eflags & EFLAGS_TEXT) {
3202
+ return parseText(parts, tag, h, param, continuationMarker, state);
3203
+ }
3204
+ }
3205
+ return tag.next;
3206
+ }
3207
+
3208
+ var endTagRe = {};
3209
+
3210
+ // Tags like <script> and <textarea> are flagged as CDATA or RCDATA,
3211
+ // which means everything is text until we see the correct closing tag.
3212
+ function parseText(parts, tag, h, param, continuationMarker, state) {
3213
+ var end = parts.length;
3214
+ if (!endTagRe.hasOwnProperty(tag.name)) {
3215
+ endTagRe[tag.name] = new RegExp('^' + tag.name + '(?:[\\s\\/]|$)', 'i');
3216
+ }
3217
+ var re = endTagRe[tag.name];
3218
+ var first = tag.next;
3219
+ var p = tag.next + 1;
3220
+ for (; p < end; p++) {
3221
+ if (parts[p - 1] === '<\/' && re.test(parts[p])) { break; }
3222
+ }
3223
+ if (p < end) { p -= 1; }
3224
+ var buf = parts.slice(first, p).join('');
3225
+ if (tag.eflags & html4.eflags.CDATA) {
3226
+ if (h.cdata) {
3227
+ h.cdata(buf, param, continuationMarker,
3228
+ continuationMaker(h, parts, p, state, param));
3229
+ }
3230
+ } else if (tag.eflags & html4.eflags.RCDATA) {
3231
+ if (h.rcdata) {
3232
+ h.rcdata(normalizeRCData(buf), param, continuationMarker,
3233
+ continuationMaker(h, parts, p, state, param));
3234
+ }
3235
+ } else {
3236
+ throw new Error('bug');
3237
+ }
3238
+ return p;
3239
+ }
3240
+
3241
+ // at this point, parts[pos-1] is either "<" or "<\/".
3242
+ function parseTagAndAttrs(parts, pos) {
3243
+ var m = /^(\w+)/.exec(parts[pos]);
3244
+ var tag = { name: lcase(m[1]) };
3245
+ if (html4.ELEMENTS.hasOwnProperty(tag.name)) {
3246
+ tag.eflags = html4.ELEMENTS[tag.name];
3247
+ } else {
3248
+ tag.eflags = void 0;
3249
+ }
3250
+ var buf = parts[pos].substr(m[0].length);
3251
+ // Find the next '>'. We optimistically assume this '>' is not in a
3252
+ // quoted context, and further down we fix things up if it turns out to
3253
+ // be quoted.
3254
+ var p = pos + 1;
3255
+ var end = parts.length;
3256
+ for (; p < end; p++) {
3257
+ if (parts[p] === '>') { break; }
3258
+ buf += parts[p];
3259
+ }
3260
+ if (end <= p) { return void 0; }
3261
+ var attrs = [];
3262
+ while (buf !== '') {
3263
+ m = ATTR_RE.exec(buf);
3264
+ if (!m) {
3265
+ // No attribute found: skip garbage
3266
+ buf = buf.replace(/^[\s\S][^a-z\s]*/, '');
3267
+
3268
+ } else if ((m[4] && !m[5]) || (m[6] && !m[7])) {
3269
+ // Unterminated quote: slurp to the next unquoted '>'
3270
+ var quote = m[4] || m[6];
3271
+ var sawQuote = false;
3272
+ var abuf = [buf, parts[p++]];
3273
+ for (; p < end; p++) {
3274
+ if (sawQuote) {
3275
+ if (parts[p] === '>') { break; }
3276
+ } else if (0 <= parts[p].indexOf(quote)) {
3277
+ sawQuote = true;
3278
+ }
3279
+ abuf.push(parts[p]);
3280
+ }
3281
+ // Slurp failed: lose the garbage
3282
+ if (end <= p) { break; }
3283
+ // Otherwise retry attribute parsing
3284
+ buf = abuf.join('');
3285
+ continue;
3286
+
3287
+ } else {
3288
+ // We have an attribute
3289
+ var aName = lcase(m[1]);
3290
+ var aValue = m[2] ? decodeValue(m[3]) : aName;
3291
+ attrs.push(aName, aValue);
3292
+ buf = buf.substr(m[0].length);
3293
+ }
3294
+ }
3295
+ tag.attrs = attrs;
3296
+ tag.next = p + 1;
3297
+ return tag;
3298
+ }
3299
+
3300
+ function decodeValue(v) {
3301
+ var q = v.charCodeAt(0);
3302
+ if (q === 0x22 || q === 0x27) { // " or '
3303
+ v = v.substr(1, v.length - 2);
3304
+ }
3305
+ return unescapeEntities(stripNULs(v));
3306
+ }
3307
+
3308
+ /**
3309
+ * Returns a function that strips unsafe tags and attributes from html.
3310
+ * @param {function(string, Array.<string>): ?Array.<string>} tagPolicy
3311
+ * A function that takes (tagName, attribs[]), where tagName is a key in
3312
+ * html4.ELEMENTS and attribs is an array of alternating attribute names
3313
+ * and values. It should return a sanitized attribute array, or null to
3314
+ * delete the tag. It's okay for tagPolicy to modify the attribs array,
3315
+ * but the same array is reused, so it should not be held between calls.
3316
+ * @return {function(string, Array)} A function that sanitizes a string of
3317
+ * HTML and appends result strings to the second argument, an array.
3318
+ */
3319
+ function makeHtmlSanitizer(tagPolicy) {
3320
+ var stack;
3321
+ var ignoring;
3322
+ var emit = function (text, out) {
3323
+ if (!ignoring) { out.push(text); }
3324
+ };
3325
+ return makeSaxParser({
3326
+ startDoc: function(_) {
3327
+ stack = [];
3328
+ ignoring = false;
3329
+ },
3330
+ startTag: function(tagName, attribs, out) {
3331
+ if (ignoring) { return; }
3332
+ if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
3333
+ var eflags = html4.ELEMENTS[tagName];
3334
+ if (eflags & html4.eflags.FOLDABLE) {
3335
+ return;
3336
+ }
3337
+ attribs = tagPolicy(tagName, attribs);
3338
+ if (!attribs) {
3339
+ ignoring = !(eflags & html4.eflags.EMPTY);
3340
+ return;
3341
+ }
3342
+ // TODO(mikesamuel): relying on tagPolicy not to insert unsafe
3343
+ // attribute names.
3344
+ if (!(eflags & html4.eflags.EMPTY)) {
3345
+ stack.push(tagName);
3346
+ }
3347
+
3348
+ out.push('<', tagName);
3349
+ for (var i = 0, n = attribs.length; i < n; i += 2) {
3350
+ var attribName = attribs[i],
3351
+ value = attribs[i + 1];
3352
+ if (value !== null && value !== void 0) {
3353
+ out.push(' ', attribName, '="', escapeAttrib(value), '"');
3354
+ }
3355
+ }
3356
+ out.push('>');
3357
+ },
3358
+ endTag: function(tagName, out) {
3359
+ if (ignoring) {
3360
+ ignoring = false;
3361
+ return;
3362
+ }
3363
+ if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
3364
+ var eflags = html4.ELEMENTS[tagName];
3365
+ if (!(eflags & (html4.eflags.EMPTY | html4.eflags.FOLDABLE))) {
3366
+ var index;
3367
+ if (eflags & html4.eflags.OPTIONAL_ENDTAG) {
3368
+ for (index = stack.length; --index >= 0;) {
3369
+ var stackEl = stack[index];
3370
+ if (stackEl === tagName) { break; }
3371
+ if (!(html4.ELEMENTS[stackEl] &
3372
+ html4.eflags.OPTIONAL_ENDTAG)) {
3373
+ // Don't pop non optional end tags looking for a match.
3374
+ return;
3375
+ }
3376
+ }
3377
+ } else {
3378
+ for (index = stack.length; --index >= 0;) {
3379
+ if (stack[index] === tagName) { break; }
3380
+ }
3381
+ }
3382
+ if (index < 0) { return; } // Not opened.
3383
+ for (var i = stack.length; --i > index;) {
3384
+ var stackEl = stack[i];
3385
+ if (!(html4.ELEMENTS[stackEl] &
3386
+ html4.eflags.OPTIONAL_ENDTAG)) {
3387
+ out.push('<\/', stackEl, '>');
3388
+ }
3389
+ }
3390
+ stack.length = index;
3391
+ out.push('<\/', tagName, '>');
3392
+ }
3393
+ },
3394
+ pcdata: emit,
3395
+ rcdata: emit,
3396
+ cdata: emit,
3397
+ endDoc: function(out) {
3398
+ for (; stack.length; stack.length--) {
3399
+ out.push('<\/', stack[stack.length - 1], '>');
3400
+ }
3401
+ }
3402
+ });
3403
+ }
3404
+
3405
+ // From RFC3986
3406
+ var URI_SCHEME_RE = new RegExp(
3407
+ '^' +
3408
+ '(?:' +
3409
+ '([^:\/?# ]+)' + // scheme
3410
+ ':)?'
3411
+ );
3412
+
3413
+ var ALLOWED_URI_SCHEMES = /^(?:https?|mailto)$/i;
3414
+
3415
+ function safeUri(uri, naiveUriRewriter) {
3416
+ if (!naiveUriRewriter) { return null; }
3417
+ var parsed = ('' + uri).match(URI_SCHEME_RE);
3418
+ if (parsed && (!parsed[1] || ALLOWED_URI_SCHEMES.test(parsed[1]))) {
3419
+ return naiveUriRewriter(uri);
3420
+ } else {
3421
+ return null;
3422
+ }
3423
+ }
3424
+
3425
+ /**
3426
+ * Sanitizes attributes on an HTML tag.
3427
+ * @param {string} tagName An HTML tag name in lowercase.
3428
+ * @param {Array.<?string>} attribs An array of alternating names and values.
3429
+ * @param {?function(?string): ?string} opt_naiveUriRewriter A transform to
3430
+ * apply to URI attributes; it can return a new string value, or null to
3431
+ * delete the attribute. If unspecified, URI attributes are deleted.
3432
+ * @param {function(?string): ?string} opt_nmTokenPolicy A transform to apply
3433
+ * to attributes containing HTML names, element IDs, and space-separated
3434
+ * lists of classes; it can return a new string value, or null to delete
3435
+ * the attribute. If unspecified, these attributes are kept unchanged.
3436
+ * @return {Array.<?string>} The sanitized attributes as a list of alternating
3437
+ * names and values, where a null value means to omit the attribute.
3438
+ */
3439
+ function sanitizeAttribs(
3440
+ tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy) {
3441
+ for (var i = 0; i < attribs.length; i += 2) {
3442
+ var attribName = attribs[i];
3443
+ var value = attribs[i + 1];
3444
+ var atype = null, attribKey;
3445
+ if ((attribKey = tagName + '::' + attribName,
3446
+ html4.ATTRIBS.hasOwnProperty(attribKey)) ||
3447
+ (attribKey = '*::' + attribName,
3448
+ html4.ATTRIBS.hasOwnProperty(attribKey))) {
3449
+ atype = html4.ATTRIBS[attribKey];
3450
+ }
3451
+ if (atype !== null) {
3452
+ switch (atype) {
3453
+ case html4.atype.NONE: break;
3454
+ case html4.atype.SCRIPT:
3455
+ value = null;
3456
+ break;
3457
+ case html4.atype.STYLE:
3458
+ if ('undefined' === typeof parseCssDeclarations) {
3459
+ value = null;
3460
+ break;
3461
+ }
3462
+ var sanitizedDeclarations = [];
3463
+ parseCssDeclarations(
3464
+ value,
3465
+ {
3466
+ declaration: function (property, tokens) {
3467
+ var normProp = property.toLowerCase();
3468
+ var schema = cssSchema[normProp];
3469
+ if (!schema) {
3470
+ return;
3471
+ }
3472
+ sanitizeCssProperty(
3473
+ normProp, schema, tokens,
3474
+ opt_naiveUriRewriter);
3475
+ sanitizedDeclarations.push(property + ': ' + tokens.join(' '));
3476
+ }
3477
+ });
3478
+ value = sanitizedDeclarations.length > 0 ? sanitizedDeclarations.join(' ; ') : null;
3479
+ break;
3480
+ case html4.atype.ID:
3481
+ case html4.atype.IDREF:
3482
+ case html4.atype.IDREFS:
3483
+ case html4.atype.GLOBAL_NAME:
3484
+ case html4.atype.LOCAL_NAME:
3485
+ case html4.atype.CLASSES:
3486
+ value = opt_nmTokenPolicy ? opt_nmTokenPolicy(value) : value;
3487
+ break;
3488
+ case html4.atype.URI:
3489
+ value = safeUri(value, opt_naiveUriRewriter);
3490
+ break;
3491
+ case html4.atype.URI_FRAGMENT:
3492
+ if (value && '#' === value.charAt(0)) {
3493
+ value = value.substring(1); // remove the leading '#'
3494
+ value = opt_nmTokenPolicy ? opt_nmTokenPolicy(value) : value;
3495
+ if (value !== null && value !== void 0) {
3496
+ value = '#' + value; // restore the leading '#'
3497
+ }
3498
+ } else {
3499
+ value = null;
3500
+ }
3501
+ break;
3502
+ default:
3503
+ value = null;
3504
+ break;
3505
+ }
3506
+ } else {
3507
+ value = null;
3508
+ }
3509
+ attribs[i + 1] = value;
3510
+ }
3511
+ return attribs;
3512
+ }
3513
+
3514
+ /**
3515
+ * Creates a tag policy that omits all tags marked UNSAFE in html4-defs.js
3516
+ * and applies the default attribute sanitizer with the supplied policy for
3517
+ * URI attributes and NMTOKEN attributes.
3518
+ * @param {?function(?string): ?string} opt_naiveUriRewriter A transform to
3519
+ * apply to URI attributes. If not given, URI attributes are deleted.
3520
+ * @param {function(?string): ?string} opt_nmTokenPolicy A transform to apply
3521
+ * to attributes containing HTML names, element IDs, and space-separated
3522
+ * lists of classes. If not given, such attributes are left unchanged.
3523
+ * @return {function(string, Array.<?string>)} A tagPolicy suitable for
3524
+ * passing to html.sanitize.
3525
+ */
3526
+ function makeTagPolicy(opt_naiveUriRewriter, opt_nmTokenPolicy) {
3527
+ return function(tagName, attribs) {
3528
+ if (!(html4.ELEMENTS[tagName] & html4.eflags.UNSAFE)) {
3529
+ return sanitizeAttribs(
3530
+ tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy);
3531
+ }
3532
+ };
3533
+ }
3534
+
3535
+ /**
3536
+ * Sanitizes HTML tags and attributes according to a given policy.
3537
+ * @param {string} inputHtml The HTML to sanitize.
3538
+ * @param {function(string, Array.<?string>)} tagPolicy A function that
3539
+ * decides which tags to accept and sanitizes their attributes (see
3540
+ * makeHtmlSanitizer above for details).
3541
+ * @return {string} The sanitized HTML.
3542
+ */
3543
+ function sanitizeWithPolicy(inputHtml, tagPolicy) {
3544
+ var outputArray = [];
3545
+ makeHtmlSanitizer(tagPolicy)(inputHtml, outputArray);
3546
+ return outputArray.join('');
3547
+ }
3548
+
3549
+ /**
3550
+ * Strips unsafe tags and attributes from HTML.
3551
+ * @param {string} inputHtml The HTML to sanitize.
3552
+ * @param {?function(?string): ?string} opt_naiveUriRewriter A transform to
3553
+ * apply to URI attributes. If not given, URI attributes are deleted.
3554
+ * @param {function(?string): ?string} opt_nmTokenPolicy A transform to apply
3555
+ * to attributes containing HTML names, element IDs, and space-separated
3556
+ * lists of classes. If not given, such attributes are left unchanged.
3557
+ */
3558
+ function sanitize(inputHtml, opt_naiveUriRewriter, opt_nmTokenPolicy) {
3559
+ var tagPolicy = makeTagPolicy(opt_naiveUriRewriter, opt_nmTokenPolicy);
3560
+ return sanitizeWithPolicy(inputHtml, tagPolicy);
3561
+ }
3562
+
3563
+ return {
3564
+ escapeAttrib: escapeAttrib,
3565
+ makeHtmlSanitizer: makeHtmlSanitizer,
3566
+ makeSaxParser: makeSaxParser,
3567
+ makeTagPolicy: makeTagPolicy,
3568
+ normalizeRCData: normalizeRCData,
3569
+ sanitize: sanitize,
3570
+ sanitizeAttribs: sanitizeAttribs,
3571
+ sanitizeWithPolicy: sanitizeWithPolicy,
3572
+ unescapeEntities: unescapeEntities
3573
+ };
3574
+ })(html4);
3575
+
3576
+ var html_sanitize = html.sanitize;
3577
+
3578
+ // Exports for closure compiler. Note this file is also cajoled
3579
+ // for domado and run in an environment without 'window'
3580
+ if (typeof window !== 'undefined') {
3581
+ window['html'] = html;
3582
+ window['html_sanitize'] = html_sanitize;
3583
+ }
3584
+
3585
+ }());