AMP for WP – Accelerated Mobile Pages - Version 0.9.91

Version Description

Download this release

Release Info

Developer mohammed_kaludi
Plugin Icon 128x128 AMP for WP – Accelerated Mobile Pages
Version 0.9.91
Comparing to
See all releases

Code changes from version 0.9.90 to 0.9.91

Files changed (74) hide show
  1. README.md +1 -1
  2. accelerated-moblie-pages.php +2 -2
  3. classes/class-ampforwp-gallery-embed.php +0 -139
  4. classes/class-ampforwp-iframe-sanitizer.php +0 -198
  5. classes/class-ampforwp-img-sanitizer.php +0 -312
  6. classes/class-ampforwp-vimeo-embed.php +0 -135
  7. images/Bitmap.png +0 -0
  8. images/amplogo.png +0 -0
  9. images/converttoamp.png +0 -0
  10. images/ex-1.png +0 -0
  11. images/ex-2.png +0 -0
  12. images/ex-3.png +0 -0
  13. images/layouts-3.png +0 -0
  14. images/layouts-4.png +0 -0
  15. images/layouts-5.png +0 -0
  16. images/layouts-6.png +0 -0
  17. images/nf.png +0 -0
  18. images/rating.png +0 -0
  19. images/tick.png +0 -0
  20. includes/options/extensions/theme_design_selector/extension_theme_design_selector.php +0 -110
  21. includes/options/extensions/theme_design_selector/theme_design_selector/field_theme_design_selector.css +0 -78
  22. includes/options/extensions/theme_design_selector/theme_design_selector/field_theme_design_selector.js +0 -7
  23. includes/options/extensions/theme_design_selector/theme_design_selector/field_theme_design_selector.php +0 -102
  24. includes/vendor/amp/assets/css/amp-customizer.css +0 -123
  25. includes/vendor/amp/assets/css/amp-default.css +0 -11
  26. includes/vendor/amp/assets/css/amp-playlist-shortcode.css +0 -19
  27. includes/vendor/amp/assets/css/amp-post-meta-box.css +0 -66
  28. includes/vendor/amp/assets/images/amp-icon.svg +0 -7
  29. includes/vendor/amp/assets/images/amp-white-icon.svg +0 -9
  30. includes/vendor/amp/assets/js/amp-customize-controls.js +0 -351
  31. includes/vendor/amp/assets/js/amp-customize-preview.js +0 -26
  32. includes/vendor/amp/assets/js/amp-post-meta-box.js +0 -179
  33. includes/vendor/amp/includes/admin/class-amp-post-meta-box.php +0 -246
  34. includes/vendor/amp/includes/class-amp-autoloader.php +0 -152
  35. includes/vendor/amp/includes/class-amp-comment-walker.php +0 -121
  36. includes/vendor/amp/includes/class-amp-post-type-support.php +0 -99
  37. includes/vendor/amp/includes/class-amp-theme-support.php +0 -1201
  38. includes/vendor/amp/includes/embeds/class-amp-issuu-embed-handler.php +0 -65
  39. includes/vendor/amp/includes/embeds/class-amp-meetup-embed-handler.php +0 -45
  40. includes/vendor/amp/includes/embeds/class-amp-playlist-embed-handler.php +0 -324
  41. includes/vendor/amp/includes/embeds/class-amp-reddit-embed-handler.php +0 -74
  42. includes/vendor/amp/includes/embeds/class-amp-tumblr-embed-handler.php +0 -60
  43. includes/vendor/amp/includes/options/class-amp-analytics-options-submenu.php +0 -61
  44. includes/vendor/amp/includes/options/class-amp-options-manager.php +0 -262
  45. includes/vendor/amp/includes/options/class-amp-options-menu.php +0 -143
  46. includes/vendor/amp/includes/options/views/class-amp-analytics-options-submenu-page.php +0 -102
  47. includes/vendor/amp/includes/sanitizers/class-amp-allowed-tags-generated.php +0 -10776
  48. includes/vendor/amp/includes/sanitizers/class-amp-comments-sanitizer.php +0 -156
  49. includes/vendor/amp/includes/sanitizers/class-amp-form-sanitizer.php +0 -141
  50. includes/vendor/amp/includes/sanitizers/class-amp-rule-spec.php +0 -154
  51. includes/vendor/amp/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php +0 -1630
  52. includes/vendor/amp/includes/templates/class-amp-content-sanitizer.php +0 -98
  53. includes/vendor/amp/includes/templates/class-amp-content.php +0 -192
  54. includes/vendor/amp/includes/templates/class-amp-post-template.php +0 -481
  55. includes/vendor/amp/includes/utils/class-amp-validation-utils.php +0 -1848
  56. includes/vendor/amp/includes/widgets/class-amp-widget-archives.php +0 -103
  57. includes/vendor/amp/includes/widgets/class-amp-widget-categories.php +0 -91
  58. includes/vendor/amp/includes/widgets/class-amp-widget-media-video.php +0 -33
  59. includes/vendor/amp/includes/widgets/class-amp-widget-recent-comments.php +0 -38
  60. includes/vendor/amp/includes/widgets/class-amp-widget-text.php +0 -33
  61. includes/vendor/amp/templates/admin/amp-status.php +0 -71
  62. includes/vendor/amp/templates/header.php +0 -14
  63. includes/vendor/amp/templates/html-end.php +0 -18
  64. includes/vendor/amp/templates/html-start.php +0 -26
  65. includes/vendor/amp/templates/page.php +0 -34
  66. includes/vendor/amp/wpcom-helper.php +0 -237
  67. includes/vendor/amp/wpcom/class-amp-polldaddy-embed.php +0 -101
  68. includes/vendor/amp/wpcom/shortcodes.php +0 -20
  69. includes/vendor/vendor-compatibility.php +0 -342
  70. includes/vendor/vendor-files/class-amp-allowed-tags-generated.php +0 -10822
  71. includes/vendor/vendor-files/class-amp-response-headers.php +0 -88
  72. includes/vendor/vendor-files/class-amp-theme-support.php +0 -1148
  73. includes/vendor/vendor-files/sanitizer/class-amp-core-theme-sanitizer.php +0 -91
  74. includes/vendor/vendor-files/sanitizer/class-amp-style-sanitizer.php +0 -1268
README.md CHANGED
@@ -4,7 +4,7 @@ Tags: AMP, accelerated mobile pages, mobile, amp project, google amp, amp wp, go
4
  Donate link: https://www.paypal.me/Kaludi/25
5
  Requires at least: 3.0
6
  Tested up to: 4.9.5
7
- Stable tag: 0.9.90
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
4
  Donate link: https://www.paypal.me/Kaludi/25
5
  Requires at least: 3.0
6
  Tested up to: 4.9.5
7
+ Stable tag: 0.9.91
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
accelerated-moblie-pages.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Accelerated Mobile Pages
4
  Plugin URI: https://wordpress.org/plugins/accelerated-mobile-pages/
5
  Description: AMP for WP - Accelerated Mobile Pages for WordPress
6
- Version: 0.9.90
7
  Author: Ahmed Kaludi, Mohammed Kaludi
8
  Author URI: https://ampforwp.com/
9
  Donate link: https://www.paypal.me/Kaludi/25
@@ -19,7 +19,7 @@ define('AMPFORWP_PLUGIN_DIR_URI', plugin_dir_url(__FILE__));
19
  define('AMPFORWP_DISQUS_URL',plugin_dir_url(__FILE__).'includes/disqus.html');
20
  define('AMPFORWP_IMAGE_DIR',plugin_dir_url(__FILE__).'images');
21
  define('AMPFORWP_MAIN_PLUGIN_DIR', plugin_dir_path( __DIR__ ) );
22
- define('AMPFORWP_VERSION','0.9.86.2');
23
 
24
  // any changes to AMP_QUERY_VAR should be refelected here
25
  function ampforwp_generate_endpoint(){
3
  Plugin Name: Accelerated Mobile Pages
4
  Plugin URI: https://wordpress.org/plugins/accelerated-mobile-pages/
5
  Description: AMP for WP - Accelerated Mobile Pages for WordPress
6
+ Version: 0.9.91
7
  Author: Ahmed Kaludi, Mohammed Kaludi
8
  Author URI: https://ampforwp.com/
9
  Donate link: https://www.paypal.me/Kaludi/25
19
  define('AMPFORWP_DISQUS_URL',plugin_dir_url(__FILE__).'includes/disqus.html');
20
  define('AMPFORWP_IMAGE_DIR',plugin_dir_url(__FILE__).'images');
21
  define('AMPFORWP_MAIN_PLUGIN_DIR', plugin_dir_path( __DIR__ ) );
22
+ define('AMPFORWP_VERSION','0.9.91');
23
 
24
  // any changes to AMP_QUERY_VAR should be refelected here
25
  function ampforwp_generate_endpoint(){
classes/class-ampforwp-gallery-embed.php DELETED
@@ -1,139 +0,0 @@
1
- <?php
2
-
3
- require_once( AMP__DIR__ . '/includes/embeds/class-amp-base-embed-handler.php' );
4
-
5
- class AMPforWP_Gallery_Embed_Handler extends AMP_Base_Embed_Handler {
6
- private static $script_slug = 'amp-carousel';
7
- private static $script_src = 'https://cdn.ampproject.org/v0/amp-carousel-0.1.js';
8
-
9
- public function register_embed() {
10
- add_shortcode( 'gallery', array( $this, 'shortcode' ) );
11
- }
12
-
13
- public function unregister_embed() {
14
- remove_shortcode( 'gallery' );
15
- }
16
-
17
- public function get_scripts() {
18
- if ( ! $this->did_convert_elements ) {
19
- return array();
20
- }
21
-
22
- return array( self::$script_slug => self::$script_src );
23
- }
24
-
25
- public function shortcode( $attr ) {
26
- $post = get_post();
27
-
28
- if ( ! empty( $attr['ids'] ) ) {
29
- // 'ids' is explicitly ordered, unless you specify otherwise.
30
- if ( empty( $attr['orderby'] ) ) {
31
- $attr['orderby'] = 'post__in';
32
- }
33
- $attr['include'] = $attr['ids'];
34
- }
35
-
36
- $atts = shortcode_atts( array(
37
- 'order' => 'ASC',
38
- 'orderby' => 'menu_order ID',
39
- 'id' => $post ? $post->ID : 0,
40
- 'include' => '',
41
- 'exclude' => '',
42
- 'size' => array( $this->args['width'], $this->args['height'] ),
43
- ), $attr, 'gallery' );
44
-
45
- $id = intval( $atts['id'] );
46
-
47
- if ( ! empty( $atts['include'] ) ) {
48
- $attachments = get_posts( array(
49
- 'include' => $atts['include'],
50
- 'post_status' => 'inherit',
51
- 'post_type' => 'attachment',
52
- 'post_mime_type' => 'image',
53
- 'order' => $atts['order'],
54
- 'orderby' => $atts['orderby'],
55
- 'fields' => 'ids',
56
- ) );
57
- } elseif ( ! empty( $atts['exclude'] ) ) {
58
- $attachments = get_children( array(
59
- 'post_parent' => $id,
60
- 'exclude' => $atts['exclude'],
61
- 'post_status' => 'inherit',
62
- 'post_type' => 'attachment',
63
- 'post_mime_type' => 'image',
64
- 'order' => $atts['order'],
65
- 'orderby' => $atts['orderby'],
66
- 'fields' => 'ids',
67
- ) );
68
- } else {
69
- $attachments = get_children( array(
70
- 'post_parent' => $id,
71
- 'post_status' => 'inherit',
72
- 'post_type' => 'attachment',
73
- 'post_mime_type' => 'image',
74
- 'order' => $atts['order'],
75
- 'orderby' => $atts['orderby'],
76
- 'fields' => 'ids',
77
- ) );
78
- }
79
-
80
- if ( empty( $attachments ) ) {
81
- return '';
82
- }
83
-
84
- $urls = array();
85
- foreach ( $attachments as $attachment_id ) {
86
- list( $url, $width, $height ) = wp_get_attachment_image_src( $attachment_id, $atts['size'], true );
87
-
88
- if ( ! $url ) {
89
- continue;
90
- }
91
-
92
- $urls[] = apply_filters('amp_gallery_image_params', array(
93
- 'url' => $url,
94
- 'width' => $width,
95
- 'height' => $height,
96
- ),$attachment_id);
97
- }
98
- return $this->render( array(
99
- 'images' => $urls,
100
- ) );
101
- }
102
-
103
- public function render( $args ) {
104
- $this->did_convert_elements = true;
105
-
106
- $args = wp_parse_args( $args, array(
107
- 'images' => false,
108
- ) );
109
-
110
- if ( empty( $args['images'] ) ) {
111
- return '';
112
- }
113
- $images = array();
114
- foreach ( $args['images'] as $key => $image ) {
115
- $images[$key] = AMP_HTML_Utils::build_tag(
116
- 'amp-img',
117
- array(
118
- 'src' => $image['url'],
119
- 'width' => $image['width'],
120
- 'height' => $image['height'],
121
- 'layout' => 'fill',
122
- 'class' => 'amp-carousel-img',
123
- )
124
- );
125
- $images[$key] = apply_filters('amp_gallery_images', $images[$key], $image);
126
- }
127
- return AMP_HTML_Utils::build_tag(
128
- 'amp-carousel',
129
- array(
130
- 'width' => $this->args['width'],
131
- 'height' => $this->args['height'],
132
- 'type' => 'slides',
133
- 'layout' => 'responsive',
134
- 'class' => 'collapsible-captions',
135
- ),
136
- implode( PHP_EOL, $images )
137
- );
138
- }
139
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/class-ampforwp-iframe-sanitizer.php DELETED
@@ -1,198 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMPforWP_Iframe_Sanitizer
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMPforWP_Iframe_Sanitizer
10
- *
11
- * Converts <iframe> tags to <amp-iframe>
12
- */
13
- class AMPforWP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
14
-
15
- /**
16
- * Value used for height attribute when $attributes['height'] is empty.
17
- *
18
- * @since 0.2
19
- *
20
- * @const int
21
- */
22
- const FALLBACK_HEIGHT = 400;
23
-
24
- /**
25
- * Default values for sandboxing IFrame.
26
- *
27
- * @since 0.2
28
- *
29
- * @const int
30
- */
31
- const SANDBOX_DEFAULTS = 'allow-scripts allow-same-origin allow-popups';
32
-
33
- /**
34
- * Tag.
35
- *
36
- * @var string HTML <iframe> tag to identify and replace with AMP version.
37
- *
38
- * @since 0.2
39
- */
40
- public static $tag = 'iframe';
41
-
42
- /**
43
- * Default args.
44
- *
45
- * @var array
46
- */
47
- protected $DEFAULT_ARGS = array(
48
- 'add_placeholder' => false,
49
- );
50
-
51
- /**
52
- * Sanitize the <iframe> elements from the HTML contained in this instance's DOMDocument.
53
- *
54
- * @since 0.2
55
- */
56
- public function sanitize() {
57
- $nodes = $this->dom->getElementsByTagName( self::$tag );
58
- $num_nodes = $nodes->length;
59
- if ( 0 === $num_nodes ) {
60
- return;
61
- }
62
-
63
- for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
64
- $node = $nodes->item( $i );
65
- $old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
66
-
67
- $new_attributes = $this->filter_attributes( $old_attributes );
68
-
69
- /**
70
- * If the src doesn't exist, remove the node. Either it never
71
- * existed or was invalidated while filtering attributes above.
72
- *
73
- * @todo: add a filter to allow for a fallback element in this instance.
74
- * @see: https://github.com/ampproject/amphtml/issues/2261
75
- */
76
- if ( empty( $new_attributes['src'] ) ) {
77
- $this->remove_invalid_child( $node );
78
- continue;
79
- }
80
-
81
- $this->did_convert_elements = true;
82
- $new_attributes = $this->set_layout( $new_attributes );
83
- if ( empty( $new_attributes['layout'] ) && ! empty( $new_attributes['width'] ) && ! empty( $new_attributes['height'] ) ) {
84
- $new_attributes['layout'] = 'intrinsic';
85
- $this->add_or_append_attribute( $new_attributes, 'class', 'amp-wp-enforced-sizes' );
86
- }
87
-
88
- $new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-iframe', $new_attributes );
89
-
90
- if ( true === $this->args['add_placeholder'] ) {
91
- $placeholder_node = $this->build_placeholder( $new_attributes );
92
- $new_node->appendChild( $placeholder_node );
93
- }
94
-
95
- $parent_node = $node->parentNode;
96
- if ( 'p' !== strtolower( $parent_node->tagName ) ) {
97
- $parent_node->replaceChild( $new_node, $node );
98
- } else {
99
- // AMP does not like iframes in <p> tags.
100
- $parent_node->removeChild( $node );
101
- $parent_node->parentNode->insertBefore( $new_node, $parent_node->nextSibling );
102
-
103
- if ( AMP_DOM_Utils::is_node_empty( $parent_node ) ) {
104
- $parent_node->parentNode->removeChild( $parent_node );
105
- }
106
- }
107
- }
108
- }
109
-
110
- /**
111
- * "Filter" HTML attributes for <amp-iframe> elements.
112
- *
113
- * @since 0.2
114
- *
115
- * @param string[] $attributes {
116
- * Attributes.
117
- *
118
- * @type string $src IFrame URL - Empty if HTTPS required per $this->args['require_https_src']
119
- * @type int $width <iframe> width attribute - Set to numeric value if px or %
120
- * @type int $height <iframe> width attribute - Set to numeric value if px or %
121
- * @type string $sandbox <iframe> `sandbox` attribute - Pass along if found; default to value of self::SANDBOX_DEFAULTS
122
- * @type string $class <iframe> `class` attribute - Pass along if found
123
- * @type string $sizes <iframe> `sizes` attribute - Pass along if found
124
- * @type int $frameborder <iframe> `frameborder` attribute - Filter to '0' or '1'; default to '0'
125
- * @type bool $allowfullscreen <iframe> `allowfullscreen` attribute - Convert 'false' to empty string ''
126
- * @type bool $allowtransparency <iframe> `allowtransparency` attribute - Convert 'false' to empty string ''
127
- * }
128
- * @return array Returns HTML attributes; removes any not specifically declared above from input.
129
- */
130
- private function filter_attributes( $attributes ) {
131
- $out = array();
132
-
133
- foreach ( $attributes as $name => $value ) {
134
- switch ( $name ) {
135
- case 'sandbox':
136
- case 'class':
137
- case 'sizes':
138
- $out[ $name ] = $value;
139
- break;
140
-
141
- case 'src':
142
- $out[ $name ] = $this->maybe_enforce_https_src( $value, true );
143
- break;
144
-
145
- case 'width':
146
- case 'height':
147
- $out[ $name ] = $this->sanitize_dimension( $value, $name );
148
- break;
149
-
150
- case 'frameborder':
151
- if ( '0' !== $value && '1' !== $value ) {
152
- $value = '0';
153
- }
154
- $out[ $name ] = $value;
155
- break;
156
-
157
- case 'allowfullscreen':
158
- case 'allowtransparency':
159
- if ( 'false' !== $value ) {
160
- $out[ $name ] = '';
161
- }
162
- break;
163
-
164
- default:
165
- break;
166
- }
167
- }
168
-
169
- if ( ! isset( $out['sandbox'] ) ) {
170
- $out['sandbox'] = self::SANDBOX_DEFAULTS;
171
- }
172
-
173
- return $out;
174
- }
175
-
176
- /**
177
- * Builds a DOMElement to use as a placeholder for an <iframe>.
178
- *
179
- * @since 0.2
180
- *
181
- * @param string[] $parent_attributes {
182
- * Attributes.
183
- *
184
- * @type string $placeholder AMP HTML <amp-iframe> `placeholder` attribute; default to 'amp-wp-iframe-placeholder'
185
- * @type string $class AMP HTML <amp-iframe> `class` attribute; default to 'amp-wp-iframe-placeholder'
186
- * }
187
- * @return DOMElement|false
188
- */
189
- private function build_placeholder( $parent_attributes ) {
190
- $placeholder_node = AMP_DOM_Utils::create_node( $this->dom, 'div', array(
191
- 'placeholder' => '',
192
- 'class' => 'amp-wp-iframe-placeholder',
193
- ) );
194
-
195
- return $placeholder_node;
196
- }
197
-
198
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/class-ampforwp-img-sanitizer.php DELETED
@@ -1,312 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMPforWP_Img_Sanitizer.
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMPforWP_Img_Sanitizer
10
- *
11
- * Converts <img> tags to <amp-img> or <amp-anim>
12
- */
13
- class AMPforWP_Img_Sanitizer extends AMP_Base_Sanitizer {
14
-
15
- /**
16
- * Value used for width attribute when $attributes['width'] is empty.
17
- *
18
- * @since 0.2
19
- *
20
- * @const int
21
- */
22
- const FALLBACK_WIDTH = 600;
23
-
24
- /**
25
- * Value used for height attribute when $attributes['height'] is empty.
26
- *
27
- * @since 0.2
28
- *
29
- * @const int
30
- */
31
- const FALLBACK_HEIGHT = 400;
32
- protected $is_lightbox = false;
33
- protected $scripts = array();
34
- private static $script_slug = 'amp-anim';
35
- private static $script_src = 'https://cdn.ampproject.org/v0/amp-anim-0.1.js';
36
- private static $script_slug_lightbox = 'amp-image-lightbox';
37
- private static $script_src_lightbox = 'https://cdn.ampproject.org/v0/amp-image-lightbox-0.1.js';
38
-
39
- /**
40
- * Tag.
41
- *
42
- * @var string HTML <img> tag to identify and replace with AMP version.
43
- *
44
- * @since 0.2
45
- */
46
- public static $tag = 'img';
47
-
48
- /**
49
- * Animation extension.
50
- *
51
- * @var string
52
- */
53
- private static $anim_extension = '.gif';
54
-
55
- /**
56
- * Sanitize the <img> elements from the HTML contained in this instance's DOMDocument.
57
- *
58
- * @since 0.2
59
- */
60
- public function sanitize() {
61
-
62
- /**
63
- * Node list.
64
- *
65
- * @var DOMNodeList $node
66
- */
67
- $nodes = $this->dom->getElementsByTagName( self::$tag );
68
- $need_dimensions = array();
69
-
70
- $num_nodes = $nodes->length;
71
-
72
- if ( 0 === $num_nodes ) {
73
- return;
74
- }
75
-
76
- for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
77
- $node = $nodes->item( $i );
78
- if ( ! $node instanceof DOMElement ) {
79
- continue;
80
- }
81
-
82
- // Add Foo Gallery Support
83
- if ( $node->hasAttribute( 'data-src-fg' ) ) {
84
- $image_scr_from_data_src = $node->getAttribute( 'data-src-fg' ) ;
85
- if ( ! $node->hasAttribute( 'src' ) || '' === $node->getAttribute( 'src' ) ) {
86
- $node->setAttribute( 'src', $image_scr_from_data_src );
87
- }
88
- }
89
-
90
- if ( ! $node->hasAttribute( 'src' ) || '' === trim( $node->getAttribute( 'src' ) ) ) {
91
- $this->remove_invalid_child( $node );
92
- continue;
93
- }
94
-
95
- // Determine which images need their dimensions determined/extracted.
96
- if ( ! is_numeric( $node->getAttribute( 'width' ) ) || ! is_numeric( $node->getAttribute( 'height' ) ) ) {
97
- $need_dimensions[ $node->getAttribute( 'src' ) ][] = $node;
98
- } else {
99
- $this->adjust_and_replace_node( $node );
100
- }
101
- }
102
-
103
- $this->determine_dimensions( $need_dimensions );
104
- $this->adjust_and_replace_nodes_in_array_map( $need_dimensions );
105
- }
106
-
107
- /**
108
- * "Filter" HTML attributes for <amp-anim> elements.
109
- *
110
- * @since 0.2
111
- *
112
- * @param string[] $attributes {
113
- * Attributes.
114
- *
115
- * @type string $src Image URL - Pass along if found
116
- * @type string $alt <img> `alt` attribute - Pass along if found
117
- * @type string $class <img> `class` attribute - Pass along if found
118
- * @type string $srcset <img> `srcset` attribute - Pass along if found
119
- * @type string $sizes <img> `sizes` attribute - Pass along if found
120
- * @type string $on <img> `on` attribute - Pass along if found
121
- * @type string $attribution <img> `attribution` attribute - Pass along if found
122
- * @type int $width <img> width attribute - Set to numeric value if px or %
123
- * @type int $height <img> width attribute - Set to numeric value if px or %
124
- * }
125
- * @return array Returns HTML attributes; removes any not specifically declared above from input.
126
- */
127
- private function filter_attributes( $attributes ) {
128
- $out = array();
129
-
130
- foreach ( $attributes as $name => $value ) {
131
- switch ( $name ) {
132
- case 'src':
133
- case 'alt':
134
- case 'class':
135
- case 'srcset':
136
- case 'on':
137
- case 'attribution':
138
- case 'role':
139
- case 'tabindex':
140
- $out[ $name ] = $value;
141
- break;
142
-
143
- case 'width':
144
- case 'height':
145
- $out[ $name ] = $this->sanitize_dimension( $value, $name );
146
- break;
147
-
148
- case 'data-amp-layout':
149
- $out['layout'] = $value;
150
- break;
151
-
152
- default:
153
- break;
154
- }
155
- }
156
-
157
- return $out;
158
- }
159
-
160
- /**
161
- * Determine width and height attribute values for images without them.
162
- *
163
- * Attempt to determine actual dimensions, otherwise set reasonable defaults.
164
- *
165
- * @param DOMElement[][] $need_dimensions Map <img> @src URLs to node for images with missing dimensions.
166
- */
167
- private function determine_dimensions( $need_dimensions ) {
168
-
169
- $dimensions_by_url = AMP_Image_Dimension_Extractor::extract( array_keys( $need_dimensions ) );
170
-
171
- foreach ( $dimensions_by_url as $url => $dimensions ) {
172
- foreach ( $need_dimensions[ $url ] as $node ) {
173
- if ( ! $node instanceof DOMElement ) {
174
- continue;
175
- }
176
- if (
177
- ! is_numeric( $node->getAttribute( 'width' ) ) &&
178
- ! is_numeric( $node->getAttribute( 'height' ) )
179
- ) {
180
- $height = self::FALLBACK_HEIGHT;
181
- $width = self::FALLBACK_WIDTH;
182
- $node->setAttribute( 'width', $width );
183
- $node->setAttribute( 'height', $height );
184
- $class = $node->hasAttribute( 'class' ) ? $node->getAttribute( 'class' ) . ' amp-wp-unknown-size' : 'amp-wp-unknown-size';
185
- $node->setAttribute( 'class', $class );
186
- } elseif (
187
- ! is_numeric( $node->getAttribute( 'height' ) )
188
- ) {
189
- $height = self::FALLBACK_HEIGHT;
190
- $node->setAttribute( 'height', $height );
191
- $class = $node->hasAttribute( 'class' ) ? $node->getAttribute( 'class' ) . ' amp-wp-unknown-size amp-wp-unknown-height' : 'amp-wp-unknown-size amp-wp-unknown-height';
192
- $node->setAttribute( 'class', $class );
193
- } elseif (
194
- ! is_numeric( $node->getAttribute( 'width' ) )
195
- ) {
196
- $width = self::FALLBACK_WIDTH;
197
- $node->setAttribute( 'width', $width );
198
- $class = $node->hasAttribute( 'class' ) ? $node->getAttribute( 'class' ) . ' amp-wp-unknown-size amp-wp-unknown-width' : 'amp-wp-unknown-size amp-wp-unknown-width';
199
- $node->setAttribute( 'class', $class );
200
- }
201
- }
202
- }
203
- }
204
-
205
- /**
206
- * Now that all images have width and height attributes, make final tweaks and replace original image nodes
207
- *
208
- * @param DOMNodeList[] $node_lists Img DOM nodes (now with width and height attributes).
209
- */
210
- private function adjust_and_replace_nodes_in_array_map( $node_lists ) {
211
- foreach ( $node_lists as $node_list ) {
212
- foreach ( $node_list as $node ) {
213
- $this->adjust_and_replace_node( $node );
214
- }
215
- }
216
- }
217
-
218
- /**
219
- * Make final modifications to DOMNode
220
- *
221
- * @param DOMNode $node The DOMNode to adjust and replace.
222
- */
223
- private function adjust_and_replace_node( $node ) {
224
- $old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
225
- $old_attributes = apply_filters('amp_img_attributes', $old_attributes);
226
- $new_attributes = $this->filter_attributes( $old_attributes );
227
- $this->add_or_append_attribute( $new_attributes, 'class', 'amp-wp-enforced-sizes' );
228
- if ( empty( $new_attributes['layout'] ) && ! empty( $new_attributes['height'] ) && ! empty( $new_attributes['width'] ) ) {
229
- $new_attributes['layout'] = 'intrinsic';
230
- }
231
- if ( $this->is_gif_url( $new_attributes['src'] ) ) {
232
- $this->did_convert_elements = true;
233
-
234
- $new_tag = 'amp-anim';
235
- } else {
236
- $new_tag = 'amp-img';
237
- }
238
- $new_node = AMP_DOM_Utils::create_node( $this->dom, $new_tag, $new_attributes );
239
- $new_node = $this->handle_centering( $new_node );
240
- $node->parentNode->replaceChild( $new_node, $node );
241
- if ( isset($new_attributes['on']) && '' != $new_attributes['on'] ) {
242
- add_action('amp_post_template_footer', 'ampforwp_amp_img_lightbox');
243
- $this->is_lightbox = true;
244
- }
245
- }
246
-
247
- /**
248
- * Determines is a URL is considered a GIF URL
249
- *
250
- * @since 0.2
251
- *
252
- * @param string $url URL to inspect for GIF vs. JPEG or PNG.
253
- *
254
- * @return bool Returns true if $url ends in `.gif`
255
- */
256
- private function is_gif_url( $url ) {
257
- $ext = self::$anim_extension;
258
- $path = AMP_WP_Utils::parse_url( $url, PHP_URL_PATH );
259
- return substr( $path, -strlen( $ext ) ) === $ext;
260
- }
261
-
262
- /**
263
- * Handles an issue with the aligncenter class.
264
- *
265
- * If the <amp-img> has the class aligncenter, this strips the class and wraps it in a <figure> to center the image.
266
- * There was an issue where the aligncenter class overrode the "display: inline-block" rule of AMP's layout="intrinsic" attribute.
267
- * So this strips that class, and instead wraps the image in a <figure> to center it.
268
- *
269
- * @since 0.7
270
- * @see https://github.com/Automattic/amp-wp/issues/1104
271
- *
272
- * @param DOMElement $node The <amp-img> node.
273
- * @return DOMElement $node The <amp-img> node, possibly wrapped in a <figure>.
274
- */
275
- public function handle_centering( $node ) {
276
- $align_class = 'aligncenter';
277
- $classes = $node->getAttribute( 'class' );
278
- $width = $node->getAttribute( 'width' );
279
-
280
- // If this doesn't have a width attribute, centering it in the <figure> wrapper won't work.
281
- if ( empty( $width ) || ! in_array( $align_class, preg_split( '/\s+/', trim( $classes ) ), true ) ) {
282
- return $node;
283
- }
284
-
285
- // Strip the class, and wrap the <amp-img> in a <figure>.
286
- $classes = trim( str_replace( $align_class, '', $classes ) );
287
- $node->setAttribute( 'class', $classes );
288
- $figure = AMP_DOM_Utils::create_node(
289
- $this->dom,
290
- 'figure',
291
- array(
292
- 'class' => $align_class,
293
- //'style' => "max-width: {$width}px;",
294
- )
295
- );
296
- $figure->appendChild( $node );
297
-
298
- return $figure;
299
- }
300
-
301
- public function get_scripts() {
302
- if ( $this->is_lightbox ) {
303
- $this->scripts[self::$script_slug_lightbox] = self::$script_src_lightbox;
304
- }
305
-
306
- if ( $this->did_convert_elements ) {
307
- $this->scripts[self::$script_slug] = self::$script_src;
308
- }
309
-
310
- return $this->scripts;
311
- }
312
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/class-ampforwp-vimeo-embed.php DELETED
@@ -1,135 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMPforWP_Vimeo_Embed_Handler
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMPforWP_Vimeo_Embed_Handler
10
- *
11
- * Much of this class is borrowed from Jetpack embeds
12
- */
13
- class AMPforWP_Vimeo_Embed_Handler extends AMP_Base_Embed_Handler {
14
-
15
- const URL_PATTERN = '#https?:\/\/(www\.)?vimeo\.com\/.*#i';
16
-
17
- const RATIO = 0.5625;
18
-
19
- protected $DEFAULT_WIDTH = 600;
20
- protected $DEFAULT_HEIGHT = 338;
21
-
22
- function __construct( $args = array() ) {
23
- parent::__construct( $args );
24
-
25
- if ( isset( $this->args['content_max_width'] ) ) {
26
- $max_width = $this->args['content_max_width'];
27
- $this->args['width'] = $max_width;
28
- $this->args['height'] = round( $max_width * self::RATIO );
29
- }
30
- }
31
-
32
- function register_embed() {
33
- wp_embed_register_handler( 'amp-vimeo', self::URL_PATTERN, array( $this, 'oembed' ), -1 );
34
- add_shortcode( 'vimeo', array( $this, 'shortcode' ) );
35
- add_filter( 'wp_video_shortcode_override', array( $this, 'video_override' ), 10, 2 );
36
- }
37
-
38
- public function unregister_embed() {
39
- wp_embed_unregister_handler( 'amp-vimeo', -1 );
40
- remove_shortcode( 'vimeo' );
41
- }
42
-
43
- public function shortcode( $attr ) {
44
- $video_id = false;
45
-
46
- if ( isset( $attr['id'] ) ) {
47
- $video_id = $attr['id'];
48
- } elseif ( isset( $attr['url'] ) ) {
49
- $video_id = $this->get_video_id_from_url($attr['url']);
50
- }elseif ( isset( $attr[0] ) ) {
51
- $video_id = $this->get_video_id_from_url($attr[0]);
52
- } elseif ( function_exists( 'shortcode_new_to_old_params' ) ) {
53
- $video_id = shortcode_new_to_old_params( $attr );
54
- }
55
-
56
- if ( empty( $video_id ) ) {
57
- return '';
58
- }
59
-
60
- return $this->render( array(
61
- 'video_id' => $video_id,
62
- ) );
63
- }
64
-
65
- public function oembed( $matches, $attr, $url, $rawattr ) {
66
- $video_id = $this->get_video_id_from_url( $url );
67
-
68
- return $this->render( array(
69
- 'url' => $url,
70
- 'video_id' => $video_id,
71
- ) );
72
- }
73
-
74
- public function render( $args ) {
75
- $args = wp_parse_args( $args, array(
76
- 'video_id' => false,
77
- ) );
78
-
79
- if ( empty( $args['video_id'] ) ) {
80
- return AMP_HTML_Utils::build_tag( 'a', array( 'href' => esc_url( $args['url'] ), 'class' => 'amp-wp-embed-fallback' ), esc_html( $args['url'] ) );
81
- }
82
-
83
- $this->did_convert_elements = true;
84
-
85
- return AMP_HTML_Utils::build_tag(
86
- 'amp-vimeo',
87
- array(
88
- 'data-videoid' => $args['video_id'],
89
- 'layout' => 'responsive',
90
- 'width' => $this->args['width'],
91
- 'height' => $this->args['height'],
92
- )
93
- );
94
- }
95
-
96
- // get_video_id_from_url()
97
- // Takes the last component of a Vimeo URL
98
- // and returns it as the associated video id
99
- private function get_video_id_from_url( $url ) {
100
- $parsed_url = parse_url( $url );
101
- parse_str( $parsed_url['path'], $path );
102
-
103
- $video_id = "";
104
- if ( $path ) {
105
- $tok = explode( '/', $parsed_url['path'] );
106
- $tok = apply_filters('amp_vimeo_parse_url',$tok);
107
- $video_id = $tok;
108
- }
109
-
110
- return $video_id;
111
- }
112
-
113
- /**
114
- * Override the output of Vimeo videos.
115
- *
116
- * This overrides the value in wp_video_shortcode().
117
- * The pattern matching is copied from WP_Widget_Media_Video::render().
118
- *
119
- * @param string $html Empty variable to be replaced with shortcode markup.
120
- * @param array $attr The shortcode attributes.
121
- * @return string|null $markup The markup to output.
122
- */
123
- public function video_override( $html, $attr ) {
124
- if ( ! isset( $attr['src'] ) ) {
125
- return $html;
126
- }
127
- $src = $attr['src'];
128
- $vimeo_pattern = '#^https?://(.+\.)?vimeo\.com/.*#';
129
- if ( 1 === preg_match( $vimeo_pattern, $src ) ) {
130
- return $this->shortcode( array( $src ) );
131
- }
132
- return $html;
133
- }
134
-
135
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
images/Bitmap.png DELETED
Binary file
images/amplogo.png DELETED
Binary file
images/converttoamp.png DELETED
Binary file
images/ex-1.png DELETED
Binary file
images/ex-2.png DELETED
Binary file
images/ex-3.png DELETED
Binary file
images/layouts-3.png DELETED
Binary file
images/layouts-4.png DELETED
Binary file
images/layouts-5.png DELETED
Binary file
images/layouts-6.png DELETED
Binary file
images/nf.png DELETED
Binary file
images/rating.png DELETED
Binary file
images/tick.png DELETED
Binary file
includes/options/extensions/theme_design_selector/extension_theme_design_selector.php DELETED
@@ -1,110 +0,0 @@
1
- <?php
2
- /**
3
- * Redux Framework is free software: you can redistribute it and/or modify
4
- * it under the terms of the GNU General Public License as published by
5
- * the Free Software Foundation, either version 2 of the License, or
6
- * any later version.
7
- *
8
- * Redux Framework is distributed in the hope that it will be useful,
9
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
- * GNU General Public License for more details.
12
- *
13
- * You should have received a copy of the GNU General Public License
14
- * along with Redux Framework. If not, see <http://www.gnu.org/licenses/>.
15
- *
16
- * @package ReduxFramework
17
- * @author Dovy Paukstys (dovy)
18
- * @version 3.0.0
19
- */
20
- // Exit if accessed directly
21
- if( !defined( 'ABSPATH' ) ) exit;
22
- // Don't duplicate me!
23
- if( !class_exists( 'ReduxFramework_extension_theme_design_selector' ) ) {
24
- /**
25
- * Main ReduxFramework demolink_image_select extension class
26
- *
27
- * @since 3.1.6
28
- */
29
- class ReduxFramework_extension_theme_design_selector {
30
-
31
- // Set the version number of your extension here
32
- public static $version = '1.0.0';
33
- // Set the name of your extension here
34
- public $ext_name = 'Theme Design Selector';
35
-
36
- // Set the minumum required version of Redux here (optional).
37
- // Leave blank to require no minimum version.
38
- // This allows you to specify a minimum required version of Redux in the event
39
- // you do not want to support older versions.
40
- public $min_redux_version = '3.0.0';
41
- // Protected vars
42
- protected $parent;
43
- public $extension_url;
44
- public $extension_dir;
45
- public static $theInstance;
46
- /**
47
- * Class Constructor. Defines the args for the extions class
48
- *
49
- * @since 1.0.0
50
- * @access public
51
- * @param array $sections Panel sections.
52
- * @param array $args Class constructor arguments.
53
- * @param array $extra_tabs Extra panel tabs.
54
- * @return void
55
- */
56
- public function __construct( $parent ) {
57
-
58
- $this->parent = $parent;
59
-
60
- if (is_admin() && !$this->is_minimum_version()) {
61
- return;
62
- }
63
-
64
- if ( empty( $this->extension_dir ) ) {
65
- $this->extension_dir = trailingslashit( str_replace( '\\', '/', dirname( __FILE__ ) ) );
66
- $this->extension_url = site_url( str_replace( trailingslashit( str_replace( '\\', '/', ABSPATH ) ), '', $this->extension_dir ) );
67
- }
68
-
69
- $this->field_name = 'theme_design_selector';
70
- self::$theInstance = $this;
71
- add_filter( 'redux/'.$this->parent->args['opt_name'].'/field/class/'.$this->field_name, array( &$this, 'overload_field_path' ) ); // Adds the local field
72
- }
73
- public function getInstance() {
74
- return self::$theInstance;
75
- }
76
- // Forces the use of the embeded field path vs what the core typically would use
77
- public function overload_field_path($field) {
78
- return dirname(__FILE__).'/'.$this->field_name.'/field_'.$this->field_name.'.php';
79
- }
80
- private function is_minimum_version () {
81
- $redux_ver = ReduxFramework::$_version;
82
- if ($this->min_redux_version != '') {
83
- if (version_compare($redux_ver, $this->min_redux_version) < 0) {
84
- $msg = '<strong>' . esc_html__( 'The', 'redux-framework') . ' ' . $this->ext_name . ' ' . esc_html__('extension requires', 'redux-framework') . ' Redux Framework ' . esc_html__('version', 'redux-framework') . ' ' . $this->min_redux_version . ' ' . esc_html__('or higher.','redux-framework' ) . '</strong>&nbsp;&nbsp;' . esc_html__( 'You are currently running', 'redux-framework') . ' Redux Framework ' . esc_html__('version','redux-framework' ) . ' ' . $redux_ver . '.<br/><br/>' . esc_html__('This field will not render in your option panel, and featuress of this extension will not be available until the latest version of','redux-framework' ) . ' Redux Framework ' . esc_html__('has been installed.','redux-framework' );
85
-
86
- $data = array(
87
- 'parent' => $this->parent,
88
- 'type' => 'error',
89
- 'msg' => $msg,
90
- 'id' => $this->ext_name . '_notice_' . self::$version,
91
- 'dismiss' => false
92
- );
93
-
94
- if (method_exists('Redux_Admin_Notices', 'set_notice')) {
95
- Redux_Admin_Notices::set_notice($data);
96
- } else {
97
- echo '<div class="error">';
98
- echo '<p>';
99
- echo $msg;
100
- echo '</p>';
101
- echo '</div>';
102
- }
103
- return false;
104
- }
105
- }
106
-
107
- return true;
108
- }
109
- } // class
110
- } // if
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/options/extensions/theme_design_selector/theme_design_selector/field_theme_design_selector.css DELETED
@@ -1,78 +0,0 @@
1
- ul.theme_design_selector input[type=radio]{
2
- display:none;
3
- }
4
- .theme_design_selector li {
5
- width: 180px !important;
6
- float: left;
7
- text-align: center;
8
- border-radius: 3px;
9
- z-index: 100;
10
- padding: 7px 4px 4px 4px;
11
- font-size: 13px;
12
- margin-right: 12px;
13
- position: relative;
14
- border: 1px solid #e8e7e7;
15
- }
16
- .amp-cnvrtr-wrap{
17
- position: absolute;
18
- left: 40px;
19
- top: 92px;
20
- font-size: 11px;
21
- text-transform: uppercase;
22
- color: #666;
23
- background: #f1f1f1;
24
- border-radius: 20px;
25
- padding: 0px 6px;
26
- }
27
- .redux-main .data-full :nth-child(2) span.amp-cnvrtr-wrap {
28
- left: 80px;
29
- }
30
- .theme_design_selector li :first{
31
- margin-left:0px;
32
- }
33
- .theme_design_selector li img{
34
- width: auto !important;
35
- display: block;
36
- margin: 0px auto;
37
- min-height: 30px !important;
38
- margin-bottom: 5px;
39
- height: 45px}
40
- .redux-main .data-full :nth-child(2) img{
41
- height: 37px;
42
- opacity: 0.9;
43
- margin: 6px auto 7px auto;
44
- }
45
- .redux-main .data-full :nth-child(2) .amp-cnvrtr-wrap{
46
- left: 70px;
47
- }
48
- .theme_design_selector li:hover .amp-cnvrtr-wrap {
49
- background: #5ec600;font-weight: bold;
50
- color: #fff;
51
- }
52
- .theme_design_selector li:nth-child(2):hover .amp-cnvrtr-wrap {
53
- font-weight: bold;background: #D32F2F; color: #fff;
54
- }
55
- .theme_design_selector li:hover{
56
- background: #f1f1f1
57
- }
58
- .theme_design_selector li.active{
59
- background: #f9f9f9;
60
- border-color: #ccc
61
- }
62
- .theme_design_selector li.active:before {
63
- content: "\f147";
64
- position: absolute;
65
- font-family: dashicons;
66
- color: #fff;
67
- background: #5EC600;
68
- font-size: 22px;
69
- border-radius: 40px;
70
- margin: -2px 0 0 -9px;
71
- padding: 3px 3px 3px 0px;
72
- }
73
- .form-table .theme_design_selector label{
74
- margin-bottom: 5px !important
75
- }
76
- .amp-design-type-selection_1 img{
77
- height: 37px !important;
78
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/options/extensions/theme_design_selector/theme_design_selector/field_theme_design_selector.js DELETED
@@ -1,7 +0,0 @@
1
- jQuery(document).ready(function($){
2
- $('.theme_design_selector li label').click(function(){
3
- var current = $(this).parent();
4
- current.siblings().removeClass('active');
5
- current.addClass('active');
6
- });
7
- });
 
 
 
 
 
 
 
includes/options/extensions/theme_design_selector/theme_design_selector/field_theme_design_selector.php DELETED
@@ -1,102 +0,0 @@
1
- <?php
2
-
3
- // Exit if accessed directly
4
- if ( ! defined( 'ABSPATH' ) ) {
5
- exit;
6
- }
7
-
8
- if ( ! class_exists( 'ReduxFramework_theme_design_selector' ) ) {
9
- class ReduxFramework_theme_design_selector {
10
-
11
- /**
12
- * Field Constructor.
13
- * Required - must call the parent constructor, then assign field and value to vars, and obviously call the render field function
14
- *
15
- * @since ReduxFramework 1.0.0
16
- */
17
- function __construct( $field = array(), $value = '', $parent ) {
18
- $this->parent = $parent;
19
- $this->field = $field;
20
- $this->value = $value;
21
- $this->time = time();
22
- if ( defined('AMPFORWP_VERSION') ) {
23
- $this->time = AMPFORWP_VERSION;
24
- }
25
- if ( empty( $this->extension_dir ) ) {
26
- $this->extension_dir = trailingslashit( str_replace( '\\', '/', dirname( __FILE__ ) ) );
27
- $this->extension_url = site_url( str_replace( trailingslashit( str_replace( '\\', '/', ABSPATH ) ), '', $this->extension_dir ) );
28
- }
29
-
30
- // Set default args for this field to avoid bad indexes. Change this to anything you use.
31
- $defaults = array(
32
- 'options' => array(),
33
- //'stylesheet' => '',
34
- //'output' => true,
35
- 'enqueue' => true,
36
- 'enqueue_frontend' => true
37
- );
38
- $this->field = wp_parse_args( $this->field, $defaults );
39
- }
40
-
41
- /**
42
- * Field Render Function.
43
- * Takes the vars and outputs the HTML for the field in the settings
44
- *
45
- * @since ReduxFramework 1.0.0
46
- */
47
- function render() {
48
-
49
- if ( ! empty( $this->field['data'] ) && empty( $this->field['options'] ) ) {
50
- if ( empty( $this->field['args'] ) ) {
51
- $this->field['args'] = array();
52
- }
53
- $this->field['options'] = $this->parent->get_wordpress_data( $this->field['data'], $this->field['args'] );
54
- }
55
-
56
- $this->field['data_class'] = ( isset( $this->field['multi_layout'] ) ) ? 'data-' . $this->field['multi_layout'] : 'data-full';
57
-
58
- if ( ! empty( $this->field['options'] ) ) {
59
- echo '<ul class="theme_design_selector ' . $this->field['data_class'] . '">';
60
-
61
- foreach ( $this->field['options'] as $k => $v ) {
62
- $liClass = '';
63
- if($this->value==$k){
64
- $liClass = 'active';
65
- }
66
- echo '<li class="'.$liClass.'">';
67
- echo '<label for="' . $this->field['id'] . '_' . array_search( $k, array_keys( $this->field['options'] ) ) . '">';
68
- echo '<span class="image-wrap"><img src="'.$this->field['options_image'][$k].'"></span>';
69
- echo '<input type="radio" class="radio ' . $this->field['class'] . '" id="' . $this->field['id'] . '_' . array_search( $k, array_keys( $this->field['options'] ) ) . '" name="' . $this->field['name'] . $this->field['name_suffix'] . '" value="' . $k . '" ' . checked( $this->value, $k, false ) . '/>';
70
- echo ' <span>' . $v . '</span>';
71
- echo '<span class="amp-cnvrtr-wrap">'.$this->field['options_message'][$k].'</span>';
72
- echo '</label>';
73
- echo '</li>';
74
- }
75
- //foreach
76
-
77
- echo '</ul>';
78
- }
79
- } //function
80
- /**
81
- * Enqueue Function.
82
- * If this field requires any scripts, or css define this function and register/enqueue the scripts/css
83
- *
84
- * @since ReduxFramework 1.0.0
85
- */
86
- function enqueue() {
87
- wp_enqueue_style(
88
- 'redux-field-theme-design-selector',
89
- $this->extension_url . 'field_theme_design_selector.css',
90
- $this->time,
91
- true
92
- );
93
- wp_enqueue_script(
94
- 'field-theme-design-selector-js',
95
- $this->extension_url .'field_theme_design_selector.js',
96
- array('jquery', 'redux-js'),
97
- $this->time,
98
- true
99
- );
100
- } //function
101
- } //class
102
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/assets/css/amp-customizer.css DELETED
@@ -1,123 +0,0 @@
1
- .amp-toggle {
2
- position: relative;
3
- display: inline-block;
4
- width: 30px;
5
- height: 15px;
6
- top: 15px;
7
- left: 130px;
8
- }
9
-
10
- .amp-toggle input,
11
- .amp-toggle input.disabled {
12
- position: absolute;
13
- top: 0;
14
- left: 0;
15
- width: 100%;
16
- height: 100%;
17
- opacity: 0;
18
- margin: 0;
19
- padding: 0;
20
- z-index: 1;
21
- }
22
-
23
- .amp-toggle .slider {
24
- position: absolute;
25
- cursor: pointer;
26
- top: 0;
27
- left: 0;
28
- right: 0;
29
- bottom: 0;
30
- border-radius: 34px;
31
- background-color: #555D66;
32
- -webkit-transition: .3s;
33
- transition: .3s;
34
- transition-property: background-color, transform, -webkit-transform, -ms-transform, opacity;
35
- }
36
- .amp-toggle input:focus,
37
- .amp-toggle input:active {
38
- outline: none;
39
- }
40
- .amp-toggle input:hover + .slider,
41
- .amp-toggle input:focus + .slider,
42
- .amp-toggle input:active + .slider {
43
- box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8);
44
- }
45
-
46
- .amp-toggle .slider:before {
47
- position: absolute;
48
- content: "";
49
- height: 13px;
50
- width: 13px;
51
- top: 1px;
52
- left: 1px;
53
- border-radius: 50%;
54
- background-color: transparent;
55
- background-image: url( '../images/amp-white-icon.svg' );
56
- background-size: 13px 13px;
57
- -webkit-transition: .3s;
58
- transition: .3s;
59
- }
60
-
61
- .amp-toggle input:checked + .slider {
62
- background-color: #0379C4;
63
- }
64
-
65
- .amp-toggle input:checked + .slider:before {
66
- -webkit-transform: translateX( 15px );
67
- -ms-transform: translateX( 15px );
68
- transform: translateX( 15px );
69
- }
70
-
71
- .amp-toggle input.disabled + .slider {
72
- opacity: 0.7;
73
- }
74
-
75
- .amp-toggle .tooltip {
76
- position: absolute;
77
- bottom: 25px;
78
- left: -115px;
79
- width: 230px;
80
- font-size: 13px;
81
- text-align: center;
82
- color: #FFFFFF;
83
- background: #191E23;
84
- padding: 15px;
85
- z-index: 1;
86
- cursor: default;
87
- display: none;
88
- }
89
- .amp-toggle .tooltip a {
90
- color: #00a0d2;
91
- }
92
- .amp-toggle .tooltip a:hover,
93
- .amp-toggle .tooltip a:focus,
94
- .amp-toggle .tooltip a:active {
95
- color: #54cbf1;
96
- }
97
-
98
- .amp-toggle .tooltip:before {
99
- position: absolute;
100
- bottom: -8px;
101
- left: 120px;
102
- content: "";
103
- border: solid;
104
- border-color: #191E23 transparent;
105
- border-width: 8px 8px 0 8px;
106
- }
107
-
108
- .js .accordion-section-title:after {
109
- z-index: 0;
110
- }
111
-
112
- #customize-footer-actions .collapse-sidebar-label {
113
- font-size: 11px;
114
- margin-left: -3px;
115
- }
116
-
117
- .devices-wrapper .preview-desktop {
118
- border-left: 1px solid #DDDDDD !important;
119
- }
120
-
121
- .wp-full-overlay-footer .devices button:before {
122
- vertical-align: initial;
123
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/assets/css/amp-default.css DELETED
@@ -1,11 +0,0 @@
1
- .amp-wp-enforced-sizes {
2
- /** Our sizes fallback is 100vw, and we have a padding on the container; the max-width here prevents the element from overflowing. **/
3
- max-width: 100%;
4
- margin: 0 auto;
5
- }
6
-
7
- .amp-wp-unknown-size img {
8
- /** Worst case scenario when we can't figure out dimensions for an image. **/
9
- /** Force the image into a box of fixed dimensions and use object-fit to scale. **/
10
- object-fit: contain;
11
- }
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/assets/css/amp-playlist-shortcode.css DELETED
@@ -1,19 +0,0 @@
1
- /**
2
- * For the custom AMP implementation of the 'playlist' shortcode.
3
- */
4
- .wp-playlist .wp-playlist-current-item img {
5
- margin-right: 0;
6
- }
7
-
8
- .wp-playlist .wp-playlist-current-item amp-img {
9
- float: left;
10
- margin-right: 10px;
11
- }
12
-
13
- .wp-playlist audio {
14
- display: block;
15
- }
16
-
17
- .wp-playlist .amp-carousel-button {
18
- visibility: hidden;
19
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/assets/css/amp-post-meta-box.css DELETED
@@ -1,66 +0,0 @@
1
- /**
2
- * 1.0 AMP preview.
3
- *
4
- * Submit box preview buttons.
5
- */
6
-
7
- /* Core preview button */
8
- .wp-core-ui #preview-action.has-amp-preview #post-preview {
9
- border-top-right-radius: 0;
10
- border-bottom-right-radius: 0;
11
- float: none;
12
- }
13
-
14
- /* AMP preview button */
15
- .wp-core-ui #amp-post-preview.preview {
16
- border-top-left-radius: 0;
17
- border-bottom-left-radius: 0;
18
- text-indent: -9999px;
19
- padding-right: 14px;
20
- padding-left: 14px;
21
- position: relative;
22
- }
23
-
24
- .wp-core-ui #amp-post-preview.preview::after {
25
- content: "icon";
26
- background: no-repeat center url( '../images/amp-icon.svg' );
27
- background-size: 14px !important;
28
- top: 0;
29
- right: 0;
30
- bottom: 0;
31
- left: 0;
32
- display: block;
33
- position: absolute;
34
- }
35
-
36
- .wp-core-ui #amp-post-preview.preview.disabled::after {
37
- opacity: 0.6;
38
- }
39
-
40
- /* AMP status */
41
- .misc-amp-status .amp-icon {
42
- float: left;
43
- background: transparent url( '../images/amp-icon.svg' ) no-repeat left;
44
- background-size: 17px;
45
- width: 17px;
46
- height: 17px;
47
- margin: 0 8px 0 1px;
48
- }
49
-
50
- #amp-status-select fieldset {
51
- margin: 7px 0 0 1px;
52
- }
53
-
54
- #amp-status-select .notice {
55
- margin: 10px 0 -5px 3px;
56
- }
57
-
58
- .amp-status-actions {
59
- margin-top: 10px;
60
- }
61
-
62
- @media screen and ( max-width: 782px ) {
63
- #amp-status-select {
64
- line-height: 280%;
65
- }
66
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/assets/images/amp-icon.svg DELETED
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
- <svg width="62px" height="62px" viewBox="0 0 62 62" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
- <title>AMP-Icon</title>
4
- <g id="AMP-Icon" fill="#82878c">
5
- <path d="M41.6288667,28.1614333 L28.6243667,49.8035667 L26.2683667,49.8035667 L28.5975,35.7016667 L21.3838,35.7109667 C21.3838,35.7109667 21.3156,35.7130333 21.2835667,35.7130333 C20.6336,35.7130333 20.1076333,35.1870667 20.1076333,34.5371 C20.1076333,34.2581 20.367,33.7858667 20.367,33.7858667 L33.3291333,12.1695667 L35.7244,12.1799 L33.3363667,26.3035 L40.5872667,26.2942 C40.5872667,26.2942 40.6647667,26.2931667 40.7019667,26.2931667 C41.3519333,26.2931667 41.8779,26.8191333 41.8779,27.4691 C41.8779,27.7326 41.7745667,27.9640667 41.6278333,28.1604 L41.6288667,28.1614333 Z M31,0 C13.8787,0 0,13.8797333 0,31 C0,48.1213 13.8787,62 31,62 C48.1202667,62 62,48.1213 62,31 C62,13.8797333 48.1202667,0 31,0 L31,0 Z" id="Fill-1"></path>
6
- </g>
7
- </svg>
 
 
 
 
 
 
 
includes/vendor/amp/assets/images/amp-white-icon.svg DELETED
@@ -1,9 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
- <svg width="62px" height="62px" viewBox="0 0 62 62" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
- <title>AMP-White-Icon</title>
4
- <g id="amp-logo-internal-site" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
5
- <g id="AMP-Brand-White-Icon" fill="#FFFFFF">
6
- <path d="M41.6288667,28.1614333 L28.6243667,49.8035667 L26.2683667,49.8035667 L28.5975,35.7016667 L21.3838,35.7109667 C21.3838,35.7109667 21.3156,35.7130333 21.2835667,35.7130333 C20.6336,35.7130333 20.1076333,35.1870667 20.1076333,34.5371 C20.1076333,34.2581 20.367,33.7858667 20.367,33.7858667 L33.3291333,12.1695667 L35.7244,12.1799 L33.3363667,26.3035 L40.5872667,26.2942 C40.5872667,26.2942 40.6647667,26.2931667 40.7019667,26.2931667 C41.3519333,26.2931667 41.8779,26.8191333 41.8779,27.4691 C41.8779,27.7326 41.7745667,27.9640667 41.6278333,28.1604 L41.6288667,28.1614333 Z M31,0 C13.8787,0 0,13.8797333 0,31 C0,48.1213 13.8787,62 31,62 C48.1202667,62 62,48.1213 62,31 C62,13.8797333 48.1202667,0 31,0 L31,0 Z" id="Fill-1"></path>
7
- </g>
8
- </g>
9
- </svg>
 
 
 
 
 
 
 
 
 
includes/vendor/amp/assets/js/amp-customize-controls.js DELETED
@@ -1,351 +0,0 @@
1
- /* exported ampCustomizeControls */
2
- /* eslint no-magic-numbers: [ "error", { "ignore": [ 0, 1, 250] } ] */
3
-
4
- var ampCustomizeControls = ( function( api, $ ) {
5
- 'use strict';
6
-
7
- var component = {
8
- data: {
9
- queryVar: 'amp',
10
- panelId: '',
11
- ampUrl: '',
12
- l10n: {
13
- unavailableMessage: '',
14
- unavailableLinkText: ''
15
- }
16
- },
17
- tooltipTimeout: 5000,
18
- tooltipVisible: new api.Value( false ),
19
- tooltipFocused: new api.Value( 0 )
20
- };
21
-
22
- /**
23
- * Boot using data sent inline.
24
- *
25
- * @param {Object} data Object data.
26
- * @return {void}
27
- */
28
- component.boot = function boot( data ) {
29
- component.data = data;
30
-
31
- function initPanel() {
32
- api.panel( component.data.panelId, component.panelReady );
33
- }
34
-
35
- if ( api.state ) {
36
- component.addState();
37
- api.bind( 'ready', initPanel );
38
- } else { // WP<4.9.
39
- api.bind( 'ready', function() {
40
- component.addState(); // Needed for WP<4.9.
41
- initPanel();
42
- } );
43
- }
44
- };
45
-
46
- /**
47
- * Add state for AMP.
48
- *
49
- * @returns {void}
50
- */
51
- component.addState = function addState() {
52
- api.state.add( 'ampEnabled', new api.Value( false ) );
53
- api.state.add( 'ampAvailable', new api.Value( false ) );
54
- };
55
-
56
- /**
57
- * Check if the URL is AMPified.
58
- *
59
- * @param {string} url URL.
60
- * @return {boolean} whether it is an AMP URL.
61
- */
62
- component.isAmpUrl = function isAmpUrl( url ) {
63
- var urlParser = document.createElement( 'a' ),
64
- regexEndpoint = new RegExp( '\\/' + component.data.queryVar + '\\/?$' );
65
-
66
- urlParser.href = url;
67
- if ( ! _.isUndefined( wp.customize.utils.parseQueryString( urlParser.search.substr( 1 ) )[ component.data.queryVar ] ) ) {
68
- return true;
69
- }
70
- return regexEndpoint.test( urlParser.pathname );
71
- };
72
-
73
- /**
74
- * Create an non-AMP version of a URL.
75
- *
76
- * @param {string} url URL.
77
- * @return {string} non-AMPified URL.
78
- */
79
- component.unampifyUrl = function unampifyUrl( url ) {
80
- var urlParser = document.createElement( 'a' ),
81
- regexEndpoint = new RegExp( '\\/' + component.data.queryVar + '\\/?$' ),
82
- params;
83
-
84
- urlParser.href = url;
85
- urlParser.pathname = urlParser.pathname.replace( regexEndpoint, '' );
86
-
87
- if ( urlParser.search.length > 1 ) {
88
- params = wp.customize.utils.parseQueryString( urlParser.search.substr( 1 ) );
89
- delete params[ component.data.queryVar ];
90
- urlParser.search = $.param( params );
91
- }
92
-
93
- return urlParser.href;
94
- };
95
-
96
- /**
97
- * Create an AMP version of a URL.
98
- *
99
- * @param {string} url URL.
100
- * @return {string} AMPified URL.
101
- */
102
- component.ampifyUrl = function ampifyUrl( url ) {
103
- var urlParser = document.createElement( 'a' );
104
- urlParser.href = component.unampifyUrl( url );
105
- if ( urlParser.search.length ) {
106
- urlParser.search += '&';
107
- }
108
- urlParser.search += component.data.queryVar + '=1';
109
- return urlParser.href;
110
- };
111
-
112
- /**
113
- * Try to close the tooltip after a given timeout.
114
- *
115
- * @returns {void}
116
- */
117
- component.tryToCloseTooltip = function tryToCloseTooltip() {
118
- clearTimeout( component.tooltipTimeoutId );
119
- component.tooltipTimeoutId = setTimeout( function() {
120
- if ( ! component.tooltipVisible.get() ) {
121
- return;
122
- }
123
- if ( component.tooltipFocused.get() > 0 ) {
124
- component.tryToCloseTooltip();
125
- } else {
126
- component.tooltipVisible.set( false );
127
- }
128
- }, component.tooltipTimeout );
129
- };
130
-
131
- /**
132
- * Make current URL AMPified if toggle is on.
133
- *
134
- * @param {string} url URL.
135
- * @return {string} AMPified URL.
136
- */
137
- component.setCurrentAmpUrl = function setCurrentAmpUrl( url ) {
138
- var enabled = api.state( 'ampEnabled' ).get();
139
- if ( ! enabled && component.isAmpUrl( url ) ) {
140
- return component.unampifyUrl( url );
141
- } else if ( enabled && ! component.isAmpUrl( url ) ) {
142
- return component.ampifyUrl( url );
143
- }
144
- return url;
145
- };
146
-
147
- /**
148
- * Swap to AMP version of URL in preview.
149
- *
150
- * @return {void}
151
- */
152
- component.updatePreviewUrl = function updatePreviewUrl() {
153
- api.previewer.previewUrl.set( component.setCurrentAmpUrl( api.previewer.previewUrl.get() ) );
154
- };
155
-
156
- /**
157
- * Enable AMP and navigate to the given URL.
158
- *
159
- * @param {string} url - URL.
160
- * @returns {void}
161
- */
162
- component.enableAndNavigateToUrl = function enableAndNavigateToUrl( url ) {
163
- api.state( 'ampEnabled' ).set( true );
164
- api.previewer.previewUrl.set( url );
165
- };
166
-
167
- /**
168
- * Update panel notifications.
169
- *
170
- * @returns {void}
171
- */
172
- component.updatePanelNotifications = function updatePanelNotifications() {
173
- var panel = api.panel( component.data.panelId ), containers;
174
- containers = panel.sections().concat( [ panel ] );
175
- if ( api.state( 'ampAvailable' ).get() ) {
176
- _.each( containers, function( container ) {
177
- container.notifications.remove( 'amp_unavailable' );
178
- } );
179
- } else {
180
- _.each( containers, function( container ) {
181
- container.notifications.add( new api.Notification( 'amp_unavailable', {
182
- message: component.data.l10n.unavailableMessage,
183
- type: 'info',
184
- linkText: component.data.l10n.unavailableLinkText,
185
- url: component.data.ampUrl,
186
- templateId: 'customize-amp-unavailable-notification',
187
- render: function() {
188
- var li = api.Notification.prototype.render.call( this );
189
- li.find( 'a' ).on( 'click', function( event ) {
190
- event.preventDefault();
191
- component.enableAndNavigateToUrl( this.href );
192
- } );
193
- return li;
194
- }
195
- } ) );
196
- } );
197
- }
198
- };
199
-
200
- /**
201
- * Hook up all AMP preview interactions once panel is ready.
202
- *
203
- * @param {wp.customize.Panel} panel The AMP panel.
204
- * @return {void}
205
- */
206
- component.panelReady = function panelReady( panel ) {
207
- var ampToggleContainer, checkbox, tooltip, tooltipLink;
208
-
209
- ampToggleContainer = $( wp.template( 'customize-amp-enabled-toggle' )( {
210
- message: component.data.l10n.unavailableMessage,
211
- linkText: component.data.l10n.unavailableLinkText,
212
- url: component.data.ampUrl
213
- } ) );
214
- checkbox = ampToggleContainer.find( 'input[type=checkbox]' );
215
- tooltip = ampToggleContainer.find( '.tooltip' );
216
- tooltipLink = tooltip.find( 'a' );
217
-
218
- // AMP panel triggers the input toggle for AMP preview.
219
- panel.expanded.bind( function( expanded ) {
220
- if ( ! expanded ) {
221
- return;
222
- }
223
- if ( api.state( 'ampAvailable' ).get() ) {
224
- api.state( 'ampEnabled' ).set( panel.expanded.get() );
225
- } else if ( ! panel.notifications ) {
226
-
227
- /*
228
- * This is only done if panel notifications aren't supported.
229
- * If they are (as of 4.9) then a notification will be shown
230
- * in the panel and its sections when AMP is not available.
231
- */
232
- setTimeout( function() {
233
- component.tooltipVisible.set( true );
234
- }, 250 );
235
- }
236
- } );
237
-
238
- if ( panel.notifications ) {
239
- api.state( 'ampAvailable' ).bind( component.updatePanelNotifications );
240
- component.updatePanelNotifications();
241
- api.section.bind( 'add', component.updatePanelNotifications );
242
- }
243
-
244
- // Enable AMP toggle if available and mobile device selected.
245
- api.previewedDevice.bind( function( device ) {
246
- if ( api.state( 'ampAvailable' ).get() ) {
247
- api.state( 'ampEnabled' ).set( 'mobile' === device );
248
- }
249
- } );
250
-
251
- // Message coming from previewer.
252
- api.previewer.bind( 'amp-status', function( data ) {
253
- api.state( 'ampAvailable' ).set( data.available );
254
- } );
255
- function setInitialAmpEnabledState( data ) {
256
- api.state( 'ampEnabled' ).set( data.enabled );
257
- api.previewer.unbind( 'amp-status', setInitialAmpEnabledState );
258
- }
259
- api.previewer.bind( 'amp-status', setInitialAmpEnabledState );
260
-
261
- /*
262
- * Persist the presence or lack of the amp=1 param when navigating in the preview,
263
- * even if current page is not yet supported.
264
- */
265
- api.previewer.previewUrl.validate = ( function( prevValidate ) {
266
- return function( value ) {
267
- var val = prevValidate.call( this, value );
268
- if ( val ) {
269
- val = component.setCurrentAmpUrl( val );
270
- }
271
- return val;
272
- };
273
- } )( api.previewer.previewUrl.validate );
274
-
275
- // Listen for ampEnabled state changes.
276
- api.state( 'ampEnabled' ).bind( function( enabled ) {
277
- checkbox.prop( 'checked', enabled );
278
- component.updatePreviewUrl();
279
- } );
280
-
281
- // Listen for ampAvailable state changes.
282
- api.state( 'ampAvailable' ).bind( function( available ) {
283
- checkbox.toggleClass( 'disabled', ! available );
284
-
285
- // Show the unavailable tooltip if AMP is enabled.
286
- if ( api.state( 'ampEnabled' ).get() ) {
287
- component.tooltipVisible.set( ! available );
288
- }
289
- } );
290
-
291
- // Adding checkbox toggle before device selection.
292
- $( '.devices-wrapper' ).before( ampToggleContainer );
293
-
294
- // User clicked link within tooltip, go to linked post in preview.
295
- tooltipLink.on( 'click', function( event ) {
296
- event.preventDefault();
297
- component.enableAndNavigateToUrl( this.href );
298
- } );
299
-
300
- // Toggle visibility of tooltip based on tooltipVisible state.
301
- component.tooltipVisible.bind( function( visible ) {
302
- tooltip.attr( 'aria-hidden', visible ? 'false' : 'true' );
303
- if ( visible ) {
304
- $( document ).on( 'click.amp-toggle-outside', function( event ) {
305
- if ( ! $.contains( ampToggleContainer[0], event.target ) ) {
306
- component.tooltipVisible.set( false );
307
- }
308
- } );
309
- tooltip.fadeIn();
310
- component.tryToCloseTooltip();
311
- } else {
312
- tooltip.fadeOut();
313
- component.tooltipFocused.set( 0 );
314
- $( document ).off( 'click.amp-toggle-outside' );
315
- }
316
- } );
317
-
318
- // Handle click on checkbox to either enable the AMP preview or show the tooltip.
319
- checkbox.on( 'click', function() {
320
- this.checked = ! this.checked; // Undo what we just did, since state is managed in ampAvailable change handler.
321
- if ( api.state( 'ampAvailable' ).get() ) {
322
- api.state( 'ampEnabled' ).set( ! api.state( 'ampEnabled' ).get() );
323
- } else {
324
- component.tooltipVisible.set( true );
325
- }
326
- } );
327
-
328
- // Keep track of the user's state interacting with the tooltip.
329
- tooltip.on( 'mouseenter', function() {
330
- if ( ! api.state( 'ampAvailable' ).get() ) {
331
- component.tooltipVisible.set( true );
332
- }
333
- component.tooltipFocused.set( component.tooltipFocused.get() + 1 );
334
- } );
335
- tooltip.on( 'mouseleave', function() {
336
- component.tooltipFocused.set( component.tooltipFocused.get() - 1 );
337
- } );
338
- tooltipLink.on( 'focus', function() {
339
- if ( ! api.state( 'ampAvailable' ).get() ) {
340
- component.tooltipVisible.set( true );
341
- }
342
- component.tooltipFocused.set( component.tooltipFocused.get() + 1 );
343
- } );
344
- tooltipLink.on( 'blur', function() {
345
- component.tooltipFocused.set( component.tooltipFocused.get() - 1 );
346
- } );
347
- };
348
-
349
- return component;
350
-
351
- } )( wp.customize, jQuery );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/assets/js/amp-customize-preview.js DELETED
@@ -1,26 +0,0 @@
1
- /* exported ampCustomizePreview */
2
-
3
- var ampCustomizePreview = ( function( api ) {
4
- 'use strict';
5
-
6
- var component = {};
7
-
8
- /**
9
- * Boot using data sent inline.
10
- *
11
- * @param {Object} data - PHP exports.
12
- * @param {boolean} data.available - Whether AMP is available.
13
- * @param {boolean} data.enabled - Whether AMP is enabled.
14
- * @return {void}
15
- */
16
- component.boot = function boot( data ) {
17
- api.bind( 'preview-ready', function() {
18
- api.preview.bind( 'active', function() {
19
- api.preview.send( 'amp-status', data );
20
- } );
21
- } );
22
- };
23
-
24
- return component;
25
-
26
- } )( wp.customize );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/assets/js/amp-post-meta-box.js DELETED
@@ -1,179 +0,0 @@
1
- /* exported ampPostMetaBox */
2
-
3
- /**
4
- * AMP Post Meta Box.
5
- *
6
- * @todo Rename this to be just the ampEditPostScreen?
7
- *
8
- * @since 0.6
9
- */
10
- var ampPostMetaBox = ( function( $ ) {
11
- 'use strict';
12
-
13
- var component = {
14
-
15
- /**
16
- * Holds data.
17
- *
18
- * @since 0.6
19
- */
20
- data: {
21
- canonical: false, // Overridden by amp_is_canonical().
22
- previewLink: '',
23
- enabled: true, // Overridden by post_supports_amp( $post ).
24
- canSupport: true, // Overridden by count( AMP_Post_Type_Support::get_support_errors( $post ) ) === 0.
25
- statusInputName: '',
26
- l10n: {
27
- ampPreviewBtnLabel: ''
28
- }
29
- },
30
-
31
- /**
32
- * Toggle animation speed.
33
- *
34
- * @since 0.6
35
- */
36
- toggleSpeed: 200,
37
-
38
- /**
39
- * Core preview button selector.
40
- *
41
- * @since 0.6
42
- */
43
- previewBtnSelector: '#post-preview',
44
-
45
- /**
46
- * AMP preview button selector.
47
- *
48
- * @since 0.6
49
- */
50
- ampPreviewBtnSelector: '#amp-post-preview'
51
- };
52
-
53
- /**
54
- * Boot plugin.
55
- *
56
- * @since 0.6
57
- * @param {Object} data Object data.
58
- * @return {void}
59
- */
60
- component.boot = function boot( data ) {
61
- component.data = data;
62
- $( document ).ready( function() {
63
- component.statusRadioInputs = $( '[name="' + component.data.statusInputName + '"]' );
64
- if ( component.data.enabled && ! component.data.canonical ) {
65
- component.addPreviewButton();
66
- }
67
- component.listen();
68
- } );
69
- };
70
-
71
- /**
72
- * Events listener.
73
- *
74
- * @since 0.6
75
- * @return {void}
76
- */
77
- component.listen = function listen() {
78
- $( component.ampPreviewBtnSelector ).on( 'click.amp-post-preview', function( e ) {
79
- e.preventDefault();
80
- component.onAmpPreviewButtonClick();
81
- } );
82
-
83
- component.statusRadioInputs.prop( 'disabled', true ); // Prevent cementing setting default status as overridden status.
84
- $( '.edit-amp-status, [href="#amp_status"]' ).click( function( e ) {
85
- e.preventDefault();
86
- component.statusRadioInputs.prop( 'disabled', false );
87
- component.toggleAmpStatus( $( e.target ) );
88
- } );
89
-
90
- $( '#submitpost input[type="submit"]' ).on( 'click', function() {
91
- $( component.ampPreviewBtnSelector ).addClass( 'disabled' );
92
- } );
93
- };
94
-
95
- /**
96
- * Add AMP Preview button.
97
- *
98
- * @since 0.6
99
- * @return {void}
100
- */
101
- component.addPreviewButton = function addPreviewButton() {
102
- var previewBtn = $( component.previewBtnSelector );
103
- previewBtn
104
- .clone()
105
- .insertAfter( previewBtn )
106
- .prop( {
107
- 'href': component.data.previewLink,
108
- 'id': component.ampPreviewBtnSelector.replace( '#', '' )
109
- } )
110
- .text( component.data.l10n.ampPreviewBtnLabel )
111
- .parent()
112
- .addClass( 'has-amp-preview' );
113
- };
114
-
115
- /**
116
- * AMP Preview button click handler.
117
- *
118
- * We trigger the Core preview link for events propagation purposes.
119
- *
120
- * @since 0.6
121
- * @return {void}
122
- */
123
- component.onAmpPreviewButtonClick = function onAmpPreviewButtonClick() {
124
- var $input;
125
-
126
- // Flag the AMP preview referer.
127
- $input = $( '<input>' )
128
- .prop( {
129
- 'type': 'hidden',
130
- 'name': 'amp-preview',
131
- 'value': 'do-preview'
132
- } )
133
- .insertAfter( component.ampPreviewBtnSelector );
134
-
135
- // Trigger Core preview button and remove AMP flag.
136
- $( component.previewBtnSelector ).click();
137
- $input.remove();
138
- };
139
-
140
- /**
141
- * Add AMP status toggle.
142
- *
143
- * @since 0.6
144
- * @param {Object} $target Event target.
145
- * @return {void}
146
- */
147
- component.toggleAmpStatus = function toggleAmpStatus( $target ) {
148
- var $container = $( '#amp-status-select' ),
149
- status = $container.data( 'amp-status' ),
150
- $checked,
151
- editAmpStatus = $( '.edit-amp-status' );
152
-
153
- // Don't modify status on cancel button click.
154
- if ( ! $target.hasClass( 'button-cancel' ) ) {
155
- status = component.statusRadioInputs.filter( ':checked' ).val();
156
- }
157
-
158
- $checked = $( '#amp-status-' + status );
159
-
160
- // Toggle elements.
161
- editAmpStatus.fadeToggle( component.toggleSpeed, function() {
162
- if ( editAmpStatus.is( ':visible' ) ) {
163
- editAmpStatus.focus();
164
- } else {
165
- $container.find( 'input[type="radio"]' ).first().focus();
166
- }
167
- } );
168
- $container.slideToggle( component.toggleSpeed );
169
-
170
- // Update status.
171
- if ( component.data.canSupport ) {
172
- $container.data( 'amp-status', status );
173
- $checked.prop( 'checked', true );
174
- $( '.amp-status-text' ).text( $checked.next().text() );
175
- }
176
- };
177
-
178
- return component;
179
- })( window.jQuery );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/admin/class-amp-post-meta-box.php DELETED
@@ -1,246 +0,0 @@
1
- <?php
2
- /**
3
- * AMP meta box settings.
4
- *
5
- * @package AMP
6
- * @since 0.6
7
- */
8
-
9
- /**
10
- * Post meta box class.
11
- *
12
- * @since 0.6
13
- */
14
- class AMP_Post_Meta_Box {
15
-
16
- /**
17
- * Assets handle.
18
- *
19
- * @since 0.6
20
- * @var string
21
- */
22
- const ASSETS_HANDLE = 'amp-post-meta-box';
23
-
24
- /**
25
- * The enabled status post meta value.
26
- *
27
- * @since 0.6
28
- * @var string
29
- */
30
- const ENABLED_STATUS = 'enabled';
31
-
32
- /**
33
- * The disabled status post meta value.
34
- *
35
- * @since 0.6
36
- * @var string
37
- */
38
- const DISABLED_STATUS = 'disabled';
39
-
40
- /**
41
- * The status post meta key.
42
- *
43
- * @since 0.6
44
- * @var string
45
- */
46
- const STATUS_POST_META_KEY = 'amp_status';
47
-
48
- /**
49
- * The field name for the enabled/disabled radio buttons.
50
- *
51
- * @since 0.6
52
- * @var string
53
- */
54
- const STATUS_INPUT_NAME = 'amp_status';
55
-
56
- /**
57
- * The nonce name.
58
- *
59
- * @since 0.6
60
- * @var string
61
- */
62
- const NONCE_NAME = 'amp-status-nonce';
63
-
64
- /**
65
- * The nonce action.
66
- *
67
- * @since 0.6
68
- * @var string
69
- */
70
- const NONCE_ACTION = 'amp-update-status';
71
-
72
- /**
73
- * Initialize.
74
- *
75
- * @since 0.6
76
- */
77
- public function init() {
78
- register_meta( 'post', self::STATUS_POST_META_KEY, array(
79
- 'sanitize_callback' => array( $this, 'sanitize_status' ),
80
- 'type' => 'string',
81
- 'description' => __( 'AMP status.', 'amp' ),
82
- 'show_in_rest' => true,
83
- 'single' => true,
84
- ) );
85
-
86
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
87
- add_action( 'post_submitbox_misc_actions', array( $this, 'render_status' ) );
88
- add_action( 'save_post', array( $this, 'save_amp_status' ) );
89
- add_filter( 'preview_post_link', array( $this, 'preview_post_link' ) );
90
- }
91
-
92
- /**
93
- * Sanitize status.
94
- *
95
- * @param string $status Status.
96
- * @return string Sanitized status. Empty string when invalid.
97
- */
98
- public function sanitize_status( $status ) {
99
- $status = strtolower( trim( $status ) );
100
- if ( ! in_array( $status, array( 'enabled', 'disabled' ), true ) ) {
101
- /*
102
- * In lieu of actual validation being available, clear the status entirely
103
- * so that the underlying default status will be used instead.
104
- * In the future it would be ideal if register_meta() accepted a
105
- * validate_callback as well which the REST API could leverage.
106
- */
107
- $status = '';
108
- }
109
- return $status;
110
- }
111
-
112
- /**
113
- * Enqueue admin assets.
114
- *
115
- * @since 0.6
116
- */
117
- public function enqueue_admin_assets() {
118
- $post = get_post();
119
- $screen = get_current_screen();
120
- $validate = (
121
- isset( $screen->base )
122
- &&
123
- 'post' === $screen->base
124
- &&
125
- is_post_type_viewable( $post->post_type )
126
- );
127
- if ( ! $validate ) {
128
- return;
129
- }
130
-
131
- // Styles.
132
- wp_enqueue_style(
133
- self::ASSETS_HANDLE,
134
- amp_get_asset_url( 'css/amp-post-meta-box.css' ),
135
- false,
136
- AMP__VERSION
137
- );
138
-
139
- // Scripts.
140
- wp_enqueue_script(
141
- self::ASSETS_HANDLE,
142
- amp_get_asset_url( 'js/amp-post-meta-box.js' ),
143
- array( 'jquery' ),
144
- AMP__VERSION
145
- );
146
- wp_add_inline_script( self::ASSETS_HANDLE, sprintf( 'ampPostMetaBox.boot( %s );',
147
- wp_json_encode( array(
148
- 'previewLink' => esc_url_raw( add_query_arg( amp_get_slug(), '', get_preview_post_link( $post ) ) ),
149
- 'canonical' => amp_is_canonical(),
150
- 'enabled' => post_supports_amp( $post ),
151
- 'canSupport' => count( AMP_Post_Type_Support::get_support_errors( $post ) ) === 0,
152
- 'statusInputName' => self::STATUS_INPUT_NAME,
153
- 'l10n' => array(
154
- 'ampPreviewBtnLabel' => __( 'Preview changes in AMP (opens in new window)', 'amp' ),
155
- ),
156
- ) )
157
- ) );
158
- }
159
-
160
- /**
161
- * Render AMP status.
162
- *
163
- * @since 0.6
164
- * @param WP_Post $post Post.
165
- */
166
- public function render_status( $post ) {
167
- $verify = (
168
- isset( $post->ID )
169
- &&
170
- is_post_type_viewable( $post->post_type )
171
- &&
172
- current_user_can( 'edit_post', $post->ID )
173
- &&
174
- ! amp_is_canonical()
175
- );
176
-
177
- if ( true !== $verify ) {
178
- return;
179
- }
180
-
181
- $errors = AMP_Post_Type_Support::get_support_errors( $post );
182
- $status = post_supports_amp( $post ) ? self::ENABLED_STATUS : self::DISABLED_STATUS;
183
- $labels = array(
184
- 'enabled' => __( 'Enabled', 'amp' ),
185
- 'disabled' => __( 'Disabled', 'amp' ),
186
- );
187
-
188
- // The preceding variables are used inside the following amp-status.php template.
189
- include_once AMP__DIR__ . '/templates/admin/amp-status.php';
190
- }
191
-
192
- /**
193
- * Save AMP Status.
194
- *
195
- * @since 0.6
196
- * @param int $post_id The Post ID.
197
- */
198
- public function save_amp_status( $post_id ) {
199
- $verify = (
200
- isset( $_POST[ self::NONCE_NAME ] )
201
- &&
202
- isset( $_POST[ self::STATUS_INPUT_NAME ] )
203
- &&
204
- wp_verify_nonce( sanitize_key( wp_unslash( $_POST[ self::NONCE_NAME ] ) ), self::NONCE_ACTION )
205
- &&
206
- current_user_can( 'edit_post', $post_id )
207
- &&
208
- ! wp_is_post_revision( $post_id )
209
- &&
210
- ! wp_is_post_autosave( $post_id )
211
- );
212
-
213
- if ( true === $verify ) {
214
- update_post_meta(
215
- $post_id,
216
- self::STATUS_POST_META_KEY,
217
- $_POST[ self::STATUS_INPUT_NAME ] // Note: The sanitize_callback has been supplied in the register_meta() call above.
218
- );
219
- }
220
- }
221
-
222
- /**
223
- * Modify post preview link.
224
- *
225
- * Add the AMP query var is the amp-preview flag is set.
226
- *
227
- * @since 0.6
228
- *
229
- * @param string $link The post preview link.
230
- * @return string Preview URL.
231
- */
232
- public function preview_post_link( $link ) {
233
- $is_amp = (
234
- isset( $_POST['amp-preview'] ) // WPCS: CSRF ok.
235
- &&
236
- 'do-preview' === sanitize_key( wp_unslash( $_POST['amp-preview'] ) ) // WPCS: CSRF ok.
237
- );
238
-
239
- if ( $is_amp ) {
240
- $link = add_query_arg( amp_get_slug(), true, $link );
241
- }
242
-
243
- return $link;
244
- }
245
-
246
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/class-amp-autoloader.php DELETED
@@ -1,152 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Autoloader
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Autoload the classes used by the AMP plugin.
10
- *
11
- * Class AMP_Autoloader
12
- */
13
- class AMP_Autoloader {
14
-
15
- /**
16
- * Map of Classname to relative filepath sans extension.
17
- *
18
- * @note We omitted the leading slash and the .php extension from each
19
- * relative filepath because they are redundant and to include
20
- * them would take up unnecessary bytes of memory at runtime.
21
- *
22
- * @example Format (note no leading / and no .php extension):
23
- *
24
- * array(
25
- * 'Class_Name1' => 'subdir-of-includes/filename1',
26
- * 'Class_Name2' => '2nd-subdir-of-includes/filename2',
27
- * );
28
- *
29
- * @var string[]
30
- */
31
- private static $_classmap = array(
32
- 'AMP_Theme_Support' => 'includes/class-amp-theme-support',
33
- 'AMP_Comment_Walker' => 'includes/class-amp-comment-walker',
34
- 'AMP_Template_Customizer' => 'includes/admin/class-amp-customizer',
35
- 'AMP_Post_Meta_Box' => 'includes/admin/class-amp-post-meta-box',
36
- 'AMP_Post_Type_Support' => 'includes/class-amp-post-type-support',
37
- 'AMP_Base_Embed_Handler' => 'includes/embeds/class-amp-base-embed-handler',
38
- 'AMP_DailyMotion_Embed_Handler' => 'includes/embeds/class-amp-dailymotion-embed',
39
- 'AMP_Facebook_Embed_Handler' => 'includes/embeds/class-amp-facebook-embed',
40
- 'AMP_Gallery_Embed_Handler' => 'includes/embeds/class-amp-gallery-embed',
41
- 'AMP_Instagram_Embed_Handler' => 'includes/embeds/class-amp-instagram-embed',
42
- 'AMP_Issuu_Embed_Handler' => 'includes/embeds/class-amp-issuu-embed-handler',
43
- 'AMP_Meetup_Embed_Handler' => 'includes/embeds/class-amp-meetup-embed-handler',
44
- 'AMP_Pinterest_Embed_Handler' => 'includes/embeds/class-amp-pinterest-embed',
45
- 'AMP_Playlist_Embed_Handler' => 'includes/embeds/class-amp-playlist-embed-handler',
46
- 'AMP_Reddit_Embed_Handler' => 'includes/embeds/class-amp-reddit-embed-handler',
47
- 'AMP_SoundCloud_Embed_Handler' => 'includes/embeds/class-amp-soundcloud-embed',
48
- 'AMP_Tumblr_Embed_Handler' => 'includes/embeds/class-amp-tumblr-embed-handler',
49
- 'AMP_Twitter_Embed_Handler' => 'includes/embeds/class-amp-twitter-embed',
50
- 'AMP_Vimeo_Embed_Handler' => 'includes/embeds/class-amp-vimeo-embed',
51
- 'AMP_Vine_Embed_Handler' => 'includes/embeds/class-amp-vine-embed',
52
- 'AMP_YouTube_Embed_Handler' => 'includes/embeds/class-amp-youtube-embed',
53
- 'FastImage' => 'includes/lib/fastimage/class-fastimage',
54
- 'WillWashburn\Stream\Exception\StreamBufferTooSmallException' => 'includes/lib/fasterimage/Stream/Exception/StreamBufferTooSmallException',
55
- 'WillWashburn\Stream\StreamableInterface' => 'includes/lib/fasterimage/Stream/StreamableInterface',
56
- 'WillWashburn\Stream\Stream' => 'includes/lib/fasterimage/Stream/Stream',
57
- 'FasterImage\Exception\InvalidImageException' => 'includes/lib/fasterimage/Exception/InvalidImageException',
58
- 'FasterImage\ExifParser' => 'includes/lib/fasterimage/ExifParser',
59
- 'FasterImage\ImageParser' => 'includes/lib/fasterimage/ImageParser',
60
- 'FasterImage\FasterImage' => 'includes/lib/fasterimage/FasterImage',
61
- 'AMP_Analytics_Options_Submenu' => 'includes/options/class-amp-analytics-options-submenu',
62
- 'AMP_Options_Menu' => 'includes/options/class-amp-options-menu',
63
- 'AMP_Options_Manager' => 'includes/options/class-amp-options-manager',
64
- 'AMP_Analytics_Options_Submenu_Page' => 'includes/options/views/class-amp-analytics-options-submenu-page',
65
- 'AMP_Options_Menu_Page' => 'includes/options/views/class-amp-options-menu-page',
66
- 'AMP_Rule_Spec' => 'includes/sanitizers/class-amp-rule-spec',
67
- 'AMP_Allowed_Tags_Generated' => 'includes/sanitizers/class-amp-allowed-tags-generated',
68
- 'AMP_Audio_Sanitizer' => 'includes/sanitizers/class-amp-audio-sanitizer',
69
- 'AMP_Base_Sanitizer' => 'includes/sanitizers/class-amp-base-sanitizer',
70
- 'AMP_Blacklist_Sanitizer' => 'includes/sanitizers/class-amp-blacklist-sanitizer',
71
- 'AMP_Iframe_Sanitizer' => 'includes/sanitizers/class-amp-iframe-sanitizer',
72
- 'AMP_Img_Sanitizer' => 'includes/sanitizers/class-amp-img-sanitizer',
73
- 'AMP_Comments_Sanitizer' => 'includes/sanitizers/class-amp-comments-sanitizer',
74
- 'AMP_Form_Sanitizer' => 'includes/sanitizers/class-amp-form-sanitizer',
75
- 'AMP_Playbuzz_Sanitizer' => 'includes/sanitizers/class-amp-playbuzz-sanitizer',
76
- 'AMP_Style_Sanitizer' => 'includes/sanitizers/class-amp-style-sanitizer',
77
- 'AMP_Tag_And_Attribute_Sanitizer' => 'includes/sanitizers/class-amp-tag-and-attribute-sanitizer',
78
- 'AMP_Video_Sanitizer' => 'includes/sanitizers/class-amp-video-sanitizer',
79
- 'AMP_Customizer_Design_Settings' => 'includes/settings/class-amp-customizer-design-settings',
80
- 'AMP_Customizer_Settings' => 'includes/settings/class-amp-customizer-settings',
81
- 'AMP_Content' => 'includes/templates/class-amp-content',
82
- 'AMP_Content_Sanitizer' => 'includes/templates/class-amp-content-sanitizer',
83
- 'AMP_Post_Template' => 'includes/templates/class-amp-post-template',
84
- 'AMP_DOM_Utils' => 'includes/utils/class-amp-dom-utils',
85
- 'AMP_HTML_Utils' => 'includes/utils/class-amp-html-utils',
86
- 'AMP_Image_Dimension_Extractor' => 'includes/utils/class-amp-image-dimension-extractor',
87
- 'AMP_Validation_Utils' => 'includes/utils/class-amp-validation-utils',
88
- 'AMP_String_Utils' => 'includes/utils/class-amp-string-utils',
89
- 'AMP_WP_Utils' => 'includes/utils/class-amp-wp-utils',
90
- 'AMP_Widget_Archives' => 'includes/widgets/class-amp-widget-archives',
91
- 'AMP_Widget_Categories' => 'includes/widgets/class-amp-widget-categories',
92
- 'AMP_Widget_Media_Video' => 'includes/widgets/class-amp-widget-media-video',
93
- 'AMP_Widget_Recent_Comments' => 'includes/widgets/class-amp-widget-recent-comments',
94
- 'AMP_Widget_Text' => 'includes/widgets/class-amp-widget-text',
95
- 'WPCOM_AMP_Polldaddy_Embed' => 'wpcom/class-amp-polldaddy-embed',
96
- 'AMP_Test_Stub_Sanitizer' => 'tests/stubs',
97
- 'AMP_Test_World_Sanitizer' => 'tests/stubs',
98
- );
99
-
100
- /**
101
- * Is registered.
102
- *
103
- * @var bool
104
- */
105
- public static $is_registered = false;
106
-
107
- /**
108
- * Perform the autoload on demand when requested by PHP runtime.
109
- *
110
- * Design Goal: Execute as few lines of code as possible each call.
111
- *
112
- * @since 0.6
113
- *
114
- * @param string $class_name Class name.
115
- */
116
- protected static function autoload( $class_name ) {
117
- if ( ! isset( self::$_classmap[ $class_name ] ) ) {
118
- return;
119
- }
120
- $is_load = apply_filters('ampforwp_update_autoload_class', self::$_classmap, $class_name);
121
- if($is_load){
122
- $filepath = self::$_classmap[ $class_name ];
123
- require AMP__DIR__ . "/{$filepath}.php";
124
- }
125
- }
126
-
127
- /**
128
- * Registers this autoloader to PHP.
129
- *
130
- * @since 0.6
131
- *
132
- * Called at the end of this file; calling a second time has no effect.
133
- */
134
- public static function register() {
135
- if ( ! self::$is_registered ) {
136
- spl_autoload_register( array( __CLASS__, 'autoload' ) );
137
- self::$is_registered = true;
138
- }
139
- }
140
-
141
- /**
142
- * Allows an extensions plugin to register a class and its file for autoloading
143
- *
144
- * @since 0.6
145
- *
146
- * @param string $class_name Full classname (include namespace if applicable).
147
- * @param string $filepath Absolute filepath to class file, including .php extension.
148
- */
149
- public static function register_autoload_class( $class_name, $filepath ) {
150
- self::$_classmap[ $class_name ] = '!' . $filepath;
151
- }
152
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/class-amp-comment-walker.php DELETED
@@ -1,121 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Comment_Walker
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Comment_Walker
10
- *
11
- * Walker to wrap comments in mustache tags for amp-template.
12
- */
13
- class AMP_Comment_Walker extends Walker_Comment {
14
-
15
- /**
16
- * The original comments arguments.
17
- *
18
- * @since 0.7
19
- * @var array
20
- */
21
- public $args;
22
-
23
- /**
24
- * Holds the timestamp of the most reacent comment in a thread.
25
- *
26
- * @since 0.7
27
- * @var array
28
- */
29
- private $comment_thread_age = array();
30
-
31
- /**
32
- * Starts the element output.
33
- *
34
- * @since 0.7.0
35
- *
36
- * @see Walker::start_el()
37
- * @see wp_list_comments()
38
- * @global int $comment_depth
39
- * @global WP_Comment $comment
40
- *
41
- * @param string $output Used to append additional content. Passed by reference.
42
- * @param WP_Comment $comment Comment data object.
43
- * @param int $depth Optional. Depth of the current comment in reference to parents. Default 0.
44
- * @param array $args Optional. An array of arguments. Default empty array.
45
- * @param int $id Optional. ID of the current comment. Default 0 (unused).
46
- */
47
- public function start_el( &$output, $comment, $depth = 0, $args = array(), $id = 0 ) {
48
-
49
- $new_out = '';
50
- parent::start_el( $new_out, $comment, $depth, $args, $id );
51
-
52
- if ( 'div' === $args['style'] ) {
53
- $tag = '<div';
54
- } else {
55
- $tag = '<li';
56
- }
57
- $new_tag = $tag . ' data-sort-time="' . esc_attr( strtotime( $comment->comment_date ) ) . '"';
58
-
59
- if ( ! empty( $this->comment_thread_age[ $comment->comment_ID ] ) ) {
60
- $new_tag .= ' data-update-time="' . esc_attr( $this->comment_thread_age[ $comment->comment_ID ] ) . '"';
61
- }
62
-
63
- $output .= $new_tag . substr( ltrim( $new_out ), strlen( $tag ) );
64
-
65
- }
66
-
67
- /**
68
- * Output amp-list template code and place holder for comments.
69
- *
70
- * @since 0.7
71
- * @see Walker::paged_walk()
72
- *
73
- * @param WP_Comment[] $elements List of comment Elements.
74
- * @param int $max_depth The maximum hierarchical depth.
75
- * @param int $page_num The specific page number, beginning with 1.
76
- * @param int $per_page Per page counter.
77
- *
78
- * @return string XHTML of the specified page of elements.
79
- */
80
- public function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
81
- if ( empty( $elements ) || $max_depth < -1 ) {
82
- return '';
83
- }
84
-
85
- $this->build_thread_latest_date( $elements );
86
-
87
- $args = array_slice( func_get_args(), 4 );
88
-
89
- return parent::paged_walk( $elements, $max_depth, $page_num, $per_page, $args[0] );
90
- }
91
-
92
- /**
93
- * Find the timestamp of the latest child comment of a thread to set the updated time.
94
- *
95
- * @since 0.7
96
- *
97
- * @param WP_Comment[] $elements The list of comments to get thread times for.
98
- * @param int $time $the timestamp to check against.
99
- * @param bool $is_child Flag used to set the the value or return the time.
100
- * @return int Latest time.
101
- */
102
- protected function build_thread_latest_date( $elements, $time = 0, $is_child = false ) {
103
-
104
- foreach ( $elements as $element ) {
105
-
106
- $children = $element->get_children();
107
- $this_time = strtotime( $element->comment_date );
108
- if ( ! empty( $children ) ) {
109
- $this_time = $this->build_thread_latest_date( $children, $this_time, true );
110
- }
111
- if ( $this_time > $time ) {
112
- $time = $this_time;
113
- }
114
- if ( false === $is_child ) {
115
- $this->comment_thread_age[ $element->comment_ID ] = $time;
116
- }
117
- }
118
-
119
- return $time;
120
- }
121
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/class-amp-post-type-support.php DELETED
@@ -1,99 +0,0 @@
1
- <?php
2
- /**
3
- * AMP Post type support.
4
- *
5
- * @package AMP
6
- * @since 0.6
7
- */
8
-
9
- /**
10
- * Class AMP_Post_Type_Support.
11
- */
12
- class AMP_Post_Type_Support {
13
-
14
- /**
15
- * Get post types that plugin supports out of the box (which cannot be disabled).
16
- *
17
- * @return string[] Post types.
18
- */
19
- public static function get_builtin_supported_post_types() {
20
- return array_filter( array( 'post' ), 'post_type_exists' );
21
- }
22
-
23
- /**
24
- * Get post types that are eligible for AMP support.
25
- *
26
- * @since 0.6
27
- * @return string[] Post types eligible for AMP.
28
- */
29
- public static function get_eligible_post_types() {
30
- return array_merge(
31
- self::get_builtin_supported_post_types(),
32
- array( 'page' ),
33
- array_values( get_post_types(
34
- array(
35
- 'public' => true,
36
- '_builtin' => false,
37
- ),
38
- 'names'
39
- ) )
40
- );
41
- }
42
-
43
- /**
44
- * Declare support for post types.
45
- *
46
- * This function should only be invoked through the 'after_setup_theme' action to
47
- * allow plugins/theme to overwrite the post types support.
48
- *
49
- * @since 0.6
50
- */
51
- public static function add_post_type_support() {
52
- $post_types = array_merge(
53
- self::get_builtin_supported_post_types(),
54
- AMP_Options_Manager::get_option( 'supported_post_types', array() )
55
- );
56
- foreach ( $post_types as $post_type ) {
57
- add_post_type_support( $post_type, amp_get_slug() );
58
- }
59
- }
60
-
61
- /**
62
- * Return error codes for why a given post does not have AMP support.
63
- *
64
- * @since 0.6
65
- *
66
- * @param WP_Post|int $post Post.
67
- * @return array Error codes for why a given post does not have AMP support.
68
- */
69
- public static function get_support_errors( $post ) {
70
- if ( ! ( $post instanceof WP_Post ) ) {
71
- $post = get_post( $post );
72
- }
73
- $errors = array();
74
-
75
- // Because `add_rewrite_endpoint` doesn't let us target specific post_types.
76
- if ( isset( $post->post_type ) && ! post_type_supports( $post->post_type, amp_get_slug() ) ) {
77
- $errors[] = 'post-type-support';
78
- }
79
-
80
- if ( post_password_required( $post ) ) {
81
- $errors[] = 'password-protected';
82
- }
83
-
84
- /**
85
- * Filters whether to skip the post from AMP.
86
- *
87
- * @since 0.3
88
- *
89
- * @param bool $skipped Skipped.
90
- * @param int $post_id Post ID.
91
- * @param WP_Post $post Post.
92
- */
93
- if ( isset( $post->ID ) && true === apply_filters( 'amp_skip_post', false, $post->ID, $post ) ) {
94
- $errors[] = 'skip-post';
95
- }
96
-
97
- return $errors;
98
- }
99
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/class-amp-theme-support.php DELETED
@@ -1,1201 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Theme_Support
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Theme_Support
10
- *
11
- * Callbacks for adding AMP-related things when theme support is added.
12
- */
13
- class AMP_Theme_Support {
14
-
15
- /**
16
- * Replaced with the necessary scripts depending on components used in output.
17
- *
18
- * @var string
19
- */
20
- const SCRIPTS_PLACEHOLDER = '<!-- AMP:SCRIPTS_PLACEHOLDER -->';
21
-
22
- /**
23
- * Sanitizer classes.
24
- *
25
- * @var array
26
- */
27
- protected static $sanitizer_classes = array();
28
-
29
- /**
30
- * Embed handlers.
31
- *
32
- * @var AMP_Base_Embed_Handler[]
33
- */
34
- protected static $embed_handlers = array();
35
-
36
- /**
37
- * Template types.
38
- *
39
- * @var array
40
- */
41
- protected static $template_types = array(
42
- 'paged', // Deprecated.
43
- 'index',
44
- '404',
45
- 'archive',
46
- 'author',
47
- 'category',
48
- 'tag',
49
- 'taxonomy',
50
- 'date',
51
- 'home',
52
- 'front_page',
53
- 'page',
54
- 'search',
55
- 'single',
56
- 'embed',
57
- 'singular',
58
- 'attachment',
59
- );
60
-
61
- /**
62
- * AMP-specific query vars that were purged.
63
- *
64
- * @since 0.7
65
- * @see AMP_Theme_Support::purge_amp_query_vars()
66
- * @var string[]
67
- */
68
- public static $purged_amp_query_vars = array();
69
-
70
- /**
71
- * Headers sent (or attempted to be sent).
72
- *
73
- * @since 0.7
74
- * @see AMP_Theme_Support::send_header()
75
- * @var array[]
76
- */
77
- public static $headers_sent = array();
78
-
79
- /**
80
- * Whether output buffering has started.
81
- *
82
- * @since 0.7
83
- * @var bool
84
- */
85
- protected static $is_output_buffering = false;
86
-
87
- /**
88
- * Initialize.
89
- */
90
- public static function init() {
91
- if ( ! current_theme_supports( 'amp' ) ) {
92
- return;
93
- }
94
-
95
- self::purge_amp_query_vars();
96
- self::handle_xhr_request();
97
-
98
- require_once AMP__DIR__ . '/includes/amp-post-template-actions.php';
99
-
100
- // Validate theme support usage.
101
- $support = get_theme_support( 'amp' );
102
- if ( WP_DEBUG && is_array( $support ) ) {
103
- $args = array_shift( $support );
104
- if ( ! is_array( $args ) ) {
105
- trigger_error( esc_html__( 'Expected AMP theme support arg to be array.', 'amp' ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
106
- } elseif ( count( array_diff( array_keys( $args ), array( 'template_dir', 'available_callback', 'comments_live_list' ) ) ) !== 0 ) {
107
- trigger_error( esc_html__( 'Expected AMP theme support to only have template_dir and/or available_callback.', 'amp' ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
108
- }
109
- }
110
-
111
- add_action( 'widgets_init', array( __CLASS__, 'register_widgets' ) );
112
-
113
- /*
114
- * Note that wp action is use instead of template_redirect because some themes/plugins output
115
- * the response at this action and then short-circuit with exit. So this is why the the preceding
116
- * action to template_redirect--the wp action--is used instead.
117
- */
118
- add_action( 'wp', array( __CLASS__, 'finish_init' ), PHP_INT_MAX );
119
- }
120
-
121
- /**
122
- * Finish initialization once query vars are set.
123
- *
124
- * @since 0.7
125
- */
126
- public static function finish_init() {
127
- if ( ! is_amp_endpoint() ) {
128
- // Add amphtml link when paired mode is available.
129
- if ( self::is_paired_available() ) {
130
- amp_add_frontend_actions(); // @todo This function is poor in how it requires a file that then does add_action().
131
- if ( ! has_action( 'wp_head', 'amp_frontend_add_canonical' ) ) {
132
- add_action( 'wp_head', 'amp_frontend_add_canonical' );
133
- }
134
- }
135
- return;
136
- }
137
-
138
- if ( amp_is_canonical() ) {
139
- self::redirect_canonical_amp();
140
- } else {
141
- self::register_paired_hooks();
142
- }
143
-
144
- self::add_hooks();
145
- self::$sanitizer_classes = amp_get_content_sanitizers();
146
- self::$embed_handlers = self::register_content_embed_handlers();
147
- }
148
-
149
- /**
150
- * Redirect to canonical URL if the AMP URL was loaded, since canonical is now AMP.
151
- *
152
- * @since 0.7
153
- */
154
- public static function redirect_canonical_amp() {
155
- if ( false !== get_query_var( amp_get_slug(), false ) ) { // Because is_amp_endpoint() now returns true if amp_is_canonical().
156
- $url = preg_replace( '#^(https?://.+?)(/.*)$#', '$1', home_url( '/' ) );
157
- if ( isset( $_SERVER['REQUEST_URI'] ) ) {
158
- $url .= wp_unslash( $_SERVER['REQUEST_URI'] );
159
- }
160
-
161
- $url = amp_remove_endpoint( $url );
162
-
163
- wp_safe_redirect( $url, 302 ); // Temporary redirect because canonical may change in future.
164
- exit;
165
- }
166
- }
167
-
168
- /**
169
- * Determines whether paired mode is available.
170
- *
171
- * When 'amp' theme support has not been added or canonical mode is enabled, then this returns false.
172
- * Returns true when there is a template_dir defined in theme support, and if a defined available_callback
173
- * returns true.
174
- *
175
- * @return bool Whether available.
176
- */
177
- public static function is_paired_available() {
178
- $support = get_theme_support( 'amp' );
179
- if ( empty( $support ) || amp_is_canonical() ) {
180
- return false;
181
- }
182
-
183
- if ( is_singular() && ! post_supports_amp( get_queried_object() ) ) {
184
- return false;
185
- }
186
-
187
- $args = array_shift( $support );
188
-
189
- if ( isset( $args['available_callback'] ) && is_callable( $args['available_callback'] ) ) {
190
- return call_user_func( $args['available_callback'] );
191
- }
192
- return true;
193
- }
194
-
195
- /**
196
- * Determine whether the user is in the Customizer preview iframe.
197
- *
198
- * @since 0.7
199
- *
200
- * @return bool Whether in Customizer preview iframe.
201
- */
202
- public static function is_customize_preview_iframe() {
203
- global $wp_customize;
204
- return is_customize_preview() && $wp_customize->get_messenger_channel();
205
- }
206
-
207
- /**
208
- * Register hooks for paired mode.
209
- */
210
- public static function register_paired_hooks() {
211
- foreach ( self::$template_types as $template_type ) {
212
- add_filter( "{$template_type}_template_hierarchy", array( __CLASS__, 'filter_paired_template_hierarchy' ) );
213
- }
214
- add_filter( 'template_include', array( __CLASS__, 'filter_paired_template_include' ), 100 );
215
- }
216
-
217
- /**
218
- * Register hooks.
219
- */
220
- public static function add_hooks() {
221
-
222
- // Remove core actions which are invalid AMP.
223
- remove_action( 'wp_head', 'wp_post_preview_js', 1 );
224
- remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
225
- remove_action( 'wp_print_styles', 'print_emoji_styles' );
226
- remove_action( 'wp_head', 'wp_oembed_add_host_js' );
227
-
228
- // Prevent MediaElement.js scripts/styles from being enqueued.
229
- add_filter( 'wp_video_shortcode_library', function() {
230
- return 'amp';
231
- } );
232
- add_filter( 'wp_audio_shortcode_library', function() {
233
- return 'amp';
234
- } );
235
-
236
- /*
237
- * Add additional markup required by AMP <https://www.ampproject.org/docs/reference/spec#required-markup>.
238
- * Note that the meta[name=viewport] is not added here because a theme may want to define one with additional
239
- * properties than included in the default configuration. If a theme doesn't include one, then the meta viewport
240
- * will be added when output buffering is finished. Note that meta charset _is_ output here because the output
241
- * buffer will need it to parse the document properly, and it must be exactly as is to be valid AMP. Nevertheless,
242
- * in this case too we should defer to the theme as well to output the meta charset because it is possible the
243
- * install is not on utf-8 and we may need to do a encoding conversion.
244
- */
245
- add_action( 'wp_print_styles', array( __CLASS__, 'print_amp_styles' ), 0 ); // Print boilerplate before theme and plugin stylesheets.
246
- add_action( 'wp_head', 'amp_add_generator_metadata', 20 );
247
-
248
- add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
249
- add_action( 'wp_enqueue_scripts', array( __CLASS__, 'dequeue_customize_preview_scripts' ), 1000 );
250
- add_filter( 'customize_partial_render', array( __CLASS__, 'filter_customize_partial_render' ) );
251
-
252
- add_action( 'wp_footer', 'amp_print_analytics' );
253
-
254
- /*
255
- * Disable admin bar because admin-bar.css (28K) and Dashicons (48K) alone
256
- * combine to surpass the 50K limit imposed for the amp-custom style.
257
- */
258
- add_filter( 'show_admin_bar', '__return_false', 100 );
259
-
260
- /*
261
- * Start output buffering at very low priority for sake of plugins and themes that use template_redirect
262
- * instead of template_include.
263
- */
264
- $priority = defined( 'PHP_INT_MIN' ) ? PHP_INT_MIN : ~PHP_INT_MAX; // phpcs:ignore PHPCompatibility.PHP.NewConstants.php_int_minFound
265
- add_action( 'template_redirect', array( __CLASS__, 'start_output_buffering' ), $priority );
266
-
267
- // Add validation hooks *after* output buffering has started for the response.
268
- if ( AMP_Validation_Utils::should_validate_response() ) {
269
- AMP_Validation_Utils::add_validation_hooks();
270
- }
271
-
272
- // Commenting hooks.
273
- add_filter( 'wp_list_comments_args', array( __CLASS__, 'set_comments_walker' ), PHP_INT_MAX );
274
- add_filter( 'comment_form_defaults', array( __CLASS__, 'filter_comment_form_defaults' ) );
275
- add_filter( 'comment_reply_link', array( __CLASS__, 'filter_comment_reply_link' ), 10, 4 );
276
- add_filter( 'cancel_comment_reply_link', array( __CLASS__, 'filter_cancel_comment_reply_link' ), 10, 3 );
277
- add_action( 'comment_form', array( __CLASS__, 'amend_comment_form' ), 100 );
278
- remove_action( 'comment_form', 'wp_comment_form_unfiltered_html_nonce' );
279
- add_filter( 'wp_kses_allowed_html', array( __CLASS__, 'whitelist_layout_in_wp_kses_allowed_html' ), 10 );
280
-
281
- // @todo Add character conversion.
282
- }
283
-
284
- /**
285
- * Remove query vars that come in requests such as for amp-live-list.
286
- *
287
- * WordPress should generally not respond differently to requests when these parameters
288
- * are present. In some cases, when a query param such as __amp_source_origin is present
289
- * then it would normally get included into pagination links generated by get_pagenum_link().
290
- * The whitelist sanitizer empties out links that contain this string as it matches the
291
- * blacklisted_value_regex. So by preemptively scrubbing any reference to these query vars
292
- * we can ensure that WordPress won't end up referencing them in any way.
293
- *
294
- * @since 0.7
295
- */
296
- public static function purge_amp_query_vars() {
297
- $query_vars = array(
298
- '__amp_source_origin',
299
- '_wp_amp_action_xhr_converted',
300
- 'amp_latest_update_time',
301
- 'amp_last_check_time',
302
- );
303
-
304
- // Scrub input vars.
305
- foreach ( $query_vars as $query_var ) {
306
- if ( ! isset( $_GET[ $query_var ] ) ) { // phpcs:ignore
307
- continue;
308
- }
309
- self::$purged_amp_query_vars[ $query_var ] = wp_unslash( $_GET[ $query_var ] ); // phpcs:ignore
310
- unset( $_REQUEST[ $query_var ], $_GET[ $query_var ] );
311
- $scrubbed = true;
312
- }
313
-
314
- if ( isset( $scrubbed ) ) {
315
- $build_query = function( $query ) use ( $query_vars ) {
316
- $pattern = '/^(' . join( '|', $query_vars ) . ')(?==|$)/';
317
- $pairs = array();
318
- foreach ( explode( '&', $query ) as $pair ) {
319
- if ( ! preg_match( $pattern, $pair ) ) {
320
- $pairs[] = $pair;
321
- }
322
- }
323
- return join( '&', $pairs );
324
- };
325
-
326
- // Scrub QUERY_STRING.
327
- if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
328
- $_SERVER['QUERY_STRING'] = $build_query( $_SERVER['QUERY_STRING'] );
329
- }
330
-
331
- // Scrub REQUEST_URI.
332
- if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
333
- list( $path, $query ) = explode( '?', $_SERVER['REQUEST_URI'], 2 );
334
-
335
- $pairs = $build_query( $query );
336
- $_SERVER['REQUEST_URI'] = $path;
337
- if ( ! empty( $pairs ) ) {
338
- $_SERVER['REQUEST_URI'] .= "?{$pairs}";
339
- }
340
- }
341
- }
342
- }
343
-
344
- /**
345
- * Send an HTTP response header.
346
- *
347
- * This largely exists to facilitate unit testing but it also provides a better interface for sending headers.
348
- *
349
- * @since 0.7.0
350
- *
351
- * @param string $name Header name.
352
- * @param string $value Header value.
353
- * @param array $args {
354
- * Args to header().
355
- *
356
- * @type bool $replace Whether to replace a header previously sent. Default true.
357
- * @type int $status_code Status code to send with the sent header.
358
- * }
359
- * @return bool Whether the header was sent.
360
- */
361
- public static function send_header( $name, $value, $args = array() ) {
362
- $args = array_merge(
363
- array(
364
- 'replace' => true,
365
- 'status_code' => null,
366
- ),
367
- $args
368
- );
369
-
370
- self::$headers_sent[] = array_merge( compact( 'name', 'value' ), $args );
371
- if ( headers_sent() ) {
372
- return false;
373
- }
374
-
375
- header(
376
- sprintf( '%s: %s', $name, $value ),
377
- $args['replace'],
378
- $args['status_code']
379
- );
380
- return true;
381
- }
382
-
383
- /**
384
- * Hook into a POST form submissions, such as the comment form or some other form submission.
385
- *
386
- * @since 0.7.0
387
- */
388
- public static function handle_xhr_request() {
389
- $is_amp_xhr = (
390
- ! empty( self::$purged_amp_query_vars['_wp_amp_action_xhr_converted'] )
391
- &&
392
- ! empty( self::$purged_amp_query_vars['__amp_source_origin'] )
393
- &&
394
- ( ! empty( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] )
395
- );
396
- if ( ! $is_amp_xhr ) {
397
- return;
398
- }
399
-
400
- // Send AMP response header.
401
- $origin = wp_validate_redirect( wp_sanitize_redirect( esc_url_raw( self::$purged_amp_query_vars['__amp_source_origin'] ) ) );
402
- if ( $origin ) {
403
- self::send_header( 'AMP-Access-Control-Allow-Source-Origin', $origin, array( 'replace' => true ) );
404
- }
405
-
406
- // Intercept POST requests which redirect.
407
- add_filter( 'wp_redirect', array( __CLASS__, 'intercept_post_request_redirect' ), PHP_INT_MAX );
408
-
409
- // Add special handling for redirecting after comment submission.
410
- add_filter( 'comment_post_redirect', array( __CLASS__, 'filter_comment_post_redirect' ), PHP_INT_MAX, 2 );
411
-
412
- // Add die handler for AMP error display, most likely due to problem with comment.
413
- add_filter( 'wp_die_handler', function() {
414
- return array( __CLASS__, 'handle_wp_die' );
415
- } );
416
-
417
- }
418
-
419
- /**
420
- * Strip tags that are not allowed in amp-mustache.
421
- *
422
- * @since 0.7.0
423
- *
424
- * @param string $text Text to sanitize.
425
- * @return string Sanitized text.
426
- */
427
- protected static function wp_kses_amp_mustache( $text ) {
428
- $amp_mustache_allowed_html_tags = array( 'strong', 'b', 'em', 'i', 'u', 's', 'small', 'mark', 'del', 'ins', 'sup', 'sub' );
429
- return wp_kses( $text, array_fill_keys( $amp_mustache_allowed_html_tags, array() ) );
430
- }
431
-
432
- /**
433
- * Handle comment_post_redirect to ensure page reload is done when comments_live_list is not supported, while sending back a success message when it is.
434
- *
435
- * @since 0.7.0
436
- *
437
- * @param string $url Comment permalink to redirect to.
438
- * @param WP_Comment $comment Posted comment.
439
- * @return string URL.
440
- */
441
- public static function filter_comment_post_redirect( $url, $comment ) {
442
- $theme_support = get_theme_support( 'amp' );
443
-
444
- // Cause a page refresh if amp-live-list is not implemented for comments via add_theme_support( 'amp', array( 'comments_live_list' => true ) ).
445
- if ( empty( $theme_support[0]['comments_live_list'] ) ) {
446
- /*
447
- * Add the comment ID to the URL to force AMP to refresh the page.
448
- * This is ideally a temporary workaround to deal with https://github.com/ampproject/amphtml/issues/14170
449
- */
450
- $url = add_query_arg( 'comment', $comment->comment_ID, $url );
451
-
452
- // Pass URL along to wp_redirect().
453
- return $url;
454
- }
455
-
456
- // Create a success message to display to the user.
457
- if ( '1' === (string) $comment->comment_approved ) {
458
- $message = __( 'Your comment has been posted.', 'amp' );
459
- } else {
460
- $message = __( 'Your comment is awaiting moderation.', 'default' ); // Note core string re-use.
461
- }
462
-
463
- /**
464
- * Filters the message when comment submitted success message when
465
- *
466
- * @since 0.7
467
- */
468
- $message = apply_filters( 'amp_comment_posted_message', $message, $comment );
469
-
470
- // Message will be shown in template defined by AMP_Theme_Support::amend_comment_form().
471
- wp_send_json( array(
472
- 'message' => self::wp_kses_amp_mustache( $message ),
473
- ) );
474
- }
475
-
476
- /**
477
- * New error handler for AMP form submission.
478
- *
479
- * @since 0.7.0
480
- * @see wp_die()
481
- *
482
- * @param WP_Error|string $error The error to handle.
483
- * @param string|int $title Optional. Error title. If `$message` is a `WP_Error` object,
484
- * error data with the key 'title' may be used to specify the title.
485
- * If `$title` is an integer, then it is treated as the response
486
- * code. Default empty.
487
- * @param string|array|int $args {
488
- * Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
489
- * as the response code. Default empty array.
490
- *
491
- * @type int $response The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
492
- * }
493
- */
494
- public static function handle_wp_die( $error, $title = '', $args = array() ) {
495
- if ( is_int( $title ) ) {
496
- $status_code = $title;
497
- } elseif ( is_int( $args ) ) {
498
- $status_code = $args;
499
- } elseif ( is_array( $args ) && isset( $args['response'] ) ) {
500
- $status_code = $args['response'];
501
- } else {
502
- $status_code = 500;
503
- }
504
- status_header( $status_code );
505
-
506
- if ( is_wp_error( $error ) ) {
507
- $error = $error->get_error_message();
508
- }
509
-
510
- // Message will be shown in template defined by AMP_Theme_Support::amend_comment_form().
511
- wp_send_json( array(
512
- 'error' => self::wp_kses_amp_mustache( $error ),
513
- ) );
514
- }
515
-
516
- /**
517
- * Intercept the response to a POST request.
518
- *
519
- * @since 0.7.0
520
- * @see wp_redirect()
521
- *
522
- * @param string $location The location to redirect to.
523
- */
524
- public static function intercept_post_request_redirect( $location ) {
525
-
526
- // Make sure relative redirects get made absolute.
527
- $parsed_location = array_merge(
528
- array(
529
- 'scheme' => 'https',
530
- 'host' => wp_parse_url( home_url(), PHP_URL_HOST ),
531
- 'path' => isset( $_SERVER['REQUEST_URI'] ) ? strtok( wp_unslash( $_SERVER['REQUEST_URI'] ), '?' ) : '/',
532
- ),
533
- wp_parse_url( $location )
534
- );
535
-
536
- $absolute_location = '';
537
- if ( 'https' === $parsed_location['scheme'] ) {
538
- $absolute_location .= $parsed_location['scheme'] . ':';
539
- }
540
- $absolute_location .= '//' . $parsed_location['host'];
541
- if ( isset( $parsed_location['port'] ) ) {
542
- $absolute_location .= ':' . $parsed_location['port'];
543
- }
544
- $absolute_location .= $parsed_location['path'];
545
- if ( isset( $parsed_location['query'] ) ) {
546
- $absolute_location .= '?' . $parsed_location['query'];
547
- }
548
- if ( isset( $parsed_location['fragment'] ) ) {
549
- $absolute_location .= '#' . $parsed_location['fragment'];
550
- }
551
-
552
- self::send_header( 'AMP-Redirect-To', $absolute_location );
553
- self::send_header( 'Access-Control-Expose-Headers', 'AMP-Redirect-To' );
554
-
555
- wp_send_json_success();
556
- }
557
-
558
- /**
559
- * Register/override widgets.
560
- *
561
- * @global WP_Widget_Factory
562
- * @return void
563
- */
564
- public static function register_widgets() {
565
- global $wp_widget_factory;
566
- foreach ( $wp_widget_factory->widgets as $registered_widget ) {
567
- $registered_widget_class_name = get_class( $registered_widget );
568
- if ( ! preg_match( '/^WP_Widget_(.+)$/', $registered_widget_class_name, $matches ) ) {
569
- continue;
570
- }
571
- $amp_class_name = 'AMP_Widget_' . $matches[1];
572
- if ( ! class_exists( $amp_class_name ) || is_a( $amp_class_name, $registered_widget_class_name ) ) {
573
- continue;
574
- }
575
-
576
- unregister_widget( $registered_widget_class_name );
577
- register_widget( $amp_class_name );
578
- }
579
- }
580
-
581
- /**
582
- * Register content embed handlers.
583
- *
584
- * This was copied from `AMP_Content::register_embed_handlers()` due to being a private method
585
- * and due to `AMP_Content` not being well suited for use in AMP canonical.
586
- *
587
- * @see AMP_Content::register_embed_handlers()
588
- * @global int $content_width
589
- * @return AMP_Base_Embed_Handler[] Handlers.
590
- */
591
- public static function register_content_embed_handlers() {
592
- global $content_width;
593
-
594
- $embed_handlers = array();
595
- foreach ( amp_get_content_embed_handlers() as $embed_handler_class => $args ) {
596
-
597
- /**
598
- * Embed handler.
599
- *
600
- * @type AMP_Base_Embed_Handler $embed_handler
601
- */
602
- $embed_handler = new $embed_handler_class( array_merge(
603
- array(
604
- 'content_max_width' => ! empty( $content_width ) ? $content_width : AMP_Post_Template::CONTENT_MAX_WIDTH, // Back-compat.
605
- ),
606
- $args
607
- ) );
608
-
609
- if ( ! is_subclass_of( $embed_handler, 'AMP_Base_Embed_Handler' ) ) {
610
- /* translators: %s is embed handler */
611
- _doing_it_wrong( __METHOD__, esc_html( sprintf( __( 'Embed Handler (%s) must extend `AMP_Embed_Handler`', 'amp' ), $embed_handler_class ) ), '0.1' );
612
- continue;
613
- }
614
-
615
- $embed_handler->register_embed();
616
- $embed_handlers[] = $embed_handler;
617
- }
618
-
619
- return $embed_handlers;
620
- }
621
-
622
- /**
623
- * Add the comments template placeholder marker
624
- *
625
- * @param array $args the args for the comments list..
626
- * @return array Args to return.
627
- */
628
- public static function set_comments_walker( $args ) {
629
- $amp_walker = new AMP_Comment_Walker();
630
- $args['walker'] = $amp_walker;
631
- return $args;
632
- }
633
-
634
- /**
635
- * Adds the form submit success and fail templates.
636
- */
637
- public static function amend_comment_form() {
638
- ?>
639
- <?php if ( is_singular() && ! amp_is_canonical() ) : ?>
640
- <input type="hidden" name="redirect_to" value="<?php echo esc_url( amp_get_permalink( get_the_ID() ) ); ?>">
641
- <?php endif; ?>
642
-
643
- <div submit-success>
644
- <template type="amp-mustache">
645
- <p>{{{message}}}</p>
646
- </template>
647
- </div>
648
- <div submit-error>
649
- <template type="amp-mustache">
650
- <p class="amp-comment-submit-error">{{{error}}}</p>
651
- </template>
652
- </div>
653
- <?php
654
- }
655
-
656
- /**
657
- * Prepends template hierarchy with template_dir for AMP paired mode templates.
658
- *
659
- * @see get_query_template()
660
- *
661
- * @param array $templates Template hierarchy.
662
- * @returns array Templates.
663
- */
664
- public static function filter_paired_template_hierarchy( $templates ) {
665
- $support = get_theme_support( 'amp' );
666
- $args = array_shift( $support );
667
- if ( isset( $args['template_dir'] ) ) {
668
- $amp_templates = array();
669
- foreach ( $templates as $template ) {
670
- $amp_templates[] = $args['template_dir'] . '/' . $template;
671
- }
672
- $templates = $amp_templates;
673
- }
674
- return $templates;
675
- }
676
-
677
- /**
678
- * Redirect to the non-canonical URL when the template to include is empty.
679
- *
680
- * This is a failsafe in case an index.php is not located in the AMP template_dir,
681
- * and the available_callback fails to omit a given request from being available in AMP.
682
- *
683
- * @param string $template Template to include.
684
- * @return string Template to include.
685
- */
686
- public static function filter_paired_template_include( $template ) {
687
- if ( empty( $template ) || ! self::is_paired_available() ) {
688
- wp_safe_redirect( self::get_current_canonical_url(), 302 ); // Temporary redirect because support may come later.
689
- exit;
690
- }
691
- return $template;
692
- }
693
-
694
- /**
695
- * Get canonical URL for current request.
696
- *
697
- * @see rel_canonical()
698
- * @global WP $wp
699
- * @global WP_Rewrite $wp_rewrite
700
- * @link https://www.ampproject.org/docs/reference/spec#canon.
701
- * @link https://core.trac.wordpress.org/ticket/18660
702
- *
703
- * @return string Canonical non-AMP URL.
704
- */
705
- public static function get_current_canonical_url() {
706
- global $wp, $wp_rewrite;
707
-
708
- $url = null;
709
- if ( is_singular() ) {
710
- $url = wp_get_canonical_url();
711
- }
712
-
713
- // For non-singular queries, make use of the request URI and public query vars to determine canonical URL.
714
- if ( empty( $url ) ) {
715
- $added_query_vars = $wp->query_vars;
716
- if ( ! $wp_rewrite->permalink_structure || empty( $wp->request ) ) {
717
- $url = home_url( '/' );
718
- } else {
719
- $url = home_url( user_trailingslashit( $wp->request ) );
720
- parse_str( $wp->matched_query, $matched_query_vars );
721
- foreach ( $wp->query_vars as $key => $value ) {
722
-
723
- // Remove query vars that were matched in the rewrite rules for the request.
724
- if ( isset( $matched_query_vars[ $key ] ) ) {
725
- unset( $added_query_vars[ $key ] );
726
- }
727
- }
728
- }
729
- }
730
-
731
- if ( ! empty( $added_query_vars ) ) {
732
- $url = add_query_arg( $added_query_vars, $url );
733
- }
734
-
735
- return amp_remove_endpoint( $url );
736
- }
737
-
738
- /**
739
- * Get the ID for the amp-state.
740
- *
741
- * @since 0.7
742
- *
743
- * @param int $post_id Post ID.
744
- * @return string ID for amp-state.
745
- */
746
- public static function get_comment_form_state_id( $post_id ) {
747
- return sprintf( 'commentform_post_%d', $post_id );
748
- }
749
-
750
- /**
751
- * Filter comment form args to an element with [text] AMP binding wrap the title reply.
752
- *
753
- * @since 0.7
754
- * @see comment_form()
755
- *
756
- * @param array $args Comment form args.
757
- * @return array Filtered comment form args.
758
- */
759
- public static function filter_comment_form_defaults( $args ) {
760
- $state_id = self::get_comment_form_state_id( get_the_ID() );
761
-
762
- $text_binding = sprintf(
763
- '%s.replyToName ? %s : %s',
764
- $state_id,
765
- str_replace(
766
- '%s',
767
- sprintf( '" + %s.replyToName + "', $state_id ),
768
- wp_json_encode( $args['title_reply_to'] )
769
- ),
770
- wp_json_encode( $args['title_reply'] )
771
- );
772
-
773
- $args['title_reply_before'] .= sprintf(
774
- '<span [text]="%s">',
775
- esc_attr( $text_binding )
776
- );
777
- $args['cancel_reply_before'] = '</span>' . $args['cancel_reply_before'];
778
- return $args;
779
- }
780
-
781
- /**
782
- * Modify the comment reply link for AMP.
783
- *
784
- * @since 0.7
785
- * @see get_comment_reply_link()
786
- *
787
- * @param string $link The HTML markup for the comment reply link.
788
- * @param array $args An array of arguments overriding the defaults.
789
- * @param WP_Comment $comment The object of the comment being replied.
790
- * @return string Comment reply link.
791
- */
792
- public static function filter_comment_reply_link( $link, $args, $comment ) {
793
-
794
- // Continue to show default link to wp-login when user is not logged-in.
795
- if ( get_option( 'comment_registration' ) && ! is_user_logged_in() ) {
796
- return $link;
797
- }
798
-
799
- $state_id = self::get_comment_form_state_id( get_the_ID() );
800
- $tap_state = array(
801
- $state_id => array(
802
- 'replyToName' => $comment->comment_author,
803
- 'values' => array(
804
- 'comment_parent' => (string) $comment->comment_ID,
805
- ),
806
- ),
807
- );
808
-
809
- // @todo Figure out how to support add_below. Instead of moving the form, what about letting the form get a fixed position?
810
- $link = sprintf(
811
- '<a rel="nofollow" class="comment-reply-link" href="%s" on="%s" aria-label="%s">%s</a>',
812
- esc_attr( '#' . $args['respond_id'] ),
813
- esc_attr( sprintf( 'tap:AMP.setState( %s )', wp_json_encode( $tap_state ) ) ),
814
- esc_attr( sprintf( $args['reply_to_text'], $comment->comment_author ) ),
815
- $args['reply_text']
816
- );
817
- return $link;
818
- }
819
-
820
- /**
821
- * Filters the cancel comment reply link HTML.
822
- *
823
- * @since 0.7
824
- * @see get_cancel_comment_reply_link()
825
- *
826
- * @param string $formatted_link The HTML-formatted cancel comment reply link.
827
- * @param string $link Cancel comment reply link URL.
828
- * @param string $text Cancel comment reply link text.
829
- * @return string Cancel reply link.
830
- */
831
- public static function filter_cancel_comment_reply_link( $formatted_link, $link, $text ) {
832
- unset( $formatted_link, $link );
833
- if ( empty( $text ) ) {
834
- $text = __( 'Click here to cancel reply.', 'default' );
835
- }
836
-
837
- $state_id = self::get_comment_form_state_id( get_the_ID() );
838
- $tap_state = array(
839
- $state_id => array(
840
- 'replyToName' => '',
841
- 'values' => array(
842
- 'comment_parent' => '0',
843
- ),
844
- ),
845
- );
846
-
847
- $respond_id = 'respond'; // Hard-coded in comment_form() and default value in get_comment_reply_link().
848
- return sprintf(
849
- '<a id="cancel-comment-reply-link" href="%s" %s [hidden]="%s" on="%s">%s</a>',
850
- esc_url( remove_query_arg( 'replytocom' ) . '#' . $respond_id ),
851
- isset( $_GET['replytocom'] ) ? '' : ' hidden', // phpcs:ignore
852
- esc_attr( sprintf( '%s.values.comment_parent == "0"', self::get_comment_form_state_id( get_the_ID() ) ) ),
853
- esc_attr( sprintf( 'tap:AMP.setState( %s )', wp_json_encode( $tap_state ) ) ),
854
- esc_html( $text )
855
- );
856
- }
857
-
858
- /**
859
- * Print AMP boilerplate and custom styles.
860
- */
861
- public static function print_amp_styles() {
862
- echo amp_get_boilerplate_code() . "\n"; // WPCS: XSS OK.
863
- echo "<style amp-custom></style>\n"; // This will by populated by AMP_Style_Sanitizer.
864
- }
865
-
866
- /**
867
- * Ensure markup required by AMP <https://www.ampproject.org/docs/reference/spec#required-markup>.
868
- *
869
- * Ensure meta[charset], meta[name=viewport], and link[rel=canonical]; a the whitelist sanitizer
870
- * may have removed an illegal meta[http-equiv] or meta[name=viewport]. Core only outputs a
871
- * canonical URL by default if a singular post.
872
- *
873
- * @since 0.7
874
- * @todo All of this might be better placed inside of a sanitizer.
875
- *
876
- * @param DOMDocument $dom Doc.
877
- */
878
- public static function ensure_required_markup( DOMDocument $dom ) {
879
- $head = $dom->getElementsByTagName( 'head' )->item( 0 );
880
- if ( ! $head ) {
881
- $head = $dom->createElement( 'head' );
882
- $dom->documentElement->insertBefore( $head, $dom->documentElement->firstChild );
883
- }
884
- $meta_charset = null;
885
- $meta_viewport = null;
886
- foreach ( $head->getElementsByTagName( 'meta' ) as $meta ) {
887
- /**
888
- * Meta.
889
- *
890
- * @var DOMElement $meta
891
- */
892
- if ( $meta->hasAttribute( 'charset' ) && 'utf-8' === strtolower( $meta->getAttribute( 'charset' ) ) ) { // @todo Also look for meta[http-equiv="Content-Type"]?
893
- $meta_charset = $meta;
894
- } elseif ( 'viewport' === $meta->getAttribute( 'name' ) ) {
895
- $meta_viewport = $meta;
896
- }
897
- }
898
- if ( ! $meta_charset ) {
899
- // Warning: This probably means the character encoding needs to be converted.
900
- $meta_charset = AMP_DOM_Utils::create_node( $dom, 'meta', array(
901
- 'charset' => 'utf-8',
902
- ) );
903
- $head->insertBefore( $meta_charset, $head->firstChild );
904
- }
905
- if ( ! $meta_viewport ) {
906
- $meta_viewport = AMP_DOM_Utils::create_node( $dom, 'meta', array(
907
- 'name' => 'viewport',
908
- 'content' => 'width=device-width,minimum-scale=1',
909
- ) );
910
- $head->insertBefore( $meta_viewport, $meta_charset->nextSibling );
911
- }
912
- // Prevent schema.org duplicates.
913
- $has_schema_org_metadata = false;
914
- foreach ( $head->getElementsByTagName( 'script' ) as $script ) {
915
- if ( 'application/ld+json' === $script->getAttribute( 'type' ) && false !== strpos( $script->nodeValue, 'schema.org' ) ) {
916
- $has_schema_org_metadata = true;
917
- break;
918
- }
919
- }
920
- if ( ! $has_schema_org_metadata ) {
921
- $script = $dom->createElement( 'script', wp_json_encode( amp_get_schemaorg_metadata() ) );
922
- $script->setAttribute( 'type', 'application/ld+json' );
923
- $head->appendChild( $script );
924
- }
925
- // Ensure rel=canonical link.
926
- $rel_canonical = null;
927
- foreach ( $head->getElementsByTagName( 'link' ) as $link ) {
928
- if ( 'canonical' === $link->getAttribute( 'rel' ) ) {
929
- $rel_canonical = $link;
930
- break;
931
- }
932
- }
933
- if ( ! $rel_canonical ) {
934
- $rel_canonical = AMP_DOM_Utils::create_node( $dom, 'link', array(
935
- 'rel' => 'canonical',
936
- 'href' => self::get_current_canonical_url(),
937
- ) );
938
- $head->appendChild( $rel_canonical );
939
- }
940
- }
941
-
942
- /**
943
- * Dequeue Customizer assets which are not necessary outside the preview iframe.
944
- *
945
- * Prevent enqueueing customize-preview styles if not in customizer preview iframe.
946
- * These are only needed for when there is live editing of content, such as selective refresh.
947
- *
948
- * @since 0.7
949
- */
950
- public static function dequeue_customize_preview_scripts() {
951
-
952
- // Dequeue styles unnecessary unless in customizer preview iframe when editing (such as for edit shortcuts).
953
- if ( ! self::is_customize_preview_iframe() ) {
954
- wp_dequeue_style( 'customize-preview' );
955
- foreach ( wp_styles()->registered as $handle => $dependency ) {
956
- if ( in_array( 'customize-preview', $dependency->deps, true ) ) {
957
- wp_dequeue_style( $handle );
958
- }
959
- }
960
- }
961
- }
962
-
963
- /**
964
- * Start output buffering.
965
- *
966
- * @since 0.7
967
- * @see AMP_Theme_Support::finish_output_buffering()
968
- */
969
- public static function start_output_buffering() {
970
- /*
971
- * Disable the New Relic Browser agent on AMP responses.
972
- * This prevents th New Relic from causing invalid AMP responses due the NREUM script it injects after the meta charset:
973
- * https://docs.newrelic.com/docs/browser/new-relic-browser/troubleshooting/google-amp-validator-fails-due-3rd-party-script
974
- * Sites with New Relic will need to specially configure New Relic for AMP:
975
- * https://docs.newrelic.com/docs/browser/new-relic-browser/installation/monitor-amp-pages-new-relic-browser
976
- */
977
- if ( function_exists( 'newrelic_disable_autorum' ) ) {
978
- newrelic_disable_autorum();
979
- }
980
-
981
- ob_start( array( __CLASS__, 'finish_output_buffering' ) );
982
- self::$is_output_buffering = true;
983
- }
984
-
985
- /**
986
- * Determine whether output buffering has started.
987
- *
988
- * @since 0.7
989
- * @see AMP_Theme_Support::start_output_buffering()
990
- * @see AMP_Theme_Support::finish_output_buffering()
991
- *
992
- * @return bool Whether output buffering has started.
993
- */
994
- public static function is_output_buffering() {
995
- return self::$is_output_buffering;
996
- }
997
-
998
- /**
999
- * Finish output buffering.
1000
- *
1001
- * @since 0.7
1002
- * @see AMP_Theme_Support::start_output_buffering()
1003
- *
1004
- * @param string $response Buffered Response.
1005
- * @return string Processed Response.
1006
- */
1007
- public static function finish_output_buffering( $response ) {
1008
- self::$is_output_buffering = false;
1009
- return self::prepare_response( $response );
1010
- }
1011
-
1012
- /**
1013
- * Filter rendered partial to convert to AMP.
1014
- *
1015
- * @see WP_Customize_Partial::render()
1016
- *
1017
- * @param string|mixed $partial Rendered partial.
1018
- * @return string|mixed Filtered partial.
1019
- * @global int $content_width
1020
- */
1021
- public static function filter_customize_partial_render( $partial ) {
1022
- global $content_width;
1023
- if ( is_string( $partial ) && preg_match( '/<\w/', $partial ) ) {
1024
- $dom = AMP_DOM_Utils::get_dom_from_content( $partial );
1025
- $args = array(
1026
- 'content_max_width' => ! empty( $content_width ) ? $content_width : AMP_Post_Template::CONTENT_MAX_WIDTH, // Back-compat.
1027
- 'use_document_element' => false,
1028
- 'allow_dirty_styles' => true,
1029
- 'allow_dirty_scripts' => false,
1030
- );
1031
- AMP_Content_Sanitizer::sanitize_document( $dom, self::$sanitizer_classes, $args ); // @todo Include script assets in response?
1032
- $partial = AMP_DOM_Utils::get_content_from_dom( $dom );
1033
- }
1034
- return $partial;
1035
- }
1036
-
1037
- /**
1038
- * Process response to ensure AMP validity.
1039
- *
1040
- * @since 0.7
1041
- *
1042
- * @param string $response HTML document response. By default it expects a complete document.
1043
- * @param array $args {
1044
- * Args to send to the preprocessor/sanitizer.
1045
- *
1046
- * @type callable $remove_invalid_callback Function to call whenever a node is removed due to being invalid.
1047
- * }
1048
- * @return string AMP document response.
1049
- * @global int $content_width
1050
- */
1051
- public static function prepare_response( $response, $args = array() ) {
1052
- global $content_width;
1053
-
1054
- /*
1055
- * Check if the response starts with HTML markup.
1056
- * Without this check, JSON responses will be erroneously corrupted,
1057
- * being wrapped in HTML documents.
1058
- */
1059
- if ( '<' !== substr( ltrim( $response ), 0, 1 ) ) {
1060
- return $response;
1061
- }
1062
-
1063
- $is_validation_debug_mode = ! empty( $_REQUEST[ AMP_Validation_Utils::DEBUG_QUERY_VAR ] ); // WPCS: csrf ok.
1064
-
1065
- $args = array_merge(
1066
- array(
1067
- 'content_max_width' => ! empty( $content_width ) ? $content_width : AMP_Post_Template::CONTENT_MAX_WIDTH, // Back-compat.
1068
- 'use_document_element' => true,
1069
- 'allow_dirty_styles' => self::is_customize_preview_iframe(), // Dirty styles only needed when editing (e.g. for edit shortcodes).
1070
- 'allow_dirty_scripts' => is_customize_preview(), // Scripts are always needed to inject changeset UUID.
1071
- 'disable_invalid_removal' => $is_validation_debug_mode,
1072
- ),
1073
- $args
1074
- );
1075
-
1076
- /*
1077
- * Make sure that <meta charset> is present in output prior to parsing.
1078
- * Note that the meta charset is supposed to appear within the first 1024 bytes.
1079
- * See <https://www.w3.org/International/questions/qa-html-encoding-declarations>.
1080
- */
1081
- if ( ! preg_match( '#<meta[^>]+charset=#i', substr( $response, 0, 1024 ) ) ) {
1082
- $response = preg_replace(
1083
- '/(<head[^>]*>)/i',
1084
- '$1' . sprintf( '<meta charset="%s">', esc_attr( get_bloginfo( 'charset' ) ) ),
1085
- $response,
1086
- 1
1087
- );
1088
- }
1089
- $dom = AMP_DOM_Utils::get_dom( $response );
1090
-
1091
- $xpath = new DOMXPath( $dom );
1092
-
1093
- $head = $dom->getElementsByTagName( 'head' )->item( 0 );
1094
-
1095
- if ( isset( $head ) ) {
1096
- // Make sure scripts from the body get moved to the head.
1097
- foreach ( $xpath->query( '//body//script[ @custom-element or @custom-template ]' ) as $script ) {
1098
- $head->appendChild( $script );
1099
- }
1100
- }
1101
-
1102
- // Ensure the mandatory amp attribute is present on the html element, as otherwise it will be stripped entirely.
1103
- if ( ! $dom->documentElement->hasAttribute( 'amp' ) && ! $dom->documentElement->hasAttribute( '⚡️' ) ) {
1104
- $dom->documentElement->setAttribute( 'amp', '' );
1105
- }
1106
-
1107
- $assets = AMP_Content_Sanitizer::sanitize_document( $dom, self::$sanitizer_classes, $args );
1108
-
1109
- self::ensure_required_markup( $dom );
1110
-
1111
- // @todo If 'utf-8' is not the blog charset, then we'll need to do some character encoding conversation or "entityification".
1112
- if ( 'utf-8' !== strtolower( get_bloginfo( 'charset' ) ) ) {
1113
- /* translators: %s is the charset of the current site */
1114
- trigger_error( esc_html( sprintf( __( 'The database has the %s encoding when it needs to be utf-8 to work with AMP.', 'amp' ), get_bloginfo( 'charset' ) ) ), E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
1115
- }
1116
-
1117
- if ( AMP_Validation_Utils::should_validate_response() ) {
1118
- AMP_Validation_Utils::finalize_validation( $dom, array(
1119
- 'remove_source_comments' => ! $is_validation_debug_mode,
1120
- ) );
1121
- }
1122
-
1123
- $response = "<!DOCTYPE html>\n";
1124
- $response .= AMP_DOM_Utils::get_content_from_dom_node( $dom, $dom->documentElement );
1125
-
1126
- $amp_scripts = $assets['scripts'];
1127
- foreach ( self::$embed_handlers as $embed_handler ) {
1128
- $amp_scripts = array_merge(
1129
- $amp_scripts,
1130
- $embed_handler->get_scripts()
1131
- );
1132
- }
1133
-
1134
- // Allow for embed handlers to override the default extension version by defining a different URL.
1135
- foreach ( $amp_scripts as $handle => $value ) {
1136
- if ( is_string( $value ) && wp_script_is( $handle, 'registered' ) ) {
1137
- wp_scripts()->registered[ $handle ]->src = $value;
1138
- }
1139
- }
1140
-
1141
- /*
1142
- * Inject additional AMP component scripts which have been discovered by the sanitizers into the head.
1143
- * This is adapted from wp_scripts()->do_items(), but it runs only the bare minimum required to output
1144
- * the missing scripts, without allowing other filters to apply which may cause an invalid AMP response.
1145
- */
1146
- $script_tags = '';
1147
- foreach ( array_diff( array_keys( $amp_scripts ), wp_scripts()->done ) as $handle ) {
1148
- if ( ! wp_script_is( $handle, 'registered' ) ) {
1149
- continue;
1150
- }
1151
- $script_dep = wp_scripts()->registered[ $handle ];
1152
- $script_tags .= amp_filter_script_loader_tag(
1153
- sprintf(
1154
- "<script type='text/javascript' src='%s'></script>\n", // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
1155
- esc_url( $script_dep->src )
1156
- ),
1157
- $handle
1158
- );
1159
- }
1160
- if ( ! empty( $script_tags ) ) {
1161
- $response = preg_replace(
1162
- '#(?=</head>)#',
1163
- $script_tags,
1164
- $response,
1165
- 1
1166
- );
1167
- }
1168
-
1169
- return $response;
1170
- }
1171
-
1172
- /**
1173
- * Adds 'data-amp-layout' to the allowed <img> attributes for wp_kses().
1174
- *
1175
- * @since 0.7
1176
- *
1177
- * @param array $context Allowed tags and their allowed attributes.
1178
- * @return array $context Filtered allowed tags and attributes.
1179
- */
1180
- public static function whitelist_layout_in_wp_kses_allowed_html( $context ) {
1181
- if ( ! empty( $context['img']['width'] ) && ! empty( $context['img']['height'] ) ) {
1182
- $context['img']['data-amp-layout'] = true;
1183
- }
1184
-
1185
- return $context;
1186
- }
1187
-
1188
- /**
1189
- * Enqueue AMP assets if this is an AMP endpoint.
1190
- *
1191
- * @since 0.7
1192
- *
1193
- * @return void
1194
- */
1195
- public static function enqueue_assets() {
1196
- wp_enqueue_script( 'amp-runtime' );
1197
-
1198
- // Enqueue default styles expected by sanitizer.
1199
- wp_enqueue_style( 'amp-default', amp_get_asset_url( 'css/amp-default.css' ), array(), AMP__VERSION );
1200
- }
1201
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/embeds/class-amp-issuu-embed-handler.php DELETED
@@ -1,65 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Issuu_Embed_Handler
4
- *
5
- * @package AMP
6
- * @since 0.7
7
- */
8
-
9
- /**
10
- * Class AMP_Issuu_Embed_Handler
11
- */
12
- class AMP_Issuu_Embed_Handler extends AMP_Base_Embed_Handler {
13
- /**
14
- * Regex matched to produce output amp-iframe.
15
- *
16
- * @const string
17
- */
18
- const URL_PATTERN = '#https?://(www\.)?issuu\.com/.+/docs/.+#i';
19
-
20
- /**
21
- * Register embed.
22
- */
23
- public function register_embed() {
24
- add_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10, 3 );
25
- }
26
-
27
- /**
28
- * Unregister embed.
29
- */
30
- public function unregister_embed() {
31
- remove_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10 );
32
- }
33
-
34
- /**
35
- * Filter oEmbed HTML for Meetup to prepare it for AMP.
36
- *
37
- * @param mixed $return The shortcode callback function to call.
38
- * @param string $url The attempted embed URL.
39
- * @param array $attr An array of shortcode attributes.
40
- * @return string Embed.
41
- */
42
- public function filter_embed_oembed_html( $return, $url, $attr ) {
43
- $parsed_url = wp_parse_url( $url );
44
- if ( false !== strpos( $parsed_url['host'], 'issuu.com' ) ) {
45
- if ( preg_match( '/width\s*:\s*(\d+)px/', $return, $matches ) ) {
46
- $attr['width'] = $matches[1];
47
- }
48
- if ( preg_match( '/height\s*:\s*(\d+)px/', $return, $matches ) ) {
49
- $attr['height'] = $matches[1];
50
- }
51
-
52
- $return = AMP_HTML_Utils::build_tag(
53
- 'amp-iframe',
54
- array(
55
- 'width' => $attr['width'],
56
- 'height' => $attr['height'],
57
- 'src' => $url,
58
- 'sandbox' => 'allow-scripts allow-same-origin',
59
- )
60
- );
61
- }
62
- return $return;
63
- }
64
- }
65
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/embeds/class-amp-meetup-embed-handler.php DELETED
@@ -1,45 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Meetup_Embed_Handler
4
- *
5
- * @package AMP
6
- * @since 0.7
7
- */
8
-
9
- /**
10
- * Class AMP_Meetup_Embed_Handler
11
- */
12
- class AMP_Meetup_Embed_Handler extends AMP_Base_Embed_Handler {
13
-
14
- /**
15
- * Register embed.
16
- */
17
- public function register_embed() {
18
- add_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10, 2 );
19
- }
20
-
21
- /**
22
- * Unregister embed.
23
- */
24
- public function unregister_embed() {
25
- remove_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10 );
26
- }
27
-
28
- /**
29
- * Filter oEmbed HTML for Meetup to prepare it for AMP.
30
- *
31
- * @param string $cache Cache for oEmbed.
32
- * @param string $url Embed URL.
33
- * @return string Embed.
34
- */
35
- public function filter_embed_oembed_html( $cache, $url ) {
36
- $parsed_url = wp_parse_url( $url );
37
- if ( false !== strpos( $parsed_url['host'], 'meetup.com' ) ) {
38
-
39
- // Supply the width/height so that we don't have to make requests to look them up later.
40
- $cache = str_replace( '<img ', '<img width="50" height="50" ', $cache );
41
- }
42
- return $cache;
43
- }
44
- }
45
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/embeds/class-amp-playlist-embed-handler.php DELETED
@@ -1,324 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Playlist_Embed_Handler
4
- *
5
- * @package AMP
6
- * @since 0.7
7
- */
8
-
9
- /**
10
- * Class AMP_Playlist_Embed_Handler
11
- *
12
- * Creates AMP-compatible markup for the WordPress 'playlist' shortcode.
13
- *
14
- * @package AMP
15
- */
16
- class AMP_Playlist_Embed_Handler extends AMP_Base_Embed_Handler {
17
-
18
- /**
19
- * The tag of the shortcode.
20
- *
21
- * @var string
22
- */
23
- const SHORTCODE = 'playlist';
24
-
25
- /**
26
- * The default height of the thumbnail image for 'audio' playlist tracks.
27
- *
28
- * @var int
29
- */
30
- const DEFAULT_THUMB_HEIGHT = 64;
31
-
32
- /**
33
- * The default width of the thumbnail image for 'audio' playlist tracks.
34
- *
35
- * @var int
36
- */
37
- const DEFAULT_THUMB_WIDTH = 48;
38
-
39
- /**
40
- * The max width of the audio thumbnail image.
41
- *
42
- * This corresponds to the max-width in wp-mediaelement.css:
43
- * .wp-playlist .wp-playlist-current-item img
44
- *
45
- * @var int
46
- */
47
- const THUMB_MAX_WIDTH = 60;
48
-
49
- /**
50
- * The height of the carousel.
51
- *
52
- * @var int
53
- */
54
- const CAROUSEL_HEIGHT = 160;
55
-
56
- /**
57
- * The pattern to get the playlist data.
58
- *
59
- * @var string
60
- */
61
- const PLAYLIST_REGEX = ':<script type="application/json" class="wp-playlist-script">(.+?)</script>:s';
62
-
63
- /**
64
- * The ID of individual playlist.
65
- *
66
- * @var int
67
- */
68
- public static $playlist_id = 0;
69
-
70
- /**
71
- * The removed shortcode callback.
72
- *
73
- * @var callable
74
- */
75
- public $removed_shortcode_callback;
76
-
77
- /**
78
- * Registers the playlist shortcode.
79
- *
80
- * @global array $shortcode_tags
81
- * @return void
82
- */
83
- public function register_embed() {
84
- global $shortcode_tags;
85
- if ( shortcode_exists( self::SHORTCODE ) ) {
86
- $this->removed_shortcode_callback = $shortcode_tags[ self::SHORTCODE ];
87
- }
88
- add_shortcode( self::SHORTCODE, array( $this, 'shortcode' ) );
89
- remove_action( 'wp_playlist_scripts', 'wp_playlist_scripts' );
90
- }
91
-
92
- /**
93
- * Unregisters the playlist shortcode.
94
- *
95
- * @return void
96
- */
97
- public function unregister_embed() {
98
- if ( $this->removed_shortcode_callback ) {
99
- add_shortcode( self::SHORTCODE, $this->removed_shortcode_callback );
100
- $this->removed_shortcode_callback = null;
101
- }
102
- add_action( 'wp_playlist_scripts', 'wp_playlist_scripts' );
103
- }
104
-
105
- /**
106
- * Enqueues the playlist styling.
107
- *
108
- * @return void
109
- */
110
- public function enqueue_styles() {
111
- wp_enqueue_style(
112
- 'amp-playlist-shortcode',
113
- amp_get_asset_url( 'css/amp-playlist-shortcode.css' ),
114
- array( 'wp-mediaelement' ),
115
- AMP__VERSION
116
- );
117
- }
118
-
119
- /**
120
- * Gets AMP-compliant markup for the playlist shortcode.
121
- *
122
- * Uses the JSON that wp_playlist_shortcode() produces.
123
- * Gets the markup, based on the type of playlist.
124
- *
125
- * @param array $attr The playlist attributes.
126
- * @return string Playlist shortcode markup.
127
- */
128
- public function shortcode( $attr ) {
129
- $data = $this->get_data( $attr );
130
- if ( isset( $data['type'] ) && ( 'audio' === $data['type'] ) ) {
131
- return $this->audio_playlist( $data );
132
- } elseif ( isset( $data['type'] ) && ( 'video' === $data['type'] ) ) {
133
- return $this->video_playlist( $data );
134
- }
135
- }
136
-
137
- /**
138
- * Gets an AMP-compliant audio playlist.
139
- *
140
- * @param array $data Data.
141
- * @return string Playlist shortcode markup, or an empty string.
142
- */
143
- public function audio_playlist( $data ) {
144
- if ( ! isset( $data['tracks'] ) ) {
145
- return '';
146
- }
147
- self::$playlist_id++;
148
- $container_id = 'wpPlaylist' . self::$playlist_id . 'Carousel';
149
- $state_id = 'wpPlaylist' . self::$playlist_id;
150
- $amp_state = array(
151
- 'selectedIndex' => 0,
152
- );
153
-
154
- $this->enqueue_styles();
155
- ob_start();
156
- ?>
157
- <div class="wp-playlist wp-audio-playlist wp-playlist-light">
158
- <amp-state id="<?php echo esc_attr( $state_id ); ?>">
159
- <script type="application/json"><?php echo wp_json_encode( $amp_state ); ?></script>
160
- </amp-state>
161
- <amp-carousel id="<?php echo esc_attr( $container_id ); ?>" [slide]="<?php echo esc_attr( $state_id . '.selectedIndex' ); ?>" height="<?php echo esc_attr( self::CAROUSEL_HEIGHT ); ?>" width="auto" type="slides">
162
- <?php
163
- foreach ( $data['tracks'] as $track ) :
164
- $title = $this->get_title( $track );
165
- $image_url = isset( $track['thumb']['src'] ) ? $track['thumb']['src'] : '';
166
- $dimensions = $this->get_thumb_dimensions( $track );
167
- ?>
168
- <div>
169
- <div class="wp-playlist-current-item">
170
- <?php if ( $image_url ) : ?>
171
- <amp-img src="<?php echo esc_url( $image_url ); ?>" height="<?php echo esc_attr( $dimensions['height'] ); ?>" width="<?php echo esc_attr( $dimensions['width'] ); ?>"></amp-img>
172
- <?php endif; ?>
173
- <div class="wp-playlist-caption">
174
- <span class="wp-playlist-item-meta wp-playlist-item-title"><?php echo esc_html( $title ); ?></span>
175
- </div>
176
- </div>
177
- <amp-audio width="auto" height="50" src="<?php echo esc_url( $track['src'] ); ?>"></amp-audio>
178
- </div>
179
- <?php endforeach; ?>
180
- </amp-carousel>
181
- <?php $this->print_tracks( $state_id, $data['tracks'] ); ?>
182
- </div>
183
- <?php
184
- return ob_get_clean();
185
- }
186
-
187
- /**
188
- * Gets an AMP-compliant video playlist.
189
- *
190
- * This uses similar markup to the native playlist shortcode output.
191
- * So the styles from wp-mediaelement.min.css will apply to it.
192
- *
193
- * @global int $content_width
194
- * @param array $data Data.
195
- * @return string $video_playlist Markup for the video playlist.
196
- */
197
- public function video_playlist( $data ) {
198
- global $content_width;
199
- if ( ! isset( $data['tracks'], $data['tracks'][0]['src'] ) ) {
200
- return '';
201
- }
202
- self::$playlist_id++;
203
- $state_id = 'wpPlaylist' . self::$playlist_id;
204
- $amp_state = array(
205
- 'selectedIndex' => 0,
206
- );
207
- foreach ( $data['tracks'] as $index => $track ) {
208
- $amp_state[ $index ] = array(
209
- 'videoUrl' => $track['src'],
210
- 'thumb' => isset( $track['thumb']['src'] ) ? $track['thumb']['src'] : '',
211
- );
212
- }
213
-
214
- $dimensions = isset( $data['tracks'][0]['dimensions']['resized'] ) ? $data['tracks'][0]['dimensions']['resized'] : null;
215
- $width = isset( $dimensions['width'] ) ? $dimensions['width'] : $content_width;
216
- $height = isset( $dimensions['height'] ) ? $dimensions['height'] : null;
217
- $src_bound = sprintf( '%s[%s.selectedIndex].videoUrl', $state_id, $state_id );
218
-
219
- $this->enqueue_styles();
220
- ob_start();
221
- ?>
222
- <div class="wp-playlist wp-video-playlist wp-playlist-light">
223
- <amp-state id="<?php echo esc_attr( $state_id ); ?>">
224
- <script type="application/json"><?php echo wp_json_encode( $amp_state ); // WPCS: XSS ok. ?></script>
225
- </amp-state>
226
- <amp-video id="amp-video" src="<?php echo esc_url( $data['tracks'][0]['src'] ); ?>" [src]="<?php echo esc_attr( $src_bound ); ?>" width="<?php echo esc_attr( $width ); ?>" height="<?php echo esc_attr( $height ); ?>" controls></amp-video>
227
- <?php $this->print_tracks( $state_id, $data['tracks'] ); ?>
228
- </div>
229
- <?php
230
- return ob_get_clean(); // WPCS: XSS ok.
231
- }
232
-
233
- /**
234
- * Gets the thumbnail image dimensions, including height and width.
235
- *
236
- * If the width is higher than the maximum width,
237
- * reduces it to the maximum width.
238
- * And it proportionally reduces the height.
239
- *
240
- * @param array $track The data for the track.
241
- * @return array {
242
- * Dimensions.
243
- *
244
- * @type int $height Image height.
245
- * @type int $width Image width.
246
- * }
247
- */
248
- public function get_thumb_dimensions( $track ) {
249
- $original_height = isset( $track['thumb']['height'] ) ? intval( $track['thumb']['height'] ) : self::DEFAULT_THUMB_HEIGHT;
250
- $original_width = isset( $track['thumb']['width'] ) ? intval( $track['thumb']['width'] ) : self::DEFAULT_THUMB_WIDTH;
251
- if ( $original_width > self::THUMB_MAX_WIDTH ) {
252
- $ratio = $original_width / self::THUMB_MAX_WIDTH;
253
- $height = intval( $original_height / $ratio );
254
- } else {
255
- $height = $original_height;
256
- }
257
- $width = min( self::THUMB_MAX_WIDTH, $original_width );
258
- return compact( 'height', 'width' );
259
- }
260
-
261
- /**
262
- * Outputs the playlist tracks, based on the type of playlist.
263
- *
264
- * These typically appear below the player.
265
- * Clicking a track triggers the player to appear with its src.
266
- *
267
- * @param string $state_id The ID of the container.
268
- * @param array $tracks Tracks.
269
- * @return void
270
- */
271
- public function print_tracks( $state_id, $tracks ) {
272
- ?>
273
- <div class="wp-playlist-tracks">
274
- <?php foreach ( $tracks as $index => $track ) : ?>
275
- <?php
276
- $on = 'tap:AMP.setState(' . wp_json_encode( array( $state_id => array( 'selectedIndex' => $index ) ) ) . ')';
277
- $initial_class = 0 === $index ? 'wp-playlist-item wp-playlist-playing' : 'wp-playlist-item';
278
- $bound_class = sprintf( '%d == %s.selectedIndex ? "wp-playlist-item wp-playlist-playing" : "wp-playlist-item"', $index, $state_id );
279
- ?>
280
- <div class="<?php echo esc_attr( $initial_class ); ?>" [class]="<?php echo esc_attr( $bound_class ); ?>" >
281
- <a class="wp-playlist-caption" on="<?php echo esc_attr( $on ); ?>">
282
- <?php echo esc_html( strval( $index + 1 ) . '.' ); ?> <span class="wp-playlist-item-title"><?php echo esc_html( $this->get_title( $track ) ); ?></span>
283
- </a>
284
- <?php if ( isset( $track['meta']['length_formatted'] ) ) : ?>
285
- <div class="wp-playlist-item-length"><?php echo esc_html( $track['meta']['length_formatted'] ); ?></div>
286
- <?php endif; ?>
287
- </div>
288
- <?php endforeach; ?>
289
- </div>
290
- <?php
291
- }
292
-
293
- /**
294
- * Gets the data for the playlist.
295
- *
296
- * @see wp_playlist_shortcode()
297
- * @param array $attr The shortcode attributes.
298
- * @return array $data The data for the playlist.
299
- */
300
- public function get_data( $attr ) {
301
- $markup = wp_playlist_shortcode( $attr );
302
- preg_match( self::PLAYLIST_REGEX, $markup, $matches );
303
- if ( empty( $matches[1] ) ) {
304
- return array();
305
- }
306
- return json_decode( $matches[1], true );
307
- }
308
-
309
- /**
310
- * Gets the title for the track.
311
- *
312
- * @param array $track The track data.
313
- * @return string $title The title of the track.
314
- */
315
- public function get_title( $track ) {
316
- if ( ! empty( $track['caption'] ) ) {
317
- return $track['caption'];
318
- } elseif ( ! empty( $track['title'] ) ) {
319
- return $track['title'];
320
- }
321
- return '';
322
- }
323
-
324
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/embeds/class-amp-reddit-embed-handler.php DELETED
@@ -1,74 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Reddit_Embed_Handler
4
- *
5
- * @package AMP
6
- * @since 0.7
7
- */
8
-
9
- /**
10
- * Class AMP_Reddit_Embed_Handler
11
- */
12
- class AMP_Reddit_Embed_Handler extends AMP_Base_Embed_Handler {
13
- /**
14
- * Regex matched to produce output amp-reddit.
15
- *
16
- * @const string
17
- */
18
- const URL_PATTERN = '#https?://(www\.)?reddit\.com/r/[^/]+/comments/.*#i';
19
-
20
- /**
21
- * Register embed.
22
- */
23
- public function register_embed() {
24
- wp_embed_register_handler( 'amp-reddit', self::URL_PATTERN, array( $this, 'oembed' ), -1 );
25
- }
26
-
27
- /**
28
- * Unregister embed.
29
- */
30
- public function unregister_embed() {
31
- wp_embed_unregister_handler( 'amp-reddit', -1 );
32
- }
33
-
34
- /**
35
- * Embed found with matching URL callback.
36
- *
37
- * @param array $matches URL regex matches.
38
- * @param array $attr Additional parameters.
39
- * @param array $url URL.
40
- * @return string Embed.
41
- */
42
- public function oembed( $matches, $attr, $url ) {
43
- return $this->render( array( 'url' => $url ) );
44
- }
45
-
46
- /**
47
- * Output the Reddit amp element.
48
- *
49
- * @param array $args parameters used for output.
50
- * @return string Rendered content.
51
- */
52
- public function render( $args ) {
53
- $args = wp_parse_args( $args, array(
54
- 'url' => false,
55
- ) );
56
-
57
- if ( empty( $args['url'] ) ) {
58
- return '';
59
- }
60
-
61
- // @todo Sizing is not yet correct. See <https://github.com/ampproject/amphtml/issues/11869>.
62
- return AMP_HTML_Utils::build_tag(
63
- 'amp-reddit',
64
- array(
65
- 'layout' => 'responsive',
66
- 'data-embedtype' => 'post',
67
- 'width' => '100',
68
- 'height' => '100',
69
- 'data-src' => $args['url'],
70
- )
71
- );
72
- }
73
- }
74
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/embeds/class-amp-tumblr-embed-handler.php DELETED
@@ -1,60 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Tumblr_Embed_Handler
4
- *
5
- * @package AMP
6
- * @since 0.7
7
- */
8
-
9
- /**
10
- * Class AMP_Tumblr_Embed_Handler
11
- */
12
- class AMP_Tumblr_Embed_Handler extends AMP_Base_Embed_Handler {
13
-
14
- /**
15
- * Register embed.
16
- */
17
- public function register_embed() {
18
- add_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10, 2 );
19
- }
20
-
21
- /**
22
- * Unregister embed.
23
- */
24
- public function unregister_embed() {
25
- remove_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10 );
26
- }
27
-
28
- /**
29
- * Filter oEmbed HTML for Tumblr to prepare it for AMP.
30
- *
31
- * @param string $cache Cache for oEmbed.
32
- * @param string $url Embed URL.
33
- * @return string Embed.
34
- */
35
- public function filter_embed_oembed_html( $cache, $url ) {
36
- $parsed_url = wp_parse_url( $url );
37
- if ( false === strpos( $parsed_url['host'], 'tumblr.com' ) ) {
38
- return $cache;
39
- }
40
-
41
- // @todo The iframe will not get sized properly.
42
- if ( preg_match( '#data-href="(?P<href>https://embed.tumblr.com/embed/post/\w+/\w+)"#', $cache, $matches ) ) {
43
- $cache = AMP_HTML_Utils::build_tag(
44
- 'amp-iframe',
45
- array(
46
- 'width' => $this->args['width'],
47
- 'height' => $this->args['height'],
48
- 'layout' => 'responsive',
49
- 'sandbox' => 'allow-scripts allow-popups', // The allow-scripts is needed to allow the iframe to render; allow-popups needed to allow clicking.
50
- 'src' => $matches['href'],
51
- ),
52
- sprintf( '<a placeholder href="%s">Tumblr</a>', $url )
53
- );
54
- }
55
-
56
- return $cache;
57
- }
58
-
59
- }
60
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/options/class-amp-analytics-options-submenu.php DELETED
@@ -1,61 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Analytics_Options_Submenu
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Analytics_Options_Submenu
10
- */
11
- class AMP_Analytics_Options_Submenu {
12
-
13
- private $parent_menu_slug;
14
- private $menu_slug;
15
- private $menu_page;
16
-
17
- public function __construct( $parent_menu_slug ) {
18
- $this->parent_menu_slug = $parent_menu_slug;
19
- $this->menu_slug = 'amp-analytics-options';
20
- $this->menu_page = new AMP_Analytics_Options_Submenu_Page();
21
- }
22
-
23
- public function init() {
24
- $this->add_submenu();
25
- add_action(
26
- 'admin_print_styles-amp_page_' . $this->menu_slug,
27
- array( $this, 'amp_options_styles' )
28
- );
29
- }
30
-
31
- private function add_submenu() {
32
- add_submenu_page(
33
- $this->parent_menu_slug,
34
- __( 'AMP Analytics Options', 'amp' ),
35
- __( 'Analytics', 'amp' ),
36
- 'manage_options',
37
- $this->menu_slug,
38
- array( $this->menu_page, 'render' )
39
- );
40
- }
41
-
42
- public function amp_options_styles() {
43
- ?>
44
- <style>
45
- .analytics-data-container .button.delete,
46
- .analytics-data-container .button.delete:hover,
47
- .analytics-data-container .button.delete:active,
48
- .analytics-data-container .button.delete:focus {
49
- background: red;
50
- border-color: red;
51
- text-shadow: 0 0 0;
52
- margin: 0 5px;
53
- }
54
- .amp-analytics-options.notice {
55
- width: 300px;
56
- }
57
- </style>;
58
-
59
- <?php
60
- }
61
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/options/class-amp-options-manager.php DELETED
@@ -1,262 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Options_Manager.
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Options_Manager
10
- */
11
- class AMP_Options_Manager {
12
-
13
- /**
14
- * Option name.
15
- *
16
- * @var string
17
- */
18
- const OPTION_NAME = 'amp-options';
19
-
20
- /**
21
- * Register settings.
22
- */
23
- public static function register_settings() {
24
- register_setting(
25
- self::OPTION_NAME,
26
- self::OPTION_NAME,
27
- array(
28
- 'type' => 'array',
29
- 'sanitize_callback' => array( __CLASS__, 'validate_options' ),
30
- )
31
- );
32
-
33
- add_action( 'update_option_' . self::OPTION_NAME, array( __CLASS__, 'maybe_flush_rewrite_rules' ), 10, 2 );
34
- }
35
-
36
- /**
37
- * Flush rewrite rules if the supported_post_types have changed.
38
- *
39
- * @since 0.6.2
40
- *
41
- * @param array $old_options Old options.
42
- * @param array $new_options New options.
43
- */
44
- public static function maybe_flush_rewrite_rules( $old_options, $new_options ) {
45
- $old_post_types = isset( $old_options['supported_post_types'] ) ? $old_options['supported_post_types'] : array();
46
- $new_post_types = isset( $new_options['supported_post_types'] ) ? $new_options['supported_post_types'] : array();
47
- sort( $old_post_types );
48
- sort( $new_post_types );
49
- if ( $old_post_types !== $new_post_types ) {
50
- flush_rewrite_rules( false );
51
- }
52
- }
53
-
54
- /**
55
- * Get plugin options.
56
- *
57
- * @return array Options.
58
- */
59
- public static function get_options() {
60
- return get_option( self::OPTION_NAME, array() );
61
- }
62
-
63
- /**
64
- * Get plugin option.
65
- *
66
- * @param string $option Plugin option name.
67
- * @param bool $default Default value.
68
- *
69
- * @return mixed Option value.
70
- */
71
- public static function get_option( $option, $default = false ) {
72
- $amp_options = self::get_options();
73
-
74
- if ( ! isset( $amp_options[ $option ] ) ) {
75
- return $default;
76
- }
77
-
78
- return $amp_options[ $option ];
79
- }
80
-
81
- /**
82
- * Validate options.
83
- *
84
- * @param array $new_options Plugin options.
85
- * @return array Options.
86
- */
87
- public static function validate_options( $new_options ) {
88
- $defaults = array(
89
- 'supported_post_types' => array(),
90
- 'analytics' => array(),
91
- );
92
-
93
- $options = array_merge(
94
- $defaults,
95
- self::get_options()
96
- );
97
-
98
- // Validate post type support.
99
- if ( isset( $new_options['supported_post_types'] ) ) {
100
- $options['supported_post_types'] = array();
101
- foreach ( $new_options['supported_post_types'] as $post_type ) {
102
- if ( ! post_type_exists( $post_type ) ) {
103
- add_settings_error( self::OPTION_NAME, 'unknown_post_type', __( 'Unrecognized post type.', 'amp' ) );
104
- } else {
105
- $options['supported_post_types'][] = $post_type;
106
- }
107
- }
108
- }
109
-
110
- // Validate analytics.
111
- if ( isset( $new_options['analytics'] ) ) {
112
- foreach ( $new_options['analytics'] as $id => $data ) {
113
-
114
- // Check save/delete pre-conditions and proceed if correct.
115
- if ( empty( $data['type'] ) || empty( $data['config'] ) ) {
116
- add_settings_error( self::OPTION_NAME, 'missing_analytics_vendor_or_config', __( 'Missing vendor type or config.', 'amp' ) );
117
- continue;
118
- }
119
-
120
- // Validate JSON configuration.
121
- $is_valid_json = AMP_HTML_Utils::is_valid_json( $data['config'] );
122
- if ( ! $is_valid_json ) {
123
- add_settings_error( self::OPTION_NAME, 'invalid_analytics_config_json', __( 'Invalid analytics config JSON.', 'amp' ) );
124
- continue;
125
- }
126
-
127
- $entry_vendor_type = sanitize_key( $data['type'] );
128
- $entry_config = trim( $data['config'] );
129
-
130
- if ( ! empty( $data['id'] ) && '__new__' !== $data['id'] ) {
131
- $entry_id = sanitize_key( $data['id'] );
132
- } else {
133
-
134
- // Generate a hash string to uniquely identify this entry.
135
- $entry_id = substr( md5( $entry_vendor_type . $entry_config ), 0, 12 );
136
-
137
- // Avoid duplicates.
138
- if ( isset( $options['analytics'][ $entry_id ] ) ) {
139
- add_settings_error( self::OPTION_NAME, 'duplicate_analytics_entry', __( 'Duplicate analytics entry found.', 'amp' ) );
140
- continue;
141
- }
142
- }
143
-
144
- if ( isset( $data['delete'] ) ) {
145
- unset( $options['analytics'][ $entry_id ] );
146
- } else {
147
- $options['analytics'][ $entry_id ] = array(
148
- 'type' => $entry_vendor_type,
149
- 'config' => $entry_config,
150
- );
151
- }
152
- }
153
- }
154
-
155
- return $options;
156
- }
157
-
158
-
159
- /**
160
- * Check for errors with updating the supported post types.
161
- *
162
- * @since 0.6
163
- * @see add_settings_error()
164
- */
165
- public static function check_supported_post_type_update_errors() {
166
- $builtin_support = AMP_Post_Type_Support::get_builtin_supported_post_types();
167
- $supported_types = self::get_option( 'supported_post_types', array() );
168
- foreach ( AMP_Post_Type_Support::get_eligible_post_types() as $name ) {
169
- $post_type = get_post_type_object( $name );
170
- if ( empty( $post_type ) || in_array( $post_type->name, $builtin_support, true ) ) {
171
- continue;
172
- }
173
-
174
- $post_type_supported = post_type_supports( $post_type->name, amp_get_slug() );
175
- $is_support_elected = in_array( $post_type->name, $supported_types, true );
176
-
177
- $error = null;
178
- $code = null;
179
- if ( $is_support_elected && ! $post_type_supported ) {
180
- /* translators: %s: Post type name. */
181
- $error = __( '"%s" could not be activated because support is removed by a plugin or theme', 'amp' );
182
- $code = sprintf( '%s_activation_error', $post_type->name );
183
- } elseif ( ! $is_support_elected && $post_type_supported ) {
184
- /* translators: %s: Post type name. */
185
- $error = __( '"%s" could not be deactivated because support is added by a plugin or theme', 'amp' );
186
- $code = sprintf( '%s_deactivation_error', $post_type->name );
187
- }
188
-
189
- if ( isset( $error, $code ) ) {
190
- add_settings_error(
191
- self::OPTION_NAME,
192
- $code,
193
- sprintf(
194
- $error,
195
- isset( $post_type->label ) ? $post_type->label : $post_type->name
196
- )
197
- );
198
- }
199
- }
200
- }
201
-
202
- /**
203
- * Update plugin option.
204
- *
205
- * @param string $option Plugin option name.
206
- * @param mixed $value Plugin option value.
207
- *
208
- * @return bool Whether update succeeded.
209
- */
210
- public static function update_option( $option, $value ) {
211
- $amp_options = self::get_options();
212
-
213
- $amp_options[ $option ] = $value;
214
-
215
- return update_option( self::OPTION_NAME, $amp_options, false );
216
- }
217
-
218
- /**
219
- * Handle analytics submission.
220
- */
221
- public static function handle_analytics_submit() {
222
-
223
- // Request must come from user with right capabilities.
224
- if ( ! current_user_can( 'manage_options' ) ) {
225
- wp_die( esc_html__( 'Sorry, you do not have the necessary permissions to perform this action', 'amp' ) );
226
- }
227
-
228
- // Ensure request is coming from analytics option form.
229
- check_admin_referer( 'analytics-options', 'analytics-options' );
230
-
231
- if ( isset( $_POST['amp-options']['analytics'] ) ) {
232
- self::update_option( 'analytics', wp_unslash( $_POST['amp-options']['analytics'] ) );
233
-
234
- $errors = get_settings_errors( self::OPTION_NAME );
235
- if ( empty( $errors ) ) {
236
- add_settings_error( self::OPTION_NAME, 'settings_updated', __( 'The analytics entry was successfully saved!', 'amp' ), 'updated' );
237
- $errors = get_settings_errors( self::OPTION_NAME );
238
- }
239
- set_transient( 'settings_errors', $errors );
240
- }
241
-
242
- /*
243
- * Redirect to keep the user in the analytics options page.
244
- * Wrap in is_admin() to enable phpunit tests to exercise this code.
245
- */
246
- wp_safe_redirect( admin_url( 'admin.php?page=amp-analytics-options&settings-updated=1' ) );
247
- exit;
248
- }
249
-
250
- /**
251
- * Update analytics options.
252
- *
253
- * @codeCoverageIgnore
254
- * @deprecated
255
- * @param array $data Unsanitized unslashed data.
256
- * @return bool Whether options were updated.
257
- */
258
- public static function update_analytics_options( $data ) {
259
- _deprecated_function( __METHOD__, '0.6', __CLASS__ . '::update_option' );
260
- return self::update_option( 'analytics', wp_unslash( $data ) );
261
- }
262
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/options/class-amp-options-menu.php DELETED
@@ -1,143 +0,0 @@
1
- <?php
2
- /**
3
- * AMP Options.
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * AMP_Options_Menu class.
10
- */
11
- class AMP_Options_Menu {
12
-
13
- /**
14
- * The AMP svg menu icon.
15
- *
16
- * @var string
17
- */
18
- const ICON_BASE64_SVG = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB3aWR0aD0iNjJweCIgaGVpZ2h0PSI2MnB4IiB2aWV3Qm94PSIwIDAgNjIgNjIiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+ICAgICAgICA8dGl0bGU+QU1QLUJyYW5kLUJsYWNrLUljb248L3RpdGxlPiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4gICAgPGRlZnM+PC9kZWZzPiAgICA8ZyBpZD0iYW1wLWxvZ28taW50ZXJuYWwtc2l0ZSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgICAgICA8ZyBpZD0iQU1QLUJyYW5kLUJsYWNrLUljb24iIGZpbGw9IiMwMDAwMDAiPiAgICAgICAgICAgIDxwYXRoIGQ9Ik00MS42Mjg4NjY3LDI4LjE2MTQzMzMgTDI4LjYyNDM2NjcsNDkuODAzNTY2NyBMMjYuMjY4MzY2Nyw0OS44MDM1NjY3IEwyOC41OTc1LDM1LjcwMTY2NjcgTDIxLjM4MzgsMzUuNzEwOTY2NyBDMjEuMzgzOCwzNS43MTA5NjY3IDIxLjMxNTYsMzUuNzEzMDMzMyAyMS4yODM1NjY3LDM1LjcxMzAzMzMgQzIwLjYzMzYsMzUuNzEzMDMzMyAyMC4xMDc2MzMzLDM1LjE4NzA2NjcgMjAuMTA3NjMzMywzNC41MzcxIEMyMC4xMDc2MzMzLDM0LjI1ODEgMjAuMzY3LDMzLjc4NTg2NjcgMjAuMzY3LDMzLjc4NTg2NjcgTDMzLjMyOTEzMzMsMTIuMTY5NTY2NyBMMzUuNzI0NCwxMi4xNzk5IEwzMy4zMzYzNjY3LDI2LjMwMzUgTDQwLjU4NzI2NjcsMjYuMjk0MiBDNDAuNTg3MjY2NywyNi4yOTQyIDQwLjY2NDc2NjcsMjYuMjkzMTY2NyA0MC43MDE5NjY3LDI2LjI5MzE2NjcgQzQxLjM1MTkzMzMsMjYuMjkzMTY2NyA0MS44Nzc5LDI2LjgxOTEzMzMgNDEuODc3OSwyNy40NjkxIEM0MS44Nzc5LDI3LjczMjYgNDEuNzc0NTY2NywyNy45NjQwNjY3IDQxLjYyNzgzMzMsMjguMTYwNCBMNDEuNjI4ODY2NywyOC4xNjE0MzMzIFogTTMxLDAgQzEzLjg3ODcsMCAwLDEzLjg3OTczMzMgMCwzMSBDMCw0OC4xMjEzIDEzLjg3ODcsNjIgMzEsNjIgQzQ4LjEyMDI2NjcsNjIgNjIsNDguMTIxMyA2MiwzMSBDNjIsMTMuODc5NzMzMyA0OC4xMjAyNjY3LDAgMzEsMCBMMzEsMCBaIiBpZD0iRmlsbC0xIj48L3BhdGg+ICAgICAgICA8L2c+ICAgIDwvZz48L3N2Zz4=';
19
-
20
- /**
21
- * Initialize.
22
- */
23
- public function init() {
24
- add_action( 'admin_post_amp_analytics_options', 'AMP_Options_Manager::handle_analytics_submit' );
25
- add_action( 'admin_menu', array( $this, 'add_menu_items' ), 9 );
26
- }
27
-
28
- /**
29
- * Add menu.
30
- */
31
- public function add_menu_items() {
32
-
33
- add_menu_page(
34
- __( 'AMP Options', 'amp' ),
35
- __( 'AMP', 'amp' ),
36
- 'manage_options',
37
- AMP_Options_Manager::OPTION_NAME,
38
- array( $this, 'render_screen' ),
39
- self::ICON_BASE64_SVG
40
- );
41
-
42
- add_submenu_page(
43
- AMP_Options_Manager::OPTION_NAME,
44
- __( 'AMP Settings', 'amp' ),
45
- __( 'General', 'amp' ),
46
- 'manage_options',
47
- AMP_Options_Manager::OPTION_NAME
48
- );
49
-
50
- add_settings_section(
51
- 'post_types',
52
- false,
53
- '__return_false',
54
- AMP_Options_Manager::OPTION_NAME
55
- );
56
- add_settings_field(
57
- 'supported_post_types',
58
- __( 'Post Type Support', 'amp' ),
59
- array( $this, 'render_post_types_support' ),
60
- AMP_Options_Manager::OPTION_NAME,
61
- 'post_types'
62
- );
63
-
64
- $submenus = array(
65
- new AMP_Analytics_Options_Submenu( AMP_Options_Manager::OPTION_NAME ),
66
- );
67
-
68
- // Create submenu items and calls on the Submenu Page object to render the actual contents of the page.
69
- foreach ( $submenus as $submenu ) {
70
- $submenu->init();
71
- }
72
- }
73
-
74
- /**
75
- * Post types support section renderer.
76
- *
77
- * @since 0.6
78
- */
79
- public function render_post_types_support() {
80
- $builtin_support = AMP_Post_Type_Support::get_builtin_supported_post_types();
81
- $element_name = AMP_Options_Manager::OPTION_NAME . '[supported_post_types][]';
82
- ?>
83
- <fieldset>
84
- <?php foreach ( array_map( 'get_post_type_object', AMP_Post_Type_Support::get_eligible_post_types() ) as $post_type ) : ?>
85
- <?php
86
- $element_id = AMP_Options_Manager::OPTION_NAME . "-supported_post_types-{$post_type->name}";
87
- $is_builtin = amp_is_canonical() || in_array( $post_type->name, $builtin_support, true );
88
- ?>
89
- <?php if ( $is_builtin ) : ?>
90
- <input type="hidden" name="<?php echo esc_attr( $element_name ); ?>" value="<?php echo esc_attr( $post_type->name ); ?>">
91
- <?php endif; ?>
92
- <input
93
- type="checkbox"
94
- id="<?php echo esc_attr( $element_id ); ?>"
95
- name="<?php echo esc_attr( $element_name ); ?>"
96
- value="<?php echo esc_attr( $post_type->name ); ?>"
97
- <?php checked( true, amp_is_canonical() || post_type_supports( $post_type->name, amp_get_slug() ) ); ?>
98
- <?php disabled( $is_builtin ); ?>
99
- >
100
- <label for="<?php echo esc_attr( $element_id ); ?>">
101
- <?php echo esc_html( $post_type->label ); ?>
102
- </label>
103
- <br>
104
- <?php endforeach; ?>
105
- <p class="description">
106
- <?php
107
- if ( ! amp_is_canonical() ) :
108
- esc_html_e( 'Enable/disable AMP post type(s) support', 'amp' );
109
- else :
110
- esc_html_e( 'Canonical AMP is enabled in your theme, so all post types will render.', 'amp' );
111
- endif;
112
- ?>
113
- </p>
114
- </fieldset>
115
- <?php
116
- }
117
-
118
- /**
119
- * Display Settings.
120
- *
121
- * @since 0.6
122
- */
123
- public function render_screen() {
124
- if ( ! empty( $_GET['settings-updated'] ) ) { // WPCS: CSRF ok.
125
- AMP_Options_Manager::check_supported_post_type_update_errors();
126
- }
127
- ?>
128
- <div class="wrap">
129
- <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
130
- <?php settings_errors(); ?>
131
- <form action="options.php" method="post">
132
- <?php
133
- settings_fields( AMP_Options_Manager::OPTION_NAME );
134
- do_settings_sections( AMP_Options_Manager::OPTION_NAME );
135
- if ( ! amp_is_canonical() ) {
136
- submit_button();
137
- }
138
- ?>
139
- </form>
140
- </div>
141
- <?php
142
- }
143
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/options/views/class-amp-analytics-options-submenu-page.php DELETED
@@ -1,102 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Analytics_Options_Submenu_Page
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Analytics_Options_Submenu_Page
10
- */
11
- class AMP_Analytics_Options_Submenu_Page {
12
-
13
- /**
14
- * Render entry.
15
- *
16
- * @param string $id Entry ID.
17
- * @param string $type Entry type.
18
- * @param string $config Entry config as serialized JSON.
19
- */
20
- private function render_entry( $id = '', $type = '', $config = '' ) {
21
- $is_existing_entry = ! empty( $id );
22
-
23
- if ( $is_existing_entry ) {
24
- $entry_slug = sprintf( '%s%s', ( $type ? $type . '-' : '' ), substr( $id, - 6 ) );
25
- /* translators: %s is the entry slug */
26
- $analytics_title = sprintf( __( 'Analytics: %s', 'amp' ), $entry_slug );
27
- } else {
28
- $analytics_title = __( 'Add new entry:', 'amp' );
29
- $id = '__new__';
30
- }
31
-
32
- $id_base = sprintf( '%s[analytics][%s]', AMP_Options_Manager::OPTION_NAME, $id );
33
- ?>
34
- <div class="analytics-data-container">
35
- <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
36
- <h2>
37
- <?php echo esc_html( $analytics_title ); ?>
38
- </h2>
39
- <div class="options">
40
- <p>
41
- <label>
42
- <?php esc_html_e( 'Type:', 'amp' ); ?>
43
- <input class="option-input" type="text" name="<?php echo esc_attr( $id_base . '[type]' ); ?>" value="<?php echo esc_attr( $type ); ?>" />
44
- </label>
45
- <label>
46
- <?php esc_html_e( 'ID:', 'amp' ); ?>
47
- <input type="text" value="<?php echo esc_attr( $is_existing_entry ? $id : '' ); ?>" readonly />
48
- </label>
49
- <input type="hidden" name="<?php echo esc_attr( $id_base . '[id]' ); ?>" value="<?php echo esc_attr( $id ); ?>" />
50
- </p>
51
- <p>
52
- <label>
53
- <?php esc_html_e( 'JSON Configuration:', 'amp' ); ?>
54
- <br />
55
- <textarea rows="10" cols="100" name="<?php echo esc_attr( $id_base . '[config]' ); ?>"><?php echo esc_textarea( $config ); ?></textarea>
56
- </label>
57
- </p>
58
- <input type="hidden" name="action" value="amp_analytics_options">
59
- </div>
60
- <p>
61
- <?php
62
- wp_nonce_field( 'analytics-options', 'analytics-options' );
63
- submit_button( esc_html__( 'Save', 'amp' ), 'primary', 'save', false );
64
- if ( $is_existing_entry ) {
65
- submit_button( esc_html__( 'Delete', 'amp' ), 'delete button-primary', esc_attr( $id_base . '[delete]' ), false );
66
- }
67
- ?>
68
- </p>
69
- </form>
70
- </div><!-- #analytics-data-container -->
71
- <?php
72
- }
73
-
74
- /**
75
- * Render title.
76
- */
77
- public function render_title() {
78
- ?>
79
- <div class="wrap">
80
- <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
81
- <?php settings_errors(); ?>
82
- </div><!-- .wrap -->
83
- <?php
84
- }
85
-
86
- /**
87
- * Render.
88
- */
89
- public function render() {
90
- $analytics_entries = AMP_Options_Manager::get_option( 'analytics', array() );
91
-
92
- $this->render_title();
93
-
94
- // Render entries stored in the DB.
95
- foreach ( $analytics_entries as $entry_id => $entry ) {
96
- $this->render_entry( $entry_id, $entry['type'], $entry['config'] );
97
- }
98
-
99
- // Empty form for adding more entries.
100
- $this->render_entry();
101
- }
102
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/sanitizers/class-amp-allowed-tags-generated.php DELETED
@@ -1,10776 +0,0 @@
1
- <?php
2
- /**
3
- * Generated by amphtml-update.py - do not edit.
4
- *
5
- * This is a list of HTML tags and attributes that are allowed by the
6
- * AMP specification. Note that tag names have been converted to lowercase.
7
- *
8
- * Note: This file only contains tags that are relevant to the `body` of
9
- * an AMP page. To include additional elements modify the variable
10
- * `mandatory_parent_blacklist` in the amp_wp_build.py script.
11
- *
12
- * phpcs:ignoreFile
13
- */
14
- class AMP_Allowed_Tags_Generated {
15
-
16
- private static $spec_file_revision = 595;
17
- private static $minimum_validator_revision_required = 322;
18
-
19
- private static $allowed_tags = array(
20
- 'a' => array(
21
- array(
22
- 'attr_spec_list' => array(
23
- '[href]' => array(),
24
- 'border' => array(),
25
- 'download' => array(),
26
- 'href' => array(
27
- 'blacklisted_value_regex' => '__amp_source_origin',
28
- 'value_url' => array(
29
- 'allow_empty' => true,
30
- 'allow_relative' => true,
31
- 'allowed_protocol' => array(
32
- 'ftp',
33
- 'geo',
34
- 'http',
35
- 'https',
36
- 'mailto',
37
- 'maps',
38
- 'bbmi',
39
- 'fb-messenger',
40
- 'intent',
41
- 'line',
42
- 'skype',
43
- 'sms',
44
- 'snapchat',
45
- 'tel',
46
- 'tg',
47
- 'threema',
48
- 'twitter',
49
- 'viber',
50
- 'whatsapp',
51
- ),
52
- ),
53
- ),
54
- 'hreflang' => array(),
55
- 'media' => array(),
56
- 'name' => array(),
57
- 'referrerpolicy' => array(),
58
- 'rel' => array(
59
- 'blacklisted_value_regex' => '(^|\\s)(components|dns-prefetch|import|manifest|preconnect|prefetch|preload|prerender|serviceworker|stylesheet|subresource|)(\\s|$)',
60
- ),
61
- 'role' => array(),
62
- 'tabindex' => array(),
63
- 'target' => array(
64
- 'value_regex' => '(_blank|_self|_top)',
65
- ),
66
- 'type' => array(
67
- 'value_casei' => 'text/html',
68
- ),
69
- ),
70
- 'tag_spec' => array(
71
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#links',
72
- ),
73
- ),
74
- ),
75
- 'abbr' => array(
76
- array(
77
- 'attr_spec_list' => array(),
78
- 'tag_spec' => array(),
79
- ),
80
- ),
81
- 'acronym' => array(
82
- array(
83
- 'attr_spec_list' => array(),
84
- 'tag_spec' => array(),
85
- ),
86
- ),
87
- 'address' => array(
88
- array(
89
- 'attr_spec_list' => array(),
90
- 'tag_spec' => array(),
91
- ),
92
- ),
93
- 'amp-3q-player' => array(
94
- array(
95
- 'attr_spec_list' => array(
96
- 'autoplay' => array(
97
- 'value' => '',
98
- ),
99
- 'data-id' => array(
100
- 'mandatory' => true,
101
- ),
102
- 'media' => array(),
103
- 'noloading' => array(
104
- 'value' => '',
105
- ),
106
- ),
107
- 'tag_spec' => array(
108
- 'requires_extension' => array(
109
- 'amp-3q-player',
110
- ),
111
- ),
112
- ),
113
- ),
114
- 'amp-accordion' => array(
115
- array(
116
- 'attr_spec_list' => array(
117
- 'disable-session-states' => array(
118
- 'value' => '',
119
- ),
120
- 'expand-single-section' => array(
121
- 'value' => '',
122
- ),
123
- ),
124
- 'tag_spec' => array(
125
- 'requires_extension' => array(
126
- 'amp-accordion',
127
- ),
128
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-accordion',
129
- ),
130
- ),
131
- ),
132
- 'amp-ad' => array(
133
- array(
134
- 'attr_spec_list' => array(
135
- 'alt' => array(),
136
- 'json' => array(),
137
- 'media' => array(),
138
- 'noloading' => array(
139
- 'value' => '',
140
- ),
141
- 'rtc-config' => array(),
142
- 'src' => array(
143
- 'blacklisted_value_regex' => '__amp_source_origin',
144
- 'value_url' => array(
145
- 'allow_relative' => true,
146
- 'allowed_protocol' => array(
147
- 'https',
148
- ),
149
- ),
150
- ),
151
- 'template' => array(),
152
- 'type' => array(
153
- 'mandatory' => true,
154
- ),
155
- ),
156
- 'tag_spec' => array(
157
- 'also_requires_tag_warning' => array(
158
- 'amp-ad extension .js script',
159
- ),
160
- 'disallowed_ancestor' => array(
161
- 'amp-app-banner',
162
- ),
163
- 'requires_extension' => array(
164
- 'amp-ad',
165
- ),
166
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
167
- ),
168
- ),
169
- array(
170
- 'attr_spec_list' => array(
171
- 'alt' => array(),
172
- 'data-multi-size' => array(
173
- 'dispatch_key' => 2,
174
- 'mandatory' => true,
175
- 'value' => '',
176
- ),
177
- 'json' => array(),
178
- 'media' => array(),
179
- 'noloading' => array(
180
- 'value' => '',
181
- ),
182
- 'rtc-config' => array(),
183
- 'src' => array(
184
- 'blacklisted_value_regex' => '__amp_source_origin',
185
- 'value_url' => array(
186
- 'allow_relative' => true,
187
- 'allowed_protocol' => array(
188
- 'https',
189
- ),
190
- ),
191
- ),
192
- 'type' => array(
193
- 'mandatory' => true,
194
- ),
195
- ),
196
- 'tag_spec' => array(
197
- 'also_requires_tag_warning' => array(
198
- 'amp-ad extension .js script',
199
- ),
200
- 'disallowed_ancestor' => array(
201
- 'amp-app-banner',
202
- 'amp-carousel',
203
- 'amp-fx-flying-carpet',
204
- 'amp-lightbox',
205
- 'amp-sticky-ad',
206
- ),
207
- 'requires_extension' => array(
208
- 'amp-ad',
209
- ),
210
- 'spec_name' => 'amp-ad with data-multi-size attribute',
211
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
212
- ),
213
- ),
214
- array(
215
- 'attr_spec_list' => array(
216
- 'alt' => array(),
217
- 'data-enable-refresh' => array(
218
- 'dispatch_key' => 2,
219
- 'mandatory' => true,
220
- 'value' => '',
221
- ),
222
- 'json' => array(),
223
- 'media' => array(),
224
- 'noloading' => array(
225
- 'value' => '',
226
- ),
227
- 'src' => array(
228
- 'blacklisted_value_regex' => '__amp_source_origin',
229
- 'value_url' => array(
230
- 'allow_relative' => true,
231
- 'allowed_protocol' => array(
232
- 'https',
233
- ),
234
- ),
235
- ),
236
- 'type' => array(
237
- 'mandatory' => true,
238
- ),
239
- ),
240
- 'tag_spec' => array(
241
- 'also_requires_tag_warning' => array(
242
- 'amp-ad extension .js script',
243
- ),
244
- 'disallowed_ancestor' => array(
245
- 'amp-app-banner',
246
- 'amp-fx-flying-carpet',
247
- 'amp-lightbox',
248
- ),
249
- 'requires_extension' => array(
250
- 'amp-ad',
251
- ),
252
- 'spec_name' => 'amp-ad with data-enable-refresh attribute',
253
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
254
- ),
255
- ),
256
- ),
257
- 'amp-analytics' => array(
258
- array(
259
- 'attr_spec_list' => array(
260
- 'config' => array(
261
- 'blacklisted_value_regex' => '__amp_source_origin',
262
- 'value_url' => array(
263
- 'allow_empty' => true,
264
- 'allow_relative' => true,
265
- 'allowed_protocol' => array(
266
- 'https',
267
- ),
268
- ),
269
- ),
270
- 'type' => array(),
271
- ),
272
- 'tag_spec' => array(
273
- 'requires_extension' => array(
274
- 'amp-analytics',
275
- ),
276
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-analytics',
277
- ),
278
- ),
279
- ),
280
- 'amp-anim' => array(
281
- array(
282
- 'attr_spec_list' => array(
283
- 'alt' => array(),
284
- 'attribution' => array(),
285
- 'controls' => array(),
286
- 'media' => array(),
287
- 'noloading' => array(
288
- 'value' => '',
289
- ),
290
- 'src' => array(
291
- 'alternative_names' => array(
292
- 'srcset',
293
- ),
294
- 'blacklisted_value_regex' => '__amp_source_origin',
295
- 'mandatory' => true,
296
- 'value_url' => array(
297
- 'allow_relative' => true,
298
- 'allowed_protocol' => array(
299
- 'data',
300
- 'http',
301
- 'https',
302
- ),
303
- ),
304
- ),
305
- ),
306
- 'tag_spec' => array(
307
- 'requires_extension' => array(
308
- 'amp-anim',
309
- ),
310
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-anim',
311
- ),
312
- ),
313
- ),
314
- 'amp-animation' => array(
315
- array(
316
- 'attr_spec_list' => array(
317
- 'media' => array(),
318
- 'noloading' => array(
319
- 'value' => '',
320
- ),
321
- 'trigger' => array(
322
- 'value' => 'visibility',
323
- ),
324
- ),
325
- 'tag_spec' => array(
326
- 'requires_extension' => array(
327
- 'amp-animation',
328
- ),
329
- ),
330
- ),
331
- ),
332
- 'amp-apester-media' => array(
333
- array(
334
- 'attr_spec_list' => array(
335
- 'data-apester-channel-token' => array(
336
- 'value_regex' => '[0-9a-zA-Z]+',
337
- ),
338
- 'data-apester-media-id' => array(
339
- 'value_regex' => '[0-9a-zA-Z]+',
340
- ),
341
- 'media' => array(),
342
- 'noloading' => array(
343
- 'value' => '',
344
- ),
345
- ),
346
- 'tag_spec' => array(
347
- 'requires_extension' => array(
348
- 'amp-apester-media',
349
- ),
350
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-apester-media',
351
- ),
352
- ),
353
- ),
354
- 'amp-app-banner' => array(
355
- array(
356
- 'attr_spec_list' => array(
357
- 'id' => array(
358
- 'mandatory' => true,
359
- ),
360
- 'media' => array(),
361
- 'noloading' => array(
362
- 'value' => '',
363
- ),
364
- ),
365
- 'tag_spec' => array(
366
- 'mandatory_parent' => 'body',
367
- 'requires_extension' => array(
368
- 'amp-app-banner',
369
- ),
370
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-app-banner',
371
- 'unique' => true,
372
- ),
373
- ),
374
- ),
375
- 'amp-audio' => array(
376
- array(
377
- 'attr_spec_list' => array(
378
- 'album' => array(),
379
- 'artist' => array(),
380
- 'artwork' => array(),
381
- 'autoplay' => array(
382
- 'value' => '',
383
- ),
384
- 'controls' => array(),
385
- 'controlslist' => array(),
386
- 'loop' => array(
387
- 'value' => '',
388
- ),
389
- 'media' => array(),
390
- 'muted' => array(
391
- 'value' => '',
392
- ),
393
- 'noloading' => array(
394
- 'value' => '',
395
- ),
396
- 'preload' => array(
397
- 'value_regex_casei' => '(auto|metadata|none|)',
398
- ),
399
- 'src' => array(
400
- 'blacklisted_value_regex' => '__amp_source_origin',
401
- 'value_url' => array(
402
- 'allow_relative' => true,
403
- 'allowed_protocol' => array(
404
- 'https',
405
- ),
406
- ),
407
- ),
408
- ),
409
- 'tag_spec' => array(
410
- 'disallowed_ancestor' => array(
411
- 'amp-story',
412
- ),
413
- 'requires_extension' => array(
414
- 'amp-audio',
415
- ),
416
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
417
- ),
418
- ),
419
- array(
420
- 'attr_spec_list' => array(
421
- 'album' => array(),
422
- 'artist' => array(),
423
- 'artwork' => array(),
424
- 'autoplay' => array(
425
- 'mandatory' => true,
426
- 'value' => '',
427
- ),
428
- 'controls' => array(),
429
- 'controlslist' => array(),
430
- 'loop' => array(
431
- 'value' => '',
432
- ),
433
- 'media' => array(),
434
- 'muted' => array(
435
- 'value' => '',
436
- ),
437
- 'noloading' => array(
438
- 'value' => '',
439
- ),
440
- 'src' => array(
441
- 'blacklisted_value_regex' => '__amp_source_origin',
442
- 'value_url' => array(
443
- 'allow_relative' => true,
444
- 'allowed_protocol' => array(
445
- 'https',
446
- ),
447
- ),
448
- ),
449
- ),
450
- 'tag_spec' => array(
451
- 'mandatory_ancestor' => 'amp-story',
452
- 'requires_extension' => array(
453
- 'amp-audio',
454
- ),
455
- 'spec_name' => 'amp-story >> amp-audio',
456
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
457
- ),
458
- ),
459
- ),
460
- 'amp-auto-ads' => array(
461
- array(
462
- 'attr_spec_list' => array(
463
- 'media' => array(),
464
- 'noloading' => array(
465
- 'value' => '',
466
- ),
467
- 'type' => array(
468
- 'mandatory' => true,
469
- ),
470
- ),
471
- 'tag_spec' => array(
472
- 'mandatory_parent' => 'body',
473
- 'requires_extension' => array(
474
- 'amp-auto-ads',
475
- ),
476
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-auto-ads',
477
- ),
478
- ),
479
- ),
480
- 'amp-beopinion' => array(
481
- array(
482
- 'attr_spec_list' => array(
483
- 'data-account' => array(
484
- 'mandatory' => true,
485
- 'value_regex_casei' => '[0-9a-f]{24}',
486
- ),
487
- 'data-content' => array(
488
- 'value_regex_casei' => '[0-9a-f]{24}',
489
- ),
490
- 'data-my-content' => array(
491
- 'value_regex' => '0|1',
492
- ),
493
- 'data-name' => array(),
494
- 'media' => array(),
495
- 'noloading' => array(
496
- 'value' => '',
497
- ),
498
- ),
499
- 'tag_spec' => array(
500
- 'requires_extension' => array(
501
- 'amp-beopinion',
502
- ),
503
- ),
504
- ),
505
- ),
506
- 'amp-bind-macro' => array(
507
- array(
508
- 'attr_spec_list' => array(
509
- 'arguments' => array(),
510
- 'expression' => array(
511
- 'mandatory' => true,
512
- ),
513
- 'id' => array(
514
- 'mandatory' => true,
515
- ),
516
- ),
517
- 'tag_spec' => array(
518
- 'requires_extension' => array(
519
- 'amp-bind',
520
- ),
521
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind',
522
- ),
523
- ),
524
- ),
525
- 'amp-bodymovin-animation' => array(
526
- array(
527
- 'attr_spec_list' => array(
528
- 'loop' => array(
529
- 'value_regex_casei' => '(false|number|true)',
530
- ),
531
- 'noautoplay' => array(
532
- 'value' => '',
533
- ),
534
- 'src' => array(
535
- 'mandatory' => true,
536
- 'value_url' => array(
537
- 'allow_relative' => false,
538
- 'allowed_protocol' => array(
539
- 'https',
540
- ),
541
- ),
542
- ),
543
- ),
544
- 'tag_spec' => array(
545
- 'requires_extension' => array(
546
- 'amp-bodymovin-animation',
547
- ),
548
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bodymovin-animation',
549
- ),
550
- ),
551
- ),
552
- 'amp-brid-player' => array(
553
- array(
554
- 'attr_spec_list' => array(
555
- 'autoplay' => array(),
556
- 'data-outstream' => array(
557
- 'value_regex' => '[0-9]+',
558
- ),
559
- 'data-partner' => array(
560
- 'mandatory' => true,
561
- 'value_regex' => '[0-9]+',
562
- ),
563
- 'data-player' => array(
564
- 'mandatory' => true,
565
- 'value_regex' => '[0-9]+',
566
- ),
567
- 'data-playlist' => array(
568
- 'value_regex' => '[0-9]+',
569
- ),
570
- 'data-video' => array(
571
- 'value_regex' => '[0-9]+',
572
- ),
573
- 'media' => array(),
574
- 'noloading' => array(
575
- 'value' => '',
576
- ),
577
- ),
578
- 'tag_spec' => array(
579
- 'requires_extension' => array(
580
- 'amp-brid-player',
581
- ),
582
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-brid-player',
583
- ),
584
- ),
585
- ),
586
- 'amp-brightcove' => array(
587
- array(
588
- 'attr_spec_list' => array(
589
- '[data-account]' => array(),
590
- '[data-embed]' => array(),
591
- '[data-player-id]' => array(),
592
- '[data-player]' => array(),
593
- '[data-playlist-id]' => array(),
594
- '[data-video-id]' => array(),
595
- 'data-account' => array(
596
- 'mandatory' => true,
597
- ),
598
- 'media' => array(),
599
- 'noloading' => array(
600
- 'value' => '',
601
- ),
602
- ),
603
- 'tag_spec' => array(
604
- 'requires_extension' => array(
605
- 'amp-brightcove',
606
- ),
607
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-brightcove',
608
- ),
609
- ),
610
- ),
611
- 'amp-byside-content' => array(
612
- array(
613
- 'attr_spec_list' => array(
614
- 'data-label' => array(
615
- 'mandatory' => true,
616
- ),
617
- 'data-webcare-id' => array(
618
- 'mandatory' => true,
619
- ),
620
- 'media' => array(),
621
- 'noloading' => array(
622
- 'value' => '',
623
- ),
624
- ),
625
- 'tag_spec' => array(
626
- 'requires_extension' => array(
627
- 'amp-byside-content',
628
- ),
629
- ),
630
- ),
631
- ),
632
- 'amp-call-tracking' => array(
633
- array(
634
- 'attr_spec_list' => array(
635
- 'config' => array(
636
- 'blacklisted_value_regex' => '__amp_source_origin',
637
- 'mandatory' => true,
638
- 'value_url' => array(
639
- 'allow_relative' => false,
640
- 'allowed_protocol' => array(
641
- 'https',
642
- ),
643
- ),
644
- ),
645
- 'media' => array(),
646
- 'noloading' => array(
647
- 'value' => '',
648
- ),
649
- ),
650
- 'tag_spec' => array(
651
- 'requires_extension' => array(
652
- 'amp-call-tracking',
653
- ),
654
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-call-tracking',
655
- ),
656
- ),
657
- ),
658
- 'amp-carousel' => array(
659
- array(
660
- 'attr_spec_list' => array(
661
- '[slide]' => array(),
662
- 'arrows' => array(
663
- 'value' => '',
664
- ),
665
- 'autoplay' => array(
666
- 'value' => '',
667
- ),
668
- 'controls' => array(),
669
- 'delay' => array(
670
- 'value_regex' => '[0-9]+',
671
- ),
672
- 'dots' => array(
673
- 'value' => '',
674
- ),
675
- 'lightbox' => array(),
676
- 'lightbox-exclude' => array(
677
- 'value' => '',
678
- ),
679
- 'lightbox-thumbnail-id' => array(
680
- 'value_regex_casei' => '^[a-z][a-z\\d_-]*',
681
- ),
682
- 'loop' => array(
683
- 'value' => '',
684
- ),
685
- 'media' => array(),
686
- 'noloading' => array(
687
- 'value' => '',
688
- ),
689
- 'type' => array(
690
- 'value_regex' => 'slides|carousel',
691
- ),
692
- ),
693
- 'tag_spec' => array(
694
- 'requires_extension' => array(
695
- 'amp-carousel',
696
- ),
697
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-carousel',
698
- ),
699
- ),
700
- ),
701
- 'amp-consent' => array(
702
- array(
703
- 'attr_spec_list' => array(
704
- 'media' => array(),
705
- 'noloading' => array(
706
- 'value' => '',
707
- ),
708
- ),
709
- 'tag_spec' => array(
710
- 'requires_extension' => array(
711
- 'amp-consent',
712
- ),
713
- 'unique' => true,
714
- ),
715
- ),
716
- ),
717
- 'amp-dailymotion' => array(
718
- array(
719
- 'attr_spec_list' => array(
720
- 'autoplay' => array(),
721
- 'data-endscreen-enable' => array(
722
- 'value_regex' => 'true|false',
723
- ),
724
- 'data-info' => array(
725
- 'value_regex' => 'true|false',
726
- ),
727
- 'data-mute' => array(
728
- 'value_regex' => 'true|false',
729
- ),
730
- 'data-sharing-enable' => array(
731
- 'value_regex' => 'true|false',
732
- ),
733
- 'data-start' => array(
734
- 'value_regex' => '[0-9]+',
735
- ),
736
- 'data-ui-highlight' => array(
737
- 'value_regex_casei' => '([0-9a-f]{3}){1,2}',
738
- ),
739
- 'data-ui-logo' => array(
740
- 'value_regex' => 'true|false',
741
- ),
742
- 'data-videoid' => array(
743
- 'mandatory' => true,
744
- 'value_regex_casei' => '[a-z0-9]+',
745
- ),
746
- 'media' => array(),
747
- 'noloading' => array(
748
- 'value' => '',
749
- ),
750
- ),
751
- 'tag_spec' => array(
752
- 'requires_extension' => array(
753
- 'amp-dailymotion',
754
- ),
755
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-dailymotion',
756
- ),
757
- ),
758
- ),
759
- 'amp-date-picker' => array(
760
- array(
761
- 'attr_spec_list' => array(
762
- 'allow-blocked-ranges' => array(
763
- 'value' => '',
764
- ),
765
- 'blocked' => array(),
766
- 'day-size' => array(
767
- 'value_regex' => '[0-9]+',
768
- ),
769
- 'first-day-of-week' => array(
770
- 'value_regex' => '[0-6]',
771
- ),
772
- 'format' => array(),
773
- 'fullscreen' => array(
774
- 'value' => '',
775
- ),
776
- 'highlighted' => array(),
777
- 'input-selector' => array(),
778
- 'locale' => array(),
779
- 'max' => array(),
780
- 'media' => array(),
781
- 'min' => array(),
782
- 'mode' => array(
783
- 'value_casei' => 'static',
784
- ),
785
- 'month-format' => array(),
786
- 'noloading' => array(
787
- 'value' => '',
788
- ),
789
- 'number-of-months' => array(
790
- 'value_regex' => '[0-9]+',
791
- ),
792
- 'open-after-clear' => array(
793
- 'value' => '',
794
- ),
795
- 'open-after-select' => array(
796
- 'value' => '',
797
- ),
798
- 'src' => array(
799
- 'blacklisted_value_regex' => '__amp_source_origin',
800
- 'value_url' => array(
801
- 'allow_relative' => true,
802
- 'allowed_protocol' => array(
803
- 'https',
804
- ),
805
- ),
806
- ),
807
- 'type' => array(
808
- 'value_casei' => 'single',
809
- ),
810
- 'week-day-format' => array(),
811
- ),
812
- 'tag_spec' => array(
813
- 'requires_extension' => array(
814
- 'amp-date-picker',
815
- ),
816
- 'spec_name' => 'amp-date-picker[type=single][mode=static]',
817
- ),
818
- ),
819
- array(
820
- 'attr_spec_list' => array(
821
- 'allow-blocked-ranges' => array(
822
- 'value' => '',
823
- ),
824
- 'blocked' => array(),
825
- 'day-size' => array(
826
- 'value_regex' => '[0-9]+',
827
- ),
828
- 'first-day-of-week' => array(
829
- 'value_regex' => '[0-6]',
830
- ),
831
- 'format' => array(),
832
- 'highlighted' => array(),
833
- 'input-selector' => array(),
834
- 'locale' => array(),
835
- 'max' => array(),
836
- 'media' => array(),
837
- 'min' => array(),
838
- 'mode' => array(
839
- 'mandatory' => true,
840
- 'value_casei' => 'overlay',
841
- ),
842
- 'month-format' => array(),
843
- 'noloading' => array(
844
- 'value' => '',
845
- ),
846
- 'number-of-months' => array(
847
- 'value_regex' => '[0-9]+',
848
- ),
849
- 'open-after-clear' => array(
850
- 'value' => '',
851
- ),
852
- 'open-after-select' => array(
853
- 'value' => '',
854
- ),
855
- 'src' => array(
856
- 'blacklisted_value_regex' => '__amp_source_origin',
857
- 'value_url' => array(
858
- 'allow_relative' => true,
859
- 'allowed_protocol' => array(
860
- 'https',
861
- ),
862
- ),
863
- ),
864
- 'type' => array(
865
- 'value_casei' => 'single',
866
- ),
867
- 'week-day-format' => array(),
868
- ),
869
- 'tag_spec' => array(
870
- 'requires_extension' => array(
871
- 'amp-date-picker',
872
- ),
873
- 'spec_name' => 'amp-date-picker[type=single][mode=overlay]',
874
- ),
875
- ),
876
- array(
877
- 'attr_spec_list' => array(
878
- 'allow-blocked-ranges' => array(
879
- 'value' => '',
880
- ),
881
- 'blocked' => array(),
882
- 'day-size' => array(
883
- 'value_regex' => '[0-9]+',
884
- ),
885
- 'end-input-selector' => array(),
886
- 'first-day-of-week' => array(
887
- 'value_regex' => '[0-6]',
888
- ),
889
- 'format' => array(),
890
- 'fullscreen' => array(
891
- 'value' => '',
892
- ),
893
- 'highlighted' => array(),
894
- 'locale' => array(),
895
- 'max' => array(),
896
- 'media' => array(),
897
- 'min' => array(),
898
- 'mode' => array(
899
- 'value_casei' => 'static',
900
- ),
901
- 'month-format' => array(),
902
- 'noloading' => array(
903
- 'value' => '',
904
- ),
905
- 'number-of-months' => array(
906
- 'value_regex' => '[0-9]+',
907
- ),
908
- 'open-after-clear' => array(
909
- 'value' => '',
910
- ),
911
- 'open-after-select' => array(
912
- 'value' => '',
913
- ),
914
- 'src' => array(
915
- 'blacklisted_value_regex' => '__amp_source_origin',
916
- 'value_url' => array(
917
- 'allow_relative' => true,
918
- 'allowed_protocol' => array(
919
- 'https',
920
- ),
921
- ),
922
- ),
923
- 'start-input-selector' => array(),
924
- 'type' => array(
925
- 'mandatory' => true,
926
- 'value_casei' => 'range',
927
- ),
928
- 'week-day-format' => array(),
929
- ),
930
- 'tag_spec' => array(
931
- 'requires_extension' => array(
932
- 'amp-date-picker',
933
- ),
934
- 'spec_name' => 'amp-date-picker[type=range][mode=static]',
935
- ),
936
- ),
937
- array(
938
- 'attr_spec_list' => array(
939
- 'allow-blocked-ranges' => array(
940
- 'value' => '',
941
- ),
942
- 'blocked' => array(),
943
- 'day-size' => array(
944
- 'value_regex' => '[0-9]+',
945
- ),
946
- 'end-input-selector' => array(),
947
- 'first-day-of-week' => array(
948
- 'value_regex' => '[0-6]',
949
- ),
950
- 'format' => array(),
951
- 'highlighted' => array(),
952
- 'locale' => array(),
953
- 'max' => array(),
954
- 'media' => array(),
955
- 'min' => array(),
956
- 'mode' => array(
957
- 'mandatory' => true,
958
- 'value_casei' => 'overlay',
959
- ),
960
- 'month-format' => array(),
961
- 'noloading' => array(
962
- 'value' => '',
963
- ),
964
- 'number-of-months' => array(
965
- 'value_regex' => '[0-9]+',
966
- ),
967
- 'open-after-clear' => array(
968
- 'value' => '',
969
- ),
970
- 'open-after-select' => array(
971
- 'value' => '',
972
- ),
973
- 'src' => array(
974
- 'blacklisted_value_regex' => '__amp_source_origin',
975
- 'value_url' => array(
976
- 'allow_relative' => true,
977
- 'allowed_protocol' => array(
978
- 'https',
979
- ),
980
- ),
981
- ),
982
- 'start-input-selector' => array(),
983
- 'type' => array(
984
- 'mandatory' => true,
985
- 'value_casei' => 'range',
986
- ),
987
- 'week-day-format' => array(),
988
- ),
989
- 'tag_spec' => array(
990
- 'requires_extension' => array(
991
- 'amp-date-picker',
992
- ),
993
- 'spec_name' => 'amp-date-picker[type=range][mode=overlay]',
994
- ),
995
- ),
996
- ),
997
- 'amp-document-recommendations' => array(
998
- array(
999
- 'attr_spec_list' => array(),
1000
- 'tag_spec' => array(
1001
- 'mandatory_parent' => 'body',
1002
- 'requires_extension' => array(
1003
- 'amp-document-recommendations',
1004
- ),
1005
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-document-recommendations',
1006
- ),
1007
- ),
1008
- ),
1009
- 'amp-embed' => array(
1010
- array(
1011
- 'attr_spec_list' => array(
1012
- 'alt' => array(),
1013
- 'json' => array(),
1014
- 'media' => array(),
1015
- 'noloading' => array(
1016
- 'value' => '',
1017
- ),
1018
- 'rtc-config' => array(),
1019
- 'src' => array(
1020
- 'blacklisted_value_regex' => '__amp_source_origin',
1021
- 'value_url' => array(
1022
- 'allow_relative' => true,
1023
- 'allowed_protocol' => array(
1024
- 'https',
1025
- ),
1026
- ),
1027
- ),
1028
- 'template' => array(),
1029
- 'type' => array(
1030
- 'mandatory' => true,
1031
- ),
1032
- ),
1033
- 'tag_spec' => array(
1034
- 'also_requires_tag_warning' => array(
1035
- 'amp-ad extension .js script',
1036
- ),
1037
- 'disallowed_ancestor' => array(
1038
- 'amp-app-banner',
1039
- ),
1040
- 'requires_extension' => array(
1041
- 'amp-ad',
1042
- ),
1043
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
1044
- ),
1045
- ),
1046
- array(
1047
- 'attr_spec_list' => array(
1048
- 'alt' => array(),
1049
- 'data-multi-size' => array(
1050
- 'dispatch_key' => 2,
1051
- 'mandatory' => true,
1052
- 'value' => '',
1053
- ),
1054
- 'json' => array(),
1055
- 'media' => array(),
1056
- 'noloading' => array(
1057
- 'value' => '',
1058
- ),
1059
- 'rtc-config' => array(),
1060
- 'src' => array(
1061
- 'blacklisted_value_regex' => '__amp_source_origin',
1062
- 'value_url' => array(
1063
- 'allow_relative' => true,
1064
- 'allowed_protocol' => array(
1065
- 'https',
1066
- ),
1067
- ),
1068
- ),
1069
- 'type' => array(
1070
- 'mandatory' => true,
1071
- ),
1072
- ),
1073
- 'tag_spec' => array(
1074
- 'also_requires_tag_warning' => array(
1075
- 'amp-ad extension .js script',
1076
- ),
1077
- 'disallowed_ancestor' => array(
1078
- 'amp-app-banner',
1079
- 'amp-carousel',
1080
- 'amp-fx-flying-carpet',
1081
- 'amp-lightbox',
1082
- 'amp-sticky-ad',
1083
- ),
1084
- 'requires_extension' => array(
1085
- 'amp-ad',
1086
- ),
1087
- 'spec_name' => 'amp-embed with data-multi-size attribute',
1088
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
1089
- ),
1090
- ),
1091
- ),
1092
- 'amp-experiment' => array(
1093
- array(
1094
- 'attr_spec_list' => array(),
1095
- 'tag_spec' => array(
1096
- 'requires_extension' => array(
1097
- 'amp-experiment',
1098
- ),
1099
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-experiment',
1100
- 'unique' => true,
1101
- ),
1102
- ),
1103
- ),
1104
- 'amp-facebook' => array(
1105
- array(
1106
- 'attr_spec_list' => array(
1107
- 'data-href' => array(
1108
- 'mandatory' => true,
1109
- ),
1110
- 'media' => array(),
1111
- 'noloading' => array(
1112
- 'value' => '',
1113
- ),
1114
- ),
1115
- 'tag_spec' => array(
1116
- 'requires_extension' => array(
1117
- 'amp-facebook',
1118
- ),
1119
- ),
1120
- ),
1121
- ),
1122
- 'amp-facebook-comments' => array(
1123
- array(
1124
- 'attr_spec_list' => array(
1125
- 'data-href' => array(
1126
- 'mandatory' => true,
1127
- ),
1128
- 'media' => array(),
1129
- 'noloading' => array(
1130
- 'value' => '',
1131
- ),
1132
- ),
1133
- 'tag_spec' => array(
1134
- 'requires_extension' => array(
1135
- 'amp-facebook-comments',
1136
- ),
1137
- ),
1138
- ),
1139
- ),
1140
- 'amp-facebook-like' => array(
1141
- array(
1142
- 'attr_spec_list' => array(
1143
- 'data-href' => array(
1144
- 'mandatory' => true,
1145
- 'value_url' => array(
1146
- 'allow_relative' => false,
1147
- 'allowed_protocol' => array(
1148
- 'http',
1149
- 'https',
1150
- ),
1151
- ),
1152
- ),
1153
- 'media' => array(),
1154
- 'noloading' => array(
1155
- 'value' => '',
1156
- ),
1157
- ),
1158
- 'tag_spec' => array(
1159
- 'requires_extension' => array(
1160
- 'amp-facebook-like',
1161
- ),
1162
- ),
1163
- ),
1164
- ),
1165
- 'amp-facebook-page' => array(
1166
- array(
1167
- 'attr_spec_list' => array(
1168
- 'data-href' => array(
1169
- 'mandatory' => true,
1170
- 'value_url' => array(
1171
- 'allow_relative' => false,
1172
- 'allowed_protocol' => array(
1173
- 'http',
1174
- 'https',
1175
- ),
1176
- ),
1177
- ),
1178
- 'media' => array(),
1179
- 'noloading' => array(
1180
- 'value' => '',
1181
- ),
1182
- ),
1183
- 'tag_spec' => array(
1184
- 'requires_extension' => array(
1185
- 'amp-facebook-page',
1186
- ),
1187
- ),
1188
- ),
1189
- ),
1190
- 'amp-fit-text' => array(
1191
- array(
1192
- 'attr_spec_list' => array(
1193
- 'max-font-size' => array(),
1194
- 'media' => array(),
1195
- 'min-font-size' => array(),
1196
- 'noloading' => array(
1197
- 'value' => '',
1198
- ),
1199
- ),
1200
- 'tag_spec' => array(
1201
- 'requires_extension' => array(
1202
- 'amp-fit-text',
1203
- ),
1204
- ),
1205
- ),
1206
- ),
1207
- 'amp-font' => array(
1208
- array(
1209
- 'attr_spec_list' => array(
1210
- 'font-family' => array(
1211
- 'mandatory' => true,
1212
- ),
1213
- 'font-style' => array(),
1214
- 'font-variant' => array(),
1215
- 'font-weight' => array(),
1216
- 'media' => array(),
1217
- 'noloading' => array(
1218
- 'value' => '',
1219
- ),
1220
- 'on-error-add-class' => array(),
1221
- 'on-error-remove-class' => array(),
1222
- 'on-load-add-class' => array(),
1223
- 'on-load-remove-class' => array(),
1224
- 'timeout' => array(
1225
- 'value_regex' => '[0-9]+',
1226
- ),
1227
- ),
1228
- 'tag_spec' => array(
1229
- 'requires_extension' => array(
1230
- 'amp-font',
1231
- ),
1232
- ),
1233
- ),
1234
- ),
1235
- 'amp-fx-flying-carpet' => array(
1236
- array(
1237
- 'attr_spec_list' => array(
1238
- 'height' => array(
1239
- 'mandatory' => true,
1240
- ),
1241
- 'media' => array(),
1242
- 'noloading' => array(
1243
- 'value' => '',
1244
- ),
1245
- ),
1246
- 'tag_spec' => array(
1247
- 'requires_extension' => array(
1248
- 'amp-fx-flying-carpet',
1249
- ),
1250
- ),
1251
- ),
1252
- ),
1253
- 'amp-gfycat' => array(
1254
- array(
1255
- 'attr_spec_list' => array(
1256
- 'data-gfyid' => array(
1257
- 'mandatory' => true,
1258
- ),
1259
- 'media' => array(),
1260
- 'noautoplay' => array(
1261
- 'value' => '',
1262
- ),
1263
- 'noloading' => array(
1264
- 'value' => '',
1265
- ),
1266
- ),
1267
- 'tag_spec' => array(
1268
- 'requires_extension' => array(
1269
- 'amp-gfycat',
1270
- ),
1271
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-gfycat',
1272
- ),
1273
- ),
1274
- ),
1275
- 'amp-gist' => array(
1276
- array(
1277
- 'attr_spec_list' => array(
1278
- 'data-gistid' => array(
1279
- 'mandatory' => true,
1280
- ),
1281
- 'media' => array(),
1282
- 'noloading' => array(
1283
- 'value' => '',
1284
- ),
1285
- ),
1286
- 'tag_spec' => array(
1287
- 'requires_extension' => array(
1288
- 'amp-gist',
1289
- ),
1290
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-gist',
1291
- ),
1292
- ),
1293
- ),
1294
- 'amp-hulu' => array(
1295
- array(
1296
- 'attr_spec_list' => array(
1297
- 'data-eid' => array(
1298
- 'mandatory' => true,
1299
- ),
1300
- 'media' => array(),
1301
- 'noloading' => array(
1302
- 'value' => '',
1303
- ),
1304
- ),
1305
- 'tag_spec' => array(
1306
- 'requires_extension' => array(
1307
- 'amp-hulu',
1308
- ),
1309
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-hulu',
1310
- ),
1311
- ),
1312
- ),
1313
- 'amp-iframe' => array(
1314
- array(
1315
- 'attr_spec_list' => array(
1316
- '[src]' => array(),
1317
- 'allow' => array(),
1318
- 'allowfullscreen' => array(
1319
- 'value' => '',
1320
- ),
1321
- 'allowpaymentrequest' => array(
1322
- 'value' => '',
1323
- ),
1324
- 'allowtransparency' => array(
1325
- 'value' => '',
1326
- ),
1327
- 'frameborder' => array(
1328
- 'value_regex' => '0|1',
1329
- ),
1330
- 'media' => array(),
1331
- 'noloading' => array(
1332
- 'value' => '',
1333
- ),
1334
- 'referrerpolicy' => array(),
1335
- 'resizable' => array(
1336
- 'value' => '',
1337
- ),
1338
- 'sandbox' => array(),
1339
- 'scrolling' => array(
1340
- 'value_regex' => 'auto|yes|no',
1341
- ),
1342
- 'src' => array(
1343
- 'blacklisted_value_regex' => '__amp_source_origin',
1344
- 'value_url' => array(
1345
- 'allow_relative' => true,
1346
- 'allowed_protocol' => array(
1347
- 'data',
1348
- 'https',
1349
- ),
1350
- ),
1351
- ),
1352
- 'srcdoc' => array(),
1353
- ),
1354
- 'tag_spec' => array(
1355
- 'requires_extension' => array(
1356
- 'amp-iframe',
1357
- ),
1358
- ),
1359
- ),
1360
- ),
1361
- 'amp-ima-video' => array(
1362
- array(
1363
- 'attr_spec_list' => array(
1364
- 'autoplay' => array(
1365
- 'value' => '',
1366
- ),
1367
- 'data-src' => array(
1368
- 'blacklisted_value_regex' => '__amp_source_origin',
1369
- 'value_url' => array(
1370
- 'allow_relative' => true,
1371
- 'allowed_protocol' => array(
1372
- 'https',
1373
- ),
1374
- ),
1375
- ),
1376
- 'data-tag' => array(
1377
- 'mandatory' => true,
1378
- 'value_url' => array(
1379
- 'allow_relative' => true,
1380
- 'allowed_protocol' => array(
1381
- 'https',
1382
- ),
1383
- ),
1384
- ),
1385
- 'media' => array(),
1386
- 'noloading' => array(
1387
- 'value' => '',
1388
- ),
1389
- ),
1390
- 'tag_spec' => array(
1391
- 'requires_extension' => array(
1392
- 'amp-ima-video',
1393
- ),
1394
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ima-video',
1395
- ),
1396
- ),
1397
- ),
1398
- 'amp-image-lightbox' => array(
1399
- array(
1400
- 'attr_spec_list' => array(
1401
- 'controls' => array(),
1402
- 'media' => array(),
1403
- 'noloading' => array(
1404
- 'value' => '',
1405
- ),
1406
- ),
1407
- 'tag_spec' => array(
1408
- 'requires_extension' => array(
1409
- 'amp-image-lightbox',
1410
- ),
1411
- ),
1412
- ),
1413
- ),
1414
- 'amp-img' => array(
1415
- array(
1416
- 'attr_spec_list' => array(
1417
- '[alt]' => array(),
1418
- '[attribution]' => array(),
1419
- '[src]' => array(),
1420
- '[srcset]' => array(),
1421
- 'alt' => array(),
1422
- 'attribution' => array(),
1423
- 'lightbox' => array(),
1424
- 'lightbox-exclude' => array(
1425
- 'value' => '',
1426
- ),
1427
- 'lightbox-thumbnail-id' => array(
1428
- 'value_regex_casei' => '^[a-z][a-z\\d_-]*',
1429
- ),
1430
- 'media' => array(),
1431
- 'noloading' => array(
1432
- 'value' => '',
1433
- ),
1434
- 'placeholder' => array(),
1435
- 'src' => array(
1436
- 'alternative_names' => array(
1437
- 'srcset',
1438
- ),
1439
- 'blacklisted_value_regex' => '__amp_source_origin',
1440
- 'mandatory' => true,
1441
- 'value_url' => array(
1442
- 'allow_relative' => true,
1443
- 'allowed_protocol' => array(
1444
- 'data',
1445
- 'http',
1446
- 'https',
1447
- ),
1448
- ),
1449
- ),
1450
- ),
1451
- 'tag_spec' => array(
1452
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-img',
1453
- ),
1454
- ),
1455
- ),
1456
- 'amp-imgur' => array(
1457
- array(
1458
- 'attr_spec_list' => array(
1459
- 'data-imgur-id' => array(
1460
- 'mandatory' => true,
1461
- ),
1462
- 'media' => array(),
1463
- 'noloading' => array(
1464
- 'value' => '',
1465
- ),
1466
- ),
1467
- 'tag_spec' => array(
1468
- 'requires_extension' => array(
1469
- 'amp-imgur',
1470
- ),
1471
- ),
1472
- ),
1473
- ),
1474
- 'amp-instagram' => array(
1475
- array(
1476
- 'attr_spec_list' => array(
1477
- 'alt' => array(),
1478
- 'data-shortcode' => array(
1479
- 'mandatory' => true,
1480
- ),
1481
- 'media' => array(),
1482
- 'noloading' => array(
1483
- 'value' => '',
1484
- ),
1485
- ),
1486
- 'tag_spec' => array(
1487
- 'requires_extension' => array(
1488
- 'amp-instagram',
1489
- ),
1490
- ),
1491
- ),
1492
- ),
1493
- 'amp-install-serviceworker' => array(
1494
- array(
1495
- 'attr_spec_list' => array(
1496
- 'data-iframe-src' => array(
1497
- 'blacklisted_value_regex' => '__amp_source_origin',
1498
- 'value_url' => array(
1499
- 'allow_relative' => true,
1500
- 'allowed_protocol' => array(
1501
- 'https',
1502
- ),
1503
- ),
1504
- ),
1505
- 'src' => array(
1506
- 'blacklisted_value_regex' => '__amp_source_origin',
1507
- 'mandatory' => true,
1508
- 'value_url' => array(
1509
- 'allow_relative' => true,
1510
- 'allowed_protocol' => array(
1511
- 'https',
1512
- ),
1513
- ),
1514
- ),
1515
- ),
1516
- 'tag_spec' => array(
1517
- 'requires_extension' => array(
1518
- 'amp-install-serviceworker',
1519
- ),
1520
- ),
1521
- ),
1522
- ),
1523
- 'amp-izlesene' => array(
1524
- array(
1525
- 'attr_spec_list' => array(
1526
- 'data-videoid' => array(
1527
- 'mandatory' => true,
1528
- 'value_regex' => '[0-9]+',
1529
- ),
1530
- 'media' => array(),
1531
- 'noloading' => array(
1532
- 'value' => '',
1533
- ),
1534
- ),
1535
- 'tag_spec' => array(
1536
- 'requires_extension' => array(
1537
- 'amp-izlesene',
1538
- ),
1539
- ),
1540
- ),
1541
- ),
1542
- 'amp-jwplayer' => array(
1543
- array(
1544
- 'attr_spec_list' => array(
1545
- 'data-media-id' => array(
1546
- 'value_regex_casei' => '[0-9a-z]{8}',
1547
- ),
1548
- 'data-player-id' => array(
1549
- 'mandatory' => true,
1550
- 'value_regex_casei' => '[0-9a-z]{8}',
1551
- ),
1552
- 'data-playlist-id' => array(
1553
- 'value_regex_casei' => '[0-9a-z]{8}',
1554
- ),
1555
- ),
1556
- 'tag_spec' => array(
1557
- 'requires_extension' => array(
1558
- 'amp-jwplayer',
1559
- ),
1560
- ),
1561
- ),
1562
- ),
1563
- 'amp-kaltura-player' => array(
1564
- array(
1565
- 'attr_spec_list' => array(
1566
- 'data-partner' => array(
1567
- 'mandatory' => true,
1568
- ),
1569
- 'media' => array(),
1570
- 'noloading' => array(
1571
- 'value' => '',
1572
- ),
1573
- ),
1574
- 'tag_spec' => array(
1575
- 'requires_extension' => array(
1576
- 'amp-kaltura-player',
1577
- ),
1578
- ),
1579
- ),
1580
- ),
1581
- 'amp-layout' => array(
1582
- array(
1583
- 'attr_spec_list' => array(
1584
- 'media' => array(),
1585
- 'noloading' => array(
1586
- 'value' => '',
1587
- ),
1588
- ),
1589
- 'tag_spec' => array(
1590
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-layout',
1591
- ),
1592
- ),
1593
- ),
1594
- 'amp-lightbox' => array(
1595
- array(
1596
- 'attr_spec_list' => array(
1597
- 'controls' => array(),
1598
- 'from' => array(),
1599
- 'media' => array(),
1600
- 'noloading' => array(
1601
- 'value' => '',
1602
- ),
1603
- 'scrollable' => array(),
1604
- ),
1605
- 'tag_spec' => array(
1606
- 'requires_extension' => array(
1607
- 'amp-lightbox',
1608
- ),
1609
- ),
1610
- ),
1611
- ),
1612
- 'amp-list' => array(
1613
- array(
1614
- 'attr_spec_list' => array(
1615
- '[src]' => array(),
1616
- '[state]' => array(),
1617
- 'credentials' => array(),
1618
- 'items' => array(),
1619
- 'max-items' => array(),
1620
- 'media' => array(),
1621
- 'noloading' => array(
1622
- 'value' => '',
1623
- ),
1624
- 'reset-on-refresh' => array(
1625
- 'value' => '',
1626
- ),
1627
- 'single-item' => array(),
1628
- 'src' => array(
1629
- 'blacklisted_value_regex' => '__amp_source_origin',
1630
- 'mandatory' => true,
1631
- 'value_url' => array(
1632
- 'allow_relative' => true,
1633
- 'allowed_protocol' => array(
1634
- 'https',
1635
- ),
1636
- ),
1637
- ),
1638
- 'template' => array(),
1639
- ),
1640
- 'tag_spec' => array(
1641
- 'requires_extension' => array(
1642
- 'amp-list',
1643
- ),
1644
- ),
1645
- ),
1646
- array(
1647
- 'attr_spec_list' => array(
1648
- '[src]' => array(
1649
- 'mandatory' => true,
1650
- ),
1651
- 'credentials' => array(),
1652
- 'items' => array(),
1653
- 'max-items' => array(),
1654
- 'media' => array(),
1655
- 'noloading' => array(
1656
- 'value' => '',
1657
- ),
1658
- 'single-item' => array(),
1659
- 'src' => array(
1660
- 'blacklisted_value_regex' => '__amp_source_origin',
1661
- 'value_url' => array(
1662
- 'allow_relative' => true,
1663
- 'allowed_protocol' => array(
1664
- 'https',
1665
- ),
1666
- ),
1667
- ),
1668
- 'template' => array(),
1669
- ),
1670
- 'tag_spec' => array(
1671
- 'requires_extension' => array(
1672
- 'amp-list',
1673
- ),
1674
- 'spec_name' => 'AMP-LIST [SRC]',
1675
- ),
1676
- ),
1677
- ),
1678
- 'amp-live-list' => array(
1679
- array(
1680
- 'attr_spec_list' => array(
1681
- 'data-max-items-per-page' => array(
1682
- 'mandatory' => true,
1683
- 'value_regex' => '\\d+',
1684
- ),
1685
- 'data-poll-interval' => array(
1686
- 'value_regex' => '\\d{5,}',
1687
- ),
1688
- 'disabled' => array(
1689
- 'value' => '',
1690
- ),
1691
- 'id' => array(
1692
- 'mandatory' => true,
1693
- ),
1694
- 'sort' => array(
1695
- 'value_regex' => 'ascending',
1696
- ),
1697
- ),
1698
- 'tag_spec' => array(
1699
- 'requires_extension' => array(
1700
- 'amp-live-list',
1701
- ),
1702
- ),
1703
- ),
1704
- ),
1705
- 'amp-mathml' => array(
1706
- array(
1707
- 'attr_spec_list' => array(
1708
- 'data-formula' => array(
1709
- 'mandatory' => true,
1710
- ),
1711
- 'inline' => array(),
1712
- 'media' => array(),
1713
- 'noloading' => array(
1714
- 'value' => '',
1715
- ),
1716
- ),
1717
- 'tag_spec' => array(
1718
- 'requires_extension' => array(
1719
- 'amp-mathml',
1720
- ),
1721
- ),
1722
- ),
1723
- ),
1724
- 'amp-nexxtv-player' => array(
1725
- array(
1726
- 'attr_spec_list' => array(
1727
- 'data-client' => array(
1728
- 'mandatory' => true,
1729
- ),
1730
- 'data-mediaid' => array(
1731
- 'mandatory' => true,
1732
- 'value_regex' => '[^=/?:]+',
1733
- ),
1734
- 'data-mode' => array(
1735
- 'value_regex' => 'api|static',
1736
- ),
1737
- 'data-origin' => array(
1738
- 'value_url' => array(
1739
- 'allow_empty' => true,
1740
- 'allowed_protocol' => array(
1741
- 'https',
1742
- 'http',
1743
- ),
1744
- ),
1745
- ),
1746
- 'data-streamtype' => array(
1747
- 'value_regex' => 'album|audio|live|playlist|playlist-marked|video',
1748
- ),
1749
- 'media' => array(),
1750
- 'noloading' => array(
1751
- 'value' => '',
1752
- ),
1753
- ),
1754
- 'tag_spec' => array(
1755
- 'requires_extension' => array(
1756
- 'amp-nexxtv-player',
1757
- ),
1758
- ),
1759
- ),
1760
- ),
1761
- 'amp-o2-player' => array(
1762
- array(
1763
- 'attr_spec_list' => array(
1764
- 'data-bcid' => array(
1765
- 'mandatory' => true,
1766
- ),
1767
- 'data-pid' => array(
1768
- 'mandatory' => true,
1769
- ),
1770
- 'media' => array(),
1771
- 'noloading' => array(
1772
- 'value' => '',
1773
- ),
1774
- ),
1775
- 'tag_spec' => array(
1776
- 'requires_extension' => array(
1777
- 'amp-o2-player',
1778
- ),
1779
- ),
1780
- ),
1781
- ),
1782
- 'amp-ooyala-player' => array(
1783
- array(
1784
- 'attr_spec_list' => array(
1785
- 'data-embedcode' => array(
1786
- 'mandatory' => true,
1787
- ),
1788
- 'data-pcode' => array(
1789
- 'mandatory' => true,
1790
- ),
1791
- 'data-playerid' => array(
1792
- 'mandatory' => true,
1793
- ),
1794
- 'media' => array(),
1795
- 'noloading' => array(
1796
- 'value' => '',
1797
- ),
1798
- ),
1799
- 'tag_spec' => array(
1800
- 'requires_extension' => array(
1801
- 'amp-ooyala-player',
1802
- ),
1803
- ),
1804
- ),
1805
- ),
1806
- 'amp-pinterest' => array(
1807
- array(
1808
- 'attr_spec_list' => array(
1809
- 'alt' => array(),
1810
- 'data-do' => array(
1811
- 'mandatory' => true,
1812
- ),
1813
- 'media' => array(),
1814
- 'noloading' => array(
1815
- 'value' => '',
1816
- ),
1817
- ),
1818
- 'tag_spec' => array(
1819
- 'requires_extension' => array(
1820
- 'amp-pinterest',
1821
- ),
1822
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-pinterest',
1823
- ),
1824
- ),
1825
- ),
1826
- 'amp-pixel' => array(
1827
- array(
1828
- 'attr_spec_list' => array(
1829
- 'allow-ssr-img' => array(),
1830
- 'media' => array(),
1831
- 'noloading' => array(
1832
- 'value' => '',
1833
- ),
1834
- 'referrerpolicy' => array(
1835
- 'value' => 'no-referrer',
1836
- ),
1837
- 'src' => array(
1838
- 'blacklisted_value_regex' => '__amp_source_origin',
1839
- 'mandatory' => true,
1840
- 'value_url' => array(
1841
- 'allow_empty' => true,
1842
- 'allow_relative' => true,
1843
- 'allowed_protocol' => array(
1844
- 'https',
1845
- ),
1846
- ),
1847
- ),
1848
- ),
1849
- 'tag_spec' => array(
1850
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-pixel',
1851
- ),
1852
- ),
1853
- ),
1854
- 'amp-playbuzz' => array(
1855
- array(
1856
- 'attr_spec_list' => array(
1857
- 'data-comments' => array(
1858
- 'value_regex_casei' => '(false|true)',
1859
- ),
1860
- 'data-item' => array(),
1861
- 'data-item-info' => array(
1862
- 'value_regex_casei' => '(false|true)',
1863
- ),
1864
- 'data-share-buttons' => array(
1865
- 'value_regex_casei' => '(false|true)',
1866
- ),
1867
- 'media' => array(),
1868
- 'noloading' => array(
1869
- 'value' => '',
1870
- ),
1871
- 'src' => array(),
1872
- ),
1873
- 'tag_spec' => array(
1874
- 'requires_extension' => array(
1875
- 'amp-playbuzz',
1876
- ),
1877
- ),
1878
- ),
1879
- ),
1880
- 'amp-position-observer' => array(
1881
- array(
1882
- 'attr_spec_list' => array(
1883
- 'intersection-ratios' => array(
1884
- 'value_regex' => '^([0]*?\\.\\d*$|1$|0$)|([0]*?\\.\\d*|1|0)\\s{1}([0]*?\\.\\d*$|1$|0$)',
1885
- ),
1886
- 'media' => array(),
1887
- 'noloading' => array(
1888
- 'value' => '',
1889
- ),
1890
- 'target' => array(),
1891
- 'viewport-margins' => array(
1892
- 'value_regex' => '^(\\d+$|\\d+px$|\\d+vh$)|((\\d+|\\d+px|\\d+vh)\\s{1}(\\d+$|\\d+px$|\\d+vh$))',
1893
- ),
1894
- ),
1895
- 'tag_spec' => array(
1896
- 'requires_extension' => array(
1897
- 'amp-position-observer',
1898
- ),
1899
- ),
1900
- ),
1901
- ),
1902
- 'amp-reach-player' => array(
1903
- array(
1904
- 'attr_spec_list' => array(
1905
- 'data-embed-id' => array(
1906
- 'mandatory' => true,
1907
- 'value_regex' => '[0-9a-z-]+',
1908
- ),
1909
- 'media' => array(),
1910
- 'noloading' => array(
1911
- 'value' => '',
1912
- ),
1913
- ),
1914
- 'tag_spec' => array(
1915
- 'requires_extension' => array(
1916
- 'amp-reach-player',
1917
- ),
1918
- ),
1919
- ),
1920
- ),
1921
- 'amp-reddit' => array(
1922
- array(
1923
- 'attr_spec_list' => array(
1924
- 'data-embedlive' => array(
1925
- 'value_regex_casei' => '(false|true)',
1926
- ),
1927
- 'data-embedparent' => array(
1928
- 'value_regex_casei' => '(false|true)',
1929
- ),
1930
- 'data-embedtype' => array(
1931
- 'mandatory' => true,
1932
- 'value_regex_casei' => '(comment|post)',
1933
- ),
1934
- 'data-src' => array(
1935
- 'mandatory' => true,
1936
- ),
1937
- 'media' => array(),
1938
- 'noloading' => array(
1939
- 'value' => '',
1940
- ),
1941
- ),
1942
- 'tag_spec' => array(
1943
- 'requires_extension' => array(
1944
- 'amp-reddit',
1945
- ),
1946
- ),
1947
- ),
1948
- ),
1949
- 'amp-riddle-quiz' => array(
1950
- array(
1951
- 'attr_spec_list' => array(
1952
- 'data-riddle-id' => array(
1953
- 'mandatory' => true,
1954
- 'value_regex' => '[0-9]+',
1955
- ),
1956
- 'media' => array(),
1957
- 'noloading' => array(
1958
- 'value' => '',
1959
- ),
1960
- ),
1961
- 'tag_spec' => array(
1962
- 'requires_extension' => array(
1963
- 'amp-riddle-quiz',
1964
- ),
1965
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-riddle-quiz',
1966
- ),
1967
- ),
1968
- ),
1969
- 'amp-selector' => array(
1970
- array(
1971
- 'attr_spec_list' => array(
1972
- '[disabled]' => array(),
1973
- '[selected]' => array(),
1974
- 'disabled' => array(
1975
- 'value' => '',
1976
- ),
1977
- 'form' => array(),
1978
- 'keyboard-select-mode' => array(
1979
- 'value_regex_casei' => 'focus|none|select',
1980
- ),
1981
- 'media' => array(),
1982
- 'multiple' => array(
1983
- 'value' => '',
1984
- ),
1985
- 'name' => array(
1986
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
1987
- ),
1988
- 'noloading' => array(
1989
- 'value' => '',
1990
- ),
1991
- ),
1992
- 'tag_spec' => array(
1993
- 'disallowed_ancestor' => array(
1994
- 'amp-selector',
1995
- ),
1996
- 'requires_extension' => array(
1997
- 'amp-selector',
1998
- ),
1999
- ),
2000
- ),
2001
- ),
2002
- 'amp-sidebar' => array(
2003
- array(
2004
- 'attr_spec_list' => array(
2005
- 'media' => array(),
2006
- 'noloading' => array(
2007
- 'value' => '',
2008
- ),
2009
- 'side' => array(
2010
- 'value_regex' => '(left|right)',
2011
- ),
2012
- ),
2013
- 'tag_spec' => array(
2014
- 'mandatory_parent' => 'body',
2015
- 'requires_extension' => array(
2016
- 'amp-sidebar',
2017
- ),
2018
- ),
2019
- ),
2020
- ),
2021
- 'amp-social-share' => array(
2022
- array(
2023
- 'attr_spec_list' => array(
2024
- 'data-share-endpoint' => array(
2025
- 'blacklisted_value_regex' => '__amp_source_origin',
2026
- 'value_url' => array(
2027
- 'allow_relative' => false,
2028
- 'allowed_protocol' => array(
2029
- 'ftp',
2030
- 'http',
2031
- 'https',
2032
- 'mailto',
2033
- 'bbmi',
2034
- 'fb-messenger',
2035
- 'intent',
2036
- 'line',
2037
- 'skype',
2038
- 'sms',
2039
- 'snapchat',
2040
- 'tel',
2041
- 'tg',
2042
- 'threema',
2043
- 'viber',
2044
- 'whatsapp',
2045
- ),
2046
- ),
2047
- ),
2048
- 'media' => array(),
2049
- 'noloading' => array(
2050
- 'value' => '',
2051
- ),
2052
- 'type' => array(
2053
- 'mandatory' => true,
2054
- ),
2055
- ),
2056
- 'tag_spec' => array(
2057
- 'requires_extension' => array(
2058
- 'amp-social-share',
2059
- ),
2060
- ),
2061
- ),
2062
- ),
2063
- 'amp-soundcloud' => array(
2064
- array(
2065
- 'attr_spec_list' => array(
2066
- 'data-color' => array(
2067
- 'value_regex_casei' => '([0-9a-f]{3}){1,2}',
2068
- ),
2069
- 'data-playlistid' => array(
2070
- 'value_regex' => '[0-9]+',
2071
- ),
2072
- 'data-secret-token' => array(
2073
- 'value_regex' => '[A-Za-z0-9_-]+',
2074
- ),
2075
- 'data-trackid' => array(
2076
- 'value_regex' => '[0-9]+',
2077
- ),
2078
- 'data-visual' => array(
2079
- 'value_regex' => 'true|false',
2080
- ),
2081
- 'media' => array(),
2082
- 'noloading' => array(
2083
- 'value' => '',
2084
- ),
2085
- ),
2086
- 'tag_spec' => array(
2087
- 'requires_extension' => array(
2088
- 'amp-soundcloud',
2089
- ),
2090
- ),
2091
- ),
2092
- ),
2093
- 'amp-springboard-player' => array(
2094
- array(
2095
- 'attr_spec_list' => array(
2096
- 'data-content-id' => array(
2097
- 'mandatory' => true,
2098
- ),
2099
- 'data-domain' => array(
2100
- 'mandatory' => true,
2101
- ),
2102
- 'data-items' => array(
2103
- 'mandatory' => true,
2104
- ),
2105
- 'data-mode' => array(
2106
- 'mandatory' => true,
2107
- 'value_regex_casei' => 'playlist|video',
2108
- ),
2109
- 'data-player-id' => array(
2110
- 'mandatory' => true,
2111
- 'value_regex_casei' => '[a-z0-9]+',
2112
- ),
2113
- 'data-site-id' => array(
2114
- 'mandatory' => true,
2115
- 'value_regex' => '[0-9]+',
2116
- ),
2117
- 'media' => array(),
2118
- 'noloading' => array(
2119
- 'value' => '',
2120
- ),
2121
- ),
2122
- 'tag_spec' => array(
2123
- 'requires_extension' => array(
2124
- 'amp-springboard-player',
2125
- ),
2126
- ),
2127
- ),
2128
- ),
2129
- 'amp-state' => array(
2130
- array(
2131
- 'attr_spec_list' => array(
2132
- '[src]' => array(),
2133
- 'credentials' => array(),
2134
- 'id' => array(
2135
- 'mandatory' => true,
2136
- ),
2137
- 'overridable' => array(),
2138
- 'src' => array(
2139
- 'blacklisted_value_regex' => '__amp_source_origin',
2140
- 'value_url' => array(
2141
- 'allow_relative' => true,
2142
- 'allowed_protocol' => array(
2143
- 'https',
2144
- ),
2145
- ),
2146
- ),
2147
- ),
2148
- 'tag_spec' => array(
2149
- 'requires_extension' => array(
2150
- 'amp-bind',
2151
- ),
2152
- 'spec_name' => 'amp-state',
2153
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind',
2154
- ),
2155
- ),
2156
- ),
2157
- 'amp-sticky-ad' => array(
2158
- array(
2159
- 'attr_spec_list' => array(
2160
- 'media' => array(),
2161
- 'noloading' => array(
2162
- 'value' => '',
2163
- ),
2164
- ),
2165
- 'tag_spec' => array(
2166
- 'disallowed_ancestor' => array(
2167
- 'amp-app-banner',
2168
- ),
2169
- 'requires_extension' => array(
2170
- 'amp-sticky-ad',
2171
- ),
2172
- 'unique' => true,
2173
- ),
2174
- ),
2175
- ),
2176
- 'amp-story' => array(
2177
- array(
2178
- 'attr_spec_list' => array(
2179
- 'background-audio' => array(
2180
- 'value_url' => array(
2181
- 'allowed_protocol' => array(
2182
- 'http',
2183
- 'https',
2184
- ),
2185
- ),
2186
- ),
2187
- 'bookend-config-src' => array(
2188
- 'value_url' => array(
2189
- 'allowed_protocol' => array(
2190
- 'http',
2191
- 'https',
2192
- ),
2193
- ),
2194
- ),
2195
- 'standalone' => array(
2196
- 'mandatory' => true,
2197
- 'value' => '',
2198
- ),
2199
- ),
2200
- 'tag_spec' => array(
2201
- 'mandatory_parent' => 'body',
2202
- 'requires_extension' => array(
2203
- 'amp-story',
2204
- ),
2205
- ),
2206
- ),
2207
- ),
2208
- 'amp-story-auto-ads' => array(
2209
- array(
2210
- 'attr_spec_list' => array(),
2211
- 'tag_spec' => array(
2212
- 'mandatory_parent' => 'amp-story',
2213
- 'requires_extension' => array(
2214
- 'amp-story-auto-ads',
2215
- ),
2216
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/extensions/amp-story/amp-story-auto-ads.md',
2217
- 'unique' => true,
2218
- ),
2219
- ),
2220
- ),
2221
- 'amp-story-cta-layer' => array(
2222
- array(
2223
- 'attr_spec_list' => array(),
2224
- 'tag_spec' => array(
2225
- 'mandatory_ancestor' => 'amp-story-page',
2226
- ),
2227
- ),
2228
- ),
2229
- 'amp-story-grid-layer' => array(
2230
- array(
2231
- 'attr_spec_list' => array(
2232
- 'template' => array(
2233
- 'mandatory' => true,
2234
- 'value_regex' => '(fill|horizontal|vertical|thirds)',
2235
- ),
2236
- ),
2237
- 'tag_spec' => array(
2238
- 'mandatory_ancestor' => 'amp-story-page',
2239
- ),
2240
- ),
2241
- ),
2242
- 'amp-story-page' => array(
2243
- array(
2244
- 'attr_spec_list' => array(
2245
- 'auto-advance-after' => array(),
2246
- 'background-audio' => array(
2247
- 'value_url' => array(
2248
- 'allowed_protocol' => array(
2249
- 'http',
2250
- 'https',
2251
- ),
2252
- ),
2253
- ),
2254
- 'id' => array(
2255
- 'mandatory' => true,
2256
- ),
2257
- ),
2258
- 'tag_spec' => array(
2259
- 'mandatory_parent' => 'amp-story',
2260
- 'requires_extension' => array(
2261
- 'amp-story',
2262
- ),
2263
- ),
2264
- ),
2265
- ),
2266
- 'amp-timeago' => array(
2267
- array(
2268
- 'attr_spec_list' => array(
2269
- 'cutoff' => array(
2270
- 'value_regex' => '\\d+',
2271
- ),
2272
- 'datetime' => array(
2273
- 'mandatory' => true,
2274
- 'value_regex' => '\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d(:[0-5]\\d(\\.\\d+)?)?(Z|[+-][0-1][0-9]:[0-5][0-9])',
2275
- ),
2276
- 'locale' => array(),
2277
- 'media' => array(),
2278
- 'noloading' => array(
2279
- 'value' => '',
2280
- ),
2281
- ),
2282
- 'tag_spec' => array(
2283
- 'requires_extension' => array(
2284
- 'amp-timeago',
2285
- ),
2286
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-timeago',
2287
- ),
2288
- ),
2289
- ),
2290
- 'amp-twitter' => array(
2291
- array(
2292
- 'attr_spec_list' => array(
2293
- 'data-tweetid' => array(
2294
- 'mandatory' => true,
2295
- ),
2296
- 'media' => array(),
2297
- 'noloading' => array(
2298
- 'value' => '',
2299
- ),
2300
- ),
2301
- 'tag_spec' => array(
2302
- 'requires_extension' => array(
2303
- 'amp-twitter',
2304
- ),
2305
- ),
2306
- ),
2307
- ),
2308
- 'amp-user-notification' => array(
2309
- array(
2310
- 'attr_spec_list' => array(
2311
- 'data-dismiss-href' => array(
2312
- 'value_url' => array(
2313
- 'allow_empty' => false,
2314
- 'allow_relative' => false,
2315
- 'allowed_protocol' => array(
2316
- 'https',
2317
- ),
2318
- ),
2319
- ),
2320
- 'data-show-if-href' => array(
2321
- 'value_url' => array(
2322
- 'allow_empty' => false,
2323
- 'allow_relative' => false,
2324
- 'allowed_protocol' => array(
2325
- 'https',
2326
- ),
2327
- ),
2328
- ),
2329
- 'enctype' => array(
2330
- 'value' => 'application/x-www-form-urlencoded',
2331
- ),
2332
- 'media' => array(),
2333
- 'noloading' => array(
2334
- 'value' => '',
2335
- ),
2336
- ),
2337
- 'tag_spec' => array(
2338
- 'requires_extension' => array(
2339
- 'amp-user-notification',
2340
- ),
2341
- ),
2342
- ),
2343
- ),
2344
- 'amp-video' => array(
2345
- array(
2346
- 'attr_spec_list' => array(
2347
- '[album]' => array(),
2348
- '[alt]' => array(),
2349
- '[artist]' => array(),
2350
- '[artwork]' => array(),
2351
- '[attribution]' => array(),
2352
- '[controls]' => array(),
2353
- '[controlslist]' => array(),
2354
- '[loop]' => array(),
2355
- '[poster]' => array(),
2356
- '[preload]' => array(),
2357
- '[src]' => array(),
2358
- '[title]' => array(),
2359
- 'album' => array(),
2360
- 'alt' => array(),
2361
- 'artist' => array(),
2362
- 'artwork' => array(),
2363
- 'attribution' => array(),
2364
- 'autoplay' => array(
2365
- 'value' => '',
2366
- ),
2367
- 'controls' => array(
2368
- 'value' => '',
2369
- ),
2370
- 'controlslist' => array(),
2371
- 'crossorigin' => array(),
2372
- 'disableremoteplayback' => array(
2373
- 'value' => '',
2374
- ),
2375
- 'lightbox' => array(),
2376
- 'lightbox-exclude' => array(
2377
- 'value' => '',
2378
- ),
2379
- 'lightbox-thumbnail-id' => array(
2380
- 'value_regex_casei' => '^[a-z][a-z\\d_-]*',
2381
- ),
2382
- 'loop' => array(
2383
- 'value' => '',
2384
- ),
2385
- 'media' => array(),
2386
- 'muted' => array(
2387
- 'value' => '',
2388
- ),
2389
- 'noloading' => array(
2390
- 'value' => '',
2391
- ),
2392
- 'placeholder' => array(),
2393
- 'poster' => array(),
2394
- 'preload' => array(
2395
- 'value_regex' => '(none|metadata|auto|)',
2396
- ),
2397
- 'src' => array(
2398
- 'blacklisted_value_regex' => '__amp_source_origin',
2399
- 'value_url' => array(
2400
- 'allow_relative' => true,
2401
- 'allowed_protocol' => array(
2402
- 'https',
2403
- ),
2404
- ),
2405
- ),
2406
- ),
2407
- 'tag_spec' => array(
2408
- 'also_requires_tag_warning' => array(
2409
- 'amp-video extension .js script',
2410
- ),
2411
- 'disallowed_ancestor' => array(
2412
- 'amp-story',
2413
- ),
2414
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
2415
- ),
2416
- ),
2417
- array(
2418
- 'attr_spec_list' => array(
2419
- '[album]' => array(),
2420
- '[alt]' => array(),
2421
- '[artist]' => array(),
2422
- '[artwork]' => array(),
2423
- '[attribution]' => array(),
2424
- '[controls]' => array(),
2425
- '[controlslist]' => array(),
2426
- '[loop]' => array(),
2427
- '[poster]' => array(),
2428
- '[preload]' => array(),
2429
- '[src]' => array(),
2430
- '[title]' => array(),
2431
- 'album' => array(),
2432
- 'alt' => array(),
2433
- 'artist' => array(),
2434
- 'artwork' => array(),
2435
- 'attribution' => array(),
2436
- 'autoplay' => array(
2437
- 'value' => '',
2438
- ),
2439
- 'controls' => array(
2440
- 'value' => '',
2441
- ),
2442
- 'controlslist' => array(),
2443
- 'crossorigin' => array(),
2444
- 'disableremoteplayback' => array(
2445
- 'value' => '',
2446
- ),
2447
- 'loop' => array(
2448
- 'value' => '',
2449
- ),
2450
- 'media' => array(),
2451
- 'muted' => array(
2452
- 'value' => '',
2453
- ),
2454
- 'noloading' => array(
2455
- 'value' => '',
2456
- ),
2457
- 'placeholder' => array(),
2458
- 'poster' => array(
2459
- 'mandatory' => true,
2460
- ),
2461
- 'preload' => array(
2462
- 'value_regex' => '(none|metadata|auto|)',
2463
- ),
2464
- 'src' => array(
2465
- 'blacklisted_value_regex' => '__amp_source_origin',
2466
- 'value_url' => array(
2467
- 'allow_relative' => true,
2468
- 'allowed_protocol' => array(
2469
- 'https',
2470
- ),
2471
- ),
2472
- ),
2473
- ),
2474
- 'tag_spec' => array(
2475
- 'mandatory_ancestor' => 'amp-story',
2476
- 'requires_extension' => array(
2477
- 'amp-video',
2478
- ),
2479
- 'spec_name' => 'amp-story >> amp-video',
2480
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
2481
- ),
2482
- ),
2483
- ),
2484
- 'amp-vimeo' => array(
2485
- array(
2486
- 'attr_spec_list' => array(
2487
- 'data-videoid' => array(
2488
- 'mandatory' => true,
2489
- 'value_regex' => '[0-9]+',
2490
- ),
2491
- 'media' => array(),
2492
- 'noloading' => array(
2493
- 'value' => '',
2494
- ),
2495
- ),
2496
- 'tag_spec' => array(
2497
- 'requires_extension' => array(
2498
- 'amp-vimeo',
2499
- ),
2500
- ),
2501
- ),
2502
- ),
2503
- 'amp-vine' => array(
2504
- array(
2505
- 'attr_spec_list' => array(
2506
- 'data-vineid' => array(
2507
- 'mandatory' => true,
2508
- ),
2509
- 'media' => array(),
2510
- 'noloading' => array(
2511
- 'value' => '',
2512
- ),
2513
- ),
2514
- 'tag_spec' => array(
2515
- 'requires_extension' => array(
2516
- 'amp-vine',
2517
- ),
2518
- ),
2519
- ),
2520
- ),
2521
- 'amp-vk' => array(
2522
- array(
2523
- 'attr_spec_list' => array(
2524
- 'data-embedtype' => array(
2525
- 'mandatory' => true,
2526
- ),
2527
- 'media' => array(),
2528
- 'noloading' => array(
2529
- 'value' => '',
2530
- ),
2531
- ),
2532
- 'tag_spec' => array(
2533
- 'requires_extension' => array(
2534
- 'amp-vk',
2535
- ),
2536
- ),
2537
- ),
2538
- ),
2539
- 'amp-web-push' => array(
2540
- array(
2541
- 'attr_spec_list' => array(
2542
- 'helper-iframe-url' => array(
2543
- 'mandatory' => true,
2544
- 'value_url' => array(
2545
- 'allow_relative' => false,
2546
- 'allowed_protocol' => array(
2547
- 'https',
2548
- ),
2549
- ),
2550
- ),
2551
- 'id' => array(
2552
- 'mandatory' => true,
2553
- 'value_regex' => 'amp-web-push',
2554
- ),
2555
- 'media' => array(),
2556
- 'noloading' => array(
2557
- 'value' => '',
2558
- ),
2559
- 'permission-dialog-url' => array(
2560
- 'mandatory' => true,
2561
- 'value_url' => array(
2562
- 'allow_relative' => false,
2563
- 'allowed_protocol' => array(
2564
- 'https',
2565
- ),
2566
- ),
2567
- ),
2568
- 'service-worker-url' => array(
2569
- 'mandatory' => true,
2570
- 'value_url' => array(
2571
- 'allow_relative' => false,
2572
- 'allowed_protocol' => array(
2573
- 'https',
2574
- ),
2575
- ),
2576
- ),
2577
- ),
2578
- 'tag_spec' => array(
2579
- 'requires_extension' => array(
2580
- 'amp-web-push',
2581
- ),
2582
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-web-push',
2583
- ),
2584
- ),
2585
- ),
2586
- 'amp-web-push-widget' => array(
2587
- array(
2588
- 'attr_spec_list' => array(
2589
- 'media' => array(),
2590
- 'noloading' => array(
2591
- 'value' => '',
2592
- ),
2593
- 'visibility' => array(
2594
- 'mandatory' => true,
2595
- 'value_regex' => '(blocked|subscribed|unsubscribed)',
2596
- ),
2597
- ),
2598
- 'tag_spec' => array(
2599
- 'requires_extension' => array(
2600
- 'amp-web-push',
2601
- ),
2602
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-web-push',
2603
- ),
2604
- ),
2605
- ),
2606
- 'amp-wistia-player' => array(
2607
- array(
2608
- 'attr_spec_list' => array(
2609
- 'data-media-hashed-id' => array(
2610
- 'mandatory' => true,
2611
- 'value_regex' => '[0-9a-zA-Z]+',
2612
- ),
2613
- 'media' => array(),
2614
- 'noloading' => array(
2615
- 'value' => '',
2616
- ),
2617
- ),
2618
- 'tag_spec' => array(
2619
- 'requires_extension' => array(
2620
- 'amp-wistia-player',
2621
- ),
2622
- ),
2623
- ),
2624
- ),
2625
- 'amp-youtube' => array(
2626
- array(
2627
- 'attr_spec_list' => array(
2628
- '[data-videoid]' => array(),
2629
- 'autoplay' => array(),
2630
- 'credentials' => array(
2631
- 'value_regex_casei' => '(include|omit)',
2632
- ),
2633
- 'data-live-channelid' => array(
2634
- 'value_regex' => '[^=/?:]+',
2635
- ),
2636
- 'data-videoid' => array(
2637
- 'value_regex' => '[^=/?:]+',
2638
- ),
2639
- 'lightbox' => array(),
2640
- 'lightbox-exclude' => array(
2641
- 'value' => '',
2642
- ),
2643
- 'lightbox-thumbnail-id' => array(
2644
- 'value_regex_casei' => '^[a-z][a-z\\d_-]*',
2645
- ),
2646
- 'media' => array(),
2647
- 'noloading' => array(
2648
- 'value' => '',
2649
- ),
2650
- ),
2651
- 'tag_spec' => array(
2652
- 'requires_extension' => array(
2653
- 'amp-youtube',
2654
- ),
2655
- ),
2656
- ),
2657
- ),
2658
- 'article' => array(
2659
- array(
2660
- 'attr_spec_list' => array(),
2661
- 'tag_spec' => array(),
2662
- ),
2663
- ),
2664
- 'aside' => array(
2665
- array(
2666
- 'attr_spec_list' => array(),
2667
- 'tag_spec' => array(),
2668
- ),
2669
- ),
2670
- 'audio' => array(
2671
- array(
2672
- 'attr_spec_list' => array(
2673
- 'autoplay' => array(),
2674
- 'controls' => array(),
2675
- 'loop' => array(),
2676
- 'muted' => array(),
2677
- 'preload' => array(),
2678
- 'src' => array(
2679
- 'blacklisted_value_regex' => '__amp_source_origin',
2680
- 'value_url' => array(
2681
- 'allow_relative' => false,
2682
- 'allowed_protocol' => array(
2683
- 'data',
2684
- 'https',
2685
- ),
2686
- ),
2687
- ),
2688
- ),
2689
- 'tag_spec' => array(
2690
- 'mandatory_ancestor' => 'noscript',
2691
- 'mandatory_ancestor_suggested_alternative' => 'amp-audio',
2692
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
2693
- ),
2694
- ),
2695
- ),
2696
- 'b' => array(
2697
- array(
2698
- 'attr_spec_list' => array(),
2699
- 'tag_spec' => array(),
2700
- ),
2701
- ),
2702
- 'base' => array(
2703
- array(
2704
- 'attr_spec_list' => array(
2705
- 'href' => array(
2706
- 'value' => '/',
2707
- ),
2708
- 'target' => array(
2709
- 'value_regex_casei' => '(_blank|_self|_top)',
2710
- ),
2711
- ),
2712
- 'tag_spec' => array(
2713
- 'mandatory_parent' => 'head',
2714
- 'unique' => true,
2715
- ),
2716
- ),
2717
- ),
2718
- 'bdi' => array(
2719
- array(
2720
- 'attr_spec_list' => array(),
2721
- 'tag_spec' => array(),
2722
- ),
2723
- ),
2724
- 'bdo' => array(
2725
- array(
2726
- 'attr_spec_list' => array(
2727
- 'dir' => array(),
2728
- ),
2729
- 'tag_spec' => array(),
2730
- ),
2731
- ),
2732
- 'big' => array(
2733
- array(
2734
- 'attr_spec_list' => array(),
2735
- 'tag_spec' => array(),
2736
- ),
2737
- ),
2738
- 'blockquote' => array(
2739
- array(
2740
- 'attr_spec_list' => array(
2741
- 'align' => array(),
2742
- 'cite' => array(
2743
- 'blacklisted_value_regex' => '__amp_source_origin',
2744
- 'value_url' => array(
2745
- 'allow_empty' => true,
2746
- 'allow_relative' => true,
2747
- 'allowed_protocol' => array(
2748
- 'http',
2749
- 'https',
2750
- ),
2751
- ),
2752
- ),
2753
- ),
2754
- 'tag_spec' => array(),
2755
- ),
2756
- ),
2757
- 'body' => array(
2758
- array(
2759
- 'attr_spec_list' => array(),
2760
- 'tag_spec' => array(
2761
- 'mandatory' => true,
2762
- 'mandatory_parent' => 'html',
2763
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
2764
- 'unique' => true,
2765
- ),
2766
- ),
2767
- ),
2768
- 'br' => array(
2769
- array(
2770
- 'attr_spec_list' => array(),
2771
- 'tag_spec' => array(),
2772
- ),
2773
- ),
2774
- 'button' => array(
2775
- array(
2776
- 'attr_spec_list' => array(
2777
- '[disabled]' => array(),
2778
- '[type]' => array(),
2779
- '[value]' => array(),
2780
- 'disabled' => array(
2781
- 'value' => '',
2782
- ),
2783
- 'name' => array(
2784
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
2785
- ),
2786
- 'role' => array(),
2787
- 'tabindex' => array(),
2788
- 'type' => array(),
2789
- 'value' => array(),
2790
- ),
2791
- 'tag_spec' => array(),
2792
- ),
2793
- array(
2794
- 'attr_spec_list' => array(
2795
- 'name' => array(
2796
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
2797
- ),
2798
- 'open-button' => array(
2799
- 'value' => '',
2800
- ),
2801
- 'role' => array(),
2802
- 'tabindex' => array(),
2803
- 'type' => array(),
2804
- 'value' => array(),
2805
- ),
2806
- 'tag_spec' => array(
2807
- 'mandatory_ancestor' => 'amp-app-banner',
2808
- 'spec_name' => 'amp-app-banner button[open-button]',
2809
- ),
2810
- ),
2811
- ),
2812
- 'caption' => array(
2813
- array(
2814
- 'attr_spec_list' => array(),
2815
- 'tag_spec' => array(),
2816
- ),
2817
- ),
2818
- 'center' => array(
2819
- array(
2820
- 'attr_spec_list' => array(),
2821
- 'tag_spec' => array(),
2822
- ),
2823
- ),
2824
- 'circle' => array(
2825
- array(
2826
- 'attr_spec_list' => array(
2827
- 'alignment-baseline' => array(),
2828
- 'baseline-shift' => array(),
2829
- 'clip' => array(),
2830
- 'clip-path' => array(),
2831
- 'clip-rule' => array(),
2832
- 'color' => array(),
2833
- 'color-interpolation' => array(),
2834
- 'color-interpolation-filters' => array(),
2835
- 'color-profile' => array(),
2836
- 'color-rendering' => array(),
2837
- 'cursor' => array(),
2838
- 'cx' => array(),
2839
- 'cy' => array(),
2840
- 'direction' => array(),
2841
- 'display' => array(),
2842
- 'dominant-baseline' => array(),
2843
- 'enable-background' => array(),
2844
- 'externalresourcesrequired' => array(),
2845
- 'fill' => array(),
2846
- 'fill-opacity' => array(),
2847
- 'fill-rule' => array(),
2848
- 'filter' => array(),
2849
- 'flood-color' => array(),
2850
- 'flood-opacity' => array(),
2851
- 'font-family' => array(),
2852
- 'font-size' => array(),
2853
- 'font-size-adjust' => array(),
2854
- 'font-stretch' => array(),
2855
- 'font-style' => array(),
2856
- 'font-variant' => array(),
2857
- 'font-weight' => array(),
2858
- 'glyph-orientation-horizontal' => array(),
2859
- 'glyph-orientation-vertical' => array(),
2860
- 'image-rendering' => array(),
2861
- 'kerning' => array(),
2862
- 'letter-spacing' => array(),
2863
- 'lighting-color' => array(),
2864
- 'marker-end' => array(),
2865
- 'marker-mid' => array(),
2866
- 'marker-start' => array(),
2867
- 'mask' => array(),
2868
- 'opacity' => array(),
2869
- 'overflow' => array(),
2870
- 'pointer-events' => array(),
2871
- 'r' => array(),
2872
- 'requiredextensions' => array(),
2873
- 'requiredfeatures' => array(),
2874
- 'shape-rendering' => array(),
2875
- 'sketch:type' => array(),
2876
- 'stop-color' => array(),
2877
- 'stop-opacity' => array(),
2878
- 'stroke' => array(),
2879
- 'stroke-dasharray' => array(),
2880
- 'stroke-dashoffset' => array(),
2881
- 'stroke-linecap' => array(),
2882
- 'stroke-linejoin' => array(),
2883
- 'stroke-miterlimit' => array(),
2884
- 'stroke-opacity' => array(),
2885
- 'stroke-width' => array(),
2886
- 'style' => array(
2887
- 'blacklisted_value_regex' => '!important',
2888
- ),
2889
- 'systemlanguage' => array(),
2890
- 'text-anchor' => array(),
2891
- 'text-decoration' => array(),
2892
- 'text-rendering' => array(),
2893
- 'transform' => array(),
2894
- 'unicode-bidi' => array(),
2895
- 'vector-effect' => array(),
2896
- 'visibility' => array(),
2897
- 'word-spacing' => array(),
2898
- 'writing-mode' => array(),
2899
- 'xml:lang' => array(),
2900
- 'xml:space' => array(),
2901
- 'xmlns' => array(),
2902
- 'xmlns:xlink' => array(),
2903
- ),
2904
- 'tag_spec' => array(
2905
- 'mandatory_ancestor' => 'svg',
2906
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
2907
- ),
2908
- ),
2909
- ),
2910
- 'cite' => array(
2911
- array(
2912
- 'attr_spec_list' => array(),
2913
- 'tag_spec' => array(),
2914
- ),
2915
- ),
2916
- 'clippath' => array(
2917
- array(
2918
- 'attr_spec_list' => array(
2919
- 'alignment-baseline' => array(),
2920
- 'baseline-shift' => array(),
2921
- 'clip' => array(),
2922
- 'clip-path' => array(),
2923
- 'clip-rule' => array(),
2924
- 'clippathunits' => array(),
2925
- 'color' => array(),
2926
- 'color-interpolation' => array(),
2927
- 'color-interpolation-filters' => array(),
2928
- 'color-profile' => array(),
2929
- 'color-rendering' => array(),
2930
- 'cursor' => array(),
2931
- 'direction' => array(),
2932
- 'display' => array(),
2933
- 'dominant-baseline' => array(),
2934
- 'enable-background' => array(),
2935
- 'externalresourcesrequired' => array(),
2936
- 'fill' => array(),
2937
- 'fill-opacity' => array(),
2938
- 'fill-rule' => array(),
2939
- 'filter' => array(),
2940
- 'flood-color' => array(),
2941
- 'flood-opacity' => array(),
2942
- 'font-family' => array(),
2943
- 'font-size' => array(),
2944
- 'font-size-adjust' => array(),
2945
- 'font-stretch' => array(),
2946
- 'font-style' => array(),
2947
- 'font-variant' => array(),
2948
- 'font-weight' => array(),
2949
- 'glyph-orientation-horizontal' => array(),
2950
- 'glyph-orientation-vertical' => array(),
2951
- 'image-rendering' => array(),
2952
- 'kerning' => array(),
2953
- 'letter-spacing' => array(),
2954
- 'lighting-color' => array(),
2955
- 'marker-end' => array(),
2956
- 'marker-mid' => array(),
2957
- 'marker-start' => array(),
2958
- 'mask' => array(),
2959
- 'opacity' => array(),
2960
- 'overflow' => array(),
2961
- 'pointer-events' => array(),
2962
- 'requiredextensions' => array(),
2963
- 'requiredfeatures' => array(),
2964
- 'shape-rendering' => array(),
2965
- 'stop-color' => array(),
2966
- 'stop-opacity' => array(),
2967
- 'stroke' => array(),
2968
- 'stroke-dasharray' => array(),
2969
- 'stroke-dashoffset' => array(),
2970
- 'stroke-linecap' => array(),
2971
- 'stroke-linejoin' => array(),
2972
- 'stroke-miterlimit' => array(),
2973
- 'stroke-opacity' => array(),
2974
- 'stroke-width' => array(),
2975
- 'style' => array(
2976
- 'blacklisted_value_regex' => '!important',
2977
- ),
2978
- 'systemlanguage' => array(),
2979
- 'text-anchor' => array(),
2980
- 'text-decoration' => array(),
2981
- 'text-rendering' => array(),
2982
- 'transform' => array(),
2983
- 'unicode-bidi' => array(),
2984
- 'vector-effect' => array(),
2985
- 'visibility' => array(),
2986
- 'word-spacing' => array(),
2987
- 'writing-mode' => array(),
2988
- 'xml:lang' => array(),
2989
- 'xml:space' => array(),
2990
- 'xmlns' => array(),
2991
- 'xmlns:xlink' => array(),
2992
- ),
2993
- 'tag_spec' => array(
2994
- 'mandatory_ancestor' => 'svg',
2995
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
2996
- ),
2997
- ),
2998
- ),
2999
- 'code' => array(
3000
- array(
3001
- 'attr_spec_list' => array(),
3002
- 'tag_spec' => array(),
3003
- ),
3004
- ),
3005
- 'col' => array(
3006
- array(
3007
- 'attr_spec_list' => array(
3008
- 'span' => array(),
3009
- ),
3010
- 'tag_spec' => array(),
3011
- ),
3012
- ),
3013
- 'colgroup' => array(
3014
- array(
3015
- 'attr_spec_list' => array(
3016
- 'span' => array(),
3017
- ),
3018
- 'tag_spec' => array(),
3019
- ),
3020
- ),
3021
- 'data' => array(
3022
- array(
3023
- 'attr_spec_list' => array(),
3024
- 'tag_spec' => array(),
3025
- ),
3026
- ),
3027
- 'datalist' => array(
3028
- array(
3029
- 'attr_spec_list' => array(),
3030
- 'tag_spec' => array(
3031
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
3032
- ),
3033
- ),
3034
- ),
3035
- 'dd' => array(
3036
- array(
3037
- 'attr_spec_list' => array(),
3038
- 'tag_spec' => array(),
3039
- ),
3040
- ),
3041
- 'defs' => array(
3042
- array(
3043
- 'attr_spec_list' => array(
3044
- 'alignment-baseline' => array(),
3045
- 'baseline-shift' => array(),
3046
- 'clip' => array(),
3047
- 'clip-path' => array(),
3048
- 'clip-rule' => array(),
3049
- 'color' => array(),
3050
- 'color-interpolation' => array(),
3051
- 'color-interpolation-filters' => array(),
3052
- 'color-profile' => array(),
3053
- 'color-rendering' => array(),
3054
- 'cursor' => array(),
3055
- 'direction' => array(),
3056
- 'display' => array(),
3057
- 'dominant-baseline' => array(),
3058
- 'enable-background' => array(),
3059
- 'externalresourcesrequired' => array(),
3060
- 'fill' => array(),
3061
- 'fill-opacity' => array(),
3062
- 'fill-rule' => array(),
3063
- 'filter' => array(),
3064
- 'flood-color' => array(),
3065
- 'flood-opacity' => array(),
3066
- 'font-family' => array(),
3067
- 'font-size' => array(),
3068
- 'font-size-adjust' => array(),
3069
- 'font-stretch' => array(),
3070
- 'font-style' => array(),
3071
- 'font-variant' => array(),
3072
- 'font-weight' => array(),
3073
- 'glyph-orientation-horizontal' => array(),
3074
- 'glyph-orientation-vertical' => array(),
3075
- 'image-rendering' => array(),
3076
- 'kerning' => array(),
3077
- 'letter-spacing' => array(),
3078
- 'lighting-color' => array(),
3079
- 'marker-end' => array(),
3080
- 'marker-mid' => array(),
3081
- 'marker-start' => array(),
3082
- 'mask' => array(),
3083
- 'opacity' => array(),
3084
- 'overflow' => array(),
3085
- 'pointer-events' => array(),
3086
- 'requiredextensions' => array(),
3087
- 'requiredfeatures' => array(),
3088
- 'shape-rendering' => array(),
3089
- 'stop-color' => array(),
3090
- 'stop-opacity' => array(),
3091
- 'stroke' => array(),
3092
- 'stroke-dasharray' => array(),
3093
- 'stroke-dashoffset' => array(),
3094
- 'stroke-linecap' => array(),
3095
- 'stroke-linejoin' => array(),
3096
- 'stroke-miterlimit' => array(),
3097
- 'stroke-opacity' => array(),
3098
- 'stroke-width' => array(),
3099
- 'style' => array(
3100
- 'blacklisted_value_regex' => '!important',
3101
- ),
3102
- 'systemlanguage' => array(),
3103
- 'text-anchor' => array(),
3104
- 'text-decoration' => array(),
3105
- 'text-rendering' => array(),
3106
- 'transform' => array(),
3107
- 'unicode-bidi' => array(),
3108
- 'vector-effect' => array(),
3109
- 'visibility' => array(),
3110
- 'word-spacing' => array(),
3111
- 'writing-mode' => array(),
3112
- 'xml:lang' => array(),
3113
- 'xml:space' => array(),
3114
- 'xmlns' => array(),
3115
- 'xmlns:xlink' => array(),
3116
- ),
3117
- 'tag_spec' => array(
3118
- 'mandatory_ancestor' => 'svg',
3119
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3120
- ),
3121
- ),
3122
- ),
3123
- 'del' => array(
3124
- array(
3125
- 'attr_spec_list' => array(
3126
- 'cite' => array(
3127
- 'blacklisted_value_regex' => '__amp_source_origin',
3128
- 'value_url' => array(
3129
- 'allow_empty' => true,
3130
- 'allow_relative' => true,
3131
- 'allowed_protocol' => array(
3132
- 'http',
3133
- 'https',
3134
- ),
3135
- ),
3136
- ),
3137
- 'datetime' => array(),
3138
- ),
3139
- 'tag_spec' => array(),
3140
- ),
3141
- ),
3142
- 'desc' => array(
3143
- array(
3144
- 'attr_spec_list' => array(
3145
- 'style' => array(
3146
- 'blacklisted_value_regex' => '!important',
3147
- ),
3148
- 'xml:lang' => array(),
3149
- 'xml:space' => array(),
3150
- 'xmlns' => array(),
3151
- 'xmlns:xlink' => array(),
3152
- ),
3153
- 'tag_spec' => array(
3154
- 'mandatory_ancestor' => 'svg',
3155
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3156
- ),
3157
- ),
3158
- ),
3159
- 'dfn' => array(
3160
- array(
3161
- 'attr_spec_list' => array(),
3162
- 'tag_spec' => array(),
3163
- ),
3164
- ),
3165
- 'dir' => array(
3166
- array(
3167
- 'attr_spec_list' => array(),
3168
- 'tag_spec' => array(),
3169
- ),
3170
- ),
3171
- 'div' => array(
3172
- array(
3173
- 'attr_spec_list' => array(
3174
- 'align' => array(),
3175
- ),
3176
- 'tag_spec' => array(),
3177
- ),
3178
- array(
3179
- 'attr_spec_list' => array(
3180
- 'align' => array(),
3181
- 'submitting' => array(
3182
- 'dispatch_key' => 1,
3183
- 'mandatory' => true,
3184
- ),
3185
- ),
3186
- 'tag_spec' => array(
3187
- 'mandatory_parent' => 'form',
3188
- 'spec_name' => 'FORM > DIV [submitting]',
3189
- ),
3190
- ),
3191
- array(
3192
- 'attr_spec_list' => array(
3193
- 'align' => array(),
3194
- 'submit-success' => array(
3195
- 'mandatory' => true,
3196
- ),
3197
- ),
3198
- 'tag_spec' => array(
3199
- 'mandatory_parent' => 'form',
3200
- 'spec_name' => 'FORM > DIV [submit-success]',
3201
- ),
3202
- ),
3203
- array(
3204
- 'attr_spec_list' => array(
3205
- 'align' => array(),
3206
- 'submit-success' => array(
3207
- 'mandatory' => true,
3208
- ),
3209
- 'template' => array(
3210
- 'mandatory' => true,
3211
- ),
3212
- ),
3213
- 'tag_spec' => array(
3214
- 'mandatory_parent' => 'form',
3215
- 'spec_name' => 'FORM > DIV [submit-success][template]',
3216
- ),
3217
- ),
3218
- array(
3219
- 'attr_spec_list' => array(
3220
- 'align' => array(),
3221
- 'submit-error' => array(
3222
- 'mandatory' => true,
3223
- ),
3224
- ),
3225
- 'tag_spec' => array(
3226
- 'mandatory_parent' => 'form',
3227
- 'spec_name' => 'FORM > DIV [submit-error]',
3228
- ),
3229
- ),
3230
- array(
3231
- 'attr_spec_list' => array(
3232
- 'align' => array(),
3233
- 'submit-error' => array(
3234
- 'mandatory' => true,
3235
- ),
3236
- 'template' => array(
3237
- 'mandatory' => true,
3238
- ),
3239
- ),
3240
- 'tag_spec' => array(
3241
- 'mandatory_parent' => 'form',
3242
- 'spec_name' => 'FORM > DIV [submit-error][template]',
3243
- ),
3244
- ),
3245
- ),
3246
- 'dl' => array(
3247
- array(
3248
- 'attr_spec_list' => array(),
3249
- 'tag_spec' => array(),
3250
- ),
3251
- ),
3252
- 'dt' => array(
3253
- array(
3254
- 'attr_spec_list' => array(),
3255
- 'tag_spec' => array(),
3256
- ),
3257
- ),
3258
- 'ellipse' => array(
3259
- array(
3260
- 'attr_spec_list' => array(
3261
- 'alignment-baseline' => array(),
3262
- 'baseline-shift' => array(),
3263
- 'clip' => array(),
3264
- 'clip-path' => array(),
3265
- 'clip-rule' => array(),
3266
- 'color' => array(),
3267
- 'color-interpolation' => array(),
3268
- 'color-interpolation-filters' => array(),
3269
- 'color-profile' => array(),
3270
- 'color-rendering' => array(),
3271
- 'cursor' => array(),
3272
- 'cx' => array(),
3273
- 'cy' => array(),
3274
- 'direction' => array(),
3275
- 'display' => array(),
3276
- 'dominant-baseline' => array(),
3277
- 'enable-background' => array(),
3278
- 'externalresourcesrequired' => array(),
3279
- 'fill' => array(),
3280
- 'fill-opacity' => array(),
3281
- 'fill-rule' => array(),
3282
- 'filter' => array(),
3283
- 'flood-color' => array(),
3284
- 'flood-opacity' => array(),
3285
- 'font-family' => array(),
3286
- 'font-size' => array(),
3287
- 'font-size-adjust' => array(),
3288
- 'font-stretch' => array(),
3289
- 'font-style' => array(),
3290
- 'font-variant' => array(),
3291
- 'font-weight' => array(),
3292
- 'glyph-orientation-horizontal' => array(),
3293
- 'glyph-orientation-vertical' => array(),
3294
- 'image-rendering' => array(),
3295
- 'kerning' => array(),
3296
- 'letter-spacing' => array(),
3297
- 'lighting-color' => array(),
3298
- 'marker-end' => array(),
3299
- 'marker-mid' => array(),
3300
- 'marker-start' => array(),
3301
- 'mask' => array(),
3302
- 'opacity' => array(),
3303
- 'overflow' => array(),
3304
- 'pointer-events' => array(),
3305
- 'requiredextensions' => array(),
3306
- 'requiredfeatures' => array(),
3307
- 'rx' => array(),
3308
- 'ry' => array(),
3309
- 'shape-rendering' => array(),
3310
- 'sketch:type' => array(),
3311
- 'stop-color' => array(),
3312
- 'stop-opacity' => array(),
3313
- 'stroke' => array(),
3314
- 'stroke-dasharray' => array(),
3315
- 'stroke-dashoffset' => array(),
3316
- 'stroke-linecap' => array(),
3317
- 'stroke-linejoin' => array(),
3318
- 'stroke-miterlimit' => array(),
3319
- 'stroke-opacity' => array(),
3320
- 'stroke-width' => array(),
3321
- 'style' => array(
3322
- 'blacklisted_value_regex' => '!important',
3323
- ),
3324
- 'systemlanguage' => array(),
3325
- 'text-anchor' => array(),
3326
- 'text-decoration' => array(),
3327
- 'text-rendering' => array(),
3328
- 'transform' => array(),
3329
- 'unicode-bidi' => array(),
3330
- 'vector-effect' => array(),
3331
- 'visibility' => array(),
3332
- 'word-spacing' => array(),
3333
- 'writing-mode' => array(),
3334
- 'xml:lang' => array(),
3335
- 'xml:space' => array(),
3336
- 'xmlns' => array(),
3337
- 'xmlns:xlink' => array(),
3338
- ),
3339
- 'tag_spec' => array(
3340
- 'mandatory_ancestor' => 'svg',
3341
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3342
- ),
3343
- ),
3344
- ),
3345
- 'em' => array(
3346
- array(
3347
- 'attr_spec_list' => array(),
3348
- 'tag_spec' => array(),
3349
- ),
3350
- ),
3351
- 'fecolormatrix' => array(
3352
- array(
3353
- 'attr_spec_list' => array(
3354
- 'alignment-baseline' => array(),
3355
- 'baseline-shift' => array(),
3356
- 'clip' => array(),
3357
- 'clip-path' => array(),
3358
- 'clip-rule' => array(),
3359
- 'color' => array(),
3360
- 'color-interpolation' => array(),
3361
- 'color-interpolation-filters' => array(),
3362
- 'color-profile' => array(),
3363
- 'color-rendering' => array(),
3364
- 'cursor' => array(),
3365
- 'direction' => array(),
3366
- 'display' => array(),
3367
- 'dominant-baseline' => array(),
3368
- 'enable-background' => array(),
3369
- 'fill' => array(),
3370
- 'fill-opacity' => array(),
3371
- 'fill-rule' => array(),
3372
- 'filter' => array(),
3373
- 'flood-color' => array(),
3374
- 'flood-opacity' => array(),
3375
- 'font-family' => array(),
3376
- 'font-size' => array(),
3377
- 'font-size-adjust' => array(),
3378
- 'font-stretch' => array(),
3379
- 'font-style' => array(),
3380
- 'font-variant' => array(),
3381
- 'font-weight' => array(),
3382
- 'glyph-orientation-horizontal' => array(),
3383
- 'glyph-orientation-vertical' => array(),
3384
- 'height' => array(),
3385
- 'image-rendering' => array(),
3386
- 'in' => array(),
3387
- 'kerning' => array(),
3388
- 'letter-spacing' => array(),
3389
- 'lighting-color' => array(),
3390
- 'marker-end' => array(),
3391
- 'marker-mid' => array(),
3392
- 'marker-start' => array(),
3393
- 'mask' => array(),
3394
- 'opacity' => array(),
3395
- 'overflow' => array(),
3396
- 'pointer-events' => array(),
3397
- 'result' => array(),
3398
- 'shape-rendering' => array(),
3399
- 'stop-color' => array(),
3400
- 'stop-opacity' => array(),
3401
- 'stroke' => array(),
3402
- 'stroke-dasharray' => array(),
3403
- 'stroke-dashoffset' => array(),
3404
- 'stroke-linecap' => array(),
3405
- 'stroke-linejoin' => array(),
3406
- 'stroke-miterlimit' => array(),
3407
- 'stroke-opacity' => array(),
3408
- 'stroke-width' => array(),
3409
- 'style' => array(
3410
- 'blacklisted_value_regex' => '!important',
3411
- ),
3412
- 'text-anchor' => array(),
3413
- 'text-decoration' => array(),
3414
- 'text-rendering' => array(),
3415
- 'type' => array(),
3416
- 'unicode-bidi' => array(),
3417
- 'values' => array(),
3418
- 'vector-effect' => array(),
3419
- 'visibility' => array(),
3420
- 'width' => array(),
3421
- 'word-spacing' => array(),
3422
- 'writing-mode' => array(),
3423
- 'x' => array(),
3424
- 'xml:lang' => array(),
3425
- 'xml:space' => array(),
3426
- 'xmlns' => array(),
3427
- 'xmlns:xlink' => array(),
3428
- 'y' => array(),
3429
- ),
3430
- 'tag_spec' => array(
3431
- 'mandatory_ancestor' => 'svg',
3432
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3433
- ),
3434
- ),
3435
- ),
3436
- 'fecomposite' => array(
3437
- array(
3438
- 'attr_spec_list' => array(
3439
- 'alignment-baseline' => array(),
3440
- 'baseline-shift' => array(),
3441
- 'clip' => array(),
3442
- 'clip-path' => array(),
3443
- 'clip-rule' => array(),
3444
- 'color' => array(),
3445
- 'color-interpolation' => array(),
3446
- 'color-interpolation-filters' => array(),
3447
- 'color-profile' => array(),
3448
- 'color-rendering' => array(),
3449
- 'cursor' => array(),
3450
- 'direction' => array(),
3451
- 'display' => array(),
3452
- 'dominant-baseline' => array(),
3453
- 'enable-background' => array(),
3454
- 'fill' => array(),
3455
- 'fill-opacity' => array(),
3456
- 'fill-rule' => array(),
3457
- 'filter' => array(),
3458
- 'flood-color' => array(),
3459
- 'flood-opacity' => array(),
3460
- 'font-family' => array(),
3461
- 'font-size' => array(),
3462
- 'font-size-adjust' => array(),
3463
- 'font-stretch' => array(),
3464
- 'font-style' => array(),
3465
- 'font-variant' => array(),
3466
- 'font-weight' => array(),
3467
- 'glyph-orientation-horizontal' => array(),
3468
- 'glyph-orientation-vertical' => array(),
3469
- 'height' => array(),
3470
- 'image-rendering' => array(),
3471
- 'in' => array(),
3472
- 'in2' => array(),
3473
- 'k1' => array(),
3474
- 'k2' => array(),
3475
- 'k3' => array(),
3476
- 'k4' => array(),
3477
- 'kerning' => array(),
3478
- 'letter-spacing' => array(),
3479
- 'lighting-color' => array(),
3480
- 'marker-end' => array(),
3481
- 'marker-mid' => array(),
3482
- 'marker-start' => array(),
3483
- 'mask' => array(),
3484
- 'opacity' => array(),
3485
- 'operator' => array(),
3486
- 'overflow' => array(),
3487
- 'pointer-events' => array(),
3488
- 'result' => array(),
3489
- 'shape-rendering' => array(),
3490
- 'stop-color' => array(),
3491
- 'stop-opacity' => array(),
3492
- 'stroke' => array(),
3493
- 'stroke-dasharray' => array(),
3494
- 'stroke-dashoffset' => array(),
3495
- 'stroke-linecap' => array(),
3496
- 'stroke-linejoin' => array(),
3497
- 'stroke-miterlimit' => array(),
3498
- 'stroke-opacity' => array(),
3499
- 'stroke-width' => array(),
3500
- 'style' => array(
3501
- 'blacklisted_value_regex' => '!important',
3502
- ),
3503
- 'text-anchor' => array(),
3504
- 'text-decoration' => array(),
3505
- 'text-rendering' => array(),
3506
- 'unicode-bidi' => array(),
3507
- 'vector-effect' => array(),
3508
- 'visibility' => array(),
3509
- 'width' => array(),
3510
- 'word-spacing' => array(),
3511
- 'writing-mode' => array(),
3512
- 'x' => array(),
3513
- 'xml:lang' => array(),
3514
- 'xml:space' => array(),
3515
- 'xmlns' => array(),
3516
- 'xmlns:xlink' => array(),
3517
- 'y' => array(),
3518
- ),
3519
- 'tag_spec' => array(
3520
- 'mandatory_ancestor' => 'svg',
3521
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3522
- ),
3523
- ),
3524
- ),
3525
- 'feflood' => array(
3526
- array(
3527
- 'attr_spec_list' => array(
3528
- 'alignment-baseline' => array(),
3529
- 'baseline-shift' => array(),
3530
- 'clip' => array(),
3531
- 'clip-path' => array(),
3532
- 'clip-rule' => array(),
3533
- 'color' => array(),
3534
- 'color-interpolation' => array(),
3535
- 'color-interpolation-filters' => array(),
3536
- 'color-profile' => array(),
3537
- 'color-rendering' => array(),
3538
- 'cursor' => array(),
3539
- 'direction' => array(),
3540
- 'display' => array(),
3541
- 'dominant-baseline' => array(),
3542
- 'enable-background' => array(),
3543
- 'fill' => array(),
3544
- 'fill-opacity' => array(),
3545
- 'fill-rule' => array(),
3546
- 'filter' => array(),
3547
- 'flood-color' => array(),
3548
- 'flood-opacity' => array(),
3549
- 'font-family' => array(),
3550
- 'font-size' => array(),
3551
- 'font-size-adjust' => array(),
3552
- 'font-stretch' => array(),
3553
- 'font-style' => array(),
3554
- 'font-variant' => array(),
3555
- 'font-weight' => array(),
3556
- 'glyph-orientation-horizontal' => array(),
3557
- 'glyph-orientation-vertical' => array(),
3558
- 'height' => array(),
3559
- 'image-rendering' => array(),
3560
- 'kerning' => array(),
3561
- 'letter-spacing' => array(),
3562
- 'lighting-color' => array(),
3563
- 'marker-end' => array(),
3564
- 'marker-mid' => array(),
3565
- 'marker-start' => array(),
3566
- 'mask' => array(),
3567
- 'opacity' => array(),
3568
- 'overflow' => array(),
3569
- 'pointer-events' => array(),
3570
- 'result' => array(),
3571
- 'shape-rendering' => array(),
3572
- 'stop-color' => array(),
3573
- 'stop-opacity' => array(),
3574
- 'stroke' => array(),
3575
- 'stroke-dasharray' => array(),
3576
- 'stroke-dashoffset' => array(),
3577
- 'stroke-linecap' => array(),
3578
- 'stroke-linejoin' => array(),
3579
- 'stroke-miterlimit' => array(),
3580
- 'stroke-opacity' => array(),
3581
- 'stroke-width' => array(),
3582
- 'style' => array(
3583
- 'blacklisted_value_regex' => '!important',
3584
- ),
3585
- 'text-anchor' => array(),
3586
- 'text-decoration' => array(),
3587
- 'text-rendering' => array(),
3588
- 'unicode-bidi' => array(),
3589
- 'vector-effect' => array(),
3590
- 'visibility' => array(),
3591
- 'width' => array(),
3592
- 'word-spacing' => array(),
3593
- 'writing-mode' => array(),
3594
- 'x' => array(),
3595
- 'xml:lang' => array(),
3596
- 'xml:space' => array(),
3597
- 'xmlns' => array(),
3598
- 'xmlns:xlink' => array(),
3599
- 'y' => array(),
3600
- ),
3601
- 'tag_spec' => array(
3602
- 'mandatory_ancestor' => 'svg',
3603
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3604
- ),
3605
- ),
3606
- ),
3607
- 'fegaussianblur' => array(
3608
- array(
3609
- 'attr_spec_list' => array(
3610
- 'alignment-baseline' => array(),
3611
- 'baseline-shift' => array(),
3612
- 'clip' => array(),
3613
- 'clip-path' => array(),
3614
- 'clip-rule' => array(),
3615
- 'color' => array(),
3616
- 'color-interpolation' => array(),
3617
- 'color-interpolation-filters' => array(),
3618
- 'color-profile' => array(),
3619
- 'color-rendering' => array(),
3620
- 'cursor' => array(),
3621
- 'direction' => array(),
3622
- 'display' => array(),
3623
- 'dominant-baseline' => array(),
3624
- 'edgemode' => array(),
3625
- 'enable-background' => array(),
3626
- 'fill' => array(),
3627
- 'fill-opacity' => array(),
3628
- 'fill-rule' => array(),
3629
- 'filter' => array(),
3630
- 'flood-color' => array(),
3631
- 'flood-opacity' => array(),
3632
- 'font-family' => array(),
3633
- 'font-size' => array(),
3634
- 'font-size-adjust' => array(),
3635
- 'font-stretch' => array(),
3636
- 'font-style' => array(),
3637
- 'font-variant' => array(),
3638
- 'font-weight' => array(),
3639
- 'glyph-orientation-horizontal' => array(),
3640
- 'glyph-orientation-vertical' => array(),
3641
- 'height' => array(),
3642
- 'image-rendering' => array(),
3643
- 'in' => array(),
3644
- 'kerning' => array(),
3645
- 'letter-spacing' => array(),
3646
- 'lighting-color' => array(),
3647
- 'marker-end' => array(),
3648
- 'marker-mid' => array(),
3649
- 'marker-start' => array(),
3650
- 'mask' => array(),
3651
- 'opacity' => array(),
3652
- 'overflow' => array(),
3653
- 'pointer-events' => array(),
3654
- 'result' => array(),
3655
- 'shape-rendering' => array(),
3656
- 'stddeviation' => array(),
3657
- 'stop-color' => array(),
3658
- 'stop-opacity' => array(),
3659
- 'stroke' => array(),
3660
- 'stroke-dasharray' => array(),
3661
- 'stroke-dashoffset' => array(),
3662
- 'stroke-linecap' => array(),
3663
- 'stroke-linejoin' => array(),
3664
- 'stroke-miterlimit' => array(),
3665
- 'stroke-opacity' => array(),
3666
- 'stroke-width' => array(),
3667
- 'style' => array(
3668
- 'blacklisted_value_regex' => '!important',
3669
- ),
3670
- 'text-anchor' => array(),
3671
- 'text-decoration' => array(),
3672
- 'text-rendering' => array(),
3673
- 'unicode-bidi' => array(),
3674
- 'vector-effect' => array(),
3675
- 'visibility' => array(),
3676
- 'width' => array(),
3677
- 'word-spacing' => array(),
3678
- 'writing-mode' => array(),
3679
- 'x' => array(),
3680
- 'xml:lang' => array(),
3681
- 'xml:space' => array(),
3682
- 'xmlns' => array(),
3683
- 'xmlns:xlink' => array(),
3684
- 'y' => array(),
3685
- ),
3686
- 'tag_spec' => array(
3687
- 'mandatory_ancestor' => 'svg',
3688
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3689
- ),
3690
- ),
3691
- ),
3692
- 'femerge' => array(
3693
- array(
3694
- 'attr_spec_list' => array(
3695
- 'alignment-baseline' => array(),
3696
- 'baseline-shift' => array(),
3697
- 'clip' => array(),
3698
- 'clip-path' => array(),
3699
- 'clip-rule' => array(),
3700
- 'color' => array(),
3701
- 'color-interpolation' => array(),
3702
- 'color-interpolation-filters' => array(),
3703
- 'color-profile' => array(),
3704
- 'color-rendering' => array(),
3705
- 'cursor' => array(),
3706
- 'direction' => array(),
3707
- 'display' => array(),
3708
- 'dominant-baseline' => array(),
3709
- 'enable-background' => array(),
3710
- 'fill' => array(),
3711
- 'fill-opacity' => array(),
3712
- 'fill-rule' => array(),
3713
- 'filter' => array(),
3714
- 'flood-color' => array(),
3715
- 'flood-opacity' => array(),
3716
- 'font-family' => array(),
3717
- 'font-size' => array(),
3718
- 'font-size-adjust' => array(),
3719
- 'font-stretch' => array(),
3720
- 'font-style' => array(),
3721
- 'font-variant' => array(),
3722
- 'font-weight' => array(),
3723
- 'glyph-orientation-horizontal' => array(),
3724
- 'glyph-orientation-vertical' => array(),
3725
- 'height' => array(),
3726
- 'image-rendering' => array(),
3727
- 'kerning' => array(),
3728
- 'letter-spacing' => array(),
3729
- 'lighting-color' => array(),
3730
- 'marker-end' => array(),
3731
- 'marker-mid' => array(),
3732
- 'marker-start' => array(),
3733
- 'mask' => array(),
3734
- 'opacity' => array(),
3735
- 'overflow' => array(),
3736
- 'pointer-events' => array(),
3737
- 'result' => array(),
3738
- 'shape-rendering' => array(),
3739
- 'stop-color' => array(),
3740
- 'stop-opacity' => array(),
3741
- 'stroke' => array(),
3742
- 'stroke-dasharray' => array(),
3743
- 'stroke-dashoffset' => array(),
3744
- 'stroke-linecap' => array(),
3745
- 'stroke-linejoin' => array(),
3746
- 'stroke-miterlimit' => array(),
3747
- 'stroke-opacity' => array(),
3748
- 'stroke-width' => array(),
3749
- 'style' => array(
3750
- 'blacklisted_value_regex' => '!important',
3751
- ),
3752
- 'text-anchor' => array(),
3753
- 'text-decoration' => array(),
3754
- 'text-rendering' => array(),
3755
- 'unicode-bidi' => array(),
3756
- 'vector-effect' => array(),
3757
- 'visibility' => array(),
3758
- 'width' => array(),
3759
- 'word-spacing' => array(),
3760
- 'writing-mode' => array(),
3761
- 'x' => array(),
3762
- 'xml:lang' => array(),
3763
- 'xml:space' => array(),
3764
- 'xmlns' => array(),
3765
- 'xmlns:xlink' => array(),
3766
- 'y' => array(),
3767
- ),
3768
- 'tag_spec' => array(
3769
- 'mandatory_ancestor' => 'svg',
3770
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3771
- ),
3772
- ),
3773
- ),
3774
- 'femergenode' => array(
3775
- array(
3776
- 'attr_spec_list' => array(
3777
- 'in' => array(),
3778
- 'style' => array(
3779
- 'blacklisted_value_regex' => '!important',
3780
- ),
3781
- 'xml:lang' => array(),
3782
- 'xml:space' => array(),
3783
- 'xmlns' => array(),
3784
- 'xmlns:xlink' => array(),
3785
- ),
3786
- 'tag_spec' => array(
3787
- 'mandatory_ancestor' => 'svg',
3788
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3789
- ),
3790
- ),
3791
- ),
3792
- 'feoffset' => array(
3793
- array(
3794
- 'attr_spec_list' => array(
3795
- 'alignment-baseline' => array(),
3796
- 'baseline-shift' => array(),
3797
- 'clip' => array(),
3798
- 'clip-path' => array(),
3799
- 'clip-rule' => array(),
3800
- 'color' => array(),
3801
- 'color-interpolation' => array(),
3802
- 'color-interpolation-filters' => array(),
3803
- 'color-profile' => array(),
3804
- 'color-rendering' => array(),
3805
- 'cursor' => array(),
3806
- 'direction' => array(),
3807
- 'display' => array(),
3808
- 'dominant-baseline' => array(),
3809
- 'dx' => array(),
3810
- 'dy' => array(),
3811
- 'enable-background' => array(),
3812
- 'fill' => array(),
3813
- 'fill-opacity' => array(),
3814
- 'fill-rule' => array(),
3815
- 'filter' => array(),
3816
- 'flood-color' => array(),
3817
- 'flood-opacity' => array(),
3818
- 'font-family' => array(),
3819
- 'font-size' => array(),
3820
- 'font-size-adjust' => array(),
3821
- 'font-stretch' => array(),
3822
- 'font-style' => array(),
3823
- 'font-variant' => array(),
3824
- 'font-weight' => array(),
3825
- 'glyph-orientation-horizontal' => array(),
3826
- 'glyph-orientation-vertical' => array(),
3827
- 'height' => array(),
3828
- 'image-rendering' => array(),
3829
- 'in' => array(),
3830
- 'kerning' => array(),
3831
- 'letter-spacing' => array(),
3832
- 'lighting-color' => array(),
3833
- 'marker-end' => array(),
3834
- 'marker-mid' => array(),
3835
- 'marker-start' => array(),
3836
- 'mask' => array(),
3837
- 'opacity' => array(),
3838
- 'overflow' => array(),
3839
- 'pointer-events' => array(),
3840
- 'result' => array(),
3841
- 'shape-rendering' => array(),
3842
- 'stop-color' => array(),
3843
- 'stop-opacity' => array(),
3844
- 'stroke' => array(),
3845
- 'stroke-dasharray' => array(),
3846
- 'stroke-dashoffset' => array(),
3847
- 'stroke-linecap' => array(),
3848
- 'stroke-linejoin' => array(),
3849
- 'stroke-miterlimit' => array(),
3850
- 'stroke-opacity' => array(),
3851
- 'stroke-width' => array(),
3852
- 'style' => array(
3853
- 'blacklisted_value_regex' => '!important',
3854
- ),
3855
- 'text-anchor' => array(),
3856
- 'text-decoration' => array(),
3857
- 'text-rendering' => array(),
3858
- 'unicode-bidi' => array(),
3859
- 'vector-effect' => array(),
3860
- 'visibility' => array(),
3861
- 'width' => array(),
3862
- 'word-spacing' => array(),
3863
- 'writing-mode' => array(),
3864
- 'x' => array(),
3865
- 'xml:lang' => array(),
3866
- 'xml:space' => array(),
3867
- 'xmlns' => array(),
3868
- 'xmlns:xlink' => array(),
3869
- 'y' => array(),
3870
- ),
3871
- 'tag_spec' => array(
3872
- 'mandatory_ancestor' => 'svg',
3873
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3874
- ),
3875
- ),
3876
- ),
3877
- 'fieldset' => array(
3878
- array(
3879
- 'attr_spec_list' => array(
3880
- '[disabled]' => array(),
3881
- 'disabled' => array(),
3882
- 'name' => array(
3883
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
3884
- ),
3885
- ),
3886
- 'tag_spec' => array(),
3887
- ),
3888
- ),
3889
- 'figcaption' => array(
3890
- array(
3891
- 'attr_spec_list' => array(),
3892
- 'tag_spec' => array(),
3893
- ),
3894
- ),
3895
- 'figure' => array(
3896
- array(
3897
- 'attr_spec_list' => array(),
3898
- 'tag_spec' => array(),
3899
- ),
3900
- ),
3901
- 'filter' => array(
3902
- array(
3903
- 'attr_spec_list' => array(
3904
- 'alignment-baseline' => array(),
3905
- 'baseline-shift' => array(),
3906
- 'clip' => array(),
3907
- 'clip-path' => array(),
3908
- 'clip-rule' => array(),
3909
- 'color' => array(),
3910
- 'color-interpolation' => array(),
3911
- 'color-interpolation-filters' => array(),
3912
- 'color-profile' => array(),
3913
- 'color-rendering' => array(),
3914
- 'cursor' => array(),
3915
- 'direction' => array(),
3916
- 'display' => array(),
3917
- 'dominant-baseline' => array(),
3918
- 'enable-background' => array(),
3919
- 'externalresourcesrequired' => array(),
3920
- 'fill' => array(),
3921
- 'fill-opacity' => array(),
3922
- 'fill-rule' => array(),
3923
- 'filter' => array(),
3924
- 'filterres' => array(),
3925
- 'filterunits' => array(),
3926
- 'flood-color' => array(),
3927
- 'flood-opacity' => array(),
3928
- 'font-family' => array(),
3929
- 'font-size' => array(),
3930
- 'font-size-adjust' => array(),
3931
- 'font-stretch' => array(),
3932
- 'font-style' => array(),
3933
- 'font-variant' => array(),
3934
- 'font-weight' => array(),
3935
- 'glyph-orientation-horizontal' => array(),
3936
- 'glyph-orientation-vertical' => array(),
3937
- 'height' => array(),
3938
- 'image-rendering' => array(),
3939
- 'kerning' => array(),
3940
- 'letter-spacing' => array(),
3941
- 'lighting-color' => array(),
3942
- 'marker-end' => array(),
3943
- 'marker-mid' => array(),
3944
- 'marker-start' => array(),
3945
- 'mask' => array(),
3946
- 'opacity' => array(),
3947
- 'overflow' => array(),
3948
- 'pointer-events' => array(),
3949
- 'primitiveunits' => array(),
3950
- 'shape-rendering' => array(),
3951
- 'stop-color' => array(),
3952
- 'stop-opacity' => array(),
3953
- 'stroke' => array(),
3954
- 'stroke-dasharray' => array(),
3955
- 'stroke-dashoffset' => array(),
3956
- 'stroke-linecap' => array(),
3957
- 'stroke-linejoin' => array(),
3958
- 'stroke-miterlimit' => array(),
3959
- 'stroke-opacity' => array(),
3960
- 'stroke-width' => array(),
3961
- 'style' => array(
3962
- 'blacklisted_value_regex' => '!important',
3963
- ),
3964
- 'text-anchor' => array(),
3965
- 'text-decoration' => array(),
3966
- 'text-rendering' => array(),
3967
- 'unicode-bidi' => array(),
3968
- 'vector-effect' => array(),
3969
- 'visibility' => array(),
3970
- 'width' => array(),
3971
- 'word-spacing' => array(),
3972
- 'writing-mode' => array(),
3973
- 'x' => array(),
3974
- 'xlink:actuate' => array(),
3975
- 'xlink:arcrole' => array(),
3976
- 'xlink:href' => array(
3977
- 'alternative_names' => array(
3978
- 'href',
3979
- ),
3980
- 'value_url' => array(
3981
- 'allow_empty' => false,
3982
- 'allow_relative' => true,
3983
- 'allowed_protocol' => array(
3984
- 'http',
3985
- 'https',
3986
- ),
3987
- ),
3988
- ),
3989
- 'xlink:role' => array(),
3990
- 'xlink:show' => array(),
3991
- 'xlink:title' => array(),
3992
- 'xlink:type' => array(),
3993
- 'xml:lang' => array(),
3994
- 'xml:space' => array(),
3995
- 'xmlns' => array(),
3996
- 'xmlns:xlink' => array(),
3997
- 'y' => array(),
3998
- ),
3999
- 'tag_spec' => array(
4000
- 'mandatory_ancestor' => 'svg',
4001
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4002
- ),
4003
- ),
4004
- ),
4005
- 'footer' => array(
4006
- array(
4007
- 'attr_spec_list' => array(),
4008
- 'tag_spec' => array(),
4009
- ),
4010
- ),
4011
- 'foreignobject' => array(
4012
- array(
4013
- 'attr_spec_list' => array(
4014
- 'alignment-baseline' => array(),
4015
- 'baseline-shift' => array(),
4016
- 'clip' => array(),
4017
- 'clip-path' => array(),
4018
- 'clip-rule' => array(),
4019
- 'color' => array(),
4020
- 'color-interpolation' => array(),
4021
- 'color-interpolation-filters' => array(),
4022
- 'color-profile' => array(),
4023
- 'color-rendering' => array(),
4024
- 'cursor' => array(),
4025
- 'direction' => array(),
4026
- 'display' => array(),
4027
- 'dominant-baseline' => array(),
4028
- 'enable-background' => array(),
4029
- 'externalresourcesrequired' => array(),
4030
- 'fill' => array(),
4031
- 'fill-opacity' => array(),
4032
- 'fill-rule' => array(),
4033
- 'filter' => array(),
4034
- 'flood-color' => array(),
4035
- 'flood-opacity' => array(),
4036
- 'font-family' => array(),
4037
- 'font-size' => array(),
4038
- 'font-size-adjust' => array(),
4039
- 'font-stretch' => array(),
4040
- 'font-style' => array(),
4041
- 'font-variant' => array(),
4042
- 'font-weight' => array(),
4043
- 'glyph-orientation-horizontal' => array(),
4044
- 'glyph-orientation-vertical' => array(),
4045
- 'height' => array(),
4046
- 'image-rendering' => array(),
4047
- 'kerning' => array(),
4048
- 'letter-spacing' => array(),
4049
- 'lighting-color' => array(),
4050
- 'marker-end' => array(),
4051
- 'marker-mid' => array(),
4052
- 'marker-start' => array(),
4053
- 'mask' => array(),
4054
- 'opacity' => array(),
4055
- 'overflow' => array(),
4056
- 'pointer-events' => array(),
4057
- 'requiredextensions' => array(),
4058
- 'requiredfeatures' => array(),
4059
- 'shape-rendering' => array(),
4060
- 'stop-color' => array(),
4061
- 'stop-opacity' => array(),
4062
- 'stroke' => array(),
4063
- 'stroke-dasharray' => array(),
4064
- 'stroke-dashoffset' => array(),
4065
- 'stroke-linecap' => array(),
4066
- 'stroke-linejoin' => array(),
4067
- 'stroke-miterlimit' => array(),
4068
- 'stroke-opacity' => array(),
4069
- 'stroke-width' => array(),
4070
- 'style' => array(
4071
- 'blacklisted_value_regex' => '!important',
4072
- ),
4073
- 'systemlanguage' => array(),
4074
- 'text-anchor' => array(),
4075
- 'text-decoration' => array(),
4076
- 'text-rendering' => array(),
4077
- 'transform' => array(),
4078
- 'unicode-bidi' => array(),
4079
- 'vector-effect' => array(),
4080
- 'visibility' => array(),
4081
- 'width' => array(),
4082
- 'word-spacing' => array(),
4083
- 'writing-mode' => array(),
4084
- 'x' => array(),
4085
- 'xml:lang' => array(),
4086
- 'xml:space' => array(),
4087
- 'xmlns' => array(),
4088
- 'xmlns:xlink' => array(),
4089
- 'y' => array(),
4090
- ),
4091
- 'tag_spec' => array(
4092
- 'mandatory_ancestor' => 'svg',
4093
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4094
- ),
4095
- ),
4096
- ),
4097
- 'form' => array(
4098
- array(
4099
- 'attr_spec_list' => array(
4100
- 'accept' => array(),
4101
- 'accept-charset' => array(),
4102
- 'action' => array(
4103
- 'blacklisted_value_regex' => '__amp_source_origin',
4104
- 'mandatory' => true,
4105
- 'value_url' => array(
4106
- 'allow_relative' => true,
4107
- 'allowed_protocol' => array(
4108
- 'https',
4109
- ),
4110
- ),
4111
- ),
4112
- 'action-xhr' => array(
4113
- 'blacklisted_value_regex' => '__amp_source_origin',
4114
- 'value_url' => array(
4115
- 'allow_relative' => true,
4116
- 'allowed_protocol' => array(
4117
- 'https',
4118
- ),
4119
- ),
4120
- ),
4121
- 'autocomplete' => array(),
4122
- 'custom-validation-reporting' => array(
4123
- 'value_regex' => '(show-first-on-submit|show-all-on-submit|as-you-go|interact-and-submit)',
4124
- ),
4125
- 'enctype' => array(),
4126
- 'method' => array(
4127
- 'value_casei' => 'get',
4128
- ),
4129
- 'name' => array(),
4130
- 'novalidate' => array(),
4131
- 'target' => array(
4132
- 'mandatory' => true,
4133
- 'value_regex_casei' => '(_blank|_top)',
4134
- ),
4135
- 'verify-xhr' => array(
4136
- 'blacklisted_value_regex' => '__amp_source_origin',
4137
- 'value_url' => array(
4138
- 'allow_relative' => true,
4139
- 'allowed_protocol' => array(
4140
- 'https',
4141
- ),
4142
- ),
4143
- ),
4144
- ),
4145
- 'tag_spec' => array(
4146
- 'disallowed_ancestor' => array(
4147
- 'amp-app-banner',
4148
- ),
4149
- 'requires_extension' => array(
4150
- 'amp-form',
4151
- ),
4152
- 'spec_name' => 'FORM [method=GET]',
4153
- ),
4154
- ),
4155
- array(
4156
- 'attr_spec_list' => array(
4157
- 'accept' => array(),
4158
- 'accept-charset' => array(),
4159
- 'action-xhr' => array(
4160
- 'blacklisted_value_regex' => '__amp_source_origin',
4161
- 'mandatory' => true,
4162
- 'value_url' => array(
4163
- 'allow_relative' => true,
4164
- 'allowed_protocol' => array(
4165
- 'https',
4166
- ),
4167
- ),
4168
- ),
4169
- 'autocomplete' => array(),
4170
- 'custom-validation-reporting' => array(
4171
- 'value_regex' => '(show-first-on-submit|show-all-on-submit|as-you-go)',
4172
- ),
4173
- 'enctype' => array(),
4174
- 'method' => array(
4175
- 'dispatch_key' => 2,
4176
- 'mandatory' => true,
4177
- 'value_casei' => 'post',
4178
- ),
4179
- 'name' => array(),
4180
- 'novalidate' => array(),
4181
- 'target' => array(
4182
- 'mandatory' => true,
4183
- 'value_regex_casei' => '(_blank|_top)',
4184
- ),
4185
- 'verify-xhr' => array(
4186
- 'blacklisted_value_regex' => '__amp_source_origin',
4187
- 'value_url' => array(
4188
- 'allow_relative' => true,
4189
- 'allowed_protocol' => array(
4190
- 'https',
4191
- ),
4192
- ),
4193
- ),
4194
- ),
4195
- 'tag_spec' => array(
4196
- 'disallowed_ancestor' => array(
4197
- 'amp-app-banner',
4198
- ),
4199
- 'requires_extension' => array(
4200
- 'amp-form',
4201
- ),
4202
- 'spec_name' => 'FORM [method=POST]',
4203
- ),
4204
- ),
4205
- ),
4206
- 'g' => array(
4207
- array(
4208
- 'attr_spec_list' => array(
4209
- 'alignment-baseline' => array(),
4210
- 'baseline-shift' => array(),
4211
- 'clip' => array(),
4212
- 'clip-path' => array(),
4213
- 'clip-rule' => array(),
4214
- 'color' => array(),
4215
- 'color-interpolation' => array(),
4216
- 'color-interpolation-filters' => array(),
4217
- 'color-profile' => array(),
4218
- 'color-rendering' => array(),
4219
- 'cursor' => array(),
4220
- 'direction' => array(),
4221
- 'display' => array(),
4222
- 'dominant-baseline' => array(),
4223
- 'enable-background' => array(),
4224
- 'externalresourcesrequired' => array(),
4225
- 'fill' => array(),
4226
- 'fill-opacity' => array(),
4227
- 'fill-rule' => array(),
4228
- 'filter' => array(),
4229
- 'flood-color' => array(),
4230
- 'flood-opacity' => array(),
4231
- 'font-family' => array(),
4232
- 'font-size' => array(),
4233
- 'font-size-adjust' => array(),
4234
- 'font-stretch' => array(),
4235
- 'font-style' => array(),
4236
- 'font-variant' => array(),
4237
- 'font-weight' => array(),
4238
- 'glyph-orientation-horizontal' => array(),
4239
- 'glyph-orientation-vertical' => array(),
4240
- 'image-rendering' => array(),
4241
- 'kerning' => array(),
4242
- 'letter-spacing' => array(),
4243
- 'lighting-color' => array(),
4244
- 'marker-end' => array(),
4245
- 'marker-mid' => array(),
4246
- 'marker-start' => array(),
4247
- 'mask' => array(),
4248
- 'opacity' => array(),
4249
- 'overflow' => array(),
4250
- 'pointer-events' => array(),
4251
- 'requiredextensions' => array(),
4252
- 'requiredfeatures' => array(),
4253
- 'shape-rendering' => array(),
4254
- 'stop-color' => array(),
4255
- 'stop-opacity' => array(),
4256
- 'stroke' => array(),
4257
- 'stroke-dasharray' => array(),
4258
- 'stroke-dashoffset' => array(),
4259
- 'stroke-linecap' => array(),
4260
- 'stroke-linejoin' => array(),
4261
- 'stroke-miterlimit' => array(),
4262
- 'stroke-opacity' => array(),
4263
- 'stroke-width' => array(),
4264
- 'style' => array(
4265
- 'blacklisted_value_regex' => '!important',
4266
- ),
4267
- 'systemlanguage' => array(),
4268
- 'text-anchor' => array(),
4269
- 'text-decoration' => array(),
4270
- 'text-rendering' => array(),
4271
- 'transform' => array(),
4272
- 'unicode-bidi' => array(),
4273
- 'vector-effect' => array(),
4274
- 'visibility' => array(),
4275
- 'word-spacing' => array(),
4276
- 'writing-mode' => array(),
4277
- 'xml:lang' => array(),
4278
- 'xml:space' => array(),
4279
- 'xmlns' => array(),
4280
- 'xmlns:xlink' => array(),
4281
- ),
4282
- 'tag_spec' => array(
4283
- 'mandatory_ancestor' => 'svg',
4284
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4285
- ),
4286
- ),
4287
- ),
4288
- 'glyph' => array(
4289
- array(
4290
- 'attr_spec_list' => array(
4291
- 'alignment-baseline' => array(),
4292
- 'arabic-form' => array(),
4293
- 'baseline-shift' => array(),
4294
- 'clip' => array(),
4295
- 'clip-path' => array(),
4296
- 'clip-rule' => array(),
4297
- 'color' => array(),
4298
- 'color-interpolation' => array(),
4299
- 'color-interpolation-filters' => array(),
4300
- 'color-profile' => array(),
4301
- 'color-rendering' => array(),
4302
- 'cursor' => array(),
4303
- 'd' => array(),
4304
- 'direction' => array(),
4305
- 'display' => array(),
4306
- 'dominant-baseline' => array(),
4307
- 'enable-background' => array(),
4308
- 'fill' => array(),
4309
- 'fill-opacity' => array(),
4310
- 'fill-rule' => array(),
4311
- 'filter' => array(),
4312
- 'flood-color' => array(),
4313
- 'flood-opacity' => array(),
4314
- 'font-family' => array(),
4315
- 'font-size' => array(),
4316
- 'font-size-adjust' => array(),
4317
- 'font-stretch' => array(),
4318
- 'font-style' => array(),
4319
- 'font-variant' => array(),
4320
- 'font-weight' => array(),
4321
- 'glyph-name' => array(),
4322
- 'glyph-orientation-horizontal' => array(),
4323
- 'glyph-orientation-vertical' => array(),
4324
- 'horiz-adv-x' => array(),
4325
- 'image-rendering' => array(),
4326
- 'kerning' => array(),
4327
- 'letter-spacing' => array(),
4328
- 'lighting-color' => array(),
4329
- 'marker-end' => array(),
4330
- 'marker-mid' => array(),
4331
- 'marker-start' => array(),
4332
- 'mask' => array(),
4333
- 'opacity' => array(),
4334
- 'orientation' => array(),
4335
- 'overflow' => array(),
4336
- 'pointer-events' => array(),
4337
- 'shape-rendering' => array(),
4338
- 'stop-color' => array(),
4339
- 'stop-opacity' => array(),
4340
- 'stroke' => array(),
4341
- 'stroke-dasharray' => array(),
4342
- 'stroke-dashoffset' => array(),
4343
- 'stroke-linecap' => array(),
4344
- 'stroke-linejoin' => array(),
4345
- 'stroke-miterlimit' => array(),
4346
- 'stroke-opacity' => array(),
4347
- 'stroke-width' => array(),
4348
- 'style' => array(
4349
- 'blacklisted_value_regex' => '!important',
4350
- ),
4351
- 'text-anchor' => array(),
4352
- 'text-decoration' => array(),
4353
- 'text-rendering' => array(),
4354
- 'unicode' => array(),
4355
- 'unicode-bidi' => array(),
4356
- 'vector-effect' => array(),
4357
- 'vert-adv-y' => array(),
4358
- 'vert-origin-x' => array(),
4359
- 'vert-origin-y' => array(),
4360
- 'visibility' => array(),
4361
- 'word-spacing' => array(),
4362
- 'writing-mode' => array(),
4363
- 'xml:lang' => array(),
4364
- 'xml:space' => array(),
4365
- 'xmlns' => array(),
4366
- 'xmlns:xlink' => array(),
4367
- ),
4368
- 'tag_spec' => array(
4369
- 'mandatory_ancestor' => 'svg',
4370
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4371
- ),
4372
- ),
4373
- ),
4374
- 'glyphref' => array(
4375
- array(
4376
- 'attr_spec_list' => array(
4377
- 'alignment-baseline' => array(),
4378
- 'baseline-shift' => array(),
4379
- 'clip' => array(),
4380
- 'clip-path' => array(),
4381
- 'clip-rule' => array(),
4382
- 'color' => array(),
4383
- 'color-interpolation' => array(),
4384
- 'color-interpolation-filters' => array(),
4385
- 'color-profile' => array(),
4386
- 'color-rendering' => array(),
4387
- 'cursor' => array(),
4388
- 'direction' => array(),
4389
- 'display' => array(),
4390
- 'dominant-baseline' => array(),
4391
- 'dx' => array(),
4392
- 'dy' => array(),
4393
- 'enable-background' => array(),
4394
- 'fill' => array(),
4395
- 'fill-opacity' => array(),
4396
- 'fill-rule' => array(),
4397
- 'filter' => array(),
4398
- 'flood-color' => array(),
4399
- 'flood-opacity' => array(),
4400
- 'font-family' => array(),
4401
- 'font-size' => array(),
4402
- 'font-size-adjust' => array(),
4403
- 'font-stretch' => array(),
4404
- 'font-style' => array(),
4405
- 'font-variant' => array(),
4406
- 'font-weight' => array(),
4407
- 'format' => array(),
4408
- 'glyph-orientation-horizontal' => array(),
4409
- 'glyph-orientation-vertical' => array(),
4410
- 'glyphref' => array(),
4411
- 'image-rendering' => array(),
4412
- 'kerning' => array(),
4413
- 'letter-spacing' => array(),
4414
- 'lighting-color' => array(),
4415
- 'marker-end' => array(),
4416
- 'marker-mid' => array(),
4417
- 'marker-start' => array(),
4418
- 'mask' => array(),
4419
- 'opacity' => array(),
4420
- 'overflow' => array(),
4421
- 'pointer-events' => array(),
4422
- 'shape-rendering' => array(),
4423
- 'stop-color' => array(),
4424
- 'stop-opacity' => array(),
4425
- 'stroke' => array(),
4426
- 'stroke-dasharray' => array(),
4427
- 'stroke-dashoffset' => array(),
4428
- 'stroke-linecap' => array(),
4429
- 'stroke-linejoin' => array(),
4430
- 'stroke-miterlimit' => array(),
4431
- 'stroke-opacity' => array(),
4432
- 'stroke-width' => array(),
4433
- 'style' => array(
4434
- 'blacklisted_value_regex' => '!important',
4435
- ),
4436
- 'text-anchor' => array(),
4437
- 'text-decoration' => array(),
4438
- 'text-rendering' => array(),
4439
- 'unicode-bidi' => array(),
4440
- 'vector-effect' => array(),
4441
- 'visibility' => array(),
4442
- 'word-spacing' => array(),
4443
- 'writing-mode' => array(),
4444
- 'x' => array(),
4445
- 'xlink:actuate' => array(),
4446
- 'xlink:arcrole' => array(),
4447
- 'xlink:href' => array(
4448
- 'alternative_names' => array(
4449
- 'href',
4450
- ),
4451
- 'value_url' => array(
4452
- 'allow_empty' => false,
4453
- 'allow_relative' => true,
4454
- 'allowed_protocol' => array(
4455
- 'http',
4456
- 'https',
4457
- ),
4458
- ),
4459
- ),
4460
- 'xlink:role' => array(),
4461
- 'xlink:show' => array(),
4462
- 'xlink:title' => array(),
4463
- 'xlink:type' => array(),
4464
- 'xml:lang' => array(),
4465
- 'xml:space' => array(),
4466
- 'xmlns' => array(),
4467
- 'xmlns:xlink' => array(),
4468
- 'y' => array(),
4469
- ),
4470
- 'tag_spec' => array(
4471
- 'mandatory_ancestor' => 'svg',
4472
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4473
- ),
4474
- ),
4475
- ),
4476
- 'h1' => array(
4477
- array(
4478
- 'attr_spec_list' => array(
4479
- 'align' => array(),
4480
- ),
4481
- 'tag_spec' => array(),
4482
- ),
4483
- ),
4484
- 'h2' => array(
4485
- array(
4486
- 'attr_spec_list' => array(
4487
- 'align' => array(),
4488
- ),
4489
- 'tag_spec' => array(),
4490
- ),
4491
- ),
4492
- 'h3' => array(
4493
- array(
4494
- 'attr_spec_list' => array(
4495
- 'align' => array(),
4496
- ),
4497
- 'tag_spec' => array(),
4498
- ),
4499
- ),
4500
- 'h4' => array(
4501
- array(
4502
- 'attr_spec_list' => array(
4503
- 'align' => array(),
4504
- ),
4505
- 'tag_spec' => array(),
4506
- ),
4507
- ),
4508
- 'h5' => array(
4509
- array(
4510
- 'attr_spec_list' => array(
4511
- 'align' => array(),
4512
- ),
4513
- 'tag_spec' => array(),
4514
- ),
4515
- ),
4516
- 'h6' => array(
4517
- array(
4518
- 'attr_spec_list' => array(
4519
- 'align' => array(),
4520
- ),
4521
- 'tag_spec' => array(),
4522
- ),
4523
- ),
4524
- 'head' => array(
4525
- array(
4526
- 'attr_spec_list' => array(),
4527
- 'tag_spec' => array(
4528
- 'mandatory' => true,
4529
- 'mandatory_parent' => 'html',
4530
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
4531
- 'unique' => true,
4532
- ),
4533
- ),
4534
- ),
4535
- 'header' => array(
4536
- array(
4537
- 'attr_spec_list' => array(),
4538
- 'tag_spec' => array(),
4539
- ),
4540
- ),
4541
- 'hgroup' => array(
4542
- array(
4543
- 'attr_spec_list' => array(),
4544
- 'tag_spec' => array(),
4545
- ),
4546
- ),
4547
- 'hkern' => array(
4548
- array(
4549
- 'attr_spec_list' => array(
4550
- 'g1' => array(),
4551
- 'g2' => array(),
4552
- 'k' => array(),
4553
- 'style' => array(
4554
- 'blacklisted_value_regex' => '!important',
4555
- ),
4556
- 'u1' => array(),
4557
- 'u2' => array(),
4558
- 'xml:lang' => array(),
4559
- 'xml:space' => array(),
4560
- 'xmlns' => array(),
4561
- 'xmlns:xlink' => array(),
4562
- ),
4563
- 'tag_spec' => array(
4564
- 'mandatory_ancestor' => 'svg',
4565
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4566
- ),
4567
- ),
4568
- ),
4569
- 'hr' => array(
4570
- array(
4571
- 'attr_spec_list' => array(),
4572
- 'tag_spec' => array(),
4573
- ),
4574
- ),
4575
- 'html' => array(
4576
- array(
4577
- 'attr_spec_list' => array(
4578
- '\\u26a1' => array(
4579
- 'alternative_names' => array(
4580
- 'amp',
4581
- ),
4582
- 'mandatory' => true,
4583
- 'value' => '',
4584
- ),
4585
- ),
4586
- 'tag_spec' => array(
4587
- 'mandatory' => true,
4588
- 'mandatory_parent' => '!doctype',
4589
- 'spec_name' => 'html \\u26a1 for top-level html',
4590
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
4591
- 'unique' => true,
4592
- ),
4593
- ),
4594
- ),
4595
- 'i' => array(
4596
- array(
4597
- 'attr_spec_list' => array(),
4598
- 'tag_spec' => array(),
4599
- ),
4600
- ),
4601
- 'iframe' => array(
4602
- array(
4603
- 'attr_spec_list' => array(
4604
- 'frameborder' => array(
4605
- 'value_regex' => '0|1',
4606
- ),
4607
- 'height' => array(),
4608
- 'name' => array(),
4609
- 'referrerpolicy' => array(),
4610
- 'resizable' => array(
4611
- 'value' => '',
4612
- ),
4613
- 'sandbox' => array(),
4614
- 'scrolling' => array(
4615
- 'value_regex' => 'auto|yes|no',
4616
- ),
4617
- 'src' => array(
4618
- 'blacklisted_value_regex' => '__amp_source_origin',
4619
- 'value_url' => array(
4620
- 'allow_relative' => false,
4621
- 'allowed_protocol' => array(
4622
- 'data',
4623
- 'https',
4624
- ),
4625
- ),
4626
- ),
4627
- 'srcdoc' => array(),
4628
- 'width' => array(),
4629
- ),
4630
- 'tag_spec' => array(
4631
- 'mandatory_ancestor' => 'noscript',
4632
- 'mandatory_ancestor_suggested_alternative' => 'amp-iframe',
4633
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-iframe',
4634
- ),
4635
- ),
4636
- ),
4637
- 'image' => array(
4638
- array(
4639
- 'attr_spec_list' => array(
4640
- 'alignment-baseline' => array(),
4641
- 'baseline-shift' => array(),
4642
- 'clip' => array(),
4643
- 'clip-path' => array(),
4644
- 'clip-rule' => array(),
4645
- 'color' => array(),
4646
- 'color-interpolation' => array(),
4647
- 'color-interpolation-filters' => array(),
4648
- 'color-profile' => array(),
4649
- 'color-rendering' => array(),
4650
- 'cursor' => array(),
4651
- 'direction' => array(),
4652
- 'display' => array(),
4653
- 'dominant-baseline' => array(),
4654
- 'enable-background' => array(),
4655
- 'externalresourcesrequired' => array(),
4656
- 'fill' => array(),
4657
- 'fill-opacity' => array(),
4658
- 'fill-rule' => array(),
4659
- 'filter' => array(),
4660
- 'flood-color' => array(),
4661
- 'flood-opacity' => array(),
4662
- 'font-family' => array(),
4663
- 'font-size' => array(),
4664
- 'font-size-adjust' => array(),
4665
- 'font-stretch' => array(),
4666
- 'font-style' => array(),
4667
- 'font-variant' => array(),
4668
- 'font-weight' => array(),
4669
- 'glyph-orientation-horizontal' => array(),
4670
- 'glyph-orientation-vertical' => array(),
4671
- 'height' => array(),
4672
- 'image-rendering' => array(),
4673
- 'kerning' => array(),
4674
- 'letter-spacing' => array(),
4675
- 'lighting-color' => array(),
4676
- 'marker-end' => array(),
4677
- 'marker-mid' => array(),
4678
- 'marker-start' => array(),
4679
- 'mask' => array(),
4680
- 'opacity' => array(),
4681
- 'overflow' => array(),
4682
- 'pointer-events' => array(),
4683
- 'preserveaspectratio' => array(),
4684
- 'requiredextensions' => array(),
4685
- 'requiredfeatures' => array(),
4686
- 'shape-rendering' => array(),
4687
- 'stop-color' => array(),
4688
- 'stop-opacity' => array(),
4689
- 'stroke' => array(),
4690
- 'stroke-dasharray' => array(),
4691
- 'stroke-dashoffset' => array(),
4692
- 'stroke-linecap' => array(),
4693
- 'stroke-linejoin' => array(),
4694
- 'stroke-miterlimit' => array(),
4695
- 'stroke-opacity' => array(),
4696
- 'stroke-width' => array(),
4697
- 'style' => array(
4698
- 'blacklisted_value_regex' => '!important',
4699
- ),
4700
- 'systemlanguage' => array(),
4701
- 'text-anchor' => array(),
4702
- 'text-decoration' => array(),
4703
- 'text-rendering' => array(),
4704
- 'transform' => array(),
4705
- 'unicode-bidi' => array(),
4706
- 'vector-effect' => array(),
4707
- 'visibility' => array(),
4708
- 'width' => array(),
4709
- 'word-spacing' => array(),
4710
- 'writing-mode' => array(),
4711
- 'x' => array(),
4712
- 'xlink:actuate' => array(),
4713
- 'xlink:arcrole' => array(),
4714
- 'xlink:href' => array(
4715
- 'alternative_names' => array(
4716
- 'href',
4717
- ),
4718
- 'blacklisted_value_regex' => '(^|\\s)data:image\\/svg\\+xml',
4719
- 'value_url' => array(
4720
- 'allow_empty' => false,
4721
- 'allow_relative' => true,
4722
- 'allowed_protocol' => array(
4723
- 'data',
4724
- 'http',
4725
- 'https',
4726
- ),
4727
- ),
4728
- ),
4729
- 'xlink:role' => array(),
4730
- 'xlink:show' => array(),
4731
- 'xlink:title' => array(),
4732
- 'xlink:type' => array(),
4733
- 'xml:lang' => array(),
4734
- 'xml:space' => array(),
4735
- 'xmlns' => array(),
4736
- 'xmlns:xlink' => array(),
4737
- 'y' => array(),
4738
- ),
4739
- 'tag_spec' => array(
4740
- 'mandatory_ancestor' => 'svg',
4741
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4742
- ),
4743
- ),
4744
- ),
4745
- 'img' => array(
4746
- array(
4747
- 'attr_spec_list' => array(
4748
- 'alt' => array(),
4749
- 'border' => array(),
4750
- 'height' => array(),
4751
- 'ismap' => array(),
4752
- 'longdesc' => array(
4753
- 'blacklisted_value_regex' => '__amp_source_origin',
4754
- 'value_url' => array(
4755
- 'allow_relative' => true,
4756
- 'allowed_protocol' => array(
4757
- 'http',
4758
- 'https',
4759
- ),
4760
- ),
4761
- ),
4762
- 'src' => array(
4763
- 'alternative_names' => array(
4764
- 'srcset',
4765
- ),
4766
- 'blacklisted_value_regex' => '__amp_source_origin',
4767
- 'mandatory' => true,
4768
- 'value_url' => array(
4769
- 'allow_relative' => true,
4770
- 'allowed_protocol' => array(
4771
- 'data',
4772
- 'https',
4773
- ),
4774
- ),
4775
- ),
4776
- 'width' => array(),
4777
- ),
4778
- 'tag_spec' => array(
4779
- 'mandatory_ancestor' => 'noscript',
4780
- 'mandatory_ancestor_suggested_alternative' => 'amp-img',
4781
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-img',
4782
- ),
4783
- ),
4784
- ),
4785
- 'input' => array(
4786
- array(
4787
- 'attr_spec_list' => array(
4788
- '[accept]' => array(),
4789
- '[accesskey]' => array(),
4790
- '[autocomplete]' => array(),
4791
- '[checked]' => array(),
4792
- '[disabled]' => array(),
4793
- '[height]' => array(),
4794
- '[inputmode]' => array(),
4795
- '[max]' => array(),
4796
- '[maxlength]' => array(),
4797
- '[min]' => array(),
4798
- '[minlength]' => array(),
4799
- '[multiple]' => array(),
4800
- '[pattern]' => array(),
4801
- '[placeholder]' => array(),
4802
- '[readonly]' => array(),
4803
- '[required]' => array(),
4804
- '[selectiondirection]' => array(),
4805
- '[size]' => array(),
4806
- '[spellcheck]' => array(),
4807
- '[step]' => array(),
4808
- '[type]' => array(),
4809
- '[value]' => array(),
4810
- '[width]' => array(),
4811
- 'accept' => array(),
4812
- 'accesskey' => array(),
4813
- 'autocomplete' => array(),
4814
- 'autofocus' => array(),
4815
- 'checked' => array(),
4816
- 'disabled' => array(),
4817
- 'height' => array(),
4818
- 'inputmode' => array(),
4819
- 'list' => array(),
4820
- 'max' => array(),
4821
- 'maxlength' => array(),
4822
- 'min' => array(),
4823
- 'minlength' => array(),
4824
- 'multiple' => array(),
4825
- 'name' => array(
4826
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
4827
- ),
4828
- 'pattern' => array(),
4829
- 'placeholder' => array(),
4830
- 'readonly' => array(),
4831
- 'required' => array(),
4832
- 'selectiondirection' => array(),
4833
- 'size' => array(),
4834
- 'spellcheck' => array(),
4835
- 'step' => array(),
4836
- 'tabindex' => array(),
4837
- 'type' => array(
4838
- 'blacklisted_value_regex' => '(^|\\s)(button|file|image|password|)(\\s|$)',
4839
- ),
4840
- 'value' => array(),
4841
- 'width' => array(),
4842
- ),
4843
- 'tag_spec' => array(
4844
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
4845
- ),
4846
- ),
4847
- ),
4848
- 'ins' => array(
4849
- array(
4850
- 'attr_spec_list' => array(
4851
- 'cite' => array(
4852
- 'blacklisted_value_regex' => '__amp_source_origin',
4853
- 'value_url' => array(
4854
- 'allow_empty' => true,
4855
- 'allow_relative' => true,
4856
- 'allowed_protocol' => array(
4857
- 'http',
4858
- 'https',
4859
- ),
4860
- ),
4861
- ),
4862
- 'datetime' => array(),
4863
- ),
4864
- 'tag_spec' => array(),
4865
- ),
4866
- ),
4867
- 'kbd' => array(
4868
- array(
4869
- 'attr_spec_list' => array(),
4870
- 'tag_spec' => array(),
4871
- ),
4872
- ),
4873
- 'label' => array(
4874
- array(
4875
- 'attr_spec_list' => array(
4876
- 'for' => array(),
4877
- ),
4878
- 'tag_spec' => array(
4879
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
4880
- ),
4881
- ),
4882
- ),
4883
- 'legend' => array(
4884
- array(
4885
- 'attr_spec_list' => array(),
4886
- 'tag_spec' => array(),
4887
- ),
4888
- ),
4889
- 'li' => array(
4890
- array(
4891
- 'attr_spec_list' => array(
4892
- 'value' => array(
4893
- 'value_regex' => '[0-9]*',
4894
- ),
4895
- ),
4896
- 'tag_spec' => array(),
4897
- ),
4898
- ),
4899
- 'line' => array(
4900
- array(
4901
- 'attr_spec_list' => array(
4902
- 'alignment-baseline' => array(),
4903
- 'baseline-shift' => array(),
4904
- 'clip' => array(),
4905
- 'clip-path' => array(),
4906
- 'clip-rule' => array(),
4907
- 'color' => array(),
4908
- 'color-interpolation' => array(),
4909
- 'color-interpolation-filters' => array(),
4910
- 'color-profile' => array(),
4911
- 'color-rendering' => array(),
4912
- 'cursor' => array(),
4913
- 'direction' => array(),
4914
- 'display' => array(),
4915
- 'dominant-baseline' => array(),
4916
- 'enable-background' => array(),
4917
- 'externalresourcesrequired' => array(),
4918
- 'fill' => array(),
4919
- 'fill-opacity' => array(),
4920
- 'fill-rule' => array(),
4921
- 'filter' => array(),
4922
- 'flood-color' => array(),
4923
- 'flood-opacity' => array(),
4924
- 'font-family' => array(),
4925
- 'font-size' => array(),
4926
- 'font-size-adjust' => array(),
4927
- 'font-stretch' => array(),
4928
- 'font-style' => array(),
4929
- 'font-variant' => array(),
4930
- 'font-weight' => array(),
4931
- 'glyph-orientation-horizontal' => array(),
4932
- 'glyph-orientation-vertical' => array(),
4933
- 'image-rendering' => array(),
4934
- 'kerning' => array(),
4935
- 'letter-spacing' => array(),
4936
- 'lighting-color' => array(),
4937
- 'marker-end' => array(),
4938
- 'marker-mid' => array(),
4939
- 'marker-start' => array(),
4940
- 'mask' => array(),
4941
- 'opacity' => array(),
4942
- 'overflow' => array(),
4943
- 'pointer-events' => array(),
4944
- 'requiredextensions' => array(),
4945
- 'requiredfeatures' => array(),
4946
- 'shape-rendering' => array(),
4947
- 'sketch:type' => array(),
4948
- 'stop-color' => array(),
4949
- 'stop-opacity' => array(),
4950
- 'stroke' => array(),
4951
- 'stroke-dasharray' => array(),
4952
- 'stroke-dashoffset' => array(),
4953
- 'stroke-linecap' => array(),
4954
- 'stroke-linejoin' => array(),
4955
- 'stroke-miterlimit' => array(),
4956
- 'stroke-opacity' => array(),
4957
- 'stroke-width' => array(),
4958
- 'style' => array(
4959
- 'blacklisted_value_regex' => '!important',
4960
- ),
4961
- 'systemlanguage' => array(),
4962
- 'text-anchor' => array(),
4963
- 'text-decoration' => array(),
4964
- 'text-rendering' => array(),
4965
- 'transform' => array(),
4966
- 'unicode-bidi' => array(),
4967
- 'vector-effect' => array(),
4968
- 'visibility' => array(),
4969
- 'word-spacing' => array(),
4970
- 'writing-mode' => array(),
4971
- 'x1' => array(),
4972
- 'x2' => array(),
4973
- 'xml:lang' => array(),
4974
- 'xml:space' => array(),
4975
- 'xmlns' => array(),
4976
- 'xmlns:xlink' => array(),
4977
- 'y1' => array(),
4978
- 'y2' => array(),
4979
- ),
4980
- 'tag_spec' => array(
4981
- 'mandatory_ancestor' => 'svg',
4982
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4983
- ),
4984
- ),
4985
- ),
4986
- 'lineargradient' => array(
4987
- array(
4988
- 'attr_spec_list' => array(
4989
- 'alignment-baseline' => array(),
4990
- 'baseline-shift' => array(),
4991
- 'clip' => array(),
4992
- 'clip-path' => array(),
4993
- 'clip-rule' => array(),
4994
- 'color' => array(),
4995
- 'color-interpolation' => array(),
4996
- 'color-interpolation-filters' => array(),
4997
- 'color-profile' => array(),
4998
- 'color-rendering' => array(),
4999
- 'cursor' => array(),
5000
- 'direction' => array(),
5001
- 'display' => array(),
5002
- 'dominant-baseline' => array(),
5003
- 'enable-background' => array(),
5004
- 'externalresourcesrequired' => array(),
5005
- 'fill' => array(),
5006
- 'fill-opacity' => array(),
5007
- 'fill-rule' => array(),
5008
- 'filter' => array(),
5009
- 'flood-color' => array(),
5010
- 'flood-opacity' => array(),
5011
- 'font-family' => array(),
5012
- 'font-size' => array(),
5013
- 'font-size-adjust' => array(),
5014
- 'font-stretch' => array(),
5015
- 'font-style' => array(),
5016
- 'font-variant' => array(),
5017
- 'font-weight' => array(),
5018
- 'glyph-orientation-horizontal' => array(),
5019
- 'glyph-orientation-vertical' => array(),
5020
- 'gradienttransform' => array(),
5021
- 'gradientunits' => array(),
5022
- 'image-rendering' => array(),
5023
- 'kerning' => array(),
5024
- 'letter-spacing' => array(),
5025
- 'lighting-color' => array(),
5026
- 'marker-end' => array(),
5027
- 'marker-mid' => array(),
5028
- 'marker-start' => array(),
5029
- 'mask' => array(),
5030
- 'opacity' => array(),
5031
- 'overflow' => array(),
5032
- 'pointer-events' => array(),
5033
- 'shape-rendering' => array(),
5034
- 'spreadmethod' => array(),
5035
- 'stop-color' => array(),
5036
- 'stop-opacity' => array(),
5037
- 'stroke' => array(),
5038
- 'stroke-dasharray' => array(),
5039
- 'stroke-dashoffset' => array(),
5040
- 'stroke-linecap' => array(),
5041
- 'stroke-linejoin' => array(),
5042
- 'stroke-miterlimit' => array(),
5043
- 'stroke-opacity' => array(),
5044
- 'stroke-width' => array(),
5045
- 'style' => array(
5046
- 'blacklisted_value_regex' => '!important',
5047
- ),
5048
- 'text-anchor' => array(),
5049
- 'text-decoration' => array(),
5050
- 'text-rendering' => array(),
5051
- 'unicode-bidi' => array(),
5052
- 'vector-effect' => array(),
5053
- 'visibility' => array(),
5054
- 'word-spacing' => array(),
5055
- 'writing-mode' => array(),
5056
- 'x1' => array(),
5057
- 'x2' => array(),
5058
- 'xlink:actuate' => array(),
5059
- 'xlink:arcrole' => array(),
5060
- 'xlink:href' => array(
5061
- 'alternative_names' => array(
5062
- 'href',
5063
- ),
5064
- 'value_url' => array(
5065
- 'allow_empty' => false,
5066
- 'allow_relative' => true,
5067
- 'allowed_protocol' => array(
5068
- 'http',
5069
- 'https',
5070
- ),
5071
- ),
5072
- ),
5073
- 'xlink:role' => array(),
5074
- 'xlink:show' => array(),
5075
- 'xlink:title' => array(),
5076
- 'xlink:type' => array(),
5077
- 'xml:lang' => array(),
5078
- 'xml:space' => array(),
5079
- 'xmlns' => array(),
5080
- 'xmlns:xlink' => array(),
5081
- 'y1' => array(),
5082
- 'y2' => array(),
5083
- ),
5084
- 'tag_spec' => array(
5085
- 'mandatory_ancestor' => 'svg',
5086
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
5087
- ),
5088
- ),
5089
- ),
5090
- 'link' => array(
5091
- array(
5092
- 'attr_spec_list' => array(
5093
- 'charset' => array(
5094
- 'value_casei' => 'utf-8',
5095
- ),
5096
- 'color' => array(),
5097
- 'crossorigin' => array(),
5098
- 'href' => array(),
5099
- 'hreflang' => array(),
5100
- 'media' => array(),
5101
- 'rel' => array(
5102
- 'blacklisted_value_regex' => '(^|\\s)(canonical|components|import|manifest|preload|serviceworker|stylesheet|subresource|)(\\s|$)',
5103
- 'mandatory' => true,
5104
- ),
5105
- 'sizes' => array(),
5106
- 'target' => array(),
5107
- 'type' => array(),
5108
- ),
5109
- 'tag_spec' => array(
5110
- 'disallowed_ancestor' => array(
5111
- 'template',
5112
- ),
5113
- 'spec_name' => 'link rel=',
5114
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5115
- ),
5116
- ),
5117
- array(
5118
- 'attr_spec_list' => array(
5119
- 'charset' => array(
5120
- 'value_casei' => 'utf-8',
5121
- ),
5122
- 'color' => array(),
5123
- 'crossorigin' => array(),
5124
- 'href' => array(
5125
- 'blacklisted_value_regex' => '__amp_source_origin',
5126
- 'mandatory' => true,
5127
- 'value_url' => array(
5128
- 'allow_relative' => true,
5129
- 'allowed_protocol' => array(
5130
- 'http',
5131
- 'https',
5132
- ),
5133
- ),
5134
- ),
5135
- 'hreflang' => array(),
5136
- 'media' => array(),
5137
- 'rel' => array(
5138
- 'dispatch_key' => 2,
5139
- 'mandatory' => true,
5140
- 'value_casei' => 'canonical',
5141
- ),
5142
- 'sizes' => array(),
5143
- 'target' => array(),
5144
- 'type' => array(),
5145
- ),
5146
- 'tag_spec' => array(
5147
- 'mandatory' => true,
5148
- 'mandatory_parent' => 'head',
5149
- 'spec_name' => 'link rel=canonical',
5150
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
5151
- 'unique' => true,
5152
- ),
5153
- ),
5154
- array(
5155
- 'attr_spec_list' => array(
5156
- 'charset' => array(
5157
- 'value_casei' => 'utf-8',
5158
- ),
5159
- 'color' => array(),
5160
- 'crossorigin' => array(),
5161
- 'href' => array(
5162
- 'blacklisted_value_regex' => '__amp_source_origin',
5163
- 'mandatory' => true,
5164
- 'value_url' => array(
5165
- 'allow_relative' => true,
5166
- 'allowed_protocol' => array(
5167
- 'https',
5168
- ),
5169
- ),
5170
- ),
5171
- 'hreflang' => array(),
5172
- 'media' => array(),
5173
- 'rel' => array(
5174
- 'dispatch_key' => 2,
5175
- 'mandatory' => true,
5176
- 'value_casei' => 'manifest',
5177
- ),
5178
- 'sizes' => array(),
5179
- 'target' => array(),
5180
- 'type' => array(),
5181
- ),
5182
- 'tag_spec' => array(
5183
- 'mandatory_parent' => 'head',
5184
- 'spec_name' => 'link rel=manifest',
5185
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5186
- ),
5187
- ),
5188
- array(
5189
- 'attr_spec_list' => array(
5190
- 'as' => array(),
5191
- 'charset' => array(
5192
- 'value_casei' => 'utf-8',
5193
- ),
5194
- 'color' => array(),
5195
- 'crossorigin' => array(),
5196
- 'href' => array(),
5197
- 'hreflang' => array(),
5198
- 'media' => array(),
5199
- 'rel' => array(
5200
- 'dispatch_key' => 2,
5201
- 'mandatory' => true,
5202
- 'value_casei' => 'preload',
5203
- ),
5204
- 'sizes' => array(),
5205
- 'target' => array(),
5206
- 'type' => array(),
5207
- ),
5208
- 'tag_spec' => array(
5209
- 'disallowed_ancestor' => array(
5210
- 'template',
5211
- ),
5212
- 'spec_name' => 'link rel=preload',
5213
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5214
- ),
5215
- ),
5216
- array(
5217
- 'attr_spec_list' => array(
5218
- 'async' => array(),
5219
- 'crossorigin' => array(),
5220
- 'href' => array(
5221
- 'mandatory' => true,
5222
- 'value_regex' => 'https://cdn\\.materialdesignicons\\.com/([0-9]+\\.?)+/css/materialdesignicons\\.min\\.css|https://cloud\\.typography\\.com/[0-9]*/[0-9]*/css/fonts\\.css|https://fast\\.fonts\\.net/.*|https://fonts\\.googleapis\\.com/css\\?.*|https://fonts\\.googleapis\\.com/icon\\?.*|https://fonts\\.googleapis\\.com/earlyaccess/.*\\.css|https://maxcdn\\.bootstrapcdn\\.com/font-awesome/([0-9]+\\.?)+/css/font-awesome\\.min\\.css(\\?.*)?|https://use\\.fontawesome\\.com/releases/v([0-9]+\\.?)+/css/(all|brands|solids|fontawesome)\\.css|https://use\\.typekit\\.net/[\\w\\p{L}\\p{N}_]+\\.css',
5223
- ),
5224
- 'integrity' => array(),
5225
- 'media' => array(),
5226
- 'rel' => array(
5227
- 'dispatch_key' => 2,
5228
- 'mandatory' => true,
5229
- 'value_casei' => 'stylesheet',
5230
- ),
5231
- 'type' => array(
5232
- 'value_casei' => 'text/css',
5233
- ),
5234
- ),
5235
- 'tag_spec' => array(
5236
- 'mandatory_parent' => 'head',
5237
- 'spec_name' => 'link rel=stylesheet for fonts',
5238
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#custom-fonts',
5239
- ),
5240
- ),
5241
- array(
5242
- 'attr_spec_list' => array(
5243
- 'charset' => array(
5244
- 'value_casei' => 'utf-8',
5245
- ),
5246
- 'color' => array(),
5247
- 'crossorigin' => array(),
5248
- 'href' => array(
5249
- 'mandatory' => true,
5250
- ),
5251
- 'hreflang' => array(),
5252
- 'itemprop' => array(
5253
- 'dispatch_key' => 2,
5254
- 'mandatory' => true,
5255
- 'value_casei' => 'sameas',
5256
- ),
5257
- 'media' => array(),
5258
- 'sizes' => array(),
5259
- 'target' => array(),
5260
- 'type' => array(),
5261
- ),
5262
- 'tag_spec' => array(
5263
- 'spec_name' => 'link itemprop=sameAs',
5264
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5265
- ),
5266
- ),
5267
- array(
5268
- 'attr_spec_list' => array(
5269
- 'charset' => array(
5270
- 'value_casei' => 'utf-8',
5271
- ),
5272
- 'color' => array(),
5273
- 'crossorigin' => array(),
5274
- 'href' => array(
5275
- 'mandatory' => true,
5276
- ),
5277
- 'hreflang' => array(),
5278
- 'itemprop' => array(
5279
- 'mandatory' => true,
5280
- ),
5281
- 'media' => array(),
5282
- 'sizes' => array(),
5283
- 'target' => array(),
5284
- 'type' => array(),
5285
- ),
5286
- 'tag_spec' => array(
5287
- 'spec_name' => 'link itemprop=',
5288
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5289
- ),
5290
- ),
5291
- array(
5292
- 'attr_spec_list' => array(
5293
- 'charset' => array(
5294
- 'value_casei' => 'utf-8',
5295
- ),
5296
- 'color' => array(),
5297
- 'crossorigin' => array(),
5298
- 'href' => array(
5299
- 'mandatory' => true,
5300
- ),
5301
- 'hreflang' => array(),
5302
- 'media' => array(),
5303
- 'property' => array(
5304
- 'mandatory' => true,
5305
- ),
5306
- 'sizes' => array(),
5307
- 'target' => array(),
5308
- 'type' => array(),
5309
- ),
5310
- 'tag_spec' => array(
5311
- 'spec_name' => 'link property=',
5312
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5313
- ),
5314
- ),
5315
- ),
5316
- 'listing' => array(
5317
- array(
5318
- 'attr_spec_list' => array(),
5319
- 'tag_spec' => array(),
5320
- ),
5321
- ),
5322
- 'main' => array(
5323
- array(
5324
- 'attr_spec_list' => array(),
5325
- 'tag_spec' => array(),
5326
- ),
5327
- ),
5328
- 'mark' => array(
5329
- array(
5330
- 'attr_spec_list' => array(),
5331
- 'tag_spec' => array(),
5332
- ),
5333
- ),
5334
- 'marker' => array(
5335
- array(
5336
- 'attr_spec_list' => array(
5337
- 'alignment-baseline' => array(),
5338
- 'baseline-shift' => array(),
5339
- 'clip' => array(),
5340
- 'clip-path' => array(),
5341
- 'clip-rule' => array(),
5342
- 'color' => array(),
5343
- 'color-interpolation' => array(),
5344
- 'color-interpolation-filters' => array(),
5345
- 'color-profile' => array(),
5346
- 'color-rendering' => array(),
5347
- 'cursor' => array(),
5348
- 'direction' => array(),
5349
- 'display' => array(),
5350
- 'dominant-baseline' => array(),
5351
- 'enable-background' => array(),
5352
- 'externalresourcesrequired' => array(),
5353
- 'fill' => array(),
5354
- 'fill-opacity' => array(),
5355
- 'fill-rule' => array(),
5356
- 'filter' => array(),
5357
- 'flood-color' => array(),
5358
- 'flood-opacity' => array(),
5359
- 'font-family' => array(),
5360
- 'font-size' => array(),
5361
- 'font-size-adjust' => array(),
5362
- 'font-stretch' => array(),
5363
- 'font-style' => array(),
5364
- 'font-variant' => array(),
5365
- 'font-weight' => array(),
5366
- 'glyph-orientation-horizontal' => array(),
5367
- 'glyph-orientation-vertical' => array(),
5368
- 'image-rendering' => array(),
5369
- 'kerning' => array(),
5370
- 'letter-spacing' => array(),
5371
- 'lighting-color' => array(),
5372
- 'marker-end' => array(),
5373
- 'marker-mid' => array(),
5374
- 'marker-start' => array(),
5375
- 'markerheight' => array(),
5376
- 'markerunits' => array(),
5377
- 'markerwidth' => array(),
5378
- 'mask' => array(),
5379
- 'opacity' => array(),
5380
- 'orient' => array(),
5381
- 'overflow' => array(),
5382
- 'pointer-events' => array(),
5383
- 'preserveaspectratio' => array(),
5384
- 'refx' => array(),
5385
- 'refy' => array(),
5386
- 'shape-rendering' => array(),
5387
- 'stop-color' => array(),
5388
- 'stop-opacity' => array(),
5389
- 'stroke' => array(),
5390
- 'stroke-dasharray' => array(),
5391
- 'stroke-dashoffset' => array(),
5392
- 'stroke-linecap' => array(),
5393
- 'stroke-linejoin' => array(),
5394
- 'stroke-miterlimit' => array(),
5395
- 'stroke-opacity' => array(),
5396
- 'stroke-width' => array(),
5397
- 'style' => array(
5398
- 'blacklisted_value_regex' => '!important',
5399
- ),
5400
- 'text-anchor' => array(),
5401
- 'text-decoration' => array(),
5402
- 'text-rendering' => array(),
5403
- 'transform' => array(),
5404
- 'unicode-bidi' => array(),
5405
- 'vector-effect' => array(),
5406
- 'viewbox' => array(),
5407
- 'visibility' => array(),
5408
- 'word-spacing' => array(),
5409
- 'writing-mode' => array(),
5410
- 'xml:lang' => array(),
5411
- 'xml:space' => array(),
5412
- 'xmlns' => array(),
5413
- 'xmlns:xlink' => array(),
5414
- ),
5415
- 'tag_spec' => array(
5416
- 'mandatory_ancestor' => 'svg',
5417
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
5418
- ),
5419
- ),
5420
- ),
5421
- 'mask' => array(
5422
- array(
5423
- 'attr_spec_list' => array(
5424
- 'alignment-baseline' => array(),
5425
- 'baseline-shift' => array(),
5426
- 'clip' => array(),
5427
- 'clip-path' => array(),
5428
- 'clip-rule' => array(),
5429
- 'color' => array(),
5430
- 'color-interpolation' => array(),
5431
- 'color-interpolation-filters' => array(),
5432
- 'color-profile' => array(),
5433
- 'color-rendering' => array(),
5434
- 'cursor' => array(),
5435
- 'direction' => array(),
5436
- 'display' => array(),
5437
- 'dominant-baseline' => array(),
5438
- 'enable-background' => array(),
5439
- 'externalresourcesrequired' => array(),
5440
- 'fill' => array(),
5441
- 'fill-opacity' => array(),
5442
- 'fill-rule' => array(),
5443
- 'filter' => array(),
5444
- 'flood-color' => array(),
5445
- 'flood-opacity' => array(),
5446
- 'font-family' => array(),
5447
- 'font-size' => array(),
5448
- 'font-size-adjust' => array(),
5449
- 'font-stretch' => array(),
5450
- 'font-style' => array(),
5451
- 'font-variant' => array(),
5452
- 'font-weight' => array(),
5453
- 'glyph-orientation-horizontal' => array(),
5454
- 'glyph-orientation-vertical' => array(),
5455
- 'height' => array(),
5456
- 'image-rendering' => array(),
5457
- 'kerning' => array(),
5458
- 'letter-spacing' => array(),
5459
- 'lighting-color' => array(),
5460
- 'marker-end' => array(),
5461
- 'marker-mid' => array(),
5462
- 'marker-start' => array(),
5463
- 'mask' => array(),
5464
- 'maskcontentunits' => array(),
5465
- 'maskunits' => array(),
5466
- 'opacity' => array(),
5467
- 'overflow' => array(),
5468
- 'pointer-events' => array(),
5469
- 'requiredextensions' => array(),
5470
- 'requiredfeatures' => array(),
5471
- 'shape-rendering' => array(),
5472
- 'stop-color' => array(),
5473
- 'stop-opacity' => array(),
5474
- 'stroke' => array(),
5475
- 'stroke-dasharray' => array(),
5476
- 'stroke-dashoffset' => array(),
5477
- 'stroke-linecap' => array(),
5478
- 'stroke-linejoin' => array(),
5479
- 'stroke-miterlimit' => array(),
5480
- 'stroke-opacity' => array(),
5481
- 'stroke-width' => array(),
5482
- 'style' => array(
5483
- 'blacklisted_value_regex' => '!important',
5484
- ),
5485
- 'systemlanguage' => array(),
5486
- 'text-anchor' => array(),
5487
- 'text-decoration' => array(),
5488
- 'text-rendering' => array(),
5489
- 'unicode-bidi' => array(),
5490
- 'vector-effect' => array(),
5491
- 'visibility' => array(),
5492
- 'width' => array(),
5493
- 'word-spacing' => array(),
5494
- 'writing-mode' => array(),
5495
- 'x' => array(),
5496
- 'xml:lang' => array(),
5497
- 'xml:space' => array(),
5498
- 'xmlns' => array(),
5499
- 'xmlns:xlink' => array(),
5500
- 'y' => array(),
5501
- ),
5502
- 'tag_spec' => array(
5503
- 'mandatory_ancestor' => 'svg',
5504
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
5505
- ),
5506
- ),
5507
- ),
5508
- 'meta' => array(
5509
- array(
5510
- 'attr_spec_list' => array(
5511
- 'charset' => array(
5512
- 'dispatch_key' => 1,
5513
- 'mandatory' => true,
5514
- 'value_casei' => 'utf-8',
5515
- ),
5516
- ),
5517
- 'tag_spec' => array(
5518
- 'mandatory' => true,
5519
- 'mandatory_parent' => 'head',
5520
- 'spec_name' => 'meta charset=utf-8',
5521
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
5522
- 'unique' => true,
5523
- ),
5524
- ),
5525
- array(
5526
- 'attr_spec_list' => array(
5527
- 'content' => array(
5528
- 'mandatory' => true,
5529
- 'value_properties' => array(
5530
- 'height' => array(),
5531
- 'initial-scale' => array(),
5532
- 'maximum-scale' => array(),
5533
- 'minimum-scale' => array(
5534
- 'mandatory' => true,
5535
- 'value_double' => 1.0,
5536
- ),
5537
- 'shrink-to-fit' => array(),
5538
- 'user-scalable' => array(),
5539
- 'viewport-fit' => array(),
5540
- 'width' => array(
5541
- 'mandatory' => true,
5542
- 'value' => 'device-width',
5543
- ),
5544
- ),
5545
- ),
5546
- 'name' => array(
5547
- 'dispatch_key' => 2,
5548
- 'mandatory' => true,
5549
- 'value' => 'viewport',
5550
- ),
5551
- ),
5552
- 'tag_spec' => array(
5553
- 'mandatory' => true,
5554
- 'mandatory_parent' => 'head',
5555
- 'spec_name' => 'meta name=viewport',
5556
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
5557
- 'unique' => true,
5558
- ),
5559
- ),
5560
- array(
5561
- 'attr_spec_list' => array(
5562
- 'content' => array(
5563
- 'mandatory' => true,
5564
- 'value_properties' => array(
5565
- 'chrome' => array(
5566
- 'value' => '1',
5567
- ),
5568
- 'ie' => array(
5569
- 'value' => 'edge',
5570
- ),
5571
- ),
5572
- ),
5573
- 'http-equiv' => array(
5574
- 'dispatch_key' => 2,
5575
- 'mandatory' => true,
5576
- 'value_casei' => 'x-ua-compatible',
5577
- ),
5578
- ),
5579
- 'tag_spec' => array(
5580
- 'mandatory_ancestor' => 'head',
5581
- 'spec_name' => 'meta http-equiv=X-UA-Compatible',
5582
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5583
- ),
5584
- ),
5585
- array(
5586
- 'attr_spec_list' => array(
5587
- 'content' => array(
5588
- 'mandatory' => true,
5589
- 'value_regex' => '.*app-id=.*',
5590
- ),
5591
- 'name' => array(
5592
- 'dispatch_key' => 2,
5593
- 'mandatory' => true,
5594
- 'value_casei' => 'apple-itunes-app',
5595
- ),
5596
- ),
5597
- 'tag_spec' => array(
5598
- 'mandatory_parent' => 'head',
5599
- 'spec_name' => 'meta name=apple-itunes-app',
5600
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5601
- ),
5602
- ),
5603
- array(
5604
- 'attr_spec_list' => array(
5605
- 'content' => array(
5606
- 'mandatory' => true,
5607
- ),
5608
- 'name' => array(
5609
- 'dispatch_key' => 2,
5610
- 'mandatory' => true,
5611
- 'value_casei' => 'amp-experiments-opt-in',
5612
- ),
5613
- ),
5614
- 'tag_spec' => array(
5615
- 'mandatory_parent' => 'head',
5616
- 'spec_name' => 'meta name=amp-experiments-opt-in',
5617
- ),
5618
- ),
5619
- array(
5620
- 'attr_spec_list' => array(
5621
- 'content' => array(
5622
- 'mandatory' => true,
5623
- 'value_url' => array(
5624
- 'allowed_protocol' => array(
5625
- 'https',
5626
- ),
5627
- ),
5628
- ),
5629
- 'name' => array(
5630
- 'dispatch_key' => 2,
5631
- 'mandatory' => true,
5632
- 'value_casei' => 'amp-3p-iframe-src',
5633
- ),
5634
- ),
5635
- 'tag_spec' => array(
5636
- 'mandatory_parent' => 'head',
5637
- 'spec_name' => 'meta name=amp-3p-iframe-src',
5638
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
5639
- ),
5640
- ),
5641
- array(
5642
- 'attr_spec_list' => array(
5643
- 'content' => array(
5644
- 'mandatory' => true,
5645
- ),
5646
- 'name' => array(
5647
- 'dispatch_key' => 2,
5648
- 'mandatory' => true,
5649
- 'value_casei' => 'amp-experiment-token',
5650
- ),
5651
- ),
5652
- 'tag_spec' => array(
5653
- 'mandatory_parent' => 'head',
5654
- 'spec_name' => 'meta name=amp-experiment-token',
5655
- ),
5656
- ),
5657
- array(
5658
- 'attr_spec_list' => array(
5659
- 'content' => array(
5660
- 'mandatory' => true,
5661
- ),
5662
- 'name' => array(
5663
- 'dispatch_key' => 2,
5664
- 'mandatory' => true,
5665
- 'value_casei' => 'amp-link-variable-allowed-origin',
5666
- ),
5667
- ),
5668
- 'tag_spec' => array(
5669
- 'mandatory_parent' => 'head',
5670
- 'spec_name' => 'meta name=amp-link-variable-allowed-origin',
5671
- ),
5672
- ),
5673
- array(
5674
- 'attr_spec_list' => array(
5675
- 'content' => array(
5676
- 'mandatory' => true,
5677
- ),
5678
- 'name' => array(
5679
- 'dispatch_key' => 2,
5680
- 'mandatory' => true,
5681
- 'value_casei' => 'amp-google-client-id-api',
5682
- ),
5683
- ),
5684
- 'tag_spec' => array(
5685
- 'mandatory_parent' => 'head',
5686
- 'spec_name' => 'meta name=amp-google-clientid-id-api',
5687
- ),
5688
- ),
5689
- array(
5690
- 'attr_spec_list' => array(
5691
- 'name' => array(
5692
- 'dispatch_key' => 2,
5693
- 'mandatory' => true,
5694
- 'value_casei' => 'amp-ad-doubleclick-sra',
5695
- ),
5696
- ),
5697
- 'tag_spec' => array(
5698
- 'mandatory_parent' => 'head',
5699
- 'spec_name' => 'meta name=amp-ad-doubleclick-sra',
5700
- ),
5701
- ),
5702
- array(
5703
- 'attr_spec_list' => array(
5704
- 'content' => array(),
5705
- 'itemprop' => array(),
5706
- 'name' => array(
5707
- 'blacklisted_value_regex' => '(^|\\s)(amp-.*|amp4ads-.*|apple-itunes-app|content-disposition|revisit-after|viewport)(\\s|$)',
5708
- ),
5709
- 'property' => array(),
5710
- 'scheme' => array(),
5711
- ),
5712
- 'tag_spec' => array(
5713
- 'spec_name' => 'meta name= and content=',
5714
- ),
5715
- ),
5716
- array(
5717
- 'attr_spec_list' => array(
5718
- 'content' => array(
5719
- 'mandatory' => true,
5720
- 'value_casei' => 'text/html; charset=utf-8',
5721
- ),
5722
- 'http-equiv' => array(
5723
- 'dispatch_key' => 2,
5724
- 'mandatory' => true,
5725
- 'value_casei' => 'content-type',
5726
- ),
5727
- ),
5728
- 'tag_spec' => array(
5729
- 'mandatory_ancestor' => 'head',
5730
- 'spec_name' => 'meta http-equiv=Content-Type',
5731
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5732
- ),
5733
- ),
5734
- array(
5735
- 'attr_spec_list' => array(
5736
- 'content' => array(
5737
- 'mandatory' => true,
5738
- ),
5739
- 'http-equiv' => array(
5740
- 'dispatch_key' => 2,
5741
- 'mandatory' => true,
5742
- 'value_casei' => 'content-language',
5743
- ),
5744
- ),
5745
- 'tag_spec' => array(
5746
- 'mandatory_ancestor' => 'head',
5747
- 'spec_name' => 'meta http-equiv=content-language',
5748
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5749
- ),
5750
- ),
5751
- array(
5752
- 'attr_spec_list' => array(
5753
- 'content' => array(
5754
- 'mandatory' => true,
5755
- ),
5756
- 'http-equiv' => array(
5757
- 'dispatch_key' => 2,
5758
- 'mandatory' => true,
5759
- 'value_casei' => 'pics-label',
5760
- ),
5761
- ),
5762
- 'tag_spec' => array(
5763
- 'mandatory_ancestor' => 'head',
5764
- 'spec_name' => 'meta http-equiv=pics-label',
5765
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5766
- ),
5767
- ),
5768
- array(
5769
- 'attr_spec_list' => array(
5770
- 'content' => array(
5771
- 'mandatory' => true,
5772
- ),
5773
- 'http-equiv' => array(
5774
- 'dispatch_key' => 2,
5775
- 'mandatory' => true,
5776
- 'value_casei' => 'imagetoolbar',
5777
- ),
5778
- ),
5779
- 'tag_spec' => array(
5780
- 'mandatory_ancestor' => 'head',
5781
- 'spec_name' => 'meta http-equiv=imagetoolbar',
5782
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5783
- ),
5784
- ),
5785
- array(
5786
- 'attr_spec_list' => array(
5787
- 'content' => array(
5788
- 'mandatory' => true,
5789
- 'value_casei' => 'text/css',
5790
- ),
5791
- 'http-equiv' => array(
5792
- 'dispatch_key' => 2,
5793
- 'mandatory' => true,
5794
- 'value_casei' => 'content-style-type',
5795
- ),
5796
- ),
5797
- 'tag_spec' => array(
5798
- 'mandatory_ancestor' => 'head',
5799
- 'spec_name' => 'meta http-equiv=Content-Style-Type',
5800
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5801
- ),
5802
- ),
5803
- array(
5804
- 'attr_spec_list' => array(
5805
- 'content' => array(
5806
- 'mandatory' => true,
5807
- 'value_casei' => 'text/javascript',
5808
- ),
5809
- 'http-equiv' => array(
5810
- 'dispatch_key' => 2,
5811
- 'mandatory' => true,
5812
- 'value_casei' => 'content-script-type',
5813
- ),
5814
- ),
5815
- 'tag_spec' => array(
5816
- 'mandatory_ancestor' => 'head',
5817
- 'spec_name' => 'meta http-equiv=Content-Script-Type',
5818
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5819
- ),
5820
- ),
5821
- array(
5822
- 'attr_spec_list' => array(
5823
- 'content' => array(
5824
- 'mandatory' => true,
5825
- ),
5826
- 'http-equiv' => array(
5827
- 'dispatch_key' => 2,
5828
- 'mandatory' => true,
5829
- 'value_casei' => 'origin-trial',
5830
- ),
5831
- ),
5832
- 'tag_spec' => array(
5833
- 'mandatory_ancestor' => 'head',
5834
- 'spec_name' => 'meta http-equiv=origin-trial',
5835
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5836
- ),
5837
- ),
5838
- array(
5839
- 'attr_spec_list' => array(
5840
- 'content' => array(
5841
- 'mandatory' => true,
5842
- ),
5843
- 'http-equiv' => array(
5844
- 'dispatch_key' => 2,
5845
- 'mandatory' => true,
5846
- 'value_casei' => 'resource-type',
5847
- ),
5848
- ),
5849
- 'tag_spec' => array(
5850
- 'mandatory_ancestor' => 'head',
5851
- 'spec_name' => 'meta http-equiv=resource-type',
5852
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5853
- ),
5854
- ),
5855
- array(
5856
- 'attr_spec_list' => array(
5857
- 'content' => array(
5858
- 'mandatory' => true,
5859
- 'value_regex_casei' => '(off|on)',
5860
- ),
5861
- 'http-equiv' => array(
5862
- 'dispatch_key' => 2,
5863
- 'mandatory' => true,
5864
- 'value_casei' => 'x-dns-prefetch-control',
5865
- ),
5866
- ),
5867
- 'tag_spec' => array(
5868
- 'mandatory_ancestor' => 'head',
5869
- 'spec_name' => 'meta http-equiv=x-dns-prefetch-control',
5870
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5871
- ),
5872
- ),
5873
- array(
5874
- 'attr_spec_list' => array(
5875
- 'content' => array(
5876
- 'mandatory' => true,
5877
- ),
5878
- 'name' => array(
5879
- 'dispatch_key' => 2,
5880
- 'mandatory' => true,
5881
- 'value_casei' => 'amp-ad-enable-refresh',
5882
- ),
5883
- ),
5884
- 'tag_spec' => array(
5885
- 'mandatory_ancestor' => 'head',
5886
- 'spec_name' => 'meta name=amp-ad-enable-refresh',
5887
- ),
5888
- ),
5889
- array(
5890
- 'attr_spec_list' => array(
5891
- 'content' => array(
5892
- 'mandatory' => true,
5893
- ),
5894
- 'name' => array(
5895
- 'dispatch_key' => 2,
5896
- 'mandatory' => true,
5897
- 'value_casei' => 'amp-to-amp-navigation',
5898
- ),
5899
- ),
5900
- 'tag_spec' => array(
5901
- 'mandatory_parent' => 'head',
5902
- 'spec_name' => 'meta name=amp-to-amp-navigation',
5903
- 'unique' => true,
5904
- ),
5905
- ),
5906
- ),
5907
- 'metadata' => array(
5908
- array(
5909
- 'attr_spec_list' => array(
5910
- 'style' => array(
5911
- 'blacklisted_value_regex' => '!important',
5912
- ),
5913
- 'xml:lang' => array(),
5914
- 'xml:space' => array(),
5915
- 'xmlns' => array(),
5916
- 'xmlns:xlink' => array(),
5917
- ),
5918
- 'tag_spec' => array(
5919
- 'mandatory_ancestor' => 'svg',
5920
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
5921
- ),
5922
- ),
5923
- ),
5924
- 'meter' => array(
5925
- array(
5926
- 'attr_spec_list' => array(
5927
- 'high' => array(),
5928
- 'low' => array(),
5929
- 'max' => array(),
5930
- 'min' => array(),
5931
- 'optimum' => array(),
5932
- 'value' => array(),
5933
- ),
5934
- 'tag_spec' => array(),
5935
- ),
5936
- ),
5937
- 'multicol' => array(
5938
- array(
5939
- 'attr_spec_list' => array(),
5940
- 'tag_spec' => array(),
5941
- ),
5942
- ),
5943
- 'nav' => array(
5944
- array(
5945
- 'attr_spec_list' => array(),
5946
- 'tag_spec' => array(),
5947
- ),
5948
- array(
5949
- 'attr_spec_list' => array(
5950
- 'toolbar' => array(
5951
- 'dispatch_key' => 1,
5952
- 'mandatory' => true,
5953
- ),
5954
- 'toolbar-target' => array(
5955
- 'mandatory' => true,
5956
- ),
5957
- ),
5958
- 'tag_spec' => array(
5959
- 'mandatory_parent' => 'amp-sidebar',
5960
- 'spec_name' => 'amp-sidebar > nav',
5961
- ),
5962
- ),
5963
- ),
5964
- 'nextid' => array(
5965
- array(
5966
- 'attr_spec_list' => array(),
5967
- 'tag_spec' => array(),
5968
- ),
5969
- ),
5970
- 'nobr' => array(
5971
- array(
5972
- 'attr_spec_list' => array(),
5973
- 'tag_spec' => array(),
5974
- ),
5975
- ),
5976
- 'noscript' => array(
5977
- array(
5978
- 'attr_spec_list' => array(),
5979
- 'tag_spec' => array(
5980
- 'mandatory' => true,
5981
- 'mandatory_parent' => 'head',
5982
- 'spec_name' => 'noscript enclosure for boilerplate',
5983
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/spec/amp-boilerplate.md',
5984
- 'unique' => true,
5985
- ),
5986
- ),
5987
- array(
5988
- 'attr_spec_list' => array(),
5989
- 'tag_spec' => array(
5990
- 'disallowed_ancestor' => array(
5991
- 'noscript',
5992
- ),
5993
- 'mandatory_ancestor' => 'body',
5994
- ),
5995
- ),
5996
- ),
5997
- 'o:p' => array(
5998
- array(
5999
- 'attr_spec_list' => array(),
6000
- 'tag_spec' => array(),
6001
- ),
6002
- ),
6003
- 'ol' => array(
6004
- array(
6005
- 'attr_spec_list' => array(
6006
- 'reversed' => array(
6007
- 'value' => '',
6008
- ),
6009
- 'start' => array(
6010
- 'value_regex' => '[0-9]*',
6011
- ),
6012
- 'type' => array(
6013
- 'value_regex' => '[1AaIi]',
6014
- ),
6015
- ),
6016
- 'tag_spec' => array(),
6017
- ),
6018
- ),
6019
- 'optgroup' => array(
6020
- array(
6021
- 'attr_spec_list' => array(
6022
- '[disabled]' => array(),
6023
- '[label]' => array(),
6024
- 'disabled' => array(),
6025
- 'label' => array(),
6026
- ),
6027
- 'tag_spec' => array(
6028
- 'mandatory_parent' => 'select',
6029
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
6030
- ),
6031
- ),
6032
- ),
6033
- 'option' => array(
6034
- array(
6035
- 'attr_spec_list' => array(
6036
- '[disabled]' => array(),
6037
- '[label]' => array(),
6038
- '[selected]' => array(),
6039
- '[value]' => array(),
6040
- 'disabled' => array(),
6041
- 'label' => array(),
6042
- 'selected' => array(),
6043
- 'value' => array(),
6044
- ),
6045
- 'tag_spec' => array(
6046
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
6047
- ),
6048
- ),
6049
- ),
6050
- 'output' => array(
6051
- array(
6052
- 'attr_spec_list' => array(
6053
- 'for' => array(),
6054
- 'form' => array(),
6055
- 'name' => array(
6056
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
6057
- ),
6058
- ),
6059
- 'tag_spec' => array(),
6060
- ),
6061
- ),
6062
- 'p' => array(
6063
- array(
6064
- 'attr_spec_list' => array(
6065
- 'align' => array(),
6066
- ),
6067
- 'tag_spec' => array(),
6068
- ),
6069
- ),
6070
- 'path' => array(
6071
- array(
6072
- 'attr_spec_list' => array(
6073
- 'alignment-baseline' => array(),
6074
- 'baseline-shift' => array(),
6075
- 'clip' => array(),
6076
- 'clip-path' => array(),
6077
- 'clip-rule' => array(),
6078
- 'color' => array(),
6079
- 'color-interpolation' => array(),
6080
- 'color-interpolation-filters' => array(),
6081
- 'color-profile' => array(),
6082
- 'color-rendering' => array(),
6083
- 'cursor' => array(),
6084
- 'd' => array(),
6085
- 'direction' => array(),
6086
- 'display' => array(),
6087
- 'dominant-baseline' => array(),
6088
- 'enable-background' => array(),
6089
- 'externalresourcesrequired' => array(),
6090
- 'fill' => array(),
6091
- 'fill-opacity' => array(),
6092
- 'fill-rule' => array(),
6093
- 'filter' => array(),
6094
- 'flood-color' => array(),
6095
- 'flood-opacity' => array(),
6096
- 'font-family' => array(),
6097
- 'font-size' => array(),
6098
- 'font-size-adjust' => array(),
6099
- 'font-stretch' => array(),
6100
- 'font-style' => array(),
6101
- 'font-variant' => array(),
6102
- 'font-weight' => array(),
6103
- 'glyph-orientation-horizontal' => array(),
6104
- 'glyph-orientation-vertical' => array(),
6105
- 'image-rendering' => array(),
6106
- 'kerning' => array(),
6107
- 'letter-spacing' => array(),
6108
- 'lighting-color' => array(),
6109
- 'marker-end' => array(),
6110
- 'marker-mid' => array(),
6111
- 'marker-start' => array(),
6112
- 'mask' => array(),
6113
- 'opacity' => array(),
6114
- 'overflow' => array(),
6115
- 'pathlength' => array(),
6116
- 'pointer-events' => array(),
6117
- 'requiredextensions' => array(),
6118
- 'requiredfeatures' => array(),
6119
- 'shape-rendering' => array(),
6120
- 'sketch:type' => array(),
6121
- 'stop-color' => array(),
6122
- 'stop-opacity' => array(),
6123
- 'stroke' => array(),
6124
- 'stroke-dasharray' => array(),
6125
- 'stroke-dashoffset' => array(),
6126
- 'stroke-linecap' => array(),
6127
- 'stroke-linejoin' => array(),
6128
- 'stroke-miterlimit' => array(),
6129
- 'stroke-opacity' => array(),
6130
- 'stroke-width' => array(),
6131
- 'style' => array(
6132
- 'blacklisted_value_regex' => '!important',
6133
- ),
6134
- 'systemlanguage' => array(),
6135
- 'text-anchor' => array(),
6136
- 'text-decoration' => array(),
6137
- 'text-rendering' => array(),
6138
- 'transform' => array(),
6139
- 'unicode-bidi' => array(),
6140
- 'vector-effect' => array(),
6141
- 'visibility' => array(),
6142
- 'word-spacing' => array(),
6143
- 'writing-mode' => array(),
6144
- 'xml:lang' => array(),
6145
- 'xml:space' => array(),
6146
- 'xmlns' => array(),
6147
- 'xmlns:xlink' => array(),
6148
- ),
6149
- 'tag_spec' => array(
6150
- 'mandatory_ancestor' => 'svg',
6151
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6152
- ),
6153
- ),
6154
- ),
6155
- 'pattern' => array(
6156
- array(
6157
- 'attr_spec_list' => array(
6158
- 'alignment-baseline' => array(),
6159
- 'baseline-shift' => array(),
6160
- 'clip' => array(),
6161
- 'clip-path' => array(),
6162
- 'clip-rule' => array(),
6163
- 'color' => array(),
6164
- 'color-interpolation' => array(),
6165
- 'color-interpolation-filters' => array(),
6166
- 'color-profile' => array(),
6167
- 'color-rendering' => array(),
6168
- 'cursor' => array(),
6169
- 'direction' => array(),
6170
- 'display' => array(),
6171
- 'dominant-baseline' => array(),
6172
- 'enable-background' => array(),
6173
- 'externalresourcesrequired' => array(),
6174
- 'fill' => array(),
6175
- 'fill-opacity' => array(),
6176
- 'fill-rule' => array(),
6177
- 'filter' => array(),
6178
- 'flood-color' => array(),
6179
- 'flood-opacity' => array(),
6180
- 'font-family' => array(),
6181
- 'font-size' => array(),
6182
- 'font-size-adjust' => array(),
6183
- 'font-stretch' => array(),
6184
- 'font-style' => array(),
6185
- 'font-variant' => array(),
6186
- 'font-weight' => array(),
6187
- 'glyph-orientation-horizontal' => array(),
6188
- 'glyph-orientation-vertical' => array(),
6189
- 'height' => array(),
6190
- 'image-rendering' => array(),
6191
- 'kerning' => array(),
6192
- 'letter-spacing' => array(),
6193
- 'lighting-color' => array(),
6194
- 'marker-end' => array(),
6195
- 'marker-mid' => array(),
6196
- 'marker-start' => array(),
6197
- 'mask' => array(),
6198
- 'opacity' => array(),
6199
- 'overflow' => array(),
6200
- 'patterncontentunits' => array(),
6201
- 'patterntransform' => array(),
6202
- 'patternunits' => array(),
6203
- 'pointer-events' => array(),
6204
- 'preserveaspectratio' => array(),
6205
- 'requiredextensions' => array(),
6206
- 'requiredfeatures' => array(),
6207
- 'shape-rendering' => array(),
6208
- 'stop-color' => array(),
6209
- 'stop-opacity' => array(),
6210
- 'stroke' => array(),
6211
- 'stroke-dasharray' => array(),
6212
- 'stroke-dashoffset' => array(),
6213
- 'stroke-linecap' => array(),
6214
- 'stroke-linejoin' => array(),
6215
- 'stroke-miterlimit' => array(),
6216
- 'stroke-opacity' => array(),
6217
- 'stroke-width' => array(),
6218
- 'style' => array(
6219
- 'blacklisted_value_regex' => '!important',
6220
- ),
6221
- 'systemlanguage' => array(),
6222
- 'text-anchor' => array(),
6223
- 'text-decoration' => array(),
6224
- 'text-rendering' => array(),
6225
- 'unicode-bidi' => array(),
6226
- 'vector-effect' => array(),
6227
- 'viewbox' => array(),
6228
- 'visibility' => array(),
6229
- 'width' => array(),
6230
- 'word-spacing' => array(),
6231
- 'writing-mode' => array(),
6232
- 'x' => array(),
6233
- 'xlink:actuate' => array(),
6234
- 'xlink:arcrole' => array(),
6235
- 'xlink:href' => array(
6236
- 'alternative_names' => array(
6237
- 'href',
6238
- ),
6239
- 'value_url' => array(
6240
- 'allow_empty' => false,
6241
- 'allow_relative' => true,
6242
- 'allowed_protocol' => array(
6243
- 'http',
6244
- 'https',
6245
- ),
6246
- ),
6247
- ),
6248
- 'xlink:role' => array(),
6249
- 'xlink:show' => array(),
6250
- 'xlink:title' => array(),
6251
- 'xlink:type' => array(),
6252
- 'xml:lang' => array(),
6253
- 'xml:space' => array(),
6254
- 'xmlns' => array(),
6255
- 'xmlns:xlink' => array(),
6256
- 'y' => array(),
6257
- ),
6258
- 'tag_spec' => array(
6259
- 'mandatory_ancestor' => 'svg',
6260
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6261
- ),
6262
- ),
6263
- ),
6264
- 'polygon' => array(
6265
- array(
6266
- 'attr_spec_list' => array(
6267
- 'alignment-baseline' => array(),
6268
- 'baseline-shift' => array(),
6269
- 'clip' => array(),
6270
- 'clip-path' => array(),
6271
- 'clip-rule' => array(),
6272
- 'color' => array(),
6273
- 'color-interpolation' => array(),
6274
- 'color-interpolation-filters' => array(),
6275
- 'color-profile' => array(),
6276
- 'color-rendering' => array(),
6277
- 'cursor' => array(),
6278
- 'direction' => array(),
6279
- 'display' => array(),
6280
- 'dominant-baseline' => array(),
6281
- 'enable-background' => array(),
6282
- 'externalresourcesrequired' => array(),
6283
- 'fill' => array(),
6284
- 'fill-opacity' => array(),
6285
- 'fill-rule' => array(),
6286
- 'filter' => array(),
6287
- 'flood-color' => array(),
6288
- 'flood-opacity' => array(),
6289
- 'font-family' => array(),
6290
- 'font-size' => array(),
6291
- 'font-size-adjust' => array(),
6292
- 'font-stretch' => array(),
6293
- 'font-style' => array(),
6294
- 'font-variant' => array(),
6295
- 'font-weight' => array(),
6296
- 'glyph-orientation-horizontal' => array(),
6297
- 'glyph-orientation-vertical' => array(),
6298
- 'image-rendering' => array(),
6299
- 'kerning' => array(),
6300
- 'letter-spacing' => array(),
6301
- 'lighting-color' => array(),
6302
- 'marker-end' => array(),
6303
- 'marker-mid' => array(),
6304
- 'marker-start' => array(),
6305
- 'mask' => array(),
6306
- 'opacity' => array(),
6307
- 'overflow' => array(),
6308
- 'pointer-events' => array(),
6309
- 'points' => array(),
6310
- 'requiredextensions' => array(),
6311
- 'requiredfeatures' => array(),
6312
- 'shape-rendering' => array(),
6313
- 'sketch:type' => array(),
6314
- 'stop-color' => array(),
6315
- 'stop-opacity' => array(),
6316
- 'stroke' => array(),
6317
- 'stroke-dasharray' => array(),
6318
- 'stroke-dashoffset' => array(),
6319
- 'stroke-linecap' => array(),
6320
- 'stroke-linejoin' => array(),
6321
- 'stroke-miterlimit' => array(),
6322
- 'stroke-opacity' => array(),
6323
- 'stroke-width' => array(),
6324
- 'style' => array(
6325
- 'blacklisted_value_regex' => '!important',
6326
- ),
6327
- 'systemlanguage' => array(),
6328
- 'text-anchor' => array(),
6329
- 'text-decoration' => array(),
6330
- 'text-rendering' => array(),
6331
- 'transform' => array(),
6332
- 'unicode-bidi' => array(),
6333
- 'vector-effect' => array(),
6334
- 'visibility' => array(),
6335
- 'word-spacing' => array(),
6336
- 'writing-mode' => array(),
6337
- 'xml:lang' => array(),
6338
- 'xml:space' => array(),
6339
- 'xmlns' => array(),
6340
- 'xmlns:xlink' => array(),
6341
- ),
6342
- 'tag_spec' => array(
6343
- 'mandatory_ancestor' => 'svg',
6344
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6345
- ),
6346
- ),
6347
- ),
6348
- 'polyline' => array(
6349
- array(
6350
- 'attr_spec_list' => array(
6351
- 'alignment-baseline' => array(),
6352
- 'baseline-shift' => array(),
6353
- 'clip' => array(),
6354
- 'clip-path' => array(),
6355
- 'clip-rule' => array(),
6356
- 'color' => array(),
6357
- 'color-interpolation' => array(),
6358
- 'color-interpolation-filters' => array(),
6359
- 'color-profile' => array(),
6360
- 'color-rendering' => array(),
6361
- 'cursor' => array(),
6362
- 'direction' => array(),
6363
- 'display' => array(),
6364
- 'dominant-baseline' => array(),
6365
- 'enable-background' => array(),
6366
- 'externalresourcesrequired' => array(),
6367
- 'fill' => array(),
6368
- 'fill-opacity' => array(),
6369
- 'fill-rule' => array(),
6370
- 'filter' => array(),
6371
- 'flood-color' => array(),
6372
- 'flood-opacity' => array(),
6373
- 'font-family' => array(),
6374
- 'font-size' => array(),
6375
- 'font-size-adjust' => array(),
6376
- 'font-stretch' => array(),
6377
- 'font-style' => array(),
6378
- 'font-variant' => array(),
6379
- 'font-weight' => array(),
6380
- 'glyph-orientation-horizontal' => array(),
6381
- 'glyph-orientation-vertical' => array(),
6382
- 'image-rendering' => array(),
6383
- 'kerning' => array(),
6384
- 'letter-spacing' => array(),
6385
- 'lighting-color' => array(),
6386
- 'marker-end' => array(),
6387
- 'marker-mid' => array(),
6388
- 'marker-start' => array(),
6389
- 'mask' => array(),
6390
- 'opacity' => array(),
6391
- 'overflow' => array(),
6392
- 'pointer-events' => array(),
6393
- 'points' => array(),
6394
- 'requiredextensions' => array(),
6395
- 'requiredfeatures' => array(),
6396
- 'shape-rendering' => array(),
6397
- 'sketch:type' => array(),
6398
- 'stop-color' => array(),
6399
- 'stop-opacity' => array(),
6400
- 'stroke' => array(),
6401
- 'stroke-dasharray' => array(),
6402
- 'stroke-dashoffset' => array(),
6403
- 'stroke-linecap' => array(),
6404
- 'stroke-linejoin' => array(),
6405
- 'stroke-miterlimit' => array(),
6406
- 'stroke-opacity' => array(),
6407
- 'stroke-width' => array(),
6408
- 'style' => array(
6409
- 'blacklisted_value_regex' => '!important',
6410
- ),
6411
- 'systemlanguage' => array(),
6412
- 'text-anchor' => array(),
6413
- 'text-decoration' => array(),
6414
- 'text-rendering' => array(),
6415
- 'transform' => array(),
6416
- 'unicode-bidi' => array(),
6417
- 'vector-effect' => array(),
6418
- 'visibility' => array(),
6419
- 'word-spacing' => array(),
6420
- 'writing-mode' => array(),
6421
- 'xml:lang' => array(),
6422
- 'xml:space' => array(),
6423
- 'xmlns' => array(),
6424
- 'xmlns:xlink' => array(),
6425
- ),
6426
- 'tag_spec' => array(
6427
- 'mandatory_ancestor' => 'svg',
6428
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6429
- ),
6430
- ),
6431
- ),
6432
- 'pre' => array(
6433
- array(
6434
- 'attr_spec_list' => array(),
6435
- 'tag_spec' => array(),
6436
- ),
6437
- ),
6438
- 'progress' => array(
6439
- array(
6440
- 'attr_spec_list' => array(
6441
- 'max' => array(),
6442
- 'value' => array(),
6443
- ),
6444
- 'tag_spec' => array(),
6445
- ),
6446
- ),
6447
- 'q' => array(
6448
- array(
6449
- 'attr_spec_list' => array(
6450
- 'cite' => array(
6451
- 'blacklisted_value_regex' => '__amp_source_origin',
6452
- 'value_url' => array(
6453
- 'allow_empty' => true,
6454
- 'allow_relative' => true,
6455
- 'allowed_protocol' => array(
6456
- 'http',
6457
- 'https',
6458
- ),
6459
- ),
6460
- ),
6461
- ),
6462
- 'tag_spec' => array(),
6463
- ),
6464
- ),
6465
- 'radialgradient' => array(
6466
- array(
6467
- 'attr_spec_list' => array(
6468
- 'alignment-baseline' => array(),
6469
- 'baseline-shift' => array(),
6470
- 'clip' => array(),
6471
- 'clip-path' => array(),
6472
- 'clip-rule' => array(),
6473
- 'color' => array(),
6474
- 'color-interpolation' => array(),
6475
- 'color-interpolation-filters' => array(),
6476
- 'color-profile' => array(),
6477
- 'color-rendering' => array(),
6478
- 'cursor' => array(),
6479
- 'cx' => array(),
6480
- 'cy' => array(),
6481
- 'direction' => array(),
6482
- 'display' => array(),
6483
- 'dominant-baseline' => array(),
6484
- 'enable-background' => array(),
6485
- 'externalresourcesrequired' => array(),
6486
- 'fill' => array(),
6487
- 'fill-opacity' => array(),
6488
- 'fill-rule' => array(),
6489
- 'filter' => array(),
6490
- 'flood-color' => array(),
6491
- 'flood-opacity' => array(),
6492
- 'font-family' => array(),
6493
- 'font-size' => array(),
6494
- 'font-size-adjust' => array(),
6495
- 'font-stretch' => array(),
6496
- 'font-style' => array(),
6497
- 'font-variant' => array(),
6498
- 'font-weight' => array(),
6499
- 'fr' => array(),
6500
- 'fx' => array(),
6501
- 'fy' => array(),
6502
- 'glyph-orientation-horizontal' => array(),
6503
- 'glyph-orientation-vertical' => array(),
6504
- 'gradienttransform' => array(),
6505
- 'gradientunits' => array(),
6506
- 'image-rendering' => array(),
6507
- 'kerning' => array(),
6508
- 'letter-spacing' => array(),
6509
- 'lighting-color' => array(),
6510
- 'marker-end' => array(),
6511
- 'marker-mid' => array(),
6512
- 'marker-start' => array(),
6513
- 'mask' => array(),
6514
- 'opacity' => array(),
6515
- 'overflow' => array(),
6516
- 'pointer-events' => array(),
6517
- 'r' => array(),
6518
- 'shape-rendering' => array(),
6519
- 'spreadmethod' => array(),
6520
- 'stop-color' => array(),
6521
- 'stop-opacity' => array(),
6522
- 'stroke' => array(),
6523
- 'stroke-dasharray' => array(),
6524
- 'stroke-dashoffset' => array(),
6525
- 'stroke-linecap' => array(),
6526
- 'stroke-linejoin' => array(),
6527
- 'stroke-miterlimit' => array(),
6528
- 'stroke-opacity' => array(),
6529
- 'stroke-width' => array(),
6530
- 'style' => array(
6531
- 'blacklisted_value_regex' => '!important',
6532
- ),
6533
- 'text-anchor' => array(),
6534
- 'text-decoration' => array(),
6535
- 'text-rendering' => array(),
6536
- 'unicode-bidi' => array(),
6537
- 'vector-effect' => array(),
6538
- 'visibility' => array(),
6539
- 'word-spacing' => array(),
6540
- 'writing-mode' => array(),
6541
- 'xlink:actuate' => array(),
6542
- 'xlink:arcrole' => array(),
6543
- 'xlink:href' => array(
6544
- 'alternative_names' => array(
6545
- 'href',
6546
- ),
6547
- 'value_url' => array(
6548
- 'allow_empty' => false,
6549
- 'allow_relative' => true,
6550
- 'allowed_protocol' => array(
6551
- 'http',
6552
- 'https',
6553
- ),
6554
- ),
6555
- ),
6556
- 'xlink:role' => array(),
6557
- 'xlink:show' => array(),
6558
- 'xlink:title' => array(),
6559
- 'xlink:type' => array(),
6560
- 'xml:lang' => array(),
6561
- 'xml:space' => array(),
6562
- 'xmlns' => array(),
6563
- 'xmlns:xlink' => array(),
6564
- ),
6565
- 'tag_spec' => array(
6566
- 'mandatory_ancestor' => 'svg',
6567
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6568
- ),
6569
- ),
6570
- ),
6571
- 'rb' => array(
6572
- array(
6573
- 'attr_spec_list' => array(),
6574
- 'tag_spec' => array(),
6575
- ),
6576
- ),
6577
- 'rect' => array(
6578
- array(
6579
- 'attr_spec_list' => array(
6580
- 'alignment-baseline' => array(),
6581
- 'baseline-shift' => array(),
6582
- 'clip' => array(),
6583
- 'clip-path' => array(),
6584
- 'clip-rule' => array(),
6585
- 'color' => array(),
6586
- 'color-interpolation' => array(),
6587
- 'color-interpolation-filters' => array(),
6588
- 'color-profile' => array(),
6589
- 'color-rendering' => array(),
6590
- 'cursor' => array(),
6591
- 'direction' => array(),
6592
- 'display' => array(),
6593
- 'dominant-baseline' => array(),
6594
- 'enable-background' => array(),
6595
- 'externalresourcesrequired' => array(),
6596
- 'fill' => array(),
6597
- 'fill-opacity' => array(),
6598
- 'fill-rule' => array(),
6599
- 'filter' => array(),
6600
- 'flood-color' => array(),
6601
- 'flood-opacity' => array(),
6602
- 'font-family' => array(),
6603
- 'font-size' => array(),
6604
- 'font-size-adjust' => array(),
6605
- 'font-stretch' => array(),
6606
- 'font-style' => array(),
6607
- 'font-variant' => array(),
6608
- 'font-weight' => array(),
6609
- 'glyph-orientation-horizontal' => array(),
6610
- 'glyph-orientation-vertical' => array(),
6611
- 'height' => array(),
6612
- 'image-rendering' => array(),
6613
- 'kerning' => array(),
6614
- 'letter-spacing' => array(),
6615
- 'lighting-color' => array(),
6616
- 'marker-end' => array(),
6617
- 'marker-mid' => array(),
6618
- 'marker-start' => array(),
6619
- 'mask' => array(),
6620
- 'opacity' => array(),
6621
- 'overflow' => array(),
6622
- 'pointer-events' => array(),
6623
- 'requiredextensions' => array(),
6624
- 'requiredfeatures' => array(),
6625
- 'rx' => array(),
6626
- 'ry' => array(),
6627
- 'shape-rendering' => array(),
6628
- 'sketch:type' => array(),
6629
- 'stop-color' => array(),
6630
- 'stop-opacity' => array(),
6631
- 'stroke' => array(),
6632
- 'stroke-dasharray' => array(),
6633
- 'stroke-dashoffset' => array(),
6634
- 'stroke-linecap' => array(),
6635
- 'stroke-linejoin' => array(),
6636
- 'stroke-miterlimit' => array(),
6637
- 'stroke-opacity' => array(),
6638
- 'stroke-width' => array(),
6639
- 'style' => array(
6640
- 'blacklisted_value_regex' => '!important',
6641
- ),
6642
- 'systemlanguage' => array(),
6643
- 'text-anchor' => array(),
6644
- 'text-decoration' => array(),
6645
- 'text-rendering' => array(),
6646
- 'transform' => array(),
6647
- 'unicode-bidi' => array(),
6648
- 'vector-effect' => array(),
6649
- 'visibility' => array(),
6650
- 'width' => array(),
6651
- 'word-spacing' => array(),
6652
- 'writing-mode' => array(),
6653
- 'x' => array(),
6654
- 'xml:lang' => array(),
6655
- 'xml:space' => array(),
6656
- 'xmlns' => array(),
6657
- 'xmlns:xlink' => array(),
6658
- 'y' => array(),
6659
- ),
6660
- 'tag_spec' => array(
6661
- 'mandatory_ancestor' => 'svg',
6662
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6663
- ),
6664
- ),
6665
- ),
6666
- 'rp' => array(
6667
- array(
6668
- 'attr_spec_list' => array(),
6669
- 'tag_spec' => array(),
6670
- ),
6671
- ),
6672
- 'rt' => array(
6673
- array(
6674
- 'attr_spec_list' => array(),
6675
- 'tag_spec' => array(),
6676
- ),
6677
- ),
6678
- 'rtc' => array(
6679
- array(
6680
- 'attr_spec_list' => array(),
6681
- 'tag_spec' => array(),
6682
- ),
6683
- ),
6684
- 'ruby' => array(
6685
- array(
6686
- 'attr_spec_list' => array(),
6687
- 'tag_spec' => array(),
6688
- ),
6689
- ),
6690
- 's' => array(
6691
- array(
6692
- 'attr_spec_list' => array(),
6693
- 'tag_spec' => array(),
6694
- ),
6695
- ),
6696
- 'samp' => array(
6697
- array(
6698
- 'attr_spec_list' => array(),
6699
- 'tag_spec' => array(),
6700
- ),
6701
- ),
6702
- 'script' => array(
6703
- array(
6704
- 'attr_spec_list' => array(
6705
- 'async' => array(
6706
- 'mandatory' => true,
6707
- 'value' => '',
6708
- ),
6709
- 'nonce' => array(),
6710
- 'src' => array(
6711
- 'dispatch_key' => 2,
6712
- 'mandatory' => true,
6713
- 'value' => 'https://cdn.ampproject.org/v0.js',
6714
- ),
6715
- 'type' => array(
6716
- 'value_casei' => 'text/javascript',
6717
- ),
6718
- ),
6719
- 'cdata' => array(
6720
- 'blacklisted_cdata_regex' => array(
6721
- 'error_message' => 'contents',
6722
- 'regex' => '.',
6723
- ),
6724
- ),
6725
- 'tag_spec' => array(
6726
- 'mandatory' => true,
6727
- 'mandatory_parent' => 'head',
6728
- 'spec_name' => 'amphtml engine v0.js script',
6729
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
6730
- 'unique' => true,
6731
- ),
6732
- ),
6733
- array(
6734
- 'attr_spec_list' => array(
6735
- 'nonce' => array(),
6736
- 'type' => array(
6737
- 'dispatch_key' => 2,
6738
- 'mandatory' => true,
6739
- 'value_casei' => 'application/ld+json',
6740
- ),
6741
- ),
6742
- 'cdata' => array(
6743
- 'blacklisted_cdata_regex' => array(
6744
- 'error_message' => 'html comments',
6745
- 'regex' => '<!--',
6746
- ),
6747
- ),
6748
- 'tag_spec' => array(
6749
- 'spec_name' => 'script type=application/ld+json',
6750
- ),
6751
- ),
6752
- array(
6753
- 'attr_spec_list' => array(
6754
- 'id' => array(
6755
- 'dispatch_key' => 2,
6756
- 'mandatory' => true,
6757
- 'value_casei' => 'amp-rtc',
6758
- ),
6759
- 'nonce' => array(),
6760
- 'type' => array(
6761
- 'mandatory' => true,
6762
- 'value_casei' => 'application/json',
6763
- ),
6764
- ),
6765
- 'cdata' => array(
6766
- 'blacklisted_cdata_regex' => array(
6767
- 'error_message' => 'html comments',
6768
- 'regex' => '<!--',
6769
- ),
6770
- ),
6771
- 'tag_spec' => array(
6772
- 'mandatory_parent' => 'head',
6773
- 'spec_name' => 'script id=amp-rtc',
6774
- 'unique' => true,
6775
- ),
6776
- ),
6777
- array(
6778
- 'attr_spec_list' => array(
6779
- 'type' => array(
6780
- 'dispatch_key' => 3,
6781
- 'mandatory' => true,
6782
- 'value_casei' => 'application/json',
6783
- ),
6784
- ),
6785
- 'cdata' => array(
6786
- 'blacklisted_cdata_regex' => array(
6787
- 'error_message' => 'html comments',
6788
- 'regex' => '<!--',
6789
- ),
6790
- ),
6791
- 'tag_spec' => array(
6792
- 'mandatory_parent' => 'amp-ima-video',
6793
- 'spec_name' => 'amp-ima-video > script[type=application/json]',
6794
- ),
6795
- ),
6796
- array(
6797
- 'attr_spec_list' => array(
6798
- 'async' => array(
6799
- 'mandatory' => true,
6800
- 'value' => '',
6801
- ),
6802
- 'nonce' => array(),
6803
- 'type' => array(
6804
- 'value_casei' => 'text/javascript',
6805
- ),
6806
- ),
6807
- 'tag_spec' => array(
6808
- 'extension_spec' => array(
6809
- 'allowed_versions' => array(
6810
- '0.1',
6811
- 'latest',
6812
- ),
6813
- 'name' => 'amp-3q-player',
6814
- ),
6815
- ),
6816
- ),
6817
- array(
6818
- 'attr_spec_list' => array(
6819
- 'async' => array(
6820
- 'mandatory' => true,
6821
- 'value' => '',
6822
- ),
6823
- 'nonce' => array(),
6824
- 'type' => array(
6825
- 'value_casei' => 'text/javascript',
6826
- ),
6827
- ),
6828
- 'tag_spec' => array(
6829
- 'extension_spec' => array(
6830
- 'allowed_versions' => array(
6831
- '0.1',
6832
- 'latest',
6833
- ),
6834
- 'name' => 'amp-access-laterpay',
6835
- 'requires_usage' => 3,
6836
- ),
6837
- 'requires_extension' => array(
6838
- 'amp-access',
6839
- ),
6840
- ),
6841
- ),
6842
- array(
6843
- 'attr_spec_list' => array(
6844
- 'async' => array(
6845
- 'mandatory' => true,
6846
- 'value' => '',
6847
- ),
6848
- 'nonce' => array(),
6849
- 'type' => array(
6850
- 'value_casei' => 'text/javascript',
6851
- ),
6852
- ),
6853
- 'tag_spec' => array(
6854
- 'extension_spec' => array(
6855
- 'allowed_versions' => array(
6856
- '0.1',
6857
- 'latest',
6858
- ),
6859
- 'name' => 'amp-access-scroll',
6860
- 'requires_usage' => 3,
6861
- ),
6862
- 'requires_extension' => array(
6863
- 'amp-access',
6864
- ),
6865
- ),
6866
- ),
6867
- array(
6868
- 'attr_spec_list' => array(
6869
- 'async' => array(
6870
- 'mandatory' => true,
6871
- 'value' => '',
6872
- ),
6873
- 'nonce' => array(),
6874
- 'type' => array(
6875
- 'value_casei' => 'text/javascript',
6876
- ),
6877
- ),
6878
- 'tag_spec' => array(
6879
- 'extension_spec' => array(
6880
- 'allowed_versions' => array(
6881
- '0.1',
6882
- 'latest',
6883
- ),
6884
- 'deprecated_allow_duplicates' => true,
6885
- 'name' => 'amp-access',
6886
- 'requires_usage' => 2,
6887
- ),
6888
- ),
6889
- ),
6890
- array(
6891
- 'attr_spec_list' => array(
6892
- 'id' => array(
6893
- 'dispatch_key' => 2,
6894
- 'mandatory' => true,
6895
- 'value' => 'amp-access',
6896
- ),
6897
- 'nonce' => array(),
6898
- 'type' => array(
6899
- 'mandatory' => true,
6900
- 'value_casei' => 'application/json',
6901
- ),
6902
- ),
6903
- 'cdata' => array(
6904
- 'blacklisted_cdata_regex' => array(
6905
- 'error_message' => 'html comments',
6906
- 'regex' => '<!--',
6907
- ),
6908
- ),
6909
- 'tag_spec' => array(
6910
- 'mandatory_parent' => 'head',
6911
- 'requires_extension' => array(
6912
- 'amp-access',
6913
- 'amp-analytics',
6914
- ),
6915
- 'spec_name' => 'amp-access extension .json script',
6916
- 'unique' => true,
6917
- ),
6918
- ),
6919
- array(
6920
- 'attr_spec_list' => array(
6921
- 'async' => array(
6922
- 'mandatory' => true,
6923
- 'value' => '',
6924
- ),
6925
- 'nonce' => array(),
6926
- 'type' => array(
6927
- 'value_casei' => 'text/javascript',
6928
- ),
6929
- ),
6930
- 'tag_spec' => array(
6931
- 'extension_spec' => array(
6932
- 'allowed_versions' => array(
6933
- '0.1',
6934
- 'latest',
6935
- ),
6936
- 'deprecated_allow_duplicates' => true,
6937
- 'name' => 'amp-accordion',
6938
- 'requires_usage' => 2,
6939
- ),
6940
- ),
6941
- ),
6942
- array(
6943
- 'attr_spec_list' => array(
6944
- 'async' => array(
6945
- 'mandatory' => true,
6946
- 'value' => '',
6947
- ),
6948
- 'nonce' => array(),
6949
- 'type' => array(
6950
- 'value_casei' => 'text/javascript',
6951
- ),
6952
- ),
6953
- 'tag_spec' => array(
6954
- 'extension_spec' => array(
6955
- 'allowed_versions' => array(
6956
- '0.1',
6957
- 'latest',
6958
- ),
6959
- 'deprecated_allow_duplicates' => true,
6960
- 'name' => 'amp-ad',
6961
- 'requires_usage' => 2,
6962
- ),
6963
- 'spec_name' => 'amp-ad extension .js script',
6964
- ),
6965
- ),
6966
- array(
6967
- 'attr_spec_list' => array(
6968
- 'async' => array(
6969
- 'mandatory' => true,
6970
- 'value' => '',
6971
- ),
6972
- 'nonce' => array(),
6973
- 'type' => array(
6974
- 'value_casei' => 'text/javascript',
6975
- ),
6976
- ),
6977
- 'tag_spec' => array(
6978
- 'extension_spec' => array(
6979
- 'allowed_versions' => array(
6980
- '0.1',
6981
- 'latest',
6982
- ),
6983
- 'deprecated_allow_duplicates' => true,
6984
- 'name' => 'amp-analytics',
6985
- 'requires_usage' => 2,
6986
- ),
6987
- ),
6988
- ),
6989
- array(
6990
- 'attr_spec_list' => array(
6991
- 'nonce' => array(),
6992
- 'type' => array(
6993
- 'dispatch_key' => 3,
6994
- 'mandatory' => true,
6995
- 'value_casei' => 'application/json',
6996
- ),
6997
- ),
6998
- 'cdata' => array(
6999
- 'blacklisted_cdata_regex' => array(
7000
- 'error_message' => 'html comments',
7001
- 'regex' => '<!--',
7002
- ),
7003
- ),
7004
- 'tag_spec' => array(
7005
- 'mandatory_parent' => 'amp-analytics',
7006
- 'requires_extension' => array(
7007
- 'amp-analytics',
7008
- ),
7009
- 'spec_name' => 'amp-analytics extension .json script',
7010
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-analytics',
7011
- ),
7012
- ),
7013
- array(
7014
- 'attr_spec_list' => array(
7015
- 'async' => array(
7016
- 'mandatory' => true,
7017
- 'value' => '',
7018
- ),
7019
- 'nonce' => array(),
7020
- 'type' => array(
7021
- 'value_casei' => 'text/javascript',
7022
- ),
7023
- ),
7024
- 'tag_spec' => array(
7025
- 'extension_spec' => array(
7026
- 'allowed_versions' => array(
7027
- '0.1',
7028
- 'latest',
7029
- ),
7030
- 'deprecated_allow_duplicates' => true,
7031
- 'name' => 'amp-anim',
7032
- 'requires_usage' => 2,
7033
- ),
7034
- ),
7035
- ),
7036
- array(
7037
- 'attr_spec_list' => array(
7038
- 'async' => array(
7039
- 'mandatory' => true,
7040
- 'value' => '',
7041
- ),
7042
- 'nonce' => array(),
7043
- 'type' => array(
7044
- 'value_casei' => 'text/javascript',
7045
- ),
7046
- ),
7047
- 'tag_spec' => array(
7048
- 'extension_spec' => array(
7049
- 'allowed_versions' => array(
7050
- '0.1',
7051
- 'latest',
7052
- ),
7053
- 'name' => 'amp-animation',
7054
- ),
7055
- ),
7056
- ),
7057
- array(
7058
- 'attr_spec_list' => array(
7059
- 'nonce' => array(),
7060
- 'type' => array(
7061
- 'dispatch_key' => 3,
7062
- 'mandatory' => true,
7063
- 'value_casei' => 'application/json',
7064
- ),
7065
- ),
7066
- 'cdata' => array(
7067
- 'blacklisted_cdata_regex' => array(
7068
- 'error_message' => 'html comments',
7069
- 'regex' => '<!--',
7070
- ),
7071
- ),
7072
- 'tag_spec' => array(
7073
- 'mandatory_parent' => 'amp-animation',
7074
- 'requires_extension' => array(
7075
- 'amp-animation',
7076
- ),
7077
- 'spec_name' => 'amp-animation extension .json script',
7078
- ),
7079
- ),
7080
- array(
7081
- 'attr_spec_list' => array(
7082
- 'async' => array(
7083
- 'mandatory' => true,
7084
- 'value' => '',
7085
- ),
7086
- 'nonce' => array(),
7087
- 'type' => array(
7088
- 'value_casei' => 'text/javascript',
7089
- ),
7090
- ),
7091
- 'tag_spec' => array(
7092
- 'extension_spec' => array(
7093
- 'allowed_versions' => array(
7094
- '0.1',
7095
- 'latest',
7096
- ),
7097
- 'deprecated_allow_duplicates' => true,
7098
- 'name' => 'amp-apester-media',
7099
- 'requires_usage' => 2,
7100
- ),
7101
- ),
7102
- ),
7103
- array(
7104
- 'attr_spec_list' => array(
7105
- 'async' => array(
7106
- 'mandatory' => true,
7107
- 'value' => '',
7108
- ),
7109
- 'nonce' => array(),
7110
- 'type' => array(
7111
- 'value_casei' => 'text/javascript',
7112
- ),
7113
- ),
7114
- 'tag_spec' => array(
7115
- 'extension_spec' => array(
7116
- 'allowed_versions' => array(
7117
- '0.1',
7118
- 'latest',
7119
- ),
7120
- 'deprecated_allow_duplicates' => true,
7121
- 'name' => 'amp-app-banner',
7122
- ),
7123
- ),
7124
- ),
7125
- array(
7126
- 'attr_spec_list' => array(
7127
- 'async' => array(
7128
- 'mandatory' => true,
7129
- 'value' => '',
7130
- ),
7131
- 'nonce' => array(),
7132
- 'type' => array(
7133
- 'value_casei' => 'text/javascript',
7134
- ),
7135
- ),
7136
- 'tag_spec' => array(
7137
- 'extension_spec' => array(
7138
- 'allowed_versions' => array(
7139
- '0.1',
7140
- 'latest',
7141
- ),
7142
- 'deprecated_allow_duplicates' => true,
7143
- 'name' => 'amp-audio',
7144
- 'requires_usage' => 2,
7145
- ),
7146
- ),
7147
- ),
7148
- array(
7149
- 'attr_spec_list' => array(
7150
- 'async' => array(
7151
- 'mandatory' => true,
7152
- 'value' => '',
7153
- ),
7154
- 'nonce' => array(),
7155
- 'type' => array(
7156
- 'value_casei' => 'text/javascript',
7157
- ),
7158
- ),
7159
- 'tag_spec' => array(
7160
- 'extension_spec' => array(
7161
- 'allowed_versions' => array(
7162
- '0.1',
7163
- 'latest',
7164
- ),
7165
- 'name' => 'amp-auto-ads',
7166
- ),
7167
- ),
7168
- ),
7169
- array(
7170
- 'attr_spec_list' => array(
7171
- 'async' => array(
7172
- 'mandatory' => true,
7173
- 'value' => '',
7174
- ),
7175
- 'nonce' => array(),
7176
- 'type' => array(
7177
- 'value_casei' => 'text/javascript',
7178
- ),
7179
- ),
7180
- 'tag_spec' => array(
7181
- 'extension_spec' => array(
7182
- 'allowed_versions' => array(
7183
- '0.1',
7184
- 'latest',
7185
- ),
7186
- 'name' => 'amp-beopinion',
7187
- ),
7188
- ),
7189
- ),
7190
- array(
7191
- 'attr_spec_list' => array(
7192
- 'async' => array(
7193
- 'mandatory' => true,
7194
- 'value' => '',
7195
- ),
7196
- 'nonce' => array(),
7197
- 'type' => array(
7198
- 'value_casei' => 'text/javascript',
7199
- ),
7200
- ),
7201
- 'tag_spec' => array(
7202
- 'extension_spec' => array(
7203
- 'allowed_versions' => array(
7204
- '0.1',
7205
- 'latest',
7206
- ),
7207
- 'name' => 'amp-bind',
7208
- 'requires_usage' => 3,
7209
- ),
7210
- ),
7211
- ),
7212
- array(
7213
- 'attr_spec_list' => array(
7214
- 'nonce' => array(),
7215
- 'type' => array(
7216
- 'dispatch_key' => 3,
7217
- 'mandatory' => true,
7218
- 'value_casei' => 'application/json',
7219
- ),
7220
- ),
7221
- 'cdata' => array(
7222
- 'blacklisted_cdata_regex' => array(
7223
- 'error_message' => 'html comments',
7224
- 'regex' => '<!--',
7225
- ),
7226
- ),
7227
- 'tag_spec' => array(
7228
- 'mandatory_parent' => 'amp-state',
7229
- 'requires_extension' => array(
7230
- 'amp-bind',
7231
- ),
7232
- 'spec_name' => 'amp-bind extension .json script',
7233
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind',
7234
- ),
7235
- ),
7236
- array(
7237
- 'attr_spec_list' => array(
7238
- 'async' => array(
7239
- 'mandatory' => true,
7240
- 'value' => '',
7241
- ),
7242
- 'nonce' => array(),
7243
- 'type' => array(
7244
- 'value_casei' => 'text/javascript',
7245
- ),
7246
- ),
7247
- 'tag_spec' => array(
7248
- 'extension_spec' => array(
7249
- 'allowed_versions' => array(
7250
- '0.1',
7251
- 'latest',
7252
- ),
7253
- 'name' => 'amp-bodymovin-animation',
7254
- ),
7255
- ),
7256
- ),
7257
- array(
7258
- 'attr_spec_list' => array(
7259
- 'async' => array(
7260
- 'mandatory' => true,
7261
- 'value' => '',
7262
- ),
7263
- 'nonce' => array(),
7264
- 'type' => array(
7265
- 'value_casei' => 'text/javascript',
7266
- ),
7267
- ),
7268
- 'tag_spec' => array(
7269
- 'extension_spec' => array(
7270
- 'allowed_versions' => array(
7271
- '0.1',
7272
- 'latest',
7273
- ),
7274
- 'deprecated_allow_duplicates' => true,
7275
- 'name' => 'amp-brid-player',
7276
- 'requires_usage' => 2,
7277
- ),
7278
- ),
7279
- ),
7280
- array(
7281
- 'attr_spec_list' => array(
7282
- 'async' => array(
7283
- 'mandatory' => true,
7284
- 'value' => '',
7285
- ),
7286
- 'nonce' => array(),
7287
- 'type' => array(
7288
- 'value_casei' => 'text/javascript',
7289
- ),
7290
- ),
7291
- 'tag_spec' => array(
7292
- 'extension_spec' => array(
7293
- 'allowed_versions' => array(
7294
- '0.1',
7295
- 'latest',
7296
- ),
7297
- 'deprecated_allow_duplicates' => true,
7298
- 'name' => 'amp-brightcove',
7299
- 'requires_usage' => 2,
7300
- ),
7301
- ),
7302
- ),
7303
- array(
7304
- 'attr_spec_list' => array(
7305
- 'async' => array(
7306
- 'mandatory' => true,
7307
- 'value' => '',
7308
- ),
7309
- 'nonce' => array(),
7310
- 'type' => array(
7311
- 'value_casei' => 'text/javascript',
7312
- ),
7313
- ),
7314
- 'tag_spec' => array(
7315
- 'extension_spec' => array(
7316
- 'allowed_versions' => array(
7317
- '0.1',
7318
- 'latest',
7319
- ),
7320
- 'name' => 'amp-byside-content',
7321
- ),
7322
- ),
7323
- ),
7324
- array(
7325
- 'attr_spec_list' => array(
7326
- 'async' => array(
7327
- 'mandatory' => true,
7328
- 'value' => '',
7329
- ),
7330
- 'nonce' => array(),
7331
- 'type' => array(
7332
- 'value_casei' => 'text/javascript',
7333
- ),
7334
- ),
7335
- 'tag_spec' => array(
7336
- 'extension_spec' => array(
7337
- 'allowed_versions' => array(
7338
- '0.1',
7339
- 'latest',
7340
- ),
7341
- 'name' => 'amp-call-tracking',
7342
- 'requires_usage' => 2,
7343
- ),
7344
- ),
7345
- ),
7346
- array(
7347
- 'attr_spec_list' => array(
7348
- 'async' => array(
7349
- 'mandatory' => true,
7350
- 'value' => '',
7351
- ),
7352
- 'nonce' => array(),
7353
- 'type' => array(
7354
- 'value_casei' => 'text/javascript',
7355
- ),
7356
- ),
7357
- 'tag_spec' => array(
7358
- 'extension_spec' => array(
7359
- 'allowed_versions' => array(
7360
- '0.1',
7361
- 'latest',
7362
- ),
7363
- 'deprecated_allow_duplicates' => true,
7364
- 'name' => 'amp-carousel',
7365
- 'requires_usage' => 2,
7366
- ),
7367
- ),
7368
- ),
7369
- array(
7370
- 'attr_spec_list' => array(
7371
- 'async' => array(
7372
- 'mandatory' => true,
7373
- 'value' => '',
7374
- ),
7375
- 'nonce' => array(),
7376
- 'type' => array(
7377
- 'value_casei' => 'text/javascript',
7378
- ),
7379
- ),
7380
- 'tag_spec' => array(
7381
- 'extension_spec' => array(
7382
- 'allowed_versions' => array(
7383
- '0.1',
7384
- 'latest',
7385
- ),
7386
- 'name' => 'amp-consent',
7387
- ),
7388
- ),
7389
- ),
7390
- array(
7391
- 'attr_spec_list' => array(
7392
- 'nonce' => array(),
7393
- 'type' => array(
7394
- 'dispatch_key' => 3,
7395
- 'mandatory' => true,
7396
- 'value_casei' => 'application/json',
7397
- ),
7398
- ),
7399
- 'cdata' => array(
7400
- 'blacklisted_cdata_regex' => array(
7401
- 'error_message' => 'html comments',
7402
- 'regex' => '<!--',
7403
- ),
7404
- ),
7405
- 'tag_spec' => array(
7406
- 'mandatory_parent' => 'amp-consent',
7407
- 'requires_extension' => array(
7408
- 'amp-consent',
7409
- ),
7410
- 'spec_name' => 'amp-consent extension .json script',
7411
- 'unique' => true,
7412
- ),
7413
- ),
7414
- array(
7415
- 'attr_spec_list' => array(
7416
- 'async' => array(
7417
- 'mandatory' => true,
7418
- 'value' => '',
7419
- ),
7420
- 'nonce' => array(),
7421
- 'type' => array(
7422
- 'value_casei' => 'text/javascript',
7423
- ),
7424
- ),
7425
- 'tag_spec' => array(
7426
- 'extension_spec' => array(
7427
- 'allowed_versions' => array(
7428
- '0.1',
7429
- 'latest',
7430
- ),
7431
- 'deprecated_allow_duplicates' => true,
7432
- 'name' => 'amp-dailymotion',
7433
- 'requires_usage' => 2,
7434
- ),
7435
- ),
7436
- ),
7437
- array(
7438
- 'attr_spec_list' => array(
7439
- 'async' => array(
7440
- 'mandatory' => true,
7441
- 'value' => '',
7442
- ),
7443
- 'nonce' => array(),
7444
- 'type' => array(
7445
- 'value_casei' => 'text/javascript',
7446
- ),
7447
- ),
7448
- 'tag_spec' => array(
7449
- 'extension_spec' => array(
7450
- 'allowed_versions' => array(
7451
- '0.1',
7452
- 'latest',
7453
- ),
7454
- 'name' => 'amp-date-picker',
7455
- ),
7456
- ),
7457
- ),
7458
- array(
7459
- 'attr_spec_list' => array(),
7460
- 'tag_spec' => array(
7461
- 'extension_spec' => array(
7462
- 'allowed_versions' => array(
7463
- '0.1',
7464
- 'latest',
7465
- ),
7466
- 'name' => 'amp-document-recommendations',
7467
- ),
7468
- ),
7469
- ),
7470
- array(
7471
- 'attr_spec_list' => array(
7472
- 'recommendations' => array(
7473
- 'dispatch_key' => 3,
7474
- 'mandatory' => true,
7475
- 'value_casei' => 'application/json',
7476
- ),
7477
- ),
7478
- 'tag_spec' => array(
7479
- 'mandatory_parent' => 'amp-document-recommendations',
7480
- 'requires_extension' => array(
7481
- 'amp-document-recommendations',
7482
- ),
7483
- 'spec_name' => 'amp-document-recommendations extension .json configuration',
7484
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-document-recommendations',
7485
- ),
7486
- ),
7487
- array(
7488
- 'attr_spec_list' => array(
7489
- 'async' => array(
7490
- 'mandatory' => true,
7491
- 'value' => '',
7492
- ),
7493
- 'nonce' => array(),
7494
- 'type' => array(
7495
- 'value_casei' => 'text/javascript',
7496
- ),
7497
- ),
7498
- 'tag_spec' => array(
7499
- 'extension_spec' => array(
7500
- 'allowed_versions' => array(
7501
- '0.1',
7502
- 'latest',
7503
- ),
7504
- 'deprecated_allow_duplicates' => true,
7505
- 'name' => 'amp-dynamic-css-classes',
7506
- 'requires_usage' => 3,
7507
- ),
7508
- ),
7509
- ),
7510
- array(
7511
- 'attr_spec_list' => array(
7512
- 'async' => array(
7513
- 'mandatory' => true,
7514
- 'value' => '',
7515
- ),
7516
- 'nonce' => array(),
7517
- 'type' => array(
7518
- 'value_casei' => 'text/javascript',
7519
- ),
7520
- ),
7521
- 'tag_spec' => array(
7522
- 'extension_spec' => array(
7523
- 'allowed_versions' => array(
7524
- '0.1',
7525
- 'latest',
7526
- ),
7527
- 'deprecated_allow_duplicates' => true,
7528
- 'name' => 'amp-experiment',
7529
- 'requires_usage' => 2,
7530
- ),
7531
- ),
7532
- ),
7533
- array(
7534
- 'attr_spec_list' => array(
7535
- 'nonce' => array(),
7536
- 'type' => array(
7537
- 'dispatch_key' => 3,
7538
- 'mandatory' => true,
7539
- 'value_casei' => 'application/json',
7540
- ),
7541
- ),
7542
- 'cdata' => array(
7543
- 'blacklisted_cdata_regex' => array(
7544
- 'error_message' => 'html comments',
7545
- 'regex' => '<!--',
7546
- ),
7547
- ),
7548
- 'tag_spec' => array(
7549
- 'mandatory_parent' => 'amp-experiment',
7550
- 'spec_name' => 'amp-experiment extension .json script',
7551
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-experiment',
7552
- ),
7553
- ),
7554
- array(
7555
- 'attr_spec_list' => array(
7556
- 'async' => array(
7557
- 'mandatory' => true,
7558
- 'value' => '',
7559
- ),
7560
- 'nonce' => array(),
7561
- 'type' => array(
7562
- 'value_casei' => 'text/javascript',
7563
- ),
7564
- ),
7565
- 'tag_spec' => array(
7566
- 'extension_spec' => array(
7567
- 'allowed_versions' => array(
7568
- '0.1',
7569
- 'latest',
7570
- ),
7571
- 'name' => 'amp-facebook-comments',
7572
- ),
7573
- ),
7574
- ),
7575
- array(
7576
- 'attr_spec_list' => array(
7577
- 'async' => array(
7578
- 'mandatory' => true,
7579
- 'value' => '',
7580
- ),
7581
- 'nonce' => array(),
7582
- 'type' => array(
7583
- 'value_casei' => 'text/javascript',
7584
- ),
7585
- ),
7586
- 'tag_spec' => array(
7587
- 'extension_spec' => array(
7588
- 'allowed_versions' => array(
7589
- '0.1',
7590
- 'latest',
7591
- ),
7592
- 'name' => 'amp-facebook-like',
7593
- ),
7594
- ),
7595
- ),
7596
- array(
7597
- 'attr_spec_list' => array(
7598
- 'async' => array(
7599
- 'mandatory' => true,
7600
- 'value' => '',
7601
- ),
7602
- 'nonce' => array(),
7603
- 'type' => array(
7604
- 'value_casei' => 'text/javascript',
7605
- ),
7606
- ),
7607
- 'tag_spec' => array(
7608
- 'extension_spec' => array(
7609
- 'allowed_versions' => array(
7610
- '0.1',
7611
- 'latest',
7612
- ),
7613
- 'name' => 'amp-facebook-page',
7614
- ),
7615
- ),
7616
- ),
7617
- array(
7618
- 'attr_spec_list' => array(
7619
- 'async' => array(
7620
- 'mandatory' => true,
7621
- 'value' => '',
7622
- ),
7623
- 'nonce' => array(),
7624
- 'type' => array(
7625
- 'value_casei' => 'text/javascript',
7626
- ),
7627
- ),
7628
- 'tag_spec' => array(
7629
- 'extension_spec' => array(
7630
- 'allowed_versions' => array(
7631
- '0.1',
7632
- 'latest',
7633
- ),
7634
- 'deprecated_allow_duplicates' => true,
7635
- 'name' => 'amp-facebook',
7636
- 'requires_usage' => 2,
7637
- ),
7638
- ),
7639
- ),
7640
- array(
7641
- 'attr_spec_list' => array(
7642
- 'async' => array(
7643
- 'mandatory' => true,
7644
- 'value' => '',
7645
- ),
7646
- 'nonce' => array(),
7647
- 'type' => array(
7648
- 'value_casei' => 'text/javascript',
7649
- ),
7650
- ),
7651
- 'tag_spec' => array(
7652
- 'extension_spec' => array(
7653
- 'allowed_versions' => array(
7654
- '0.1',
7655
- 'latest',
7656
- ),
7657
- 'deprecated_allow_duplicates' => true,
7658
- 'name' => 'amp-fit-text',
7659
- 'requires_usage' => 2,
7660
- ),
7661
- ),
7662
- ),
7663
- array(
7664
- 'attr_spec_list' => array(
7665
- 'async' => array(
7666
- 'mandatory' => true,
7667
- 'value' => '',
7668
- ),
7669
- 'nonce' => array(),
7670
- 'type' => array(
7671
- 'value_casei' => 'text/javascript',
7672
- ),
7673
- ),
7674
- 'tag_spec' => array(
7675
- 'extension_spec' => array(
7676
- 'allowed_versions' => array(
7677
- '0.1',
7678
- 'latest',
7679
- ),
7680
- 'deprecated_allow_duplicates' => true,
7681
- 'name' => 'amp-font',
7682
- 'requires_usage' => 2,
7683
- ),
7684
- ),
7685
- ),
7686
- array(
7687
- 'attr_spec_list' => array(
7688
- 'async' => array(
7689
- 'mandatory' => true,
7690
- 'value' => '',
7691
- ),
7692
- 'nonce' => array(),
7693
- 'type' => array(
7694
- 'value_casei' => 'text/javascript',
7695
- ),
7696
- ),
7697
- 'tag_spec' => array(
7698
- 'extension_spec' => array(
7699
- 'allowed_versions' => array(
7700
- '0.1',
7701
- 'latest',
7702
- ),
7703
- 'deprecated_allow_duplicates' => true,
7704
- 'name' => 'amp-form',
7705
- 'requires_usage' => 2,
7706
- ),
7707
- ),
7708
- ),
7709
- array(
7710
- 'attr_spec_list' => array(
7711
- 'async' => array(
7712
- 'mandatory' => true,
7713
- 'value' => '',
7714
- ),
7715
- 'nonce' => array(),
7716
- 'type' => array(
7717
- 'value_casei' => 'text/javascript',
7718
- ),
7719
- ),
7720
- 'tag_spec' => array(
7721
- 'extension_spec' => array(
7722
- 'allowed_versions' => array(
7723
- '0.1',
7724
- 'latest',
7725
- ),
7726
- 'name' => 'amp-fx-collection',
7727
- 'requires_usage' => 3,
7728
- ),
7729
- ),
7730
- ),
7731
- array(
7732
- 'attr_spec_list' => array(
7733
- 'async' => array(
7734
- 'mandatory' => true,
7735
- 'value' => '',
7736
- ),
7737
- 'nonce' => array(),
7738
- 'type' => array(
7739
- 'value_casei' => 'text/javascript',
7740
- ),
7741
- ),
7742
- 'tag_spec' => array(
7743
- 'extension_spec' => array(
7744
- 'allowed_versions' => array(
7745
- '0.1',
7746
- 'latest',
7747
- ),
7748
- 'deprecated_allow_duplicates' => true,
7749
- 'name' => 'amp-fx-flying-carpet',
7750
- 'requires_usage' => 2,
7751
- ),
7752
- ),
7753
- ),
7754
- array(
7755
- 'attr_spec_list' => array(
7756
- 'async' => array(
7757
- 'mandatory' => true,
7758
- 'value' => '',
7759
- ),
7760
- 'nonce' => array(),
7761
- 'type' => array(
7762
- 'value_casei' => 'text/javascript',
7763
- ),
7764
- ),
7765
- 'tag_spec' => array(
7766
- 'extension_spec' => array(
7767
- 'allowed_versions' => array(
7768
- '0.1',
7769
- 'latest',
7770
- ),
7771
- 'deprecated_allow_duplicates' => true,
7772
- 'name' => 'amp-gfycat',
7773
- 'requires_usage' => 2,
7774
- ),
7775
- ),
7776
- ),
7777
- array(
7778
- 'attr_spec_list' => array(
7779
- 'async' => array(
7780
- 'mandatory' => true,
7781
- 'value' => '',
7782
- ),
7783
- 'nonce' => array(),
7784
- 'type' => array(
7785
- 'value_casei' => 'text/javascript',
7786
- ),
7787
- ),
7788
- 'tag_spec' => array(
7789
- 'extension_spec' => array(
7790
- 'allowed_versions' => array(
7791
- '0.1',
7792
- 'latest',
7793
- ),
7794
- 'name' => 'amp-gist',
7795
- ),
7796
- ),
7797
- ),
7798
- array(
7799
- 'attr_spec_list' => array(
7800
- 'async' => array(
7801
- 'mandatory' => true,
7802
- 'value' => '',
7803
- ),
7804
- 'nonce' => array(),
7805
- 'type' => array(
7806
- 'value_casei' => 'text/javascript',
7807
- ),
7808
- ),
7809
- 'tag_spec' => array(
7810
- 'extension_spec' => array(
7811
- 'allowed_versions' => array(
7812
- '0.1',
7813
- 'latest',
7814
- ),
7815
- 'name' => 'amp-hulu',
7816
- ),
7817
- ),
7818
- ),
7819
- array(
7820
- 'attr_spec_list' => array(
7821
- 'async' => array(
7822
- 'mandatory' => true,
7823
- 'value' => '',
7824
- ),
7825
- 'nonce' => array(),
7826
- 'type' => array(
7827
- 'value_casei' => 'text/javascript',
7828
- ),
7829
- ),
7830
- 'tag_spec' => array(
7831
- 'extension_spec' => array(
7832
- 'allowed_versions' => array(
7833
- '0.1',
7834
- 'latest',
7835
- ),
7836
- 'deprecated_allow_duplicates' => true,
7837
- 'name' => 'amp-iframe',
7838
- 'requires_usage' => 2,
7839
- ),
7840
- ),
7841
- ),
7842
- array(
7843
- 'attr_spec_list' => array(
7844
- 'async' => array(
7845
- 'mandatory' => true,
7846
- 'value' => '',
7847
- ),
7848
- 'nonce' => array(),
7849
- 'type' => array(
7850
- 'value_casei' => 'text/javascript',
7851
- ),
7852
- ),
7853
- 'tag_spec' => array(
7854
- 'extension_spec' => array(
7855
- 'allowed_versions' => array(
7856
- '0.1',
7857
- 'latest',
7858
- ),
7859
- 'name' => 'amp-ima-video',
7860
- ),
7861
- ),
7862
- ),
7863
- array(
7864
- 'attr_spec_list' => array(
7865
- 'async' => array(
7866
- 'mandatory' => true,
7867
- 'value' => '',
7868
- ),
7869
- 'nonce' => array(),
7870
- 'type' => array(
7871
- 'value_casei' => 'text/javascript',
7872
- ),
7873
- ),
7874
- 'tag_spec' => array(
7875
- 'extension_spec' => array(
7876
- 'allowed_versions' => array(
7877
- '0.1',
7878
- 'latest',
7879
- ),
7880
- 'deprecated_allow_duplicates' => true,
7881
- 'name' => 'amp-image-lightbox',
7882
- 'requires_usage' => 2,
7883
- ),
7884
- ),
7885
- ),
7886
- array(
7887
- 'attr_spec_list' => array(
7888
- 'async' => array(
7889
- 'mandatory' => true,
7890
- 'value' => '',
7891
- ),
7892
- 'nonce' => array(),
7893
- 'type' => array(
7894
- 'value_casei' => 'text/javascript',
7895
- ),
7896
- ),
7897
- 'tag_spec' => array(
7898
- 'extension_spec' => array(
7899
- 'allowed_versions' => array(
7900
- '0.1',
7901
- 'latest',
7902
- ),
7903
- 'name' => 'amp-imgur',
7904
- ),
7905
- ),
7906
- ),
7907
- array(
7908
- 'attr_spec_list' => array(
7909
- 'async' => array(
7910
- 'mandatory' => true,
7911
- 'value' => '',
7912
- ),
7913
- 'nonce' => array(),
7914
- 'type' => array(
7915
- 'value_casei' => 'text/javascript',
7916
- ),
7917
- ),
7918
- 'tag_spec' => array(
7919
- 'extension_spec' => array(
7920
- 'allowed_versions' => array(
7921
- '0.1',
7922
- 'latest',
7923
- ),
7924
- 'deprecated_allow_duplicates' => true,
7925
- 'name' => 'amp-instagram',
7926
- 'requires_usage' => 2,
7927
- ),
7928
- ),
7929
- ),
7930
- array(
7931
- 'attr_spec_list' => array(
7932
- 'async' => array(
7933
- 'mandatory' => true,
7934
- 'value' => '',
7935
- ),
7936
- 'nonce' => array(),
7937
- 'type' => array(
7938
- 'value_casei' => 'text/javascript',
7939
- ),
7940
- ),
7941
- 'tag_spec' => array(
7942
- 'extension_spec' => array(
7943
- 'allowed_versions' => array(
7944
- '0.1',
7945
- 'latest',
7946
- ),
7947
- 'deprecated_allow_duplicates' => true,
7948
- 'name' => 'amp-install-serviceworker',
7949
- 'requires_usage' => 2,
7950
- ),
7951
- ),
7952
- ),
7953
- array(
7954
- 'attr_spec_list' => array(
7955
- 'async' => array(
7956
- 'mandatory' => true,
7957
- 'value' => '',
7958
- ),
7959
- 'nonce' => array(),
7960
- 'type' => array(
7961
- 'value_casei' => 'text/javascript',
7962
- ),
7963
- ),
7964
- 'tag_spec' => array(
7965
- 'extension_spec' => array(
7966
- 'allowed_versions' => array(
7967
- '0.1',
7968
- 'latest',
7969
- ),
7970
- 'name' => 'amp-izlesene',
7971
- 'requires_usage' => 2,
7972
- ),
7973
- ),
7974
- ),
7975
- array(
7976
- 'attr_spec_list' => array(
7977
- 'async' => array(
7978
- 'mandatory' => true,
7979
- 'value' => '',
7980
- ),
7981
- 'nonce' => array(),
7982
- 'type' => array(
7983
- 'value_casei' => 'text/javascript',
7984
- ),
7985
- ),
7986
- 'tag_spec' => array(
7987
- 'extension_spec' => array(
7988
- 'allowed_versions' => array(
7989
- '0.1',
7990
- 'latest',
7991
- ),
7992
- 'deprecated_allow_duplicates' => true,
7993
- 'name' => 'amp-jwplayer',
7994
- 'requires_usage' => 2,
7995
- ),
7996
- ),
7997
- ),
7998
- array(
7999
- 'attr_spec_list' => array(
8000
- 'async' => array(
8001
- 'mandatory' => true,
8002
- 'value' => '',
8003
- ),
8004
- 'nonce' => array(),
8005
- 'type' => array(
8006
- 'value_casei' => 'text/javascript',
8007
- ),
8008
- ),
8009
- 'tag_spec' => array(
8010
- 'extension_spec' => array(
8011
- 'allowed_versions' => array(
8012
- '0.1',
8013
- 'latest',
8014
- ),
8015
- 'deprecated_allow_duplicates' => true,
8016
- 'name' => 'amp-kaltura-player',
8017
- 'requires_usage' => 2,
8018
- ),
8019
- ),
8020
- ),
8021
- array(
8022
- 'attr_spec_list' => array(
8023
- 'async' => array(
8024
- 'mandatory' => true,
8025
- 'value' => '',
8026
- ),
8027
- 'nonce' => array(),
8028
- 'type' => array(
8029
- 'value_casei' => 'text/javascript',
8030
- ),
8031
- ),
8032
- 'tag_spec' => array(
8033
- 'extension_spec' => array(
8034
- 'allowed_versions' => array(
8035
- '0.1',
8036
- 'latest',
8037
- ),
8038
- 'name' => 'amp-lightbox-gallery',
8039
- 'requires_usage' => 3,
8040
- ),
8041
- ),
8042
- ),
8043
- array(
8044
- 'attr_spec_list' => array(
8045
- 'async' => array(
8046
- 'mandatory' => true,
8047
- 'value' => '',
8048
- ),
8049
- 'nonce' => array(),
8050
- 'type' => array(
8051
- 'value_casei' => 'text/javascript',
8052
- ),
8053
- ),
8054
- 'tag_spec' => array(
8055
- 'extension_spec' => array(
8056
- 'allowed_versions' => array(
8057
- '0.1',
8058
- 'latest',
8059
- ),
8060
- 'deprecated_allow_duplicates' => true,
8061
- 'name' => 'amp-lightbox',
8062
- 'requires_usage' => 2,
8063
- ),
8064
- ),
8065
- ),
8066
- array(
8067
- 'attr_spec_list' => array(
8068
- 'async' => array(
8069
- 'mandatory' => true,
8070
- 'value' => '',
8071
- ),
8072
- 'nonce' => array(),
8073
- 'type' => array(
8074
- 'value_casei' => 'text/javascript',
8075
- ),
8076
- ),
8077
- 'tag_spec' => array(
8078
- 'extension_spec' => array(
8079
- 'allowed_versions' => array(
8080
- '0.1',
8081
- 'latest',
8082
- ),
8083
- 'deprecated_allow_duplicates' => true,
8084
- 'name' => 'amp-list',
8085
- 'requires_usage' => 2,
8086
- ),
8087
- ),
8088
- ),
8089
- array(
8090
- 'attr_spec_list' => array(
8091
- 'async' => array(
8092
- 'mandatory' => true,
8093
- 'value' => '',
8094
- ),
8095
- 'nonce' => array(),
8096
- 'type' => array(
8097
- 'value_casei' => 'text/javascript',
8098
- ),
8099
- ),
8100
- 'tag_spec' => array(
8101
- 'extension_spec' => array(
8102
- 'allowed_versions' => array(
8103
- '0.1',
8104
- 'latest',
8105
- ),
8106
- 'name' => 'amp-live-list',
8107
- 'requires_usage' => 2,
8108
- ),
8109
- 'mandatory_parent' => 'head',
8110
- 'unique_warning' => true,
8111
- ),
8112
- ),
8113
- array(
8114
- 'attr_spec_list' => array(
8115
- 'async' => array(
8116
- 'mandatory' => true,
8117
- 'value' => '',
8118
- ),
8119
- 'nonce' => array(),
8120
- 'type' => array(
8121
- 'value_casei' => 'text/javascript',
8122
- ),
8123
- ),
8124
- 'tag_spec' => array(
8125
- 'extension_spec' => array(
8126
- 'allowed_versions' => array(
8127
- '0.1',
8128
- 'latest',
8129
- ),
8130
- 'name' => 'amp-mathml',
8131
- ),
8132
- ),
8133
- ),
8134
- array(
8135
- 'attr_spec_list' => array(
8136
- 'async' => array(
8137
- 'mandatory' => true,
8138
- 'value' => '',
8139
- ),
8140
- 'nonce' => array(),
8141
- 'type' => array(
8142
- 'value_casei' => 'text/javascript',
8143
- ),
8144
- ),
8145
- 'tag_spec' => array(
8146
- 'extension_spec' => array(
8147
- 'allowed_versions' => array(
8148
- '0.1',
8149
- 'latest',
8150
- ),
8151
- 'deprecated_allow_duplicates' => true,
8152
- 'is_custom_template' => true,
8153
- 'name' => 'amp-mustache',
8154
- 'requires_usage' => 2,
8155
- ),
8156
- ),
8157
- ),
8158
- array(
8159
- 'attr_spec_list' => array(
8160
- 'async' => array(
8161
- 'mandatory' => true,
8162
- 'value' => '',
8163
- ),
8164
- 'nonce' => array(),
8165
- 'type' => array(
8166
- 'value_casei' => 'text/javascript',
8167
- ),
8168
- ),
8169
- 'tag_spec' => array(
8170
- 'extension_spec' => array(
8171
- 'allowed_versions' => array(
8172
- '0.1',
8173
- 'latest',
8174
- ),
8175
- 'name' => 'amp-nexxtv-player',
8176
- ),
8177
- ),
8178
- ),
8179
- array(
8180
- 'attr_spec_list' => array(
8181
- 'async' => array(
8182
- 'mandatory' => true,
8183
- 'value' => '',
8184
- ),
8185
- 'nonce' => array(),
8186
- 'type' => array(
8187
- 'value_casei' => 'text/javascript',
8188
- ),
8189
- ),
8190
- 'tag_spec' => array(
8191
- 'extension_spec' => array(
8192
- 'allowed_versions' => array(
8193
- '0.1',
8194
- 'latest',
8195
- ),
8196
- 'deprecated_allow_duplicates' => true,
8197
- 'name' => 'amp-o2-player',
8198
- 'requires_usage' => 2,
8199
- ),
8200
- ),
8201
- ),
8202
- array(
8203
- 'attr_spec_list' => array(
8204
- 'async' => array(
8205
- 'mandatory' => true,
8206
- 'value' => '',
8207
- ),
8208
- 'nonce' => array(),
8209
- 'type' => array(
8210
- 'value_casei' => 'text/javascript',
8211
- ),
8212
- ),
8213
- 'tag_spec' => array(
8214
- 'extension_spec' => array(
8215
- 'allowed_versions' => array(
8216
- '0.1',
8217
- 'latest',
8218
- ),
8219
- 'name' => 'amp-ooyala-player',
8220
- ),
8221
- ),
8222
- ),
8223
- array(
8224
- 'attr_spec_list' => array(
8225
- 'async' => array(
8226
- 'mandatory' => true,
8227
- 'value' => '',
8228
- ),
8229
- 'nonce' => array(),
8230
- 'type' => array(
8231
- 'value_casei' => 'text/javascript',
8232
- ),
8233
- ),
8234
- 'tag_spec' => array(
8235
- 'extension_spec' => array(
8236
- 'allowed_versions' => array(
8237
- '0.1',
8238
- 'latest',
8239
- ),
8240
- 'deprecated_allow_duplicates' => true,
8241
- 'name' => 'amp-pinterest',
8242
- 'requires_usage' => 2,
8243
- ),
8244
- ),
8245
- ),
8246
- array(
8247
- 'attr_spec_list' => array(
8248
- 'async' => array(
8249
- 'mandatory' => true,
8250
- 'value' => '',
8251
- ),
8252
- 'nonce' => array(),
8253
- 'type' => array(
8254
- 'value_casei' => 'text/javascript',
8255
- ),
8256
- ),
8257
- 'tag_spec' => array(
8258
- 'extension_spec' => array(
8259
- 'allowed_versions' => array(
8260
- '0.1',
8261
- 'latest',
8262
- ),
8263
- 'name' => 'amp-playbuzz',
8264
- ),
8265
- ),
8266
- ),
8267
- array(
8268
- 'attr_spec_list' => array(
8269
- 'async' => array(
8270
- 'mandatory' => true,
8271
- 'value' => '',
8272
- ),
8273
- 'nonce' => array(),
8274
- 'type' => array(
8275
- 'value_casei' => 'text/javascript',
8276
- ),
8277
- ),
8278
- 'tag_spec' => array(
8279
- 'extension_spec' => array(
8280
- 'allowed_versions' => array(
8281
- '0.1',
8282
- 'latest',
8283
- ),
8284
- 'name' => 'amp-position-observer',
8285
- ),
8286
- ),
8287
- ),
8288
- array(
8289
- 'attr_spec_list' => array(
8290
- 'async' => array(
8291
- 'mandatory' => true,
8292
- 'value' => '',
8293
- ),
8294
- 'nonce' => array(),
8295
- 'type' => array(
8296
- 'value_casei' => 'text/javascript',
8297
- ),
8298
- ),
8299
- 'tag_spec' => array(
8300
- 'extension_spec' => array(
8301
- 'allowed_versions' => array(
8302
- '0.1',
8303
- 'latest',
8304
- ),
8305
- 'deprecated_allow_duplicates' => true,
8306
- 'name' => 'amp-reach-player',
8307
- 'requires_usage' => 2,
8308
- ),
8309
- ),
8310
- ),
8311
- array(
8312
- 'attr_spec_list' => array(
8313
- 'async' => array(
8314
- 'mandatory' => true,
8315
- 'value' => '',
8316
- ),
8317
- 'nonce' => array(),
8318
- 'type' => array(
8319
- 'value_casei' => 'text/javascript',
8320
- ),
8321
- ),
8322
- 'tag_spec' => array(
8323
- 'extension_spec' => array(
8324
- 'allowed_versions' => array(
8325
- '0.1',
8326
- 'latest',
8327
- ),
8328
- 'deprecated_allow_duplicates' => true,
8329
- 'name' => 'amp-reddit',
8330
- ),
8331
- ),
8332
- ),
8333
- array(
8334
- 'attr_spec_list' => array(
8335
- 'async' => array(
8336
- 'mandatory' => true,
8337
- 'value' => '',
8338
- ),
8339
- 'nonce' => array(),
8340
- 'type' => array(
8341
- 'value_casei' => 'text/javascript',
8342
- ),
8343
- ),
8344
- 'tag_spec' => array(
8345
- 'extension_spec' => array(
8346
- 'allowed_versions' => array(
8347
- '0.1',
8348
- 'latest',
8349
- ),
8350
- 'name' => 'amp-riddle-quiz',
8351
- ),
8352
- ),
8353
- ),
8354
- array(
8355
- 'attr_spec_list' => array(
8356
- 'async' => array(
8357
- 'mandatory' => true,
8358
- 'value' => '',
8359
- ),
8360
- 'nonce' => array(),
8361
- 'type' => array(
8362
- 'value_casei' => 'text/javascript',
8363
- ),
8364
- ),
8365
- 'tag_spec' => array(
8366
- 'extension_spec' => array(
8367
- 'allowed_versions' => array(
8368
- '0.1',
8369
- 'latest',
8370
- ),
8371
- 'name' => 'amp-selector',
8372
- 'requires_usage' => 2,
8373
- ),
8374
- ),
8375
- ),
8376
- array(
8377
- 'attr_spec_list' => array(
8378
- 'async' => array(
8379
- 'mandatory' => true,
8380
- 'value' => '',
8381
- ),
8382
- 'nonce' => array(),
8383
- 'type' => array(
8384
- 'value_casei' => 'text/javascript',
8385
- ),
8386
- ),
8387
- 'tag_spec' => array(
8388
- 'extension_spec' => array(
8389
- 'allowed_versions' => array(
8390
- '0.1',
8391
- 'latest',
8392
- ),
8393
- 'deprecated_allow_duplicates' => true,
8394
- 'name' => 'amp-sidebar',
8395
- 'requires_usage' => 2,
8396
- ),
8397
- ),
8398
- ),
8399
- array(
8400
- 'attr_spec_list' => array(
8401
- 'async' => array(
8402
- 'mandatory' => true,
8403
- 'value' => '',
8404
- ),
8405
- 'nonce' => array(),
8406
- 'type' => array(
8407
- 'value_casei' => 'text/javascript',
8408
- ),
8409
- ),
8410
- 'tag_spec' => array(
8411
- 'extension_spec' => array(
8412
- 'allowed_versions' => array(
8413
- '0.1',
8414
- 'latest',
8415
- ),
8416
- 'deprecated_allow_duplicates' => true,
8417
- 'name' => 'amp-social-share',
8418
- 'requires_usage' => 2,
8419
- ),
8420
- ),
8421
- ),
8422
- array(
8423
- 'attr_spec_list' => array(
8424
- 'async' => array(
8425
- 'mandatory' => true,
8426
- 'value' => '',
8427
- ),
8428
- 'nonce' => array(),
8429
- 'type' => array(
8430
- 'value_casei' => 'text/javascript',
8431
- ),
8432
- ),
8433
- 'tag_spec' => array(
8434
- 'extension_spec' => array(
8435
- 'allowed_versions' => array(
8436
- '0.1',
8437
- 'latest',
8438
- ),
8439
- 'deprecated_allow_duplicates' => true,
8440
- 'name' => 'amp-soundcloud',
8441
- 'requires_usage' => 2,
8442
- ),
8443
- ),
8444
- ),
8445
- array(
8446
- 'attr_spec_list' => array(
8447
- 'async' => array(
8448
- 'mandatory' => true,
8449
- 'value' => '',
8450
- ),
8451
- 'nonce' => array(),
8452
- 'type' => array(
8453
- 'value_casei' => 'text/javascript',
8454
- ),
8455
- ),
8456
- 'tag_spec' => array(
8457
- 'extension_spec' => array(
8458
- 'allowed_versions' => array(
8459
- '0.1',
8460
- 'latest',
8461
- ),
8462
- 'deprecated_allow_duplicates' => true,
8463
- 'name' => 'amp-springboard-player',
8464
- 'requires_usage' => 2,
8465
- ),
8466
- ),
8467
- ),
8468
- array(
8469
- 'attr_spec_list' => array(
8470
- 'async' => array(
8471
- 'mandatory' => true,
8472
- 'value' => '',
8473
- ),
8474
- 'nonce' => array(),
8475
- 'type' => array(
8476
- 'value_casei' => 'text/javascript',
8477
- ),
8478
- ),
8479
- 'tag_spec' => array(
8480
- 'extension_spec' => array(
8481
- 'allowed_versions' => array(
8482
- '0.1',
8483
- '1.0',
8484
- 'latest',
8485
- ),
8486
- 'deprecated_versions' => array(
8487
- '0.1',
8488
- ),
8489
- 'name' => 'amp-sticky-ad',
8490
- 'requires_usage' => 2,
8491
- ),
8492
- ),
8493
- ),
8494
- array(
8495
- 'attr_spec_list' => array(
8496
- 'async' => array(
8497
- 'mandatory' => true,
8498
- 'value' => '',
8499
- ),
8500
- 'nonce' => array(),
8501
- 'type' => array(
8502
- 'value_casei' => 'text/javascript',
8503
- ),
8504
- ),
8505
- 'tag_spec' => array(
8506
- 'extension_spec' => array(
8507
- 'allowed_versions' => array(
8508
- '0.1',
8509
- 'latest',
8510
- ),
8511
- 'name' => 'amp-story-auto-ads',
8512
- ),
8513
- ),
8514
- ),
8515
- array(
8516
- 'attr_spec_list' => array(
8517
- 'nonce' => array(),
8518
- 'type' => array(
8519
- 'dispatch_key' => 3,
8520
- 'mandatory' => true,
8521
- 'value_casei' => 'application/json',
8522
- ),
8523
- ),
8524
- 'cdata' => array(
8525
- 'blacklisted_cdata_regex' => array(
8526
- 'error_message' => 'html comments',
8527
- 'regex' => '<!--',
8528
- ),
8529
- ),
8530
- 'tag_spec' => array(
8531
- 'mandatory_parent' => 'amp-story-auto-ads',
8532
- 'requires_extension' => array(
8533
- 'amp-story-auto-ads',
8534
- ),
8535
- 'spec_name' => 'amp-story-auto-ads config script',
8536
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/extensions/amp-story/amp-story-auto-ads.md',
8537
- ),
8538
- ),
8539
- array(
8540
- 'attr_spec_list' => array(
8541
- 'async' => array(
8542
- 'mandatory' => true,
8543
- 'value' => '',
8544
- ),
8545
- 'nonce' => array(),
8546
- 'type' => array(
8547
- 'value_casei' => 'text/javascript',
8548
- ),
8549
- ),
8550
- 'tag_spec' => array(
8551
- 'extension_spec' => array(
8552
- 'allowed_versions' => array(
8553
- '0.1',
8554
- 'latest',
8555
- ),
8556
- 'name' => 'amp-story',
8557
- ),
8558
- ),
8559
- ),
8560
- array(
8561
- 'attr_spec_list' => array(
8562
- 'async' => array(
8563
- 'mandatory' => true,
8564
- 'value' => '',
8565
- ),
8566
- 'nonce' => array(),
8567
- 'type' => array(
8568
- 'value_casei' => 'text/javascript',
8569
- ),
8570
- ),
8571
- 'tag_spec' => array(
8572
- 'extension_spec' => array(
8573
- 'allowed_versions' => array(
8574
- '0.1',
8575
- 'latest',
8576
- ),
8577
- 'name' => 'amp-subscriptions',
8578
- 'requires_usage' => 3,
8579
- ),
8580
- ),
8581
- ),
8582
- array(
8583
- 'attr_spec_list' => array(
8584
- 'id' => array(
8585
- 'dispatch_key' => 2,
8586
- 'mandatory' => true,
8587
- 'value' => 'amp-subscriptions',
8588
- ),
8589
- 'nonce' => array(),
8590
- 'type' => array(
8591
- 'mandatory' => true,
8592
- 'value_casei' => 'application/json',
8593
- ),
8594
- ),
8595
- 'cdata' => array(
8596
- 'blacklisted_cdata_regex' => array(
8597
- 'error_message' => 'html comments',
8598
- 'regex' => '<!--',
8599
- ),
8600
- ),
8601
- 'tag_spec' => array(
8602
- 'mandatory_parent' => 'head',
8603
- 'requires_extension' => array(
8604
- 'amp-subscriptions',
8605
- ),
8606
- 'spec_name' => 'amp-subscriptions extension .json script',
8607
- 'unique' => true,
8608
- ),
8609
- ),
8610
- array(
8611
- 'attr_spec_list' => array(
8612
- 'async' => array(
8613
- 'mandatory' => true,
8614
- 'value' => '',
8615
- ),
8616
- 'nonce' => array(),
8617
- 'type' => array(
8618
- 'value_casei' => 'text/javascript',
8619
- ),
8620
- ),
8621
- 'tag_spec' => array(
8622
- 'extension_spec' => array(
8623
- 'allowed_versions' => array(
8624
- '0.1',
8625
- 'latest',
8626
- ),
8627
- 'name' => 'amp-subscriptions-google',
8628
- 'requires_usage' => 3,
8629
- ),
8630
- 'requires_extension' => array(
8631
- 'amp-subscriptions',
8632
- ),
8633
- ),
8634
- ),
8635
- array(
8636
- 'attr_spec_list' => array(
8637
- 'async' => array(
8638
- 'mandatory' => true,
8639
- 'value' => '',
8640
- ),
8641
- 'nonce' => array(),
8642
- 'type' => array(
8643
- 'value_casei' => 'text/javascript',
8644
- ),
8645
- ),
8646
- 'tag_spec' => array(
8647
- 'extension_spec' => array(
8648
- 'allowed_versions' => array(
8649
- '0.1',
8650
- 'latest',
8651
- ),
8652
- 'name' => 'amp-timeago',
8653
- ),
8654
- ),
8655
- ),
8656
- array(
8657
- 'attr_spec_list' => array(
8658
- 'async' => array(
8659
- 'mandatory' => true,
8660
- 'value' => '',
8661
- ),
8662
- 'nonce' => array(),
8663
- 'type' => array(
8664
- 'value_casei' => 'text/javascript',
8665
- ),
8666
- ),
8667
- 'tag_spec' => array(
8668
- 'extension_spec' => array(
8669
- 'allowed_versions' => array(
8670
- '0.1',
8671
- 'latest',
8672
- ),
8673
- 'deprecated_allow_duplicates' => true,
8674
- 'name' => 'amp-twitter',
8675
- 'requires_usage' => 2,
8676
- ),
8677
- ),
8678
- ),
8679
- array(
8680
- 'attr_spec_list' => array(
8681
- 'async' => array(
8682
- 'mandatory' => true,
8683
- 'value' => '',
8684
- ),
8685
- 'nonce' => array(),
8686
- 'type' => array(
8687
- 'value_casei' => 'text/javascript',
8688
- ),
8689
- ),
8690
- 'tag_spec' => array(
8691
- 'extension_spec' => array(
8692
- 'allowed_versions' => array(
8693
- '0.1',
8694
- 'latest',
8695
- ),
8696
- 'deprecated_allow_duplicates' => true,
8697
- 'name' => 'amp-user-notification',
8698
- 'requires_usage' => 2,
8699
- ),
8700
- ),
8701
- ),
8702
- array(
8703
- 'attr_spec_list' => array(
8704
- 'async' => array(
8705
- 'mandatory' => true,
8706
- 'value' => '',
8707
- ),
8708
- 'nonce' => array(),
8709
- 'type' => array(
8710
- 'value_casei' => 'text/javascript',
8711
- ),
8712
- ),
8713
- 'tag_spec' => array(
8714
- 'extension_spec' => array(
8715
- 'allowed_versions' => array(
8716
- '0.1',
8717
- 'latest',
8718
- ),
8719
- 'name' => 'amp-video',
8720
- 'requires_usage' => 3,
8721
- ),
8722
- 'spec_name' => 'amp-video extension .js script',
8723
- ),
8724
- ),
8725
- array(
8726
- 'attr_spec_list' => array(
8727
- 'async' => array(
8728
- 'mandatory' => true,
8729
- 'value' => '',
8730
- ),
8731
- 'nonce' => array(),
8732
- 'type' => array(
8733
- 'value_casei' => 'text/javascript',
8734
- ),
8735
- ),
8736
- 'tag_spec' => array(
8737
- 'extension_spec' => array(
8738
- 'allowed_versions' => array(
8739
- '0.1',
8740
- 'latest',
8741
- ),
8742
- 'deprecated_allow_duplicates' => true,
8743
- 'name' => 'amp-vimeo',
8744
- 'requires_usage' => 2,
8745
- ),
8746
- ),
8747
- ),
8748
- array(
8749
- 'attr_spec_list' => array(
8750
- 'async' => array(
8751
- 'mandatory' => true,
8752
- 'value' => '',
8753
- ),
8754
- 'nonce' => array(),
8755
- 'type' => array(
8756
- 'value_casei' => 'text/javascript',
8757
- ),
8758
- ),
8759
- 'tag_spec' => array(
8760
- 'extension_spec' => array(
8761
- 'allowed_versions' => array(
8762
- '0.1',
8763
- 'latest',
8764
- ),
8765
- 'deprecated_allow_duplicates' => true,
8766
- 'name' => 'amp-vine',
8767
- 'requires_usage' => 2,
8768
- ),
8769
- ),
8770
- ),
8771
- array(
8772
- 'attr_spec_list' => array(
8773
- 'async' => array(
8774
- 'mandatory' => true,
8775
- 'value' => '',
8776
- ),
8777
- 'nonce' => array(),
8778
- 'type' => array(
8779
- 'value_casei' => 'text/javascript',
8780
- ),
8781
- ),
8782
- 'tag_spec' => array(
8783
- 'extension_spec' => array(
8784
- 'allowed_versions' => array(
8785
- '0.1',
8786
- 'latest',
8787
- ),
8788
- 'name' => 'amp-vk',
8789
- ),
8790
- ),
8791
- ),
8792
- array(
8793
- 'attr_spec_list' => array(
8794
- 'async' => array(
8795
- 'mandatory' => true,
8796
- 'value' => '',
8797
- ),
8798
- 'nonce' => array(),
8799
- 'type' => array(
8800
- 'value_casei' => 'text/javascript',
8801
- ),
8802
- ),
8803
- 'tag_spec' => array(
8804
- 'extension_spec' => array(
8805
- 'allowed_versions' => array(
8806
- '0.1',
8807
- 'latest',
8808
- ),
8809
- 'name' => 'amp-web-push',
8810
- ),
8811
- ),
8812
- ),
8813
- array(
8814
- 'attr_spec_list' => array(
8815
- 'async' => array(
8816
- 'mandatory' => true,
8817
- 'value' => '',
8818
- ),
8819
- 'nonce' => array(),
8820
- 'type' => array(
8821
- 'value_casei' => 'text/javascript',
8822
- ),
8823
- ),
8824
- 'tag_spec' => array(
8825
- 'extension_spec' => array(
8826
- 'allowed_versions' => array(
8827
- '0.1',
8828
- 'latest',
8829
- ),
8830
- 'name' => 'amp-wistia-player',
8831
- ),
8832
- ),
8833
- ),
8834
- array(
8835
- 'attr_spec_list' => array(
8836
- 'async' => array(
8837
- 'mandatory' => true,
8838
- 'value' => '',
8839
- ),
8840
- 'nonce' => array(),
8841
- 'type' => array(
8842
- 'value_casei' => 'text/javascript',
8843
- ),
8844
- ),
8845
- 'tag_spec' => array(
8846
- 'extension_spec' => array(
8847
- 'allowed_versions' => array(
8848
- '0.1',
8849
- 'latest',
8850
- ),
8851
- 'deprecated_allow_duplicates' => true,
8852
- 'name' => 'amp-youtube',
8853
- 'requires_usage' => 2,
8854
- ),
8855
- ),
8856
- ),
8857
- ),
8858
- 'section' => array(
8859
- array(
8860
- 'attr_spec_list' => array(),
8861
- 'tag_spec' => array(
8862
- 'disallowed_ancestor' => array(
8863
- 'amp-accordion',
8864
- ),
8865
- ),
8866
- ),
8867
- array(
8868
- 'attr_spec_list' => array(
8869
- 'expanded' => array(
8870
- 'value' => '',
8871
- ),
8872
- ),
8873
- 'tag_spec' => array(
8874
- 'mandatory_parent' => 'amp-accordion',
8875
- 'spec_name' => 'amp-accordion > section',
8876
- ),
8877
- ),
8878
- ),
8879
- 'select' => array(
8880
- array(
8881
- 'attr_spec_list' => array(
8882
- '[autofocus]' => array(),
8883
- '[disabled]' => array(),
8884
- '[multiple]' => array(),
8885
- '[required]' => array(),
8886
- '[size]' => array(),
8887
- 'autofocus' => array(),
8888
- 'disabled' => array(),
8889
- 'multiple' => array(),
8890
- 'name' => array(
8891
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
8892
- ),
8893
- 'required' => array(),
8894
- 'size' => array(),
8895
- ),
8896
- 'tag_spec' => array(
8897
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
8898
- ),
8899
- ),
8900
- ),
8901
- 'slot' => array(
8902
- array(
8903
- 'attr_spec_list' => array(
8904
- 'name' => array(),
8905
- ),
8906
- 'tag_spec' => array(),
8907
- ),
8908
- ),
8909
- 'small' => array(
8910
- array(
8911
- 'attr_spec_list' => array(),
8912
- 'tag_spec' => array(),
8913
- ),
8914
- ),
8915
- 'solidcolor' => array(
8916
- array(
8917
- 'attr_spec_list' => array(
8918
- 'alignment-baseline' => array(),
8919
- 'baseline-shift' => array(),
8920
- 'clip' => array(),
8921
- 'clip-path' => array(),
8922
- 'clip-rule' => array(),
8923
- 'color' => array(),
8924
- 'color-interpolation' => array(),
8925
- 'color-interpolation-filters' => array(),
8926
- 'color-profile' => array(),
8927
- 'color-rendering' => array(),
8928
- 'cursor' => array(),
8929
- 'direction' => array(),
8930
- 'display' => array(),
8931
- 'dominant-baseline' => array(),
8932
- 'enable-background' => array(),
8933
- 'fill' => array(),
8934
- 'fill-opacity' => array(),
8935
- 'fill-rule' => array(),
8936
- 'filter' => array(),
8937
- 'flood-color' => array(),
8938
- 'flood-opacity' => array(),
8939
- 'font-family' => array(),
8940
- 'font-size' => array(),
8941
- 'font-size-adjust' => array(),
8942
- 'font-stretch' => array(),
8943
- 'font-style' => array(),
8944
- 'font-variant' => array(),
8945
- 'font-weight' => array(),
8946
- 'glyph-orientation-horizontal' => array(),
8947
- 'glyph-orientation-vertical' => array(),
8948
- 'image-rendering' => array(),
8949
- 'kerning' => array(),
8950
- 'letter-spacing' => array(),
8951
- 'lighting-color' => array(),
8952
- 'marker-end' => array(),
8953
- 'marker-mid' => array(),
8954
- 'marker-start' => array(),
8955
- 'mask' => array(),
8956
- 'opacity' => array(),
8957
- 'overflow' => array(),
8958
- 'pointer-events' => array(),
8959
- 'shape-rendering' => array(),
8960
- 'solid-color' => array(),
8961
- 'solid-opacity' => array(),
8962
- 'stop-color' => array(),
8963
- 'stop-opacity' => array(),
8964
- 'stroke' => array(),
8965
- 'stroke-dasharray' => array(),
8966
- 'stroke-dashoffset' => array(),
8967
- 'stroke-linecap' => array(),
8968
- 'stroke-linejoin' => array(),
8969
- 'stroke-miterlimit' => array(),
8970
- 'stroke-opacity' => array(),
8971
- 'stroke-width' => array(),
8972
- 'style' => array(
8973
- 'blacklisted_value_regex' => '!important',
8974
- ),
8975
- 'text-anchor' => array(),
8976
- 'text-decoration' => array(),
8977
- 'text-rendering' => array(),
8978
- 'unicode-bidi' => array(),
8979
- 'vector-effect' => array(),
8980
- 'visibility' => array(),
8981
- 'word-spacing' => array(),
8982
- 'writing-mode' => array(),
8983
- 'xml:lang' => array(),
8984
- 'xml:space' => array(),
8985
- 'xmlns' => array(),
8986
- 'xmlns:xlink' => array(),
8987
- ),
8988
- 'tag_spec' => array(
8989
- 'mandatory_ancestor' => 'svg',
8990
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
8991
- ),
8992
- ),
8993
- ),
8994
- 'source' => array(
8995
- array(
8996
- 'attr_spec_list' => array(
8997
- '[src]' => array(),
8998
- '[type]' => array(),
8999
- 'media' => array(),
9000
- 'src' => array(
9001
- 'blacklisted_value_regex' => '__amp_source_origin',
9002
- 'value_url' => array(
9003
- 'allow_relative' => true,
9004
- 'allowed_protocol' => array(
9005
- 'https',
9006
- ),
9007
- ),
9008
- ),
9009
- 'type' => array(),
9010
- ),
9011
- 'tag_spec' => array(
9012
- 'mandatory_parent' => 'amp-video',
9013
- 'spec_name' => 'amp-video > source',
9014
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
9015
- ),
9016
- ),
9017
- array(
9018
- 'attr_spec_list' => array(
9019
- '[src]' => array(),
9020
- '[type]' => array(),
9021
- 'media' => array(),
9022
- 'src' => array(
9023
- 'blacklisted_value_regex' => '__amp_source_origin',
9024
- 'value_url' => array(
9025
- 'allow_relative' => true,
9026
- 'allowed_protocol' => array(
9027
- 'https',
9028
- ),
9029
- ),
9030
- ),
9031
- 'type' => array(),
9032
- ),
9033
- 'tag_spec' => array(
9034
- 'mandatory_parent' => 'amp-audio',
9035
- 'spec_name' => 'amp-audio > source',
9036
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
9037
- ),
9038
- ),
9039
- array(
9040
- 'attr_spec_list' => array(
9041
- 'media' => array(),
9042
- 'src' => array(
9043
- 'blacklisted_value_regex' => '__amp_source_origin',
9044
- 'mandatory' => true,
9045
- 'value_url' => array(
9046
- 'allow_relative' => true,
9047
- 'allowed_protocol' => array(
9048
- 'https',
9049
- ),
9050
- ),
9051
- ),
9052
- 'type' => array(
9053
- 'mandatory' => true,
9054
- ),
9055
- ),
9056
- 'tag_spec' => array(
9057
- 'mandatory_parent' => 'audio',
9058
- 'spec_name' => 'audio > source',
9059
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
9060
- ),
9061
- ),
9062
- array(
9063
- 'attr_spec_list' => array(
9064
- 'media' => array(),
9065
- 'src' => array(
9066
- 'blacklisted_value_regex' => '__amp_source_origin',
9067
- 'mandatory' => true,
9068
- 'value_url' => array(
9069
- 'allow_relative' => true,
9070
- 'allowed_protocol' => array(
9071
- 'https',
9072
- ),
9073
- ),
9074
- ),
9075
- 'type' => array(
9076
- 'mandatory' => true,
9077
- ),
9078
- ),
9079
- 'tag_spec' => array(
9080
- 'mandatory_parent' => 'video',
9081
- 'spec_name' => 'video > source',
9082
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
9083
- ),
9084
- ),
9085
- array(
9086
- 'attr_spec_list' => array(
9087
- '[src]' => array(),
9088
- '[type]' => array(),
9089
- 'media' => array(),
9090
- 'src' => array(
9091
- 'blacklisted_value_regex' => '__amp_source_origin',
9092
- 'value_url' => array(
9093
- 'allow_relative' => true,
9094
- 'allowed_protocol' => array(
9095
- 'https',
9096
- ),
9097
- ),
9098
- ),
9099
- 'type' => array(),
9100
- ),
9101
- 'tag_spec' => array(
9102
- 'mandatory_parent' => 'amp-ima-video',
9103
- 'requires_extension' => array(
9104
- 'amp-ima-video',
9105
- ),
9106
- 'spec_name' => 'amp-ima-video > source',
9107
- ),
9108
- ),
9109
- ),
9110
- 'spacer' => array(
9111
- array(
9112
- 'attr_spec_list' => array(),
9113
- 'tag_spec' => array(),
9114
- ),
9115
- ),
9116
- 'span' => array(
9117
- array(
9118
- 'attr_spec_list' => array(),
9119
- 'tag_spec' => array(),
9120
- ),
9121
- ),
9122
- 'stop' => array(
9123
- array(
9124
- 'attr_spec_list' => array(
9125
- 'offset' => array(),
9126
- 'stop-color' => array(),
9127
- 'stop-opacity' => array(),
9128
- 'style' => array(
9129
- 'blacklisted_value_regex' => '!important',
9130
- ),
9131
- ),
9132
- 'tag_spec' => array(
9133
- 'mandatory_ancestor' => 'lineargradient',
9134
- 'spec_name' => 'lineargradient > stop',
9135
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9136
- ),
9137
- ),
9138
- array(
9139
- 'attr_spec_list' => array(
9140
- 'offset' => array(),
9141
- 'stop-color' => array(),
9142
- 'stop-opacity' => array(),
9143
- 'style' => array(
9144
- 'blacklisted_value_regex' => '!important',
9145
- ),
9146
- ),
9147
- 'tag_spec' => array(
9148
- 'mandatory_ancestor' => 'radialgradient',
9149
- 'spec_name' => 'radialgradient > stop',
9150
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9151
- ),
9152
- ),
9153
- ),
9154
- 'strike' => array(
9155
- array(
9156
- 'attr_spec_list' => array(),
9157
- 'tag_spec' => array(),
9158
- ),
9159
- ),
9160
- 'strong' => array(
9161
- array(
9162
- 'attr_spec_list' => array(),
9163
- 'tag_spec' => array(),
9164
- ),
9165
- ),
9166
- 'style' => array(
9167
- array(
9168
- 'attr_spec_list' => array(
9169
- 'amp-custom' => array(
9170
- 'mandatory' => true,
9171
- 'value' => '',
9172
- ),
9173
- 'nonce' => array(),
9174
- 'type' => array(
9175
- 'value_casei' => 'text/css',
9176
- ),
9177
- ),
9178
- 'cdata' => array(
9179
- 'blacklisted_cdata_regex' => array(
9180
- 'error_message' => 'CSS !important',
9181
- 'regex' => '!important',
9182
- ),
9183
- 'max_bytes' => 50000,
9184
- 'max_bytes_spec_url' => 'https://www.ampproject.org/docs/reference/spec#maximum-size',
9185
- ),
9186
- 'tag_spec' => array(
9187
- 'mandatory_parent' => 'head',
9188
- 'spec_name' => 'style amp-custom',
9189
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#stylesheets',
9190
- 'unique' => true,
9191
- ),
9192
- ),
9193
- array(
9194
- 'attr_spec_list' => array(
9195
- 'amp-boilerplate' => array(
9196
- 'dispatch_key' => 3,
9197
- 'mandatory' => true,
9198
- 'value' => '',
9199
- ),
9200
- 'nonce' => array(),
9201
- ),
9202
- 'cdata' => array(
9203
- 'cdata_regex' => '\\s*body{-webkit-animation:-amp-start\\s+8s\\s+steps\\(1,end\\)\\s+0s\\s+1\\s+normal\\s+both;-moz-animation:-amp-start\\s+8s\\s+steps\\(1,end\\)\\s+0s\\s+1\\s+normal\\s+both;-ms-animation:-amp-start\\s+8s\\s+steps\\(1,end\\)\\s+0s\\s+1\\s+normal\\s+both;animation:-amp-start\\s+8s\\s+steps\\(1,end\\)\\s+0s\\s+1\\s+normal\\s+both}@-webkit-keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}\\s*',
9204
- ),
9205
- 'tag_spec' => array(
9206
- 'mandatory_alternatives' => 'head > style[amp-boilerplate]',
9207
- 'mandatory_parent' => 'head',
9208
- 'spec_name' => 'head > style[amp-boilerplate]',
9209
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/spec/amp-boilerplate.md',
9210
- 'unique' => true,
9211
- ),
9212
- ),
9213
- array(
9214
- 'attr_spec_list' => array(
9215
- 'amp-boilerplate' => array(
9216
- 'dispatch_key' => 3,
9217
- 'mandatory' => true,
9218
- 'value' => '',
9219
- ),
9220
- 'nonce' => array(),
9221
- ),
9222
- 'cdata' => array(
9223
- 'cdata_regex' => '\\s*body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}\\s*',
9224
- ),
9225
- 'tag_spec' => array(
9226
- 'mandatory_alternatives' => 'noscript > style[amp-boilerplate]',
9227
- 'mandatory_ancestor' => 'head',
9228
- 'mandatory_parent' => 'noscript',
9229
- 'spec_name' => 'noscript > style[amp-boilerplate]',
9230
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/spec/amp-boilerplate.md',
9231
- 'unique' => true,
9232
- ),
9233
- ),
9234
- array(
9235
- 'attr_spec_list' => array(
9236
- 'amp-keyframes' => array(
9237
- 'dispatch_key' => 1,
9238
- 'mandatory' => true,
9239
- 'value' => '',
9240
- ),
9241
- ),
9242
- 'cdata' => array(
9243
- 'max_bytes' => 500000,
9244
- 'max_bytes_spec_url' => 'https://www.ampproject.org/docs/reference/spec#keyframes-stylesheet',
9245
- ),
9246
- 'tag_spec' => array(
9247
- 'mandatory_parent' => 'body',
9248
- 'spec_name' => 'style[amp-keyframes]',
9249
- 'unique' => true,
9250
- ),
9251
- ),
9252
- ),
9253
- 'sub' => array(
9254
- array(
9255
- 'attr_spec_list' => array(),
9256
- 'tag_spec' => array(),
9257
- ),
9258
- ),
9259
- 'sup' => array(
9260
- array(
9261
- 'attr_spec_list' => array(),
9262
- 'tag_spec' => array(),
9263
- ),
9264
- ),
9265
- 'svg' => array(
9266
- array(
9267
- 'attr_spec_list' => array(
9268
- 'alignment-baseline' => array(),
9269
- 'baseline-shift' => array(),
9270
- 'clip' => array(),
9271
- 'clip-path' => array(),
9272
- 'clip-rule' => array(),
9273
- 'color' => array(),
9274
- 'color-interpolation' => array(),
9275
- 'color-interpolation-filters' => array(),
9276
- 'color-profile' => array(),
9277
- 'color-rendering' => array(),
9278
- 'contentscripttype' => array(),
9279
- 'contentstyletype' => array(),
9280
- 'cursor' => array(),
9281
- 'direction' => array(),
9282
- 'display' => array(),
9283
- 'dominant-baseline' => array(),
9284
- 'enable-background' => array(),
9285
- 'externalresourcesrequired' => array(),
9286
- 'fill' => array(),
9287
- 'fill-opacity' => array(),
9288
- 'fill-rule' => array(),
9289
- 'filter' => array(),
9290
- 'flood-color' => array(),
9291
- 'flood-opacity' => array(),
9292
- 'font-family' => array(),
9293
- 'font-size' => array(),
9294
- 'font-size-adjust' => array(),
9295
- 'font-stretch' => array(),
9296
- 'font-style' => array(),
9297
- 'font-variant' => array(),
9298
- 'font-weight' => array(),
9299
- 'glyph-orientation-horizontal' => array(),
9300
- 'glyph-orientation-vertical' => array(),
9301
- 'height' => array(),
9302
- 'image-rendering' => array(),
9303
- 'kerning' => array(),
9304
- 'letter-spacing' => array(),
9305
- 'lighting-color' => array(),
9306
- 'marker-end' => array(),
9307
- 'marker-mid' => array(),
9308
- 'marker-start' => array(),
9309
- 'mask' => array(),
9310
- 'opacity' => array(),
9311
- 'overflow' => array(),
9312
- 'pointer-events' => array(),
9313
- 'preserveaspectratio' => array(),
9314
- 'requiredextensions' => array(),
9315
- 'requiredfeatures' => array(),
9316
- 'shape-rendering' => array(),
9317
- 'stop-color' => array(),
9318
- 'stop-opacity' => array(),
9319
- 'stroke' => array(),
9320
- 'stroke-dasharray' => array(),
9321
- 'stroke-dashoffset' => array(),
9322
- 'stroke-linecap' => array(),
9323
- 'stroke-linejoin' => array(),
9324
- 'stroke-miterlimit' => array(),
9325
- 'stroke-opacity' => array(),
9326
- 'stroke-width' => array(),
9327
- 'systemlanguage' => array(),
9328
- 'text-anchor' => array(),
9329
- 'text-decoration' => array(),
9330
- 'text-rendering' => array(),
9331
- 'unicode-bidi' => array(),
9332
- 'vector-effect' => array(),
9333
- 'version' => array(
9334
- 'value_regex' => '(1.0|1.1)',
9335
- ),
9336
- 'viewbox' => array(),
9337
- 'visibility' => array(),
9338
- 'width' => array(),
9339
- 'word-spacing' => array(),
9340
- 'writing-mode' => array(),
9341
- 'x' => array(),
9342
- 'xml:lang' => array(),
9343
- 'xml:space' => array(),
9344
- 'xmlns' => array(),
9345
- 'xmlns:xlink' => array(),
9346
- 'y' => array(),
9347
- 'zoomandpan' => array(),
9348
- ),
9349
- 'tag_spec' => array(
9350
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9351
- ),
9352
- ),
9353
- ),
9354
- 'switch' => array(
9355
- array(
9356
- 'attr_spec_list' => array(
9357
- 'alignment-baseline' => array(),
9358
- 'baseline-shift' => array(),
9359
- 'clip' => array(),
9360
- 'clip-path' => array(),
9361
- 'clip-rule' => array(),
9362
- 'color' => array(),
9363
- 'color-interpolation' => array(),
9364
- 'color-interpolation-filters' => array(),
9365
- 'color-profile' => array(),
9366
- 'color-rendering' => array(),
9367
- 'cursor' => array(),
9368
- 'direction' => array(),
9369
- 'display' => array(),
9370
- 'dominant-baseline' => array(),
9371
- 'enable-background' => array(),
9372
- 'fill' => array(),
9373
- 'fill-opacity' => array(),
9374
- 'fill-rule' => array(),
9375
- 'filter' => array(),
9376
- 'flood-color' => array(),
9377
- 'flood-opacity' => array(),
9378
- 'font-family' => array(),
9379
- 'font-size' => array(),
9380
- 'font-size-adjust' => array(),
9381
- 'font-stretch' => array(),
9382
- 'font-style' => array(),
9383
- 'font-variant' => array(),
9384
- 'font-weight' => array(),
9385
- 'glyph-orientation-horizontal' => array(),
9386
- 'glyph-orientation-vertical' => array(),
9387
- 'image-rendering' => array(),
9388
- 'kerning' => array(),
9389
- 'letter-spacing' => array(),
9390
- 'lighting-color' => array(),
9391
- 'marker-end' => array(),
9392
- 'marker-mid' => array(),
9393
- 'marker-start' => array(),
9394
- 'mask' => array(),
9395
- 'opacity' => array(),
9396
- 'overflow' => array(),
9397
- 'pointer-events' => array(),
9398
- 'requiredextensions' => array(),
9399
- 'requiredfeatures' => array(),
9400
- 'shape-rendering' => array(),
9401
- 'stop-color' => array(),
9402
- 'stop-opacity' => array(),
9403
- 'stroke' => array(),
9404
- 'stroke-dasharray' => array(),
9405
- 'stroke-dashoffset' => array(),
9406
- 'stroke-linecap' => array(),
9407
- 'stroke-linejoin' => array(),
9408
- 'stroke-miterlimit' => array(),
9409
- 'stroke-opacity' => array(),
9410
- 'stroke-width' => array(),
9411
- 'style' => array(
9412
- 'blacklisted_value_regex' => '!important',
9413
- ),
9414
- 'systemlanguage' => array(),
9415
- 'text-anchor' => array(),
9416
- 'text-decoration' => array(),
9417
- 'text-rendering' => array(),
9418
- 'unicode-bidi' => array(),
9419
- 'vector-effect' => array(),
9420
- 'visibility' => array(),
9421
- 'word-spacing' => array(),
9422
- 'writing-mode' => array(),
9423
- 'xml:lang' => array(),
9424
- 'xml:space' => array(),
9425
- 'xmlns' => array(),
9426
- 'xmlns:xlink' => array(),
9427
- ),
9428
- 'tag_spec' => array(
9429
- 'mandatory_ancestor' => 'svg',
9430
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9431
- ),
9432
- ),
9433
- ),
9434
- 'symbol' => array(
9435
- array(
9436
- 'attr_spec_list' => array(
9437
- 'alignment-baseline' => array(),
9438
- 'baseline-shift' => array(),
9439
- 'clip' => array(),
9440
- 'clip-path' => array(),
9441
- 'clip-rule' => array(),
9442
- 'color' => array(),
9443
- 'color-interpolation' => array(),
9444
- 'color-interpolation-filters' => array(),
9445
- 'color-profile' => array(),
9446
- 'color-rendering' => array(),
9447
- 'cursor' => array(),
9448
- 'direction' => array(),
9449
- 'display' => array(),
9450
- 'dominant-baseline' => array(),
9451
- 'enable-background' => array(),
9452
- 'externalresourcesrequired' => array(),
9453
- 'fill' => array(),
9454
- 'fill-opacity' => array(),
9455
- 'fill-rule' => array(),
9456
- 'filter' => array(),
9457
- 'flood-color' => array(),
9458
- 'flood-opacity' => array(),
9459
- 'font-family' => array(),
9460
- 'font-size' => array(),
9461
- 'font-size-adjust' => array(),
9462
- 'font-stretch' => array(),
9463
- 'font-style' => array(),
9464
- 'font-variant' => array(),
9465
- 'font-weight' => array(),
9466
- 'glyph-orientation-horizontal' => array(),
9467
- 'glyph-orientation-vertical' => array(),
9468
- 'image-rendering' => array(),
9469
- 'kerning' => array(),
9470
- 'letter-spacing' => array(),
9471
- 'lighting-color' => array(),
9472
- 'marker-end' => array(),
9473
- 'marker-mid' => array(),
9474
- 'marker-start' => array(),
9475
- 'mask' => array(),
9476
- 'opacity' => array(),
9477
- 'overflow' => array(),
9478
- 'pointer-events' => array(),
9479
- 'preserveaspectratio' => array(),
9480
- 'shape-rendering' => array(),
9481
- 'stop-color' => array(),
9482
- 'stop-opacity' => array(),
9483
- 'stroke' => array(),
9484
- 'stroke-dasharray' => array(),
9485
- 'stroke-dashoffset' => array(),
9486
- 'stroke-linecap' => array(),
9487
- 'stroke-linejoin' => array(),
9488
- 'stroke-miterlimit' => array(),
9489
- 'stroke-opacity' => array(),
9490
- 'stroke-width' => array(),
9491
- 'style' => array(
9492
- 'blacklisted_value_regex' => '!important',
9493
- ),
9494
- 'text-anchor' => array(),
9495
- 'text-decoration' => array(),
9496
- 'text-rendering' => array(),
9497
- 'unicode-bidi' => array(),
9498
- 'vector-effect' => array(),
9499
- 'viewbox' => array(),
9500
- 'visibility' => array(),
9501
- 'word-spacing' => array(),
9502
- 'writing-mode' => array(),
9503
- 'xml:lang' => array(),
9504
- 'xml:space' => array(),
9505
- 'xmlns' => array(),
9506
- 'xmlns:xlink' => array(),
9507
- ),
9508
- 'tag_spec' => array(
9509
- 'mandatory_ancestor' => 'svg',
9510
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9511
- ),
9512
- ),
9513
- ),
9514
- 'table' => array(
9515
- array(
9516
- 'attr_spec_list' => array(
9517
- 'align' => array(),
9518
- 'bgcolor' => array(),
9519
- 'border' => array(
9520
- 'value_regex' => '0|1',
9521
- ),
9522
- 'cellpadding' => array(),
9523
- 'cellspacing' => array(),
9524
- 'sortable' => array(),
9525
- 'width' => array(),
9526
- ),
9527
- 'tag_spec' => array(),
9528
- ),
9529
- ),
9530
- 'tbody' => array(
9531
- array(
9532
- 'attr_spec_list' => array(),
9533
- 'tag_spec' => array(),
9534
- ),
9535
- ),
9536
- 'td' => array(
9537
- array(
9538
- 'attr_spec_list' => array(
9539
- 'align' => array(),
9540
- 'bgcolor' => array(),
9541
- 'colspan' => array(),
9542
- 'headers' => array(),
9543
- 'height' => array(),
9544
- 'rowspan' => array(),
9545
- 'valign' => array(),
9546
- 'width' => array(),
9547
- ),
9548
- 'tag_spec' => array(),
9549
- ),
9550
- ),
9551
- 'template' => array(
9552
- array(
9553
- 'attr_spec_list' => array(
9554
- 'type' => array(
9555
- 'mandatory' => true,
9556
- 'value' => 'amp-mustache',
9557
- ),
9558
- ),
9559
- 'tag_spec' => array(
9560
- 'disallowed_ancestor' => array(
9561
- 'template',
9562
- 'amp-story-auto-ads',
9563
- 'form > div [submit-success][template]',
9564
- 'form > div [submit-error][template]',
9565
- ),
9566
- 'requires_extension' => array(
9567
- 'amp-mustache',
9568
- ),
9569
- ),
9570
- ),
9571
- array(
9572
- 'attr_spec_list' => array(
9573
- 'type' => array(
9574
- 'mandatory' => true,
9575
- 'value' => 'amp-mustache',
9576
- ),
9577
- ),
9578
- 'tag_spec' => array(
9579
- 'mandatory_parent' => 'amp-story-auto-ads',
9580
- 'requires_extension' => array(
9581
- 'amp-mustache',
9582
- ),
9583
- 'spec_name' => 'amp-story-auto-ads > template',
9584
- ),
9585
- ),
9586
- ),
9587
- 'text' => array(
9588
- array(
9589
- 'attr_spec_list' => array(
9590
- 'alignment-baseline' => array(),
9591
- 'baseline-shift' => array(),
9592
- 'clip' => array(),
9593
- 'clip-path' => array(),
9594
- 'clip-rule' => array(),
9595
- 'color' => array(),
9596
- 'color-interpolation' => array(),
9597
- 'color-interpolation-filters' => array(),
9598
- 'color-profile' => array(),
9599
- 'color-rendering' => array(),
9600
- 'cursor' => array(),
9601
- 'direction' => array(),
9602
- 'display' => array(),
9603
- 'dominant-baseline' => array(),
9604
- 'dx' => array(),
9605
- 'dy' => array(),
9606
- 'enable-background' => array(),
9607
- 'externalresourcesrequired' => array(),
9608
- 'fill' => array(),
9609
- 'fill-opacity' => array(),
9610
- 'fill-rule' => array(),
9611
- 'filter' => array(),
9612
- 'flood-color' => array(),
9613
- 'flood-opacity' => array(),
9614
- 'font-family' => array(),
9615
- 'font-size' => array(),
9616
- 'font-size-adjust' => array(),
9617
- 'font-stretch' => array(),
9618
- 'font-style' => array(),
9619
- 'font-variant' => array(),
9620
- 'font-weight' => array(),
9621
- 'glyph-orientation-horizontal' => array(),
9622
- 'glyph-orientation-vertical' => array(),
9623
- 'image-rendering' => array(),
9624
- 'kerning' => array(),
9625
- 'lengthadjust' => array(),
9626
- 'letter-spacing' => array(),
9627
- 'lighting-color' => array(),
9628
- 'marker-end' => array(),
9629
- 'marker-mid' => array(),
9630
- 'marker-start' => array(),
9631
- 'mask' => array(),
9632
- 'opacity' => array(),
9633
- 'overflow' => array(),
9634
- 'pointer-events' => array(),
9635
- 'requiredextensions' => array(),
9636
- 'requiredfeatures' => array(),
9637
- 'rotate' => array(),
9638
- 'shape-rendering' => array(),
9639
- 'stop-color' => array(),
9640
- 'stop-opacity' => array(),
9641
- 'stroke' => array(),
9642
- 'stroke-dasharray' => array(),
9643
- 'stroke-dashoffset' => array(),
9644
- 'stroke-linecap' => array(),
9645
- 'stroke-linejoin' => array(),
9646
- 'stroke-miterlimit' => array(),
9647
- 'stroke-opacity' => array(),
9648
- 'stroke-width' => array(),
9649
- 'style' => array(
9650
- 'blacklisted_value_regex' => '!important',
9651
- ),
9652
- 'systemlanguage' => array(),
9653
- 'text-anchor' => array(),
9654
- 'text-decoration' => array(),
9655
- 'text-rendering' => array(),
9656
- 'textlength' => array(),
9657
- 'transform' => array(),
9658
- 'unicode-bidi' => array(),
9659
- 'vector-effect' => array(),
9660
- 'visibility' => array(),
9661
- 'word-spacing' => array(),
9662
- 'writing-mode' => array(),
9663
- 'x' => array(),
9664
- 'xml:lang' => array(),
9665
- 'xml:space' => array(),
9666
- 'xmlns' => array(),
9667
- 'xmlns:xlink' => array(),
9668
- 'y' => array(),
9669
- ),
9670
- 'tag_spec' => array(
9671
- 'mandatory_ancestor' => 'svg',
9672
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9673
- ),
9674
- ),
9675
- ),
9676
- 'textarea' => array(
9677
- array(
9678
- 'attr_spec_list' => array(
9679
- '[autocomplete]' => array(),
9680
- '[autofocus]' => array(),
9681
- '[cols]' => array(),
9682
- '[disabled]' => array(),
9683
- '[maxlength]' => array(),
9684
- '[minlength]' => array(),
9685
- '[placeholder]' => array(),
9686
- '[readonly]' => array(),
9687
- '[required]' => array(),
9688
- '[rows]' => array(),
9689
- '[selectiondirection]' => array(),
9690
- '[selectionend]' => array(),
9691
- '[selectionstart]' => array(),
9692
- '[spellcheck]' => array(),
9693
- '[wrap]' => array(),
9694
- 'autocomplete' => array(),
9695
- 'autofocus' => array(),
9696
- 'cols' => array(),
9697
- 'disabled' => array(),
9698
- 'maxlength' => array(),
9699
- 'minlength' => array(),
9700
- 'name' => array(
9701
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
9702
- ),
9703
- 'placeholder' => array(),
9704
- 'readonly' => array(),
9705
- 'required' => array(),
9706
- 'rows' => array(),
9707
- 'selectiondirection' => array(),
9708
- 'selectionend' => array(),
9709
- 'selectionstart' => array(),
9710
- 'spellcheck' => array(),
9711
- 'wrap' => array(),
9712
- ),
9713
- 'tag_spec' => array(
9714
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
9715
- ),
9716
- ),
9717
- ),
9718
- 'textpath' => array(
9719
- array(
9720
- 'attr_spec_list' => array(
9721
- 'alignment-baseline' => array(),
9722
- 'baseline-shift' => array(),
9723
- 'clip' => array(),
9724
- 'clip-path' => array(),
9725
- 'clip-rule' => array(),
9726
- 'color' => array(),
9727
- 'color-interpolation' => array(),
9728
- 'color-interpolation-filters' => array(),
9729
- 'color-profile' => array(),
9730
- 'color-rendering' => array(),
9731
- 'cursor' => array(),
9732
- 'direction' => array(),
9733
- 'display' => array(),
9734
- 'dominant-baseline' => array(),
9735
- 'enable-background' => array(),
9736
- 'externalresourcesrequired' => array(),
9737
- 'fill' => array(),
9738
- 'fill-opacity' => array(),
9739
- 'fill-rule' => array(),
9740
- 'filter' => array(),
9741
- 'flood-color' => array(),
9742
- 'flood-opacity' => array(),
9743
- 'font-family' => array(),
9744
- 'font-size' => array(),
9745
- 'font-size-adjust' => array(),
9746
- 'font-stretch' => array(),
9747
- 'font-style' => array(),
9748
- 'font-variant' => array(),
9749
- 'font-weight' => array(),
9750
- 'glyph-orientation-horizontal' => array(),
9751
- 'glyph-orientation-vertical' => array(),
9752
- 'image-rendering' => array(),
9753
- 'kerning' => array(),
9754
- 'letter-spacing' => array(),
9755
- 'lighting-color' => array(),
9756
- 'marker-end' => array(),
9757
- 'marker-mid' => array(),
9758
- 'marker-start' => array(),
9759
- 'mask' => array(),
9760
- 'method' => array(),
9761
- 'opacity' => array(),
9762
- 'overflow' => array(),
9763
- 'pointer-events' => array(),
9764
- 'requiredextensions' => array(),
9765
- 'requiredfeatures' => array(),
9766
- 'shape-rendering' => array(),
9767
- 'spacing' => array(),
9768
- 'startoffset' => array(),
9769
- 'stop-color' => array(),
9770
- 'stop-opacity' => array(),
9771
- 'stroke' => array(),
9772
- 'stroke-dasharray' => array(),
9773
- 'stroke-dashoffset' => array(),
9774
- 'stroke-linecap' => array(),
9775
- 'stroke-linejoin' => array(),
9776
- 'stroke-miterlimit' => array(),
9777
- 'stroke-opacity' => array(),
9778
- 'stroke-width' => array(),
9779
- 'style' => array(
9780
- 'blacklisted_value_regex' => '!important',
9781
- ),
9782
- 'systemlanguage' => array(),
9783
- 'text-anchor' => array(),
9784
- 'text-decoration' => array(),
9785
- 'text-rendering' => array(),
9786
- 'unicode-bidi' => array(),
9787
- 'vector-effect' => array(),
9788
- 'visibility' => array(),
9789
- 'word-spacing' => array(),
9790
- 'writing-mode' => array(),
9791
- 'xlink:actuate' => array(),
9792
- 'xlink:arcrole' => array(),
9793
- 'xlink:href' => array(
9794
- 'alternative_names' => array(
9795
- 'href',
9796
- ),
9797
- 'value_url' => array(
9798
- 'allow_empty' => false,
9799
- 'allow_relative' => true,
9800
- 'allowed_protocol' => array(
9801
- 'http',
9802
- 'https',
9803
- ),
9804
- ),
9805
- ),
9806
- 'xlink:role' => array(),
9807
- 'xlink:show' => array(),
9808
- 'xlink:title' => array(),
9809
- 'xlink:type' => array(),
9810
- 'xml:lang' => array(),
9811
- 'xml:space' => array(),
9812
- 'xmlns' => array(),
9813
- 'xmlns:xlink' => array(),
9814
- ),
9815
- 'tag_spec' => array(
9816
- 'mandatory_ancestor' => 'svg',
9817
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9818
- ),
9819
- ),
9820
- ),
9821
- 'tfoot' => array(
9822
- array(
9823
- 'attr_spec_list' => array(),
9824
- 'tag_spec' => array(),
9825
- ),
9826
- ),
9827
- 'th' => array(
9828
- array(
9829
- 'attr_spec_list' => array(
9830
- 'abbr' => array(),
9831
- 'align' => array(),
9832
- 'bgcolor' => array(),
9833
- 'colspan' => array(),
9834
- 'headers' => array(),
9835
- 'height' => array(),
9836
- 'rowspan' => array(),
9837
- 'scope' => array(),
9838
- 'sorted' => array(),
9839
- 'valign' => array(),
9840
- 'width' => array(),
9841
- ),
9842
- 'tag_spec' => array(),
9843
- ),
9844
- ),
9845
- 'thead' => array(
9846
- array(
9847
- 'attr_spec_list' => array(),
9848
- 'tag_spec' => array(),
9849
- ),
9850
- ),
9851
- 'time' => array(
9852
- array(
9853
- 'attr_spec_list' => array(
9854
- 'datetime' => array(),
9855
- ),
9856
- 'tag_spec' => array(),
9857
- ),
9858
- ),
9859
- 'title' => array(
9860
- array(
9861
- 'attr_spec_list' => array(),
9862
- 'tag_spec' => array(
9863
- 'spec_name' => 'title',
9864
- ),
9865
- ),
9866
- array(
9867
- 'attr_spec_list' => array(
9868
- 'style' => array(
9869
- 'blacklisted_value_regex' => '!important',
9870
- ),
9871
- 'xml:lang' => array(),
9872
- 'xml:space' => array(),
9873
- 'xmlns' => array(),
9874
- 'xmlns:xlink' => array(),
9875
- ),
9876
- 'tag_spec' => array(
9877
- 'mandatory_ancestor' => 'svg',
9878
- 'spec_name' => 'svg title',
9879
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9880
- ),
9881
- ),
9882
- ),
9883
- 'tr' => array(
9884
- array(
9885
- 'attr_spec_list' => array(
9886
- 'align' => array(),
9887
- 'bgcolor' => array(),
9888
- 'height' => array(),
9889
- 'valign' => array(),
9890
- ),
9891
- 'tag_spec' => array(),
9892
- ),
9893
- ),
9894
- 'track' => array(
9895
- array(
9896
- 'attr_spec_list' => array(
9897
- 'default' => array(
9898
- 'value' => '',
9899
- ),
9900
- 'kind' => array(
9901
- 'value_regex' => '(captions|descriptions|chapters|metadata)',
9902
- ),
9903
- 'label' => array(),
9904
- 'src' => array(
9905
- 'blacklisted_value_regex' => '__amp_source_origin',
9906
- 'mandatory' => true,
9907
- 'value_url' => array(
9908
- 'allow_relative' => false,
9909
- 'allowed_protocol' => array(
9910
- 'https',
9911
- ),
9912
- ),
9913
- ),
9914
- 'srclang' => array(),
9915
- ),
9916
- 'tag_spec' => array(
9917
- 'mandatory_parent' => 'audio',
9918
- 'spec_name' => 'audio > track',
9919
- ),
9920
- ),
9921
- array(
9922
- 'attr_spec_list' => array(
9923
- 'default' => array(
9924
- 'value' => '',
9925
- ),
9926
- 'kind' => array(
9927
- 'mandatory' => true,
9928
- 'value_casei' => 'subtitles',
9929
- ),
9930
- 'label' => array(),
9931
- 'src' => array(
9932
- 'blacklisted_value_regex' => '__amp_source_origin',
9933
- 'mandatory' => true,
9934
- 'value_url' => array(
9935
- 'allow_relative' => false,
9936
- 'allowed_protocol' => array(
9937
- 'https',
9938
- ),
9939
- ),
9940
- ),
9941
- 'srclang' => array(
9942
- 'mandatory' => true,
9943
- ),
9944
- ),
9945
- 'tag_spec' => array(
9946
- 'mandatory_parent' => 'audio',
9947
- 'spec_name' => 'audio > track[kind=subtitles]',
9948
- ),
9949
- ),
9950
- array(
9951
- 'attr_spec_list' => array(
9952
- 'default' => array(
9953
- 'value' => '',
9954
- ),
9955
- 'kind' => array(
9956
- 'value_regex' => '(captions|descriptions|chapters|metadata)',
9957
- ),
9958
- 'label' => array(),
9959
- 'src' => array(
9960
- 'blacklisted_value_regex' => '__amp_source_origin',
9961
- 'mandatory' => true,
9962
- 'value_url' => array(
9963
- 'allow_relative' => false,
9964
- 'allowed_protocol' => array(
9965
- 'https',
9966
- ),
9967
- ),
9968
- ),
9969
- 'srclang' => array(),
9970
- ),
9971
- 'tag_spec' => array(
9972
- 'mandatory_parent' => 'video',
9973
- 'spec_name' => 'video > track',
9974
- ),
9975
- ),
9976
- array(
9977
- 'attr_spec_list' => array(
9978
- 'default' => array(
9979
- 'value' => '',
9980
- ),
9981
- 'kind' => array(
9982
- 'mandatory' => true,
9983
- 'value_casei' => 'subtitles',
9984
- ),
9985
- 'label' => array(),
9986
- 'src' => array(
9987
- 'blacklisted_value_regex' => '__amp_source_origin',
9988
- 'mandatory' => true,
9989
- 'value_url' => array(
9990
- 'allow_relative' => false,
9991
- 'allowed_protocol' => array(
9992
- 'https',
9993
- ),
9994
- ),
9995
- ),
9996
- 'srclang' => array(
9997
- 'mandatory' => true,
9998
- ),
9999
- ),
10000
- 'tag_spec' => array(
10001
- 'mandatory_parent' => 'video',
10002
- 'spec_name' => 'video > track[kind=subtitles]',
10003
- ),
10004
- ),
10005
- array(
10006
- 'attr_spec_list' => array(
10007
- '[label]' => array(),
10008
- '[src]' => array(),
10009
- '[srclang]' => array(),
10010
- 'default' => array(
10011
- 'value' => '',
10012
- ),
10013
- 'kind' => array(
10014
- 'value_regex' => '(captions|descriptions|chapters|metadata)',
10015
- ),
10016
- 'label' => array(),
10017
- 'src' => array(
10018
- 'blacklisted_value_regex' => '__amp_source_origin',
10019
- 'mandatory' => true,
10020
- 'value_url' => array(
10021
- 'allow_relative' => false,
10022
- 'allowed_protocol' => array(
10023
- 'https',
10024
- ),
10025
- ),
10026
- ),
10027
- 'srclang' => array(),
10028
- ),
10029
- 'tag_spec' => array(
10030
- 'mandatory_parent' => 'amp-audio',
10031
- 'spec_name' => 'amp-audio > track',
10032
- ),
10033
- ),
10034
- array(
10035
- 'attr_spec_list' => array(
10036
- '[label]' => array(),
10037
- '[src]' => array(),
10038
- '[srclang]' => array(),
10039
- 'default' => array(
10040
- 'value' => '',
10041
- ),
10042
- 'kind' => array(
10043
- 'mandatory' => true,
10044
- 'value_casei' => 'subtitles',
10045
- ),
10046
- 'label' => array(),
10047
- 'src' => array(
10048
- 'blacklisted_value_regex' => '__amp_source_origin',
10049
- 'mandatory' => true,
10050
- 'value_url' => array(
10051
- 'allow_relative' => false,
10052
- 'allowed_protocol' => array(
10053
- 'https',
10054
- ),
10055
- ),
10056
- ),
10057
- 'srclang' => array(
10058
- 'mandatory' => true,
10059
- ),
10060
- ),
10061
- 'tag_spec' => array(
10062
- 'mandatory_parent' => 'amp-audio',
10063
- 'spec_name' => 'amp-audio > track[kind=subtitles]',
10064
- ),
10065
- ),
10066
- array(
10067
- 'attr_spec_list' => array(
10068
- '[label]' => array(),
10069
- '[src]' => array(),
10070
- '[srclang]' => array(),
10071
- 'default' => array(
10072
- 'value' => '',
10073
- ),
10074
- 'kind' => array(
10075
- 'value_regex' => '(captions|descriptions|chapters|metadata)',
10076
- ),
10077
- 'label' => array(),
10078
- 'src' => array(
10079
- 'blacklisted_value_regex' => '__amp_source_origin',
10080
- 'mandatory' => true,
10081
- 'value_url' => array(
10082
- 'allow_relative' => false,
10083
- 'allowed_protocol' => array(
10084
- 'https',
10085
- ),
10086
- ),
10087
- ),
10088
- 'srclang' => array(),
10089
- ),
10090
- 'tag_spec' => array(
10091
- 'mandatory_parent' => 'amp-video',
10092
- 'spec_name' => 'amp-video > track',
10093
- ),
10094
- ),
10095
- array(
10096
- 'attr_spec_list' => array(
10097
- '[label]' => array(),
10098
- '[src]' => array(),
10099
- '[srclang]' => array(),
10100
- 'default' => array(
10101
- 'value' => '',
10102
- ),
10103
- 'kind' => array(
10104
- 'mandatory' => true,
10105
- 'value_casei' => 'subtitles',
10106
- ),
10107
- 'label' => array(),
10108
- 'src' => array(
10109
- 'blacklisted_value_regex' => '__amp_source_origin',
10110
- 'mandatory' => true,
10111
- 'value_url' => array(
10112
- 'allow_relative' => false,
10113
- 'allowed_protocol' => array(
10114
- 'https',
10115
- ),
10116
- ),
10117
- ),
10118
- 'srclang' => array(
10119
- 'mandatory' => true,
10120
- ),
10121
- ),
10122
- 'tag_spec' => array(
10123
- 'mandatory_parent' => 'amp-video',
10124
- 'spec_name' => 'amp-video > track[kind=subtitles]',
10125
- ),
10126
- ),
10127
- array(
10128
- 'attr_spec_list' => array(
10129
- '[label]' => array(),
10130
- '[src]' => array(),
10131
- '[srclang]' => array(),
10132
- 'default' => array(
10133
- 'value' => '',
10134
- ),
10135
- 'kind' => array(
10136
- 'mandatory' => true,
10137
- 'value_casei' => 'subtitles',
10138
- ),
10139
- 'label' => array(),
10140
- 'src' => array(
10141
- 'blacklisted_value_regex' => '__amp_source_origin',
10142
- 'mandatory' => true,
10143
- 'value_url' => array(
10144
- 'allow_relative' => false,
10145
- 'allowed_protocol' => array(
10146
- 'https',
10147
- ),
10148
- ),
10149
- ),
10150
- 'srclang' => array(
10151
- 'mandatory' => true,
10152
- ),
10153
- ),
10154
- 'tag_spec' => array(
10155
- 'mandatory_parent' => 'amp-ima-video',
10156
- 'spec_name' => 'amp-ima-video > track[kind=subtitles]',
10157
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ima-video',
10158
- ),
10159
- ),
10160
- ),
10161
- 'tref' => array(
10162
- array(
10163
- 'attr_spec_list' => array(
10164
- 'alignment-baseline' => array(),
10165
- 'baseline-shift' => array(),
10166
- 'clip' => array(),
10167
- 'clip-path' => array(),
10168
- 'clip-rule' => array(),
10169
- 'color' => array(),
10170
- 'color-interpolation' => array(),
10171
- 'color-interpolation-filters' => array(),
10172
- 'color-profile' => array(),
10173
- 'color-rendering' => array(),
10174
- 'cursor' => array(),
10175
- 'direction' => array(),
10176
- 'display' => array(),
10177
- 'dominant-baseline' => array(),
10178
- 'enable-background' => array(),
10179
- 'externalresourcesrequired' => array(),
10180
- 'fill' => array(),
10181
- 'fill-opacity' => array(),
10182
- 'fill-rule' => array(),
10183
- 'filter' => array(),
10184
- 'flood-color' => array(),
10185
- 'flood-opacity' => array(),
10186
- 'font-family' => array(),
10187
- 'font-size' => array(),
10188
- 'font-size-adjust' => array(),
10189
- 'font-stretch' => array(),
10190
- 'font-style' => array(),
10191
- 'font-variant' => array(),
10192
- 'font-weight' => array(),
10193
- 'glyph-orientation-horizontal' => array(),
10194
- 'glyph-orientation-vertical' => array(),
10195
- 'image-rendering' => array(),
10196
- 'kerning' => array(),
10197
- 'letter-spacing' => array(),
10198
- 'lighting-color' => array(),
10199
- 'marker-end' => array(),
10200
- 'marker-mid' => array(),
10201
- 'marker-start' => array(),
10202
- 'mask' => array(),
10203
- 'opacity' => array(),
10204
- 'overflow' => array(),
10205
- 'pointer-events' => array(),
10206
- 'requiredextensions' => array(),
10207
- 'requiredfeatures' => array(),
10208
- 'shape-rendering' => array(),
10209
- 'stop-color' => array(),
10210
- 'stop-opacity' => array(),
10211
- 'stroke' => array(),
10212
- 'stroke-dasharray' => array(),
10213
- 'stroke-dashoffset' => array(),
10214
- 'stroke-linecap' => array(),
10215
- 'stroke-linejoin' => array(),
10216
- 'stroke-miterlimit' => array(),
10217
- 'stroke-opacity' => array(),
10218
- 'stroke-width' => array(),
10219
- 'style' => array(
10220
- 'blacklisted_value_regex' => '!important',
10221
- ),
10222
- 'systemlanguage' => array(),
10223
- 'text-anchor' => array(),
10224
- 'text-decoration' => array(),
10225
- 'text-rendering' => array(),
10226
- 'unicode-bidi' => array(),
10227
- 'vector-effect' => array(),
10228
- 'visibility' => array(),
10229
- 'word-spacing' => array(),
10230
- 'writing-mode' => array(),
10231
- 'xlink:actuate' => array(),
10232
- 'xlink:arcrole' => array(),
10233
- 'xlink:href' => array(
10234
- 'alternative_names' => array(
10235
- 'href',
10236
- ),
10237
- 'value_url' => array(
10238
- 'allow_empty' => false,
10239
- 'allow_relative' => true,
10240
- 'allowed_protocol' => array(
10241
- 'http',
10242
- 'https',
10243
- ),
10244
- ),
10245
- ),
10246
- 'xlink:role' => array(),
10247
- 'xlink:show' => array(),
10248
- 'xlink:title' => array(),
10249
- 'xlink:type' => array(),
10250
- 'xml:lang' => array(),
10251
- 'xml:space' => array(),
10252
- 'xmlns' => array(),
10253
- 'xmlns:xlink' => array(),
10254
- ),
10255
- 'tag_spec' => array(
10256
- 'mandatory_ancestor' => 'svg',
10257
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10258
- ),
10259
- ),
10260
- ),
10261
- 'tspan' => array(
10262
- array(
10263
- 'attr_spec_list' => array(
10264
- 'alignment-baseline' => array(),
10265
- 'baseline-shift' => array(),
10266
- 'clip' => array(),
10267
- 'clip-path' => array(),
10268
- 'clip-rule' => array(),
10269
- 'color' => array(),
10270
- 'color-interpolation' => array(),
10271
- 'color-interpolation-filters' => array(),
10272
- 'color-profile' => array(),
10273
- 'color-rendering' => array(),
10274
- 'cursor' => array(),
10275
- 'direction' => array(),
10276
- 'display' => array(),
10277
- 'dominant-baseline' => array(),
10278
- 'dx' => array(),
10279
- 'dy' => array(),
10280
- 'enable-background' => array(),
10281
- 'externalresourcesrequired' => array(),
10282
- 'fill' => array(),
10283
- 'fill-opacity' => array(),
10284
- 'fill-rule' => array(),
10285
- 'filter' => array(),
10286
- 'flood-color' => array(),
10287
- 'flood-opacity' => array(),
10288
- 'font-family' => array(),
10289
- 'font-size' => array(),
10290
- 'font-size-adjust' => array(),
10291
- 'font-stretch' => array(),
10292
- 'font-style' => array(),
10293
- 'font-variant' => array(),
10294
- 'font-weight' => array(),
10295
- 'glyph-orientation-horizontal' => array(),
10296
- 'glyph-orientation-vertical' => array(),
10297
- 'image-rendering' => array(),
10298
- 'kerning' => array(),
10299
- 'lengthadjust' => array(),
10300
- 'letter-spacing' => array(),
10301
- 'lighting-color' => array(),
10302
- 'marker-end' => array(),
10303
- 'marker-mid' => array(),
10304
- 'marker-start' => array(),
10305
- 'mask' => array(),
10306
- 'opacity' => array(),
10307
- 'overflow' => array(),
10308
- 'pointer-events' => array(),
10309
- 'requiredextensions' => array(),
10310
- 'requiredfeatures' => array(),
10311
- 'rotate' => array(),
10312
- 'shape-rendering' => array(),
10313
- 'stop-color' => array(),
10314
- 'stop-opacity' => array(),
10315
- 'stroke' => array(),
10316
- 'stroke-dasharray' => array(),
10317
- 'stroke-dashoffset' => array(),
10318
- 'stroke-linecap' => array(),
10319
- 'stroke-linejoin' => array(),
10320
- 'stroke-miterlimit' => array(),
10321
- 'stroke-opacity' => array(),
10322
- 'stroke-width' => array(),
10323
- 'style' => array(
10324
- 'blacklisted_value_regex' => '!important',
10325
- ),
10326
- 'systemlanguage' => array(),
10327
- 'text-anchor' => array(),
10328
- 'text-decoration' => array(),
10329
- 'text-rendering' => array(),
10330
- 'textlength' => array(),
10331
- 'unicode-bidi' => array(),
10332
- 'vector-effect' => array(),
10333
- 'visibility' => array(),
10334
- 'word-spacing' => array(),
10335
- 'writing-mode' => array(),
10336
- 'x' => array(),
10337
- 'xml:lang' => array(),
10338
- 'xml:space' => array(),
10339
- 'xmlns' => array(),
10340
- 'xmlns:xlink' => array(),
10341
- 'y' => array(),
10342
- ),
10343
- 'tag_spec' => array(
10344
- 'mandatory_ancestor' => 'svg',
10345
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10346
- ),
10347
- ),
10348
- ),
10349
- 'tt' => array(
10350
- array(
10351
- 'attr_spec_list' => array(),
10352
- 'tag_spec' => array(),
10353
- ),
10354
- ),
10355
- 'u' => array(
10356
- array(
10357
- 'attr_spec_list' => array(),
10358
- 'tag_spec' => array(),
10359
- ),
10360
- ),
10361
- 'ul' => array(
10362
- array(
10363
- 'attr_spec_list' => array(),
10364
- 'tag_spec' => array(),
10365
- ),
10366
- ),
10367
- 'use' => array(
10368
- array(
10369
- 'attr_spec_list' => array(
10370
- 'alignment-baseline' => array(),
10371
- 'baseline-shift' => array(),
10372
- 'clip' => array(),
10373
- 'clip-path' => array(),
10374
- 'clip-rule' => array(),
10375
- 'color' => array(),
10376
- 'color-interpolation' => array(),
10377
- 'color-interpolation-filters' => array(),
10378
- 'color-profile' => array(),
10379
- 'color-rendering' => array(),
10380
- 'cursor' => array(),
10381
- 'direction' => array(),
10382
- 'display' => array(),
10383
- 'dominant-baseline' => array(),
10384
- 'enable-background' => array(),
10385
- 'externalresourcesrequired' => array(),
10386
- 'fill' => array(),
10387
- 'fill-opacity' => array(),
10388
- 'fill-rule' => array(),
10389
- 'filter' => array(),
10390
- 'flood-color' => array(),
10391
- 'flood-opacity' => array(),
10392
- 'font-family' => array(),
10393
- 'font-size' => array(),
10394
- 'font-size-adjust' => array(),
10395
- 'font-stretch' => array(),
10396
- 'font-style' => array(),
10397
- 'font-variant' => array(),
10398
- 'font-weight' => array(),
10399
- 'glyph-orientation-horizontal' => array(),
10400
- 'glyph-orientation-vertical' => array(),
10401
- 'height' => array(),
10402
- 'image-rendering' => array(),
10403
- 'kerning' => array(),
10404
- 'letter-spacing' => array(),
10405
- 'lighting-color' => array(),
10406
- 'marker-end' => array(),
10407
- 'marker-mid' => array(),
10408
- 'marker-start' => array(),
10409
- 'mask' => array(),
10410
- 'opacity' => array(),
10411
- 'overflow' => array(),
10412
- 'pointer-events' => array(),
10413
- 'requiredextensions' => array(),
10414
- 'requiredfeatures' => array(),
10415
- 'shape-rendering' => array(),
10416
- 'stop-color' => array(),
10417
- 'stop-opacity' => array(),
10418
- 'stroke' => array(),
10419
- 'stroke-dasharray' => array(),
10420
- 'stroke-dashoffset' => array(),
10421
- 'stroke-linecap' => array(),
10422
- 'stroke-linejoin' => array(),
10423
- 'stroke-miterlimit' => array(),
10424
- 'stroke-opacity' => array(),
10425
- 'stroke-width' => array(),
10426
- 'style' => array(
10427
- 'blacklisted_value_regex' => '!important',
10428
- ),
10429
- 'systemlanguage' => array(),
10430
- 'text-anchor' => array(),
10431
- 'text-decoration' => array(),
10432
- 'text-rendering' => array(),
10433
- 'transform' => array(),
10434
- 'unicode-bidi' => array(),
10435
- 'vector-effect' => array(),
10436
- 'visibility' => array(),
10437
- 'width' => array(),
10438
- 'word-spacing' => array(),
10439
- 'writing-mode' => array(),
10440
- 'x' => array(),
10441
- 'xlink:actuate' => array(),
10442
- 'xlink:arcrole' => array(),
10443
- 'xlink:href' => array(
10444
- 'alternative_names' => array(
10445
- 'href',
10446
- ),
10447
- 'value_url' => array(
10448
- 'allow_empty' => false,
10449
- 'allow_relative' => true,
10450
- 'allowed_protocol' => array(
10451
- 'http',
10452
- 'https',
10453
- ),
10454
- ),
10455
- ),
10456
- 'xlink:role' => array(),
10457
- 'xlink:show' => array(),
10458
- 'xlink:title' => array(),
10459
- 'xlink:type' => array(),
10460
- 'xml:lang' => array(),
10461
- 'xml:space' => array(),
10462
- 'xmlns' => array(),
10463
- 'xmlns:xlink' => array(),
10464
- 'y' => array(),
10465
- ),
10466
- 'tag_spec' => array(
10467
- 'mandatory_ancestor' => 'svg',
10468
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10469
- ),
10470
- ),
10471
- ),
10472
- 'var' => array(
10473
- array(
10474
- 'attr_spec_list' => array(),
10475
- 'tag_spec' => array(),
10476
- ),
10477
- ),
10478
- 'video' => array(
10479
- array(
10480
- 'attr_spec_list' => array(
10481
- 'autoplay' => array(),
10482
- 'controls' => array(),
10483
- 'height' => array(),
10484
- 'loop' => array(),
10485
- 'muted' => array(),
10486
- 'playsinline' => array(),
10487
- 'poster' => array(),
10488
- 'preload' => array(),
10489
- 'src' => array(
10490
- 'blacklisted_value_regex' => '__amp_source_origin',
10491
- 'value_url' => array(
10492
- 'allow_relative' => false,
10493
- 'allowed_protocol' => array(
10494
- 'data',
10495
- 'https',
10496
- ),
10497
- ),
10498
- ),
10499
- 'width' => array(),
10500
- ),
10501
- 'tag_spec' => array(
10502
- 'mandatory_ancestor' => 'noscript',
10503
- 'mandatory_ancestor_suggested_alternative' => 'amp-video',
10504
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
10505
- ),
10506
- ),
10507
- ),
10508
- 'view' => array(
10509
- array(
10510
- 'attr_spec_list' => array(
10511
- 'externalresourcesrequired' => array(),
10512
- 'preserveaspectratio' => array(),
10513
- 'style' => array(
10514
- 'blacklisted_value_regex' => '!important',
10515
- ),
10516
- 'viewbox' => array(),
10517
- 'viewtarget' => array(),
10518
- 'xml:lang' => array(),
10519
- 'xml:space' => array(),
10520
- 'xmlns' => array(),
10521
- 'xmlns:xlink' => array(),
10522
- 'zoomandpan' => array(),
10523
- ),
10524
- 'tag_spec' => array(
10525
- 'mandatory_ancestor' => 'svg',
10526
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10527
- ),
10528
- ),
10529
- ),
10530
- 'vkern' => array(
10531
- array(
10532
- 'attr_spec_list' => array(
10533
- 'g1' => array(),
10534
- 'g2' => array(),
10535
- 'k' => array(),
10536
- 'style' => array(
10537
- 'blacklisted_value_regex' => '!important',
10538
- ),
10539
- 'u1' => array(),
10540
- 'u2' => array(),
10541
- 'xml:lang' => array(),
10542
- 'xml:space' => array(),
10543
- 'xmlns' => array(),
10544
- 'xmlns:xlink' => array(),
10545
- ),
10546
- 'tag_spec' => array(
10547
- 'mandatory_ancestor' => 'svg',
10548
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10549
- ),
10550
- ),
10551
- ),
10552
- 'wbr' => array(
10553
- array(
10554
- 'attr_spec_list' => array(),
10555
- 'tag_spec' => array(),
10556
- ),
10557
- ),
10558
- 'xmp' => array(
10559
- array(
10560
- 'attr_spec_list' => array(),
10561
- 'tag_spec' => array(),
10562
- ),
10563
- ),
10564
- );
10565
-
10566
- private static $layout_allowed_attrs = array(
10567
- '[height]' => array(),
10568
- '[width]' => array(),
10569
- 'height' => array(),
10570
- 'heights' => array(),
10571
- 'layout' => array(),
10572
- 'sizes' => array(),
10573
- 'width' => array(),
10574
- );
10575
-
10576
-
10577
- private static $globally_allowed_attrs = array(
10578
- '[aria-activedescendant]' => array(),
10579
- '[aria-atomic]' => array(),
10580
- '[aria-autocomplete]' => array(),
10581
- '[aria-busy]' => array(),
10582
- '[aria-checked]' => array(),
10583
- '[aria-controls]' => array(),
10584
- '[aria-describedby]' => array(),
10585
- '[aria-disabled]' => array(),
10586
- '[aria-dropeffect]' => array(),
10587
- '[aria-expanded]' => array(),
10588
- '[aria-flowto]' => array(),
10589
- '[aria-grabbed]' => array(),
10590
- '[aria-haspopup]' => array(),
10591
- '[aria-hidden]' => array(),
10592
- '[aria-invalid]' => array(),
10593
- '[aria-label]' => array(),
10594
- '[aria-labelledby]' => array(),
10595
- '[aria-level]' => array(),
10596
- '[aria-live]' => array(),
10597
- '[aria-multiline]' => array(),
10598
- '[aria-multiselectable]' => array(),
10599
- '[aria-orientation]' => array(),
10600
- '[aria-owns]' => array(),
10601
- '[aria-posinset]' => array(),
10602
- '[aria-pressed]' => array(),
10603
- '[aria-readonly]' => array(),
10604
- '[aria-relevant]' => array(),
10605
- '[aria-required]' => array(),
10606
- '[aria-selected]' => array(),
10607
- '[aria-setsize]' => array(),
10608
- '[aria-sort]' => array(),
10609
- '[aria-valuemax]' => array(),
10610
- '[aria-valuemin]' => array(),
10611
- '[aria-valuenow]' => array(),
10612
- '[aria-valuetext]' => array(),
10613
- '[class]' => array(),
10614
- '[hidden]' => array(),
10615
- '[text]' => array(),
10616
- 'about' => array(),
10617
- 'accesskey' => array(),
10618
- 'amp-access' => array(),
10619
- 'amp-access-behavior' => array(),
10620
- 'amp-access-hide' => array(),
10621
- 'amp-access-id' => array(),
10622
- 'amp-access-loader' => array(),
10623
- 'amp-access-loading' => array(),
10624
- 'amp-access-off' => array(),
10625
- 'amp-access-on' => array(),
10626
- 'amp-access-show' => array(),
10627
- 'amp-access-style' => array(),
10628
- 'amp-access-template' => array(),
10629
- 'amp-fx' => array(
10630
- 'value_casei' => 'parallax',
10631
- ),
10632
- 'aria-activedescendant' => array(),
10633
- 'aria-atomic' => array(),
10634
- 'aria-autocomplete' => array(),
10635
- 'aria-busy' => array(),
10636
- 'aria-checked' => array(),
10637
- 'aria-controls' => array(),
10638
- 'aria-current' => array(),
10639
- 'aria-describedby' => array(),
10640
- 'aria-disabled' => array(),
10641
- 'aria-dropeffect' => array(),
10642
- 'aria-expanded' => array(),
10643
- 'aria-flowto' => array(),
10644
- 'aria-grabbed' => array(),
10645
- 'aria-haspopup' => array(),
10646
- 'aria-hidden' => array(),
10647
- 'aria-invalid' => array(),
10648
- 'aria-label' => array(),
10649
- 'aria-labelledby' => array(),
10650
- 'aria-level' => array(),
10651
- 'aria-live' => array(),
10652
- 'aria-multiline' => array(),
10653
- 'aria-multiselectable' => array(),
10654
- 'aria-orientation' => array(),
10655
- 'aria-owns' => array(),
10656
- 'aria-posinset' => array(),
10657
- 'aria-pressed' => array(),
10658
- 'aria-readonly' => array(),
10659
- 'aria-relevant' => array(),
10660
- 'aria-required' => array(),
10661
- 'aria-selected' => array(),
10662
- 'aria-setsize' => array(),
10663
- 'aria-sort' => array(),
10664
- 'aria-valuemax' => array(),
10665
- 'aria-valuemin' => array(),
10666
- 'aria-valuenow' => array(),
10667
- 'aria-valuetext' => array(),
10668
- 'class' => array(
10669
- 'blacklisted_value_regex' => '(^|\\W)i-amphtml-',
10670
- ),
10671
- 'content' => array(),
10672
- 'datatype' => array(),
10673
- 'dir' => array(),
10674
- 'draggable' => array(),
10675
- 'fallback' => array(
10676
- 'value' => '',
10677
- ),
10678
- 'hidden' => array(
10679
- 'value' => '',
10680
- ),
10681
- 'i-amp-access-id' => array(),
10682
- 'id' => array(
10683
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|AMP|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|i-amphtml-\\S*|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
10684
- ),
10685
- 'inlist' => array(),
10686
- 'itemid' => array(),
10687
- 'itemprop' => array(),
10688
- 'itemref' => array(),
10689
- 'itemscope' => array(),
10690
- 'itemtype' => array(),
10691
- 'lang' => array(),
10692
- 'lightbox' => array(),
10693
- 'on' => array(),
10694
- 'overflow' => array(),
10695
- 'placeholder' => array(
10696
- 'value' => '',
10697
- ),
10698
- 'prefix' => array(),
10699
- 'property' => array(),
10700
- 'rel' => array(
10701
- 'blacklisted_value_regex' => '(^|\\s)(canonical|components|dns-prefetch|import|manifest|preconnect|preload|prerender|serviceworker|stylesheet|subresource)(\\s|$)',
10702
- ),
10703
- 'resource' => array(),
10704
- 'rev' => array(),
10705
- 'role' => array(),
10706
- 'subscriptions-action' => array(),
10707
- 'subscriptions-actions' => array(
10708
- 'value' => '',
10709
- ),
10710
- 'subscriptions-dialog' => array(
10711
- 'value' => '',
10712
- ),
10713
- 'subscriptions-display' => array(),
10714
- 'subscriptions-section' => array(
10715
- 'value_regex_casei' => '(actions|content|content-not-granted)',
10716
- ),
10717
- 'subscriptions-service' => array(),
10718
- 'tabindex' => array(),
10719
- 'title' => array(),
10720
- 'translate' => array(),
10721
- 'typeof' => array(),
10722
- 'validation-for' => array(),
10723
- 'visible-when-invalid' => array(
10724
- 'value_regex' => '(badInput|customError|patternMismatch|rangeOverflow|rangeUnderflow|stepMismatch|tooLong|typeMismatch|valueMissing)',
10725
- ),
10726
- 'vocab' => array(),
10727
- );
10728
-
10729
-
10730
- /**
10731
- * Get allowed tags.
10732
- *
10733
- * @since 0.5
10734
- * @return array Allowed tags.
10735
- */
10736
- public static function get_allowed_tags() {
10737
- return self::$allowed_tags;
10738
- }
10739
-
10740
- /**
10741
- * Get allowed tag.
10742
- *
10743
- * Get the rules for a single tag so that the entire data structure needn't be passed around.
10744
- *
10745
- * @since 0.7
10746
- * @param string $node_name Tag name.
10747
- * @return array|null Allowed tag, or null if the tag does not exist.
10748
- */
10749
- public static function get_allowed_tag( $node_name ) {
10750
- if ( isset( self::$allowed_tags[ $node_name ] ) ) {
10751
- return self::$allowed_tags[ $node_name ];
10752
- }
10753
- return null;
10754
- }
10755
-
10756
- /**
10757
- * Get list of globally-allowed attributes.
10758
- *
10759
- * @since 0.5
10760
- * @return array Allowed tag.
10761
- */
10762
- public static function get_allowed_attributes() {
10763
- return self::$globally_allowed_attrs;
10764
- }
10765
-
10766
- /**
10767
- * Get layout attributes.
10768
- *
10769
- * @since 0.5
10770
- * @return array Allowed tag.
10771
- */
10772
- public static function get_layout_attributes() {
10773
- return self::$layout_allowed_attrs;
10774
- }
10775
-
10776
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/sanitizers/class-amp-comments-sanitizer.php DELETED
@@ -1,156 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Comments_Sanitizer.
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Comments_Sanitizer
10
- *
11
- * Strips and corrects attributes in forms.
12
- */
13
- class AMP_Comments_Sanitizer extends AMP_Base_Sanitizer {
14
-
15
- /**
16
- * Pre-process the comment form and comment list for AMP.
17
- *
18
- * @since 0.7
19
- */
20
- public function sanitize() {
21
-
22
- foreach ( $this->dom->getElementsByTagName( 'form' ) as $comment_form ) {
23
- /**
24
- * Comment form.
25
- *
26
- * @var DOMElement $comment_form
27
- */
28
- $action = $comment_form->getAttribute( 'action-xhr' );
29
- if ( ! $action ) {
30
- $action = $comment_form->getAttribute( 'action' );
31
- }
32
- $action_path = wp_parse_url( $action, PHP_URL_PATH );
33
- if ( preg_match( '#/wp-comments-post\.php$#', $action_path ) ) {
34
- $this->process_comment_form( $comment_form );
35
- }
36
- }
37
- }
38
-
39
- /**
40
- * Comment form.
41
- *
42
- * @param DOMElement $comment_form Comment form.
43
- */
44
- protected function process_comment_form( $comment_form ) {
45
- /**
46
- * Element.
47
- *
48
- * @var DOMElement $element
49
- */
50
-
51
- /**
52
- * Named input elements.
53
- *
54
- * @var DOMElement[][] $form_fields
55
- */
56
- $form_fields = array();
57
- foreach ( $comment_form->getElementsByTagName( 'input' ) as $element ) {
58
- $name = $element->getAttribute( 'name' );
59
- if ( $name ) {
60
- $form_fields[ $name ][] = $element;
61
- }
62
- }
63
- foreach ( $comment_form->getElementsByTagName( 'textarea' ) as $element ) {
64
- $name = $element->getAttribute( 'name' );
65
- if ( $name ) {
66
- $form_fields[ $name ][] = $element;
67
- }
68
- }
69
-
70
- if ( empty( $form_fields['comment_post_ID'] ) ) {
71
- return;
72
- }
73
- $post_id = (int) $form_fields['comment_post_ID'][0]->getAttribute( 'value' );
74
- $state_id = AMP_Theme_Support::get_comment_form_state_id( $post_id );
75
-
76
- $form_state = array(
77
- 'values' => array(),
78
- 'submitting' => false,
79
- 'replyToName' => '',
80
- );
81
-
82
- if ( ! empty( $form_fields['comment_parent'] ) ) {
83
- $comment_id = (int) $form_fields['comment_parent'][0]->getAttribute( 'value' );
84
- if ( $comment_id ) {
85
- $reply_comment = get_comment( $comment_id );
86
- if ( $reply_comment ) {
87
- $form_state['replyToName'] = $reply_comment->comment_author;
88
- }
89
- }
90
- }
91
-
92
- $amp_bind_attr_format = AMP_DOM_Utils::get_amp_bind_placeholder_prefix() . '%s';
93
- foreach ( $form_fields as $name => $form_field ) {
94
- foreach ( $form_field as $element ) {
95
-
96
- // @todo Radio and checkbox inputs are not supported yet.
97
- if ( in_array( strtolower( $element->getAttribute( 'type' ) ), array( 'checkbox', 'radio' ), true ) ) {
98
- continue;
99
- }
100
-
101
- $element->setAttribute( sprintf( $amp_bind_attr_format, 'disabled' ), "$state_id.submitting" );
102
-
103
- if ( 'textarea' === strtolower( $element->nodeName ) ) {
104
- $form_state['values'][ $name ] = $element->textContent;
105
- $element->setAttribute( sprintf( $amp_bind_attr_format, 'text' ), "$state_id.values.$name" );
106
- } else {
107
- $form_state['values'][ $name ] = $element->hasAttribute( 'value' ) ? $element->getAttribute( 'value' ) : '';
108
- $element->setAttribute( sprintf( $amp_bind_attr_format, 'value' ), "$state_id.values.$name" );
109
- }
110
-
111
- // Update the state in response to changing the input.
112
- $element->setAttribute( 'on', sprintf(
113
- 'change:AMP.setState( { %s: { values: { %s: event.value } } } )',
114
- $state_id,
115
- wp_json_encode( $name )
116
- ) );
117
- }
118
- }
119
-
120
- // Add amp-state to the document.
121
- $amp_state = $this->dom->createElement( 'amp-state' );
122
- $amp_state->setAttribute( 'id', $state_id );
123
- $script = $this->dom->createElement( 'script' );
124
- $script->setAttribute( 'type', 'application/json' );
125
- $amp_state->appendChild( $script );
126
- $script->appendChild( $this->dom->createTextNode( wp_json_encode( $form_state ) ) );
127
- $comment_form->insertBefore( $amp_state, $comment_form->firstChild );
128
-
129
- // Update state when submitting form.
130
- $form_reset_state = $form_state;
131
- unset(
132
- $form_reset_state['values']['author'],
133
- $form_reset_state['values']['email'],
134
- $form_reset_state['values']['url']
135
- );
136
- $on = array(
137
- // Disable the form when submitting.
138
- sprintf(
139
- 'submit:AMP.setState( { %s: { submitting: true } } )',
140
- wp_json_encode( $state_id )
141
- ),
142
- // Re-enable the form fields when the submission fails.
143
- sprintf(
144
- 'submit-error:AMP.setState( { %s: { submitting: false } } )',
145
- wp_json_encode( $state_id )
146
- ),
147
- // Reset the form to its initial state (with enabled form fields), except for the author, email, and url.
148
- sprintf(
149
- 'submit-success:AMP.setState( { %s: %s } )',
150
- $state_id,
151
- wp_json_encode( $form_reset_state )
152
- ),
153
- );
154
- $comment_form->setAttribute( 'on', implode( ';', $on ) );
155
- }
156
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/sanitizers/class-amp-form-sanitizer.php DELETED
@@ -1,141 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Form_Sanitizer.
4
- *
5
- * @package AMP
6
- * @since 0.7
7
- */
8
-
9
- /**
10
- * Class AMP_Form_Sanitizer
11
- *
12
- * Strips and corrects attributes in forms.
13
- *
14
- * @since 0.7
15
- */
16
- class AMP_Form_Sanitizer extends AMP_Base_Sanitizer {
17
-
18
- /**
19
- * Tag.
20
- *
21
- * @var string HTML <form> tag to identify and process.
22
- *
23
- * @since 0.7
24
- */
25
- public static $tag = 'form';
26
-
27
- /**
28
- * Sanitize the <form> elements from the HTML contained in this instance's DOMDocument.
29
- *
30
- * @link https://www.ampproject.org/docs/reference/components/amp-form
31
- * @since 0.7
32
- */
33
- public function sanitize() {
34
-
35
- /**
36
- * Node list.
37
- *
38
- * @var DOMNodeList $node
39
- */
40
- $nodes = $this->dom->getElementsByTagName( self::$tag );
41
- $num_nodes = $nodes->length;
42
-
43
- if ( 0 === $num_nodes ) {
44
- return;
45
- }
46
-
47
- for ( $i = $num_nodes - 1; $i >= 0; $i-- ) {
48
- $node = $nodes->item( $i );
49
- if ( ! $node instanceof DOMElement ) {
50
- continue;
51
- }
52
-
53
- // In HTML, the default method is 'get'.
54
- $method = 'get';
55
- if ( $node->getAttribute( 'method' ) ) {
56
- $method = strtolower( $node->getAttribute( 'method' ) );
57
- } else {
58
- $node->setAttribute( 'method', $method );
59
- }
60
-
61
- /*
62
- * In HTML, the default action is just the current URL that the page is served from.
63
- * The action "specifies a server endpoint to handle the form input. The value must be an
64
- * https URL and must not be a link to a CDN".
65
- */
66
- if ( ! $node->getAttribute( 'action' ) ) {
67
- $action_url = esc_url_raw( '//' . $_SERVER['HTTP_HOST'] . wp_unslash( $_SERVER['REQUEST_URI'] ) ); // WPCS: ignore. input var okay, sanitization ok.
68
- } else {
69
- $action_url = $node->getAttribute( 'action' );
70
- }
71
- $xhr_action = $node->getAttribute( 'action-xhr' );
72
-
73
- // Make HTTP URLs protocol-less, since HTTPS is required for forms.
74
- if ( 'http://' === strtolower( substr( $action_url, 0, 7 ) ) ) {
75
- $action_url = substr( $action_url, 5 );
76
- }
77
-
78
- /*
79
- * "For GET submissions, provide at least one of action or action-xhr".
80
- * "This attribute is required for method=GET. For method=POST, the
81
- * action attribute is invalid, use action-xhr instead".
82
- */
83
- if ( 'get' === $method ) {
84
- if ( $action_url !== $node->getAttribute( 'action' ) ) {
85
- $node->setAttribute( 'action', $action_url );
86
- }
87
- } elseif ( 'post' === $method ) {
88
- $node->removeAttribute( 'action' );
89
- if ( ! $xhr_action ) {
90
- // record that action was converted tp action-xhr.
91
- $action_url = add_query_arg( '_wp_amp_action_xhr_converted', 1, $action_url );
92
- $node->setAttribute( 'action-xhr', $action_url );
93
- // Append error handler if not found.
94
- $this->ensure_submit_error_element( $node );
95
- } elseif ( 'http://' === substr( $xhr_action, 0, 7 ) ) {
96
- $node->setAttribute( 'action-xhr', substr( $xhr_action, 5 ) );
97
- }
98
- }
99
-
100
- /*
101
- * The target "indicates where to display the form response after submitting the form.
102
- * The value must be _blank or _top". The _self and _parent values are treated
103
- * as synonymous with _top, and anything else is treated like _blank.
104
- */
105
- $target = $node->getAttribute( 'target' );
106
- if ( '_top' !== $target ) {
107
- if ( ! $target || in_array( $target, array( '_self', '_parent' ), true ) ) {
108
- $node->setAttribute( 'target', '_top' );
109
- } elseif ( '_blank' !== $target ) {
110
- $node->setAttribute( 'target', '_blank' );
111
- }
112
- }
113
- }
114
- }
115
-
116
- /**
117
- * Checks if the form has an error handler else create one if not.
118
- *
119
- * @link https://www.ampproject.org/docs/reference/components/amp-form#success/error-response-rendering
120
- * @since 0.7
121
- *
122
- * @param DOMElement $form The form node to check.
123
- */
124
- public function ensure_submit_error_element( $form ) {
125
- $templates = $form->getElementsByTagName( 'template' );
126
- for ( $i = $templates->length - 1; $i >= 0; $i-- ) {
127
- if ( $templates->item( $i )->parentNode->hasAttribute( 'submit-error' ) ) {
128
- return; // Found error template, do nothing.
129
- }
130
- }
131
-
132
- $div = $this->dom->createElement( 'div' );
133
- $template = $this->dom->createElement( 'template' );
134
- $mustache = $this->dom->createTextNode( '{{{error}}}' );
135
- $div->setAttribute( 'submit-error', '' );
136
- $template->setAttribute( 'type', 'amp-mustache' );
137
- $template->appendChild( $mustache );
138
- $div->appendChild( $template );
139
- $form->appendChild( $div );
140
- }
141
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/sanitizers/class-amp-rule-spec.php DELETED
@@ -1,154 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Rule_Spec
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Rule_Spec
10
- *
11
- * Set of constants used throughout the sanitizer.
12
- */
13
- abstract class AMP_Rule_Spec {
14
-
15
- /**
16
- * AMP rule_spec types
17
- */
18
- const ATTR_SPEC_LIST = 'attr_spec_list';
19
- const TAG_SPEC = 'tag_spec';
20
- const CDATA = 'cdata';
21
-
22
- /**
23
- * AMP attr_spec value check results.
24
- *
25
- * In 0.7 these changed from strings to integers to speed up comparisons.
26
- */
27
- const PASS = 1;
28
- const FAIL = 0;
29
- const NOT_APPLICABLE = -1;
30
-
31
- /**
32
- * HTML Element Tag rule names
33
- */
34
- const DISALLOWED_ANCESTOR = 'disallowed_ancestor';
35
- const MANDATORY_ANCESTOR = 'mandatory_ancestor';
36
- const MANDATORY_PARENT = 'mandatory_parent';
37
-
38
- /**
39
- * HTML Element Attribute rule names
40
- */
41
- const ALLOW_EMPTY = 'allow_empty';
42
- const ALLOW_RELATIVE = 'allow_relative';
43
- const ALLOWED_PROTOCOL = 'allowed_protocol';
44
- const ALTERNATIVE_NAMES = 'alternative_names';
45
- const BLACKLISTED_VALUE_REGEX = 'blacklisted_value_regex';
46
- const DISALLOWED_DOMAIN = 'disallowed_domain';
47
- const MANDATORY = 'mandatory';
48
- const VALUE = 'value';
49
- const VALUE_CASEI = 'value_casei';
50
- const VALUE_REGEX = 'value_regex';
51
- const VALUE_REGEX_CASEI = 'value_regex_casei';
52
- const VALUE_PROPERTIES = 'value_properties';
53
- const VALUE_URL = 'value_url';
54
-
55
- /**
56
- * If a node type listed here is invalid, it and it's subtree will be
57
- * removed if it is invalid. This is mainly because any children will be
58
- * non-functional without this parent.
59
- *
60
- * If a tag is not listed here, it will be replaced by its children if it
61
- * is invalid.
62
- *
63
- * @todo There are other nodes that should probably be listed here as well.
64
- *
65
- * @var array
66
- */
67
- public static $node_types_to_remove_if_invalid = array(
68
- 'form',
69
- 'input',
70
- 'link',
71
- 'meta',
72
- 'style',
73
- // Include 'script' here?
74
- );
75
-
76
- /**
77
- * It is mentioned in the documentation in several places that data-*
78
- * is generally allowed, but there is no specific rule for it in the
79
- * protoascii file, so we include it here.
80
- *
81
- * @var array
82
- */
83
- public static $whitelisted_attr_regex = array(
84
- '@^data-[a-zA-Z][\\w:.-]*$@uis',
85
- '(update|item|pagination|option|selected|disabled)', // Allowed for live reference points.
86
- );
87
-
88
- /**
89
- * List of boolean attributes.
90
- *
91
- * @since 0.7
92
- * @var array
93
- */
94
- public static $boolean_attributes = array(
95
- 'allowfullscreen',
96
- 'async',
97
- 'autofocus',
98
- 'autoplay',
99
- 'checked',
100
- 'compact',
101
- 'controls',
102
- 'declare',
103
- 'default',
104
- 'defaultchecked',
105
- 'defaultmuted',
106
- 'defaultselected',
107
- 'defer',
108
- 'disabled',
109
- 'draggable',
110
- 'enabled',
111
- 'formnovalidate',
112
- 'hidden',
113
- 'indeterminate',
114
- 'inert',
115
- 'ismap',
116
- 'itemscope',
117
- 'loop',
118
- 'multiple',
119
- 'muted',
120
- 'nohref',
121
- 'noresize',
122
- 'noshade',
123
- 'novalidate',
124
- 'nowrap',
125
- 'open',
126
- 'pauseonexit',
127
- 'readonly',
128
- 'required',
129
- 'reversed',
130
- 'scoped',
131
- 'seamless',
132
- 'selected',
133
- 'sortable',
134
- 'spellcheck',
135
- 'translate',
136
- 'truespeed',
137
- 'typemustmatch',
138
- 'visible',
139
- );
140
-
141
- /**
142
- * Additional allowed tags.
143
- *
144
- * @var array
145
- */
146
- public static $additional_allowed_tags = array(
147
-
148
- // An experimental tag with no protoascii.
149
- 'amp-share-tracking' => array(
150
- 'attr_spec_list' => array(),
151
- 'tag_spec' => array(),
152
- ),
153
- );
154
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php DELETED
@@ -1,1630 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Tag_And_Attribute_Sanitizer
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Strips the tags and attributes from the content that are not allowed by the AMP spec.
10
- *
11
- * Allowed tags array is generated from this protocol buffer:
12
- *
13
- * https://github.com/ampproject/amphtml/blob/master/validator/validator-main.protoascii
14
- * by the python script in amp-wp/bin/amp_wp_build.py. See the comment at the top
15
- * of that file for instructions to generate class-amp-allowed-tags-generated.php.
16
- *
17
- * @todo Need to check the following items that are not yet checked by this sanitizer:
18
- *
19
- * - `also_requires_attr` - if one attribute is present, this requires another.
20
- * - `ChildTagSpec` - Places restrictions on the number and type of child tags.
21
- * - `if_value_regex` - if one attribute value matches, this places a restriction
22
- * on another attribute/value.
23
- * - `mandatory_oneof` - Within the context of the tag, exactly one of the attributes
24
- * must be present.
25
- */
26
- class AMP_Tag_And_Attribute_Sanitizer extends AMP_Base_Sanitizer {
27
-
28
- /**
29
- * Allowed tags.
30
- *
31
- * @since 0.5
32
- *
33
- * @var string[]
34
- */
35
- protected $allowed_tags;
36
-
37
- /**
38
- * Globally-allowed attributes.
39
- *
40
- * @since 0.5
41
- *
42
- * @var array[][]
43
- */
44
- protected $globally_allowed_attributes;
45
-
46
- /**
47
- * Layout-allowed attributes.
48
- *
49
- * @since 0.5
50
- *
51
- * @var string[]
52
- */
53
- protected $layout_allowed_attributes;
54
-
55
- /**
56
- * Mapping of alternative names back to their primary names.
57
- *
58
- * @since 0.7
59
- * @var array
60
- */
61
- protected $rev_alternate_attr_name_lookup = array();
62
-
63
- /**
64
- * Stack.
65
- *
66
- * @since 0.5
67
- *
68
- * @var DOMElement[]
69
- */
70
- private $stack = array();
71
-
72
- /**
73
- * Default args.
74
- *
75
- * @since 0.5
76
- *
77
- * @var array
78
- */
79
- protected $DEFAULT_ARGS = array();
80
-
81
- /**
82
- * AMP script components that are discovered being required through sanitization.
83
- *
84
- * @var string[]
85
- */
86
- protected $script_components = array();
87
-
88
- /**
89
- * AMP_Tag_And_Attribute_Sanitizer constructor.
90
- *
91
- * @since 0.5
92
- *
93
- * @param DOMDocument $dom DOM.
94
- * @param array $args Args.
95
- */
96
- public function __construct( $dom, $args = array() ) {
97
- $this->DEFAULT_ARGS = array(
98
- 'amp_allowed_tags' => AMP_Allowed_Tags_Generated::get_allowed_tags(),
99
- 'amp_globally_allowed_attributes' => AMP_Allowed_Tags_Generated::get_allowed_attributes(),
100
- 'amp_layout_allowed_attributes' => AMP_Allowed_Tags_Generated::get_layout_attributes(),
101
- 'amp_bind_placeholder_prefix' => AMP_DOM_Utils::get_amp_bind_placeholder_prefix(),
102
- );
103
-
104
- parent::__construct( $dom, $args );
105
-
106
- if ( ! empty( $this->args['allow_dirty_styles'] ) ) {
107
-
108
- // Allow style attribute on all elements.
109
- $this->args['amp_globally_allowed_attributes']['style'] = array();
110
-
111
- // Allow style elements.
112
- $this->args['amp_allowed_tags']['style'][] = array(
113
- 'attr_spec_list' => array(
114
- 'type' => array(
115
- 'value_casei' => 'text/css',
116
- ),
117
- ),
118
- 'cdata' => array(),
119
- 'tag_spec' => array(
120
- 'spec_name' => 'style for Customizer preview',
121
- ),
122
- );
123
-
124
- // Allow stylesheet links.
125
- $this->args['amp_allowed_tags']['link'][] = array(
126
- 'attr_spec_list' => array(
127
- 'async' => array(),
128
- 'crossorigin' => array(),
129
- 'href' => array(
130
- 'mandatory' => true,
131
- ),
132
- 'integrity' => array(),
133
- 'media' => array(),
134
- 'rel' => array(
135
- 'dispatch_key' => 2,
136
- 'mandatory' => true,
137
- 'value_casei' => 'stylesheet',
138
- ),
139
- 'type' => array(
140
- 'value_casei' => 'text/css',
141
- ),
142
- ),
143
- 'tag_spec' => array(
144
- 'spec_name' => 'link rel=stylesheet for Customizer preview', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
145
- ),
146
- );
147
- }
148
-
149
- // Allow scripts if requested.
150
- if ( ! empty( $this->args['allow_dirty_scripts'] ) ) {
151
- $this->args['amp_allowed_tags']['script'][] = array(
152
- 'attr_spec_list' => array(
153
- 'type' => array(),
154
- 'src' => array(),
155
- 'async' => array(),
156
- 'defer' => array(),
157
- ),
158
- 'cdata' => array(),
159
- 'tag_spec' => array(
160
- 'spec_name' => 'scripts for Customizer preview',
161
- ),
162
- );
163
- }
164
-
165
- // Prepare whitelists.
166
- $this->allowed_tags = $this->args['amp_allowed_tags'];
167
- foreach ( AMP_Rule_Spec::$additional_allowed_tags as $tag_name => $tag_rule_spec ) {
168
- $this->allowed_tags[ $tag_name ][] = $tag_rule_spec;
169
- }
170
-
171
- // @todo Do the same for body when !use_document_element?
172
- if ( ! empty( $this->args['use_document_element'] ) ) {
173
- foreach ( $this->allowed_tags['html'] as &$rule_spec ) {
174
- unset( $rule_spec[ AMP_Rule_Spec::TAG_SPEC ][ AMP_Rule_Spec::MANDATORY_PARENT ] );
175
- }
176
- }
177
-
178
- foreach ( $this->allowed_tags as &$tag_specs ) {
179
- foreach ( $tag_specs as &$tag_spec ) {
180
- if ( isset( $tag_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] ) ) {
181
- $tag_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] = $this->process_alternate_names( $tag_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] );
182
- }
183
- }
184
- }
185
- $this->globally_allowed_attributes = $this->process_alternate_names( $this->args['amp_globally_allowed_attributes'] );
186
- $this->layout_allowed_attributes = $this->process_alternate_names( $this->args['amp_layout_allowed_attributes'] );
187
- }
188
-
189
- /**
190
- * Return array of values that would be valid as an HTML `script` element.
191
- *
192
- * Array keys are AMP element names and array values are their respective
193
- * Javascript URLs from https://cdn.ampproject.org
194
- *
195
- * @since 0.7
196
- * @see amp_register_default_scripts()
197
- *
198
- * @return array() Returns component name as array key and true as value (or JavaScript URL string),
199
- * respectively. When true then the default component script URL will be used.
200
- * Will return an empty array if sanitization has yet to be run
201
- * or if it did not find any HTML elements to convert to AMP equivalents.
202
- */
203
- public function get_scripts() {
204
- return array_fill_keys( $this->script_components, true );
205
- }
206
-
207
- /**
208
- * Process alternative names in attribute spec list.
209
- *
210
- * @since 0.7
211
- *
212
- * @param array $attr_spec_list Attribute spec list.
213
- * @return array Modified attribute spec list.
214
- */
215
- private function process_alternate_names( $attr_spec_list ) {
216
- foreach ( $attr_spec_list as $attr_name => &$attr_spec ) {
217
- if ( '[' === $attr_name[0] ) {
218
- $placeholder_attr_name = $this->args['amp_bind_placeholder_prefix'] . trim( $attr_name, '[]' );
219
- if ( ! isset( $attr_spec[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
220
- $attr_spec[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] = array();
221
- }
222
- $attr_spec[ AMP_Rule_Spec::ALTERNATIVE_NAMES ][] = $placeholder_attr_name;
223
- }
224
-
225
- // Save all alternative names in lookup to improve performance.
226
- if ( isset( $attr_spec[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
227
- foreach ( $attr_spec[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
228
- $this->rev_alternate_attr_name_lookup[ $alternative_name ] = $attr_name;
229
- }
230
- }
231
- }
232
- return $attr_spec_list;
233
- }
234
-
235
- /**
236
- * Sanitize the <video> elements from the HTML contained in this instance's DOMDocument.
237
- *
238
- * @since 0.5
239
- */
240
- public function sanitize() {
241
-
242
- // Add root of content to the stack.
243
- $this->stack[] = $this->root_element;
244
-
245
- /**
246
- * This loop traverses through the DOM tree iteratively.
247
- */
248
- while ( ! empty( $this->stack ) ) {
249
-
250
- // Get the next node to process.
251
- $node = array_pop( $this->stack );
252
-
253
- /**
254
- * Process this node.
255
- */
256
- $this->process_node( $node );
257
-
258
- /*
259
- * Push child nodes onto the stack, if any exist.
260
- * if node was removed, then it's parentNode value is null.
261
- */
262
- if ( $node->parentNode ) {
263
- $child = $node->firstChild;
264
- while ( $child ) {
265
- $this->stack[] = $child;
266
- $child = $child->nextSibling;
267
- }
268
- }
269
- }
270
- }
271
-
272
- /**
273
- * Process a node by sanitizing and/or validating it per.
274
- *
275
- * @param DOMNode $node Node.
276
- */
277
- private function process_node( $node ) {
278
-
279
- // Don't process text or comment nodes.
280
- if ( XML_TEXT_NODE === $node->nodeType || XML_COMMENT_NODE === $node->nodeType || XML_CDATA_SECTION_NODE === $node->nodeType ) {
281
- return;
282
- }
283
-
284
- // Remove nodes with tags that have not been whitelisted.
285
- if ( ! $this->is_amp_allowed_tag( $node ) ) {
286
-
287
- // If it's not an allowed tag, replace the node with it's children.
288
- $this->replace_node_with_children( $node );
289
-
290
- // Return early since this node no longer exists.
291
- return;
292
- }
293
-
294
- /**
295
- * Node is now an element.
296
- *
297
- * @var DOMElement $node
298
- */
299
-
300
- /*
301
- * Compile a list of rule_specs to validate for this node
302
- * based on tag name of the node.
303
- */
304
- $rule_spec_list_to_validate = array();
305
- $rule_spec_list = array();
306
- if ( isset( $this->allowed_tags[ $node->nodeName ] ) ) {
307
- $rule_spec_list = $this->allowed_tags[ $node->nodeName ];
308
- }
309
- foreach ( $rule_spec_list as $id => $rule_spec ) {
310
- if ( $this->validate_tag_spec_for_node( $node, $rule_spec[ AMP_Rule_Spec::TAG_SPEC ] ) ) {
311
-
312
- // Expand extension_spec into a set of attr_spec_list.
313
- if ( isset( $rule_spec[ AMP_Rule_Spec::TAG_SPEC ]['extension_spec'] ) ) {
314
- $extension_spec = $rule_spec[ AMP_Rule_Spec::TAG_SPEC ]['extension_spec'];
315
- $custom_attr = 'amp-mustache' === $extension_spec['name'] ? 'custom-template' : 'custom-element';
316
-
317
- $rule_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ][ $custom_attr ] = array(
318
- AMP_Rule_Spec::VALUE => $extension_spec['name'],
319
- AMP_Rule_Spec::MANDATORY => true,
320
- );
321
-
322
- $rule_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ]['src'] = array(
323
- AMP_Rule_Spec::VALUE_REGEX => implode( '', array(
324
- '^',
325
- preg_quote( 'https://cdn.ampproject.org/v0/' . $extension_spec['name'] . '-' ),
326
- '(' . implode( '|', $extension_spec['allowed_versions'] ) . ')',
327
- '\.js$',
328
- ) ),
329
- );
330
- }
331
-
332
- $rule_spec_list_to_validate[ $id ] = $rule_spec;
333
- }
334
- }
335
-
336
- // If no valid rule_specs exist, then remove this node and return.
337
- if ( empty( $rule_spec_list_to_validate ) ) {
338
- $this->remove_node( $node );
339
- return;
340
- }
341
-
342
- // The remaining validations all have to do with attributes.
343
- $attr_spec_list = array();
344
- $tag_spec = array();
345
- $cdata = array();
346
-
347
- /*
348
- * If we have exactly one rule_spec, use it's attr_spec_list
349
- * to validate the node's attributes.
350
- */
351
- if ( 1 === count( $rule_spec_list_to_validate ) ) {
352
- $rule_spec = array_pop( $rule_spec_list_to_validate );
353
- $attr_spec_list = $rule_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ];
354
- $tag_spec = $rule_spec[ AMP_Rule_Spec::TAG_SPEC ];
355
- if ( isset( $rule_spec[ AMP_Rule_Spec::CDATA ] ) ) {
356
- $cdata = $rule_spec[ AMP_Rule_Spec::CDATA ];
357
- }
358
- } else {
359
- /*
360
- * If there is more than one valid rule_spec for this node,
361
- * then try to deduce which one is intended by inspecting
362
- * the node's attributes.
363
- */
364
-
365
- /*
366
- * Get a score from each attr_spec_list by seeing how many
367
- * attributes and values match the node.
368
- */
369
- $attr_spec_scores = array();
370
- foreach ( $rule_spec_list_to_validate as $spec_id => $rule_spec ) {
371
- $attr_spec_scores[ $spec_id ] = $this->validate_attr_spec_list_for_node( $node, $rule_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] );
372
- }
373
-
374
- // Remove all spec lists that didn't match.
375
- $attr_spec_scores = array_filter( $attr_spec_scores );
376
-
377
- // If no attribute spec lists match, then the element must be removed.
378
- if ( empty( $attr_spec_scores ) ) {
379
- $this->remove_node( $node );
380
- return;
381
- }
382
-
383
- // Get the key(s) to the highest score(s).
384
- $spec_ids_sorted = array_keys( $attr_spec_scores, max( $attr_spec_scores ), true );
385
-
386
- // If there is exactly one attr_spec with a max score, use that one.
387
- if ( 1 === count( $spec_ids_sorted ) ) {
388
- $attr_spec_list = $rule_spec_list_to_validate[ $spec_ids_sorted[0] ][ AMP_Rule_Spec::ATTR_SPEC_LIST ];
389
- $tag_spec = $rule_spec_list_to_validate[ $spec_ids_sorted[0] ][ AMP_Rule_Spec::TAG_SPEC ];
390
- if ( isset( $rule_spec_list_to_validate[ $spec_ids_sorted[0] ][ AMP_Rule_Spec::CDATA ] ) ) {
391
- $cdata = $rule_spec_list_to_validate[ $spec_ids_sorted[0] ][ AMP_Rule_Spec::CDATA ];
392
- }
393
- } else {
394
- // This should not happen very often, but...
395
- // If we're here, then we're not sure which spec should
396
- // be used. Let's use the top scoring ones.
397
- foreach ( $spec_ids_sorted as $id ) {
398
- $spec_list = isset( $rule_spec_list_to_validate[ $id ][ AMP_Rule_Spec::ATTR_SPEC_LIST ] ) ? $rule_spec_list_to_validate[ $id ][ AMP_Rule_Spec::ATTR_SPEC_LIST ] : null;
399
- if ( ! $this->is_missing_mandatory_attribute( $spec_list, $node ) ) {
400
- $attr_spec_list = array_merge( $attr_spec_list, $spec_list );
401
- $tag_spec = array_merge(
402
- $tag_spec,
403
- $rule_spec_list_to_validate[ $id ][ AMP_Rule_Spec::TAG_SPEC ]
404
- );
405
- if ( isset( $rule_spec_list_to_validate[ $id ][ AMP_Rule_Spec::CDATA ] ) ) {
406
- $cdata = array_merge( $cdata, $rule_spec_list_to_validate[ $id ][ AMP_Rule_Spec::CDATA ] );
407
- }
408
- }
409
- }
410
- $first_spec = reset( $rule_spec_list_to_validate );
411
- if ( empty( $attr_spec_list ) && isset( $first_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] ) ) {
412
- $attr_spec_list = $first_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ];
413
- }
414
- }
415
- } // End if().
416
-
417
- if ( ! empty( $attr_spec_list ) && $this->is_missing_mandatory_attribute( $attr_spec_list, $node ) ) {
418
- $this->remove_node( $node );
419
- return;
420
- }
421
-
422
- // Remove element if it has illegal CDATA.
423
- if ( ! empty( $cdata ) && $node instanceof DOMElement ) {
424
- $validity = $this->validate_cdata_for_node( $node, $cdata );
425
- if ( is_wp_error( $validity ) ) {
426
- $this->remove_node( $node );
427
- return;
428
- }
429
- }
430
-
431
- $merged_attr_spec_list = array_merge(
432
- $this->globally_allowed_attributes,
433
- $attr_spec_list
434
- );
435
-
436
- // Identify any remaining disallowed attributes.
437
- $disallowed_attributes = $this->get_disallowed_attributes_in_node( $node, $merged_attr_spec_list );
438
-
439
- // Identify attribute values that don't conform to the attr_spec.
440
- $disallowed_attributes = $this->sanitize_disallowed_attribute_values_in_node( $node, $merged_attr_spec_list, $disallowed_attributes );
441
-
442
- // If $disallowed_attributes is false then the entire element should be removed.
443
- if ( false === $disallowed_attributes ) {
444
- $this->remove_node( $node );
445
- return;
446
- }
447
-
448
- // Remove all invalid attributes.
449
- foreach ( $disallowed_attributes as $disallowed_attribute ) {
450
- $this->remove_invalid_attribute( $node, $disallowed_attribute );
451
- }
452
-
453
- // Add required AMP component scripts if the element is still in the document.
454
- if ( $node->parentNode ) {
455
- if ( ! empty( $tag_spec['also_requires_tag_warning'] ) ) {
456
- $this->script_components[] = strtok( $tag_spec['also_requires_tag_warning'][0], ' ' );
457
- }
458
- if ( ! empty( $tag_spec['requires_extension'] ) ) {
459
- $this->script_components = array_merge( $this->script_components, $tag_spec['requires_extension'] );
460
- }
461
-
462
- // Check if element needs amp-bind component.
463
- if ( $node instanceof DOMElement && ! in_array( 'amp-bind', $this->script_components, true ) ) {
464
- foreach ( $node->attributes as $name => $value ) {
465
- $is_bind_attribute = (
466
- '[' === $name[0]
467
- ||
468
- ( isset( $this->rev_alternate_attr_name_lookup[ $name ] ) && '[' === $this->rev_alternate_attr_name_lookup[ $name ][0] )
469
- );
470
- if ( $is_bind_attribute ) {
471
- $this->script_components[] = 'amp-bind';
472
- break;
473
- }
474
- }
475
- }
476
- }
477
- }
478
-
479
- /**
480
- * Whether a node is missing a mandatory attribute.
481
- *
482
- * @param array $attr_spec The attribute specification.
483
- * @param DOMElement $node The DOMElement of the node to check.
484
- * @return boolean $is_missing boolean Whether a required attribute is missing.
485
- */
486
- public function is_missing_mandatory_attribute( $attr_spec, $node ) {
487
- if ( ! is_array( $attr_spec ) ) {
488
- return false;
489
- }
490
- foreach ( $attr_spec as $attr_name => $attr_spec_rule_value ) {
491
- if ( '\u' === substr( $attr_name, 0, 2 ) ) {
492
- $attr_name = html_entity_decode( '&#x' . substr( $attr_name, 2 ) . ';' ); // Probably ⚡.
493
- }
494
- $is_mandatory = isset( $attr_spec_rule_value[ AMP_Rule_Spec::MANDATORY ] ) ? ( true === $attr_spec_rule_value[ AMP_Rule_Spec::MANDATORY ] ) : false;
495
- $attribute_exists = false;
496
- if ( method_exists( $node, 'hasAttribute' ) ) {
497
- $attribute_exists = $node->hasAttribute( $attr_name );
498
- if ( ! $attribute_exists && ! empty( $attr_spec_rule_value[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
499
- foreach ( $attr_spec_rule_value[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_attr_name ) {
500
- if ( $node->hasAttribute( $alternative_attr_name ) ) {
501
- $attribute_exists = true;
502
- break;
503
- }
504
- }
505
- }
506
- }
507
- if ( $is_mandatory && ! $attribute_exists ) {
508
- return true;
509
- }
510
- }
511
- return false;
512
- }
513
-
514
- /**
515
- * Validate element for its CDATA.
516
- *
517
- * @since 0.7
518
- *
519
- * @param DOMElement $element Element.
520
- * @param array $cdata_spec CDATA.
521
- * @return true|WP_Error True when valid or error when invalid.
522
- */
523
- private function validate_cdata_for_node( $element, $cdata_spec ) {
524
- if ( isset( $cdata_spec['blacklisted_cdata_regex'] ) ) {
525
- if ( preg_match( '@' . $cdata_spec['blacklisted_cdata_regex']['regex'] . '@u', $element->textContent ) ) {
526
- return new WP_Error( $cdata_spec['blacklisted_cdata_regex']['error_message'] );
527
- }
528
- }
529
- return true;
530
- }
531
-
532
- /**
533
- * Determines is a node is currently valid per its tag specification.
534
- *
535
- * Checks to see if a node's placement with the DOM is be valid for the
536
- * given tag_spec. If there are restrictions placed on the type of node
537
- * that can be an immediate parent or an ancestor of this node, then make
538
- * sure those restrictions are met.
539
- *
540
- * @since 0.5
541
- *
542
- * @param DOMNode $node The node to validate.
543
- * @param array $tag_spec The specification.
544
- * @return boolean $valid Whether the node's placement is valid.
545
- */
546
- private function validate_tag_spec_for_node( $node, $tag_spec ) {
547
-
548
- if ( ! empty( $tag_spec[ AMP_Rule_Spec::MANDATORY_PARENT ] ) && ! $this->has_parent( $node, $tag_spec[ AMP_Rule_Spec::MANDATORY_PARENT ] ) ) {
549
- return false;
550
- }
551
-
552
- // Extension scripts must be in the head.
553
- if ( isset( $tag_spec['extension_spec'] ) && ! $this->has_parent( $node, 'head' ) ) {
554
- return false;
555
- }
556
-
557
- if ( ! empty( $tag_spec[ AMP_Rule_Spec::DISALLOWED_ANCESTOR ] ) ) {
558
- foreach ( $tag_spec[ AMP_Rule_Spec::DISALLOWED_ANCESTOR ] as $disallowed_ancestor_node_name ) {
559
- if ( $this->has_ancestor( $node, $disallowed_ancestor_node_name ) ) {
560
- return false;
561
- }
562
- }
563
- }
564
-
565
- if ( ! empty( $tag_spec[ AMP_Rule_Spec::MANDATORY_ANCESTOR ] ) && ! $this->has_ancestor( $node, $tag_spec[ AMP_Rule_Spec::MANDATORY_ANCESTOR ] ) ) {
566
- return false;
567
- }
568
-
569
- return true;
570
- }
571
-
572
- /**
573
- * Checks to see if a spec is potentially valid.
574
- *
575
- * Checks the given node based on the attributes present in the node.
576
- *
577
- * @note This can be a very expensive function. Use it sparingly.
578
- *
579
- * @param DOMNode $node Node.
580
- * @param array[] $attr_spec_list Attribute Spec list.
581
- *
582
- * @return float Number of times the attribute spec list matched. If there was a mismatch, then 0 is returned. 0.5 is returned if there is an implicit match.
583
- */
584
- private function validate_attr_spec_list_for_node( $node, $attr_spec_list ) {
585
- /*
586
- * If node has no attributes there is no point in continuing, but if none of attributes
587
- * in the spec list are mandatory, then we give this a score.
588
- */
589
- if ( ! $node->hasAttributes() ) {
590
- foreach ( $attr_spec_list as $attr_name => $attr_spec_rule ) {
591
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] ) ) {
592
- return 0;
593
- }
594
- }
595
- return 0.5;
596
- }
597
-
598
- if ( ! $node instanceof DOMElement ) {
599
- /*
600
- * A DOMNode is not valid for checks so might
601
- * as well bail here is not an DOMElement.
602
- */
603
- return 0;
604
- }
605
-
606
- foreach ( $node->attributes as $attr_name => $attr_node ) {
607
- if ( ! isset( $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
608
- continue;
609
- }
610
- foreach ( $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $attr_alt_name ) {
611
- $attr_spec_list[ $attr_alt_name ] = $attr_spec_list[ $attr_name ];
612
- }
613
- }
614
-
615
- $score = 0;
616
-
617
- /*
618
- * Keep track of how many of the attribute spec rules are mandatory,
619
- * because if none are mandatory, then we will let this rule have a
620
- * score since all the invalid attributes can just be removed.
621
- */
622
- $mandatory_count = 0;
623
-
624
- /*
625
- * Iterate through each attribute rule in this attr spec list and run
626
- * the series of tests. Each filter is given a `$node`, an `$attr_name`,
627
- * and an `$attr_spec_rule`. If the `$attr_spec_rule` seems to be valid
628
- * for the given node, then the filter should increment the score by one.
629
- */
630
- foreach ( $attr_spec_list as $attr_name => $attr_spec_rule ) {
631
-
632
- // If attr spec rule is empty, then it allows anything.
633
- if ( empty( $attr_spec_rule ) && $node->hasAttribute( $attr_name ) ) {
634
- $score++;
635
- continue;
636
- }
637
-
638
- // If a mandatory attribute is required, and attribute exists, pass.
639
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] ) ) {
640
- $mandatory_count++;
641
- $result = $this->check_attr_spec_rule_mandatory( $node, $attr_name, $attr_spec_rule );
642
- if ( AMP_Rule_Spec::PASS === $result ) {
643
- $score++;
644
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
645
- return 0;
646
- }
647
- }
648
-
649
- /*
650
- * Check 'value' - case sensitive
651
- * Given attribute's value must exactly equal value of the rule to pass.
652
- */
653
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) ) {
654
- $result = $this->check_attr_spec_rule_value( $node, $attr_name, $attr_spec_rule );
655
- if ( AMP_Rule_Spec::PASS === $result ) {
656
- $score++;
657
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
658
- return 0;
659
- }
660
- }
661
-
662
- /*
663
- * Check 'value_regex' - case sensitive regex match
664
- * Given attribute's value must be a case insensitive match to regex pattern
665
- * specified by the value of rule to pass.
666
- */
667
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX ] ) ) {
668
- $result = $this->check_attr_spec_rule_value_regex( $node, $attr_name, $attr_spec_rule );
669
- if ( AMP_Rule_Spec::PASS === $result ) {
670
- $score++;
671
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
672
- return 0;
673
- }
674
- }
675
-
676
- /*
677
- * Check 'value_casei' - case insensitive
678
- * Given attribute's value must be a case insensitive match to the value of
679
- * the rule to pass.
680
- */
681
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_CASEI ] ) ) {
682
- $result = $this->check_attr_spec_rule_value_casei( $node, $attr_name, $attr_spec_rule );
683
- if ( AMP_Rule_Spec::PASS === $result ) {
684
- $score++;
685
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
686
- return 0;
687
- }
688
- }
689
-
690
- /*
691
- * Check 'value_regex_casei' - case insensitive regex match
692
- * Given attribute's value must be a case insensitive match to the regex
693
- * pattern specified by the value of the rule to pass.
694
- */
695
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX_CASEI ] ) ) {
696
- $result = $this->check_attr_spec_rule_value_regex_casei( $node, $attr_name, $attr_spec_rule );
697
- if ( AMP_Rule_Spec::PASS === $result ) {
698
- $score++;
699
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
700
- return 0;
701
- }
702
- }
703
-
704
- /*
705
- * If given attribute's value is a URL with a protocol, the protocol must
706
- * be in the array specified by the rule's value to pass.
707
- */
708
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOWED_PROTOCOL ] ) ) {
709
- $result = $this->check_attr_spec_rule_allowed_protocol( $node, $attr_name, $attr_spec_rule );
710
- if ( AMP_Rule_Spec::PASS === $result ) {
711
- $score++;
712
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
713
- return 0;
714
- }
715
- }
716
-
717
- /*
718
- * If given attribute's value is a URL with a host, the host must
719
- * be valid
720
- */
721
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ] ) ) {
722
- $result = $this->check_attr_spec_rule_valid_url( $node, $attr_name, $attr_spec_rule );
723
- if ( AMP_Rule_Spec::PASS === $result ) {
724
- $score++;
725
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
726
- return 0;
727
- }
728
- }
729
-
730
- /*
731
- * If the given attribute's value is *not* a relative path, and the rule's
732
- * value is `false`, then pass.
733
- */
734
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_RELATIVE ] ) ) {
735
- $result = $this->check_attr_spec_rule_disallowed_relative( $node, $attr_name, $attr_spec_rule );
736
- if ( AMP_Rule_Spec::PASS === $result ) {
737
- $score++;
738
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
739
- return 0;
740
- }
741
- }
742
-
743
- /*
744
- * If the given attribute's value exists, is non-empty and the rule's value
745
- * is false, then pass.
746
- */
747
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_EMPTY ] ) ) {
748
- $result = $this->check_attr_spec_rule_disallowed_empty( $node, $attr_name, $attr_spec_rule );
749
- if ( AMP_Rule_Spec::PASS === $result ) {
750
- $score++;
751
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
752
- return 0;
753
- }
754
- }
755
-
756
- /*
757
- * If the given attribute's value is a URL and does not match any of the list
758
- * of domains in the value of the rule, then pass.
759
- */
760
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::DISALLOWED_DOMAIN ] ) ) {
761
- $result = $this->check_attr_spec_rule_disallowed_domain( $node, $attr_name, $attr_spec_rule );
762
- if ( AMP_Rule_Spec::PASS === $result ) {
763
- $score++;
764
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
765
- return 0;
766
- }
767
- }
768
-
769
- /*
770
- * If the attribute's value exists and does not match the regex specified
771
- * by the rule's value, then pass.
772
- */
773
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX ] ) ) {
774
- $result = $this->check_attr_spec_rule_blacklisted_value_regex( $node, $attr_name, $attr_spec_rule );
775
- if ( AMP_Rule_Spec::PASS === $result ) {
776
- $score++;
777
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
778
- return 0;
779
- }
780
- }
781
-
782
- // If the attribute's value exists and it matches the value properties spec.
783
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_PROPERTIES ] ) && $node->hasAttribute( $attr_name ) ) {
784
- $result = $this->check_attr_spec_rule_value_properties( $node, $attr_name, $attr_spec_rule );
785
- if ( AMP_Rule_Spec::PASS === $result ) {
786
- $score++;
787
- } elseif ( AMP_Rule_Spec::FAIL === $result ) {
788
- return 0;
789
- }
790
- }
791
- }
792
-
793
- // Give the spec a score if it doesn't have any mandatory attributes.
794
- if ( 0 === $mandatory_count && 0 === $score ) {
795
- $score = 0.5;
796
- }
797
-
798
- return $score;
799
- }
800
-
801
- /**
802
- * Remove attributes from $node that are not listed in $allowed_attrs.
803
- *
804
- * @param DOMNode $node Node.
805
- * @param array[] $attr_spec_list Attribute spec list.
806
- * @return DOMAttr[] Attributes to remove.
807
- */
808
- private function get_disallowed_attributes_in_node( $node, $attr_spec_list ) {
809
-
810
- if ( ! $node instanceof DOMElement ) {
811
- /**
812
- * If $node is only a DOMNode and not a DOMElement we can't
813
- * remove an attribute from it anyway. So bail out now.
814
- */
815
- return array();
816
- }
817
-
818
- /*
819
- * We can't remove attributes inside the 'foreach' loop without
820
- * breaking the iteration. So we keep track of the attributes to
821
- * remove in the first loop, then remove them in the second loop.
822
- */
823
- $attrs_to_remove = array();
824
- foreach ( $node->attributes as $attr_name => $attr_node ) {
825
- if ( ! $this->is_amp_allowed_attribute( $attr_name, $attr_spec_list ) ) {
826
- $attrs_to_remove[] = $attr_node;
827
- }
828
- }
829
-
830
- return $attrs_to_remove;
831
- }
832
-
833
- /**
834
- * Remove invalid AMP attributes values from $node that have been implicitly disallowed.
835
- *
836
- * Allowed values are found $this->globally_allowed_attributes and in parameter $attr_spec_list
837
- *
838
- * @param DOMNode $node Node.
839
- * @param array[][] $attr_spec_list Attribute spec list.
840
- * @param DOMAttr[] $attributes_pending_removal Attributes pending removal.
841
- * @return DOMAttr[]|false Attributes to remove, or false if the element itself should be removed.
842
- */
843
- private function sanitize_disallowed_attribute_values_in_node( $node, $attr_spec_list, $attributes_pending_removal ) {
844
-
845
- if ( ! $node instanceof DOMElement ) {
846
- /*
847
- * If $node is only a DOMNode and not a DOMElement we can't
848
- * remove an attribute from it anyway. So bail out now.
849
- */
850
- return $attributes_pending_removal;
851
- }
852
-
853
- return $this->delegated_sanitize_disallowed_attribute_values_in_node(
854
- $node,
855
- array_merge(
856
- $this->globally_allowed_attributes,
857
- $attr_spec_list
858
- ),
859
- $attributes_pending_removal
860
- );
861
- }
862
-
863
- /**
864
- * Remove attributes values from $node that have been disallowed by AMP.
865
- *
866
- * @see $this->sanitize_disallowed_attribute_values_in_node() which delegates to this method
867
- *
868
- * @param DOMElement $node Node.
869
- * @param array[][] $attr_spec_list Attribute spec list.
870
- * @param DOMAttr[] $attributes_pending_removal Attributes pending removal.
871
- * @return DOMAttr[]|false Attributes to remove, or false if the element itself should be removed.
872
- */
873
- private function delegated_sanitize_disallowed_attribute_values_in_node( $node, $attr_spec_list, $attributes_pending_removal ) {
874
- $attrs_to_remove = array();
875
-
876
- foreach ( $attr_spec_list as $attr_name => $attr_val ) {
877
- if ( isset( $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
878
- foreach ( $attr_spec_list[ $attr_name ][ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $attr_alt_name ) {
879
- $attr_spec_list[ $attr_alt_name ] = $attr_spec_list[ $attr_name ];
880
- }
881
- }
882
- }
883
-
884
- foreach ( $node->attributes as $attr_name => $attr_node ) {
885
-
886
- if ( ! isset( $attr_spec_list[ $attr_name ] ) || in_array( $attr_node, $attributes_pending_removal, true ) ) {
887
- continue;
888
- }
889
-
890
- $should_remove_node = false;
891
- $attr_spec_rule = $attr_spec_list[ $attr_name ];
892
-
893
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) &&
894
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_value( $node, $attr_name, $attr_spec_rule ) ) {
895
- $should_remove_node = true;
896
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_CASEI ] ) &&
897
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_value_casei( $node, $attr_name, $attr_spec_rule ) ) {
898
- $should_remove_node = true;
899
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX ] ) &&
900
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
901
- $should_remove_node = true;
902
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX_CASEI ] ) &&
903
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_value_regex_casei( $node, $attr_name, $attr_spec_rule ) ) {
904
- $should_remove_node = true;
905
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOWED_PROTOCOL ] ) &&
906
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_allowed_protocol( $node, $attr_name, $attr_spec_rule ) ) {
907
- $should_remove_node = true;
908
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ] ) &&
909
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_valid_url( $node, $attr_name, $attr_spec_rule ) ) {
910
- $should_remove_node = true;
911
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_RELATIVE ] ) &&
912
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_disallowed_relative( $node, $attr_name, $attr_spec_rule ) ) {
913
- $should_remove_node = true;
914
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_EMPTY ] ) &&
915
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_disallowed_empty( $node, $attr_name, $attr_spec_rule ) ) {
916
- $should_remove_node = true;
917
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::DISALLOWED_DOMAIN ] ) &&
918
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_disallowed_domain( $node, $attr_name, $attr_spec_rule ) ) {
919
- $should_remove_node = true;
920
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX ] ) &&
921
- AMP_Rule_Spec::FAIL === $this->check_attr_spec_rule_blacklisted_value_regex( $node, $attr_name, $attr_spec_rule ) ) {
922
- $should_remove_node = true;
923
- }
924
-
925
- if ( $should_remove_node ) {
926
- $is_mandatory =
927
- isset( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] )
928
- ? (bool) $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ]
929
- : false;
930
-
931
- if ( $is_mandatory ) {
932
- $this->remove_node( $node );
933
- return false;
934
- }
935
-
936
- $attrs_to_remove[] = $attr_node;
937
- }
938
- }
939
-
940
- // Remove the disallowed values.
941
- foreach ( $attrs_to_remove as $attr_node ) {
942
- if ( isset( $attr_spec_list[ $attr_node->nodeName ][ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_EMPTY ] ) &&
943
- ( true === $attr_spec_list[ $attr_node->nodeName ][ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_EMPTY ] ) ) {
944
- $attr_node->nodeValue = '';
945
- } else {
946
- $attributes_pending_removal[] = $attr_node;
947
- }
948
- }
949
-
950
- return $attributes_pending_removal;
951
- }
952
-
953
- /**
954
- * Check if attribute is mandatory determine whether it exists in $node.
955
- *
956
- * When checking for the given attribute it also checks valid alternates.
957
- *
958
- * @param DOMElement $node Node.
959
- * @param string $attr_name Attribute name.
960
- * @param array[] $attr_spec_rule Attribute spec rule.
961
- *
962
- * @return string:
963
- * - AMP_Rule_Spec::PASS - $attr_name is mandatory and it exists
964
- * - AMP_Rule_Spec::FAIL - $attr_name is mandatory, but doesn't exist
965
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name is not mandatory
966
- */
967
- private function check_attr_spec_rule_mandatory( $node, $attr_name, $attr_spec_rule ) {
968
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] ) && ( $attr_spec_rule[ AMP_Rule_Spec::MANDATORY ] ) ) {
969
- if ( $node->hasAttribute( $attr_name ) ) {
970
- return AMP_Rule_Spec::PASS;
971
- } else {
972
- // Check if an alternative name list is specified.
973
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
974
- foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alt_name ) {
975
- if ( $node->hasAttribute( $alt_name ) ) {
976
- return AMP_Rule_Spec::PASS;
977
- }
978
- }
979
- }
980
- return AMP_Rule_Spec::FAIL;
981
- }
982
- }
983
- return AMP_Rule_Spec::NOT_APPLICABLE;
984
- }
985
-
986
- /**
987
- * Check if attribute has a value rule determine if its value is valid.
988
- *
989
- * Checks for value validity by matches against valid values.
990
- *
991
- * @param DOMElement $node Node.
992
- * @param string $attr_name Attribute name.
993
- * @param array $attr_spec_rule Attribute spec rule.
994
- *
995
- * @return string:
996
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
997
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
998
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
999
- * is no rule for this attribute.
1000
- */
1001
- private function check_attr_spec_rule_value( $node, $attr_name, $attr_spec_rule ) {
1002
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) ) {
1003
- if ( $node->hasAttribute( $attr_name ) ) {
1004
- if ( $this->check_matching_attribute_value( $attr_name, $node->getAttribute( $attr_name ), $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) ) {
1005
- return AMP_Rule_Spec::PASS;
1006
- } else {
1007
- return AMP_Rule_Spec::FAIL;
1008
- }
1009
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
1010
- foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
1011
- if ( $node->hasAttribute( $alternative_name ) ) {
1012
- if ( $this->check_matching_attribute_value( $attr_name, $node->getAttribute( $alternative_name ), $attr_spec_rule[ AMP_Rule_Spec::VALUE ] ) ) {
1013
- return AMP_Rule_Spec::PASS;
1014
- } else {
1015
- return AMP_Rule_Spec::FAIL;
1016
- }
1017
- }
1018
- }
1019
- }
1020
- }
1021
- return AMP_Rule_Spec::NOT_APPLICABLE;
1022
- }
1023
-
1024
- /**
1025
- * Check that an attribute's value matches is given spec value.
1026
- *
1027
- * This takes into account boolean attributes where value can match name (e.g. selected="selected").
1028
- *
1029
- * @since 0.7.0
1030
- *
1031
- * @param string $attr_name Attribute name.
1032
- * @param string $attr_value Attribute value.
1033
- * @param string $spec_value Attribute spec value.
1034
- * @return bool Is value valid.
1035
- */
1036
- private function check_matching_attribute_value( $attr_name, $attr_value, $spec_value ) {
1037
- if ( $spec_value === $attr_value ) {
1038
- return true;
1039
- }
1040
-
1041
- // Check for boolean attribute.
1042
- return (
1043
- '' === $spec_value
1044
- &&
1045
- in_array( $attr_name, AMP_Rule_Spec::$boolean_attributes, true )
1046
- &&
1047
- strtolower( $attr_value ) === strtolower( $attr_name )
1048
- );
1049
- }
1050
-
1051
- /**
1052
- * Check if attribute has a value rule determine if its value matches ignoring case.
1053
- *
1054
- * @param DOMElement $node Node.
1055
- * @param string $attr_name Attribute name.
1056
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1057
- *
1058
- * @return string:
1059
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1060
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1061
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1062
- * is no rule for this attribute.
1063
- */
1064
- private function check_attr_spec_rule_value_casei( $node, $attr_name, $attr_spec_rule ) {
1065
- /**
1066
- * Check 'value_casei' - case insensitive
1067
- */
1068
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_CASEI ] ) ) {
1069
- $rule_value = strtolower( $attr_spec_rule[ AMP_Rule_Spec::VALUE_CASEI ] );
1070
- if ( $node->hasAttribute( $attr_name ) ) {
1071
- $attr_value = strtolower( $node->getAttribute( $attr_name ) );
1072
- if ( $attr_value === (string) $rule_value ) {
1073
- return AMP_Rule_Spec::PASS;
1074
- } else {
1075
- return AMP_Rule_Spec::FAIL;
1076
- }
1077
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
1078
- foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
1079
- if ( $node->hasAttribute( $alternative_name ) ) {
1080
- $attr_value = strtolower( $node->getAttribute( $alternative_name ) );
1081
- if ( $attr_value === (string) $rule_value ) {
1082
- return AMP_Rule_Spec::PASS;
1083
- } else {
1084
- return AMP_Rule_Spec::FAIL;
1085
- }
1086
- }
1087
- }
1088
- }
1089
- }
1090
- return AMP_Rule_Spec::NOT_APPLICABLE;
1091
- }
1092
-
1093
- /**
1094
- * Check if attribute has a regex value rule determine if it matches.
1095
- *
1096
- * @param DOMElement $node Node.
1097
- * @param string $attr_name Attribute name.
1098
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1099
- *
1100
- * @return string:
1101
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1102
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1103
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1104
- * is no rule for this attribute.
1105
- */
1106
- private function check_attr_spec_rule_value_regex( $node, $attr_name, $attr_spec_rule ) {
1107
- // Check 'value_regex' - case sensitive regex match.
1108
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX ] ) && $node->hasAttribute( $attr_name ) ) {
1109
- $rule_value = $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX ];
1110
-
1111
- /*
1112
- * The regex pattern has '^' and '$' though they are not in the AMP spec.
1113
- * Leaving them out would allow both '_blank' and 'yyy_blankzzz' to be
1114
- * matched by a regex rule of '(_blank|_self|_top)'. As the AMP JS validator
1115
- * only accepts '_blank' we leave it this way for now.
1116
- */
1117
- if ( preg_match( '@^' . $rule_value . '$@u', $node->getAttribute( $attr_name ) ) ) {
1118
- return AMP_Rule_Spec::PASS;
1119
- } else {
1120
- return AMP_Rule_Spec::FAIL;
1121
- }
1122
- }
1123
- return AMP_Rule_Spec::NOT_APPLICABLE;
1124
- }
1125
-
1126
- /**
1127
- * Check if attribute has a case-insensitive regex value rule determine if it matches.
1128
- *
1129
- * @param DOMElement $node Node.
1130
- * @param string $attr_name Attribute name.
1131
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1132
- *
1133
- * @return string:
1134
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1135
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1136
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1137
- * is no rule for this attribute.
1138
- */
1139
- private function check_attr_spec_rule_value_regex_casei( $node, $attr_name, $attr_spec_rule ) {
1140
- /**
1141
- * Check 'value_regex_casei' - case insensitive regex match
1142
- */
1143
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX_CASEI ] ) && $node->hasAttribute( $attr_name ) ) {
1144
- $rule_value = $attr_spec_rule[ AMP_Rule_Spec::VALUE_REGEX_CASEI ];
1145
-
1146
- // See note above regarding the '^' and '$' that are added here.
1147
- if ( preg_match( '/^' . $rule_value . '$/ui', $node->getAttribute( $attr_name ) ) ) {
1148
- return AMP_Rule_Spec::PASS;
1149
- } else {
1150
- return AMP_Rule_Spec::FAIL;
1151
- }
1152
- }
1153
- return AMP_Rule_Spec::NOT_APPLICABLE;
1154
- }
1155
-
1156
- /**
1157
- * Check if attribute has a valid host value
1158
- *
1159
- * @since 0.7
1160
- *
1161
- * @param DOMElement $node Node.
1162
- * @param string $attr_name Attribute name.
1163
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1164
- *
1165
- * @return string:
1166
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1167
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1168
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1169
- * is no rule for this attribute.
1170
- */
1171
- private function check_attr_spec_rule_valid_url( $node, $attr_name, $attr_spec_rule ) {
1172
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ] ) ) {
1173
- if ( $node->hasAttribute( $attr_name ) ) {
1174
- $urls_to_test = preg_split( '/\s*,\s*/', $node->getAttribute( $attr_name ) );
1175
- foreach ( $urls_to_test as $url ) {
1176
- $url = urldecode( $url );
1177
- // Check if the host contains invalid chars.
1178
- $url_host = wp_parse_url( $url, PHP_URL_HOST );
1179
- if ( $url_host && preg_match( '/[!"#$%&\'()*+,\/:;<=>?@[\]^`{|}~\s]/i', $url_host ) ) {
1180
- return AMP_Rule_Spec::FAIL;
1181
- }
1182
-
1183
- // Check if the protocol contains invalid chars.
1184
- $dots_pos = strpos( $url, ':' );
1185
- if ( false !== $dots_pos && preg_match( '/[!"#$%&\'()*+,\/:;<=>?@[\]^`{|}~\s]/i', substr( $url, 0, $dots_pos ) ) ) {
1186
- return AMP_Rule_Spec::FAIL;
1187
- }
1188
- }
1189
-
1190
- return AMP_Rule_Spec::PASS;
1191
- }
1192
- }
1193
-
1194
- return AMP_Rule_Spec::NOT_APPLICABLE;
1195
- }
1196
-
1197
- /**
1198
- * Check if attribute has a protocol value rule determine if it matches.
1199
- *
1200
- * @param DOMElement $node Node.
1201
- * @param string $attr_name Attribute name.
1202
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1203
- *
1204
- * @return string:
1205
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1206
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1207
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1208
- * is no rule for this attribute.
1209
- */
1210
- private function check_attr_spec_rule_allowed_protocol( $node, $attr_name, $attr_spec_rule ) {
1211
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOWED_PROTOCOL ] ) ) {
1212
- if ( $node->hasAttribute( $attr_name ) ) {
1213
- $urls_to_test = preg_split( '/\s*,\s*/', $node->getAttribute( $attr_name ) );
1214
- foreach ( $urls_to_test as $url ) {
1215
- /*
1216
- * This seems to be an acceptable check since the AMP validator
1217
- * will allow a URL with no protocol to pass validation.
1218
- */
1219
- $url_scheme = AMP_WP_Utils::parse_url( $url, PHP_URL_SCHEME );
1220
- if ( $url_scheme ) {
1221
- if ( ! in_array( strtolower( $url_scheme ), $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOWED_PROTOCOL ], true ) ) {
1222
- return AMP_Rule_Spec::FAIL;
1223
- }
1224
- }
1225
- }
1226
- return AMP_Rule_Spec::PASS;
1227
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
1228
- foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
1229
- if ( $node->hasAttribute( $alternative_name ) ) {
1230
- $urls_to_test = preg_split( '/\s*,\s*/', $node->getAttribute( $alternative_name ) );
1231
- foreach ( $urls_to_test as $url ) {
1232
- /*
1233
- * This seems to be an acceptable check since the AMP validator
1234
- * will allow a URL with no protocol to pass validation.
1235
- */
1236
- $url_scheme = AMP_WP_Utils::parse_url( $url, PHP_URL_SCHEME );
1237
- if ( $url_scheme ) {
1238
- if ( ! in_array( strtolower( $url_scheme ), $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOWED_PROTOCOL ], true ) ) {
1239
- return AMP_Rule_Spec::FAIL;
1240
- }
1241
- }
1242
- }
1243
- return AMP_Rule_Spec::PASS;
1244
- }
1245
- }
1246
- }
1247
- }
1248
- return AMP_Rule_Spec::NOT_APPLICABLE;
1249
- }
1250
-
1251
- /**
1252
- * Check if attribute has disallowed relative value rule determine if disallowed relative value matches.
1253
- *
1254
- * @param DOMElement $node Node.
1255
- * @param string $attr_name Attribute name.
1256
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1257
- *
1258
- * @return string:
1259
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1260
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1261
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1262
- * is no rule for this attribute.
1263
- */
1264
- private function check_attr_spec_rule_disallowed_relative( $node, $attr_name, $attr_spec_rule ) {
1265
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_RELATIVE ] ) && ! ( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_RELATIVE ] ) ) {
1266
- if ( $node->hasAttribute( $attr_name ) ) {
1267
- $urls_to_test = preg_split( '/\s*,\s*/', $node->getAttribute( $attr_name ) );
1268
- foreach ( $urls_to_test as $url ) {
1269
- $parsed_url = AMP_WP_Utils::parse_url( $url );
1270
-
1271
- /*
1272
- * The JS AMP validator seems to consider 'relative' to mean
1273
- * *protocol* relative, not *host* relative for this rule. So,
1274
- * a url with an empty 'scheme' is considered "relative" by AMP.
1275
- * ie. '//domain.com/path' and '/path' should both be considered
1276
- * relative for purposes of AMP validation.
1277
- */
1278
- if ( empty( $parsed_url['scheme'] ) ) {
1279
- return AMP_Rule_Spec::FAIL;
1280
- }
1281
- }
1282
- return AMP_Rule_Spec::PASS;
1283
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
1284
- foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
1285
- if ( $node->hasAttribute( $alternative_name ) ) {
1286
- $urls_to_test = preg_split( '/\s*,\s*/', $node->getAttribute( $alternative_name ) );
1287
- foreach ( $urls_to_test as $url ) {
1288
- $parsed_url = AMP_WP_Utils::parse_url( $url );
1289
- if ( empty( $parsed_url['scheme'] ) ) {
1290
- return AMP_Rule_Spec::FAIL;
1291
- }
1292
- }
1293
- }
1294
- }
1295
- return AMP_Rule_Spec::PASS;
1296
- }
1297
- }
1298
- return AMP_Rule_Spec::NOT_APPLICABLE;
1299
- }
1300
-
1301
- /**
1302
- * Check if attribute has disallowed empty value rule determine if value is empty.
1303
- *
1304
- * @param DOMElement $node Node.
1305
- * @param string $attr_name Attribute name.
1306
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1307
- *
1308
- * @return string:
1309
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1310
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1311
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1312
- * is no rule for this attribute.
1313
- */
1314
- private function check_attr_spec_rule_disallowed_empty( $node, $attr_name, $attr_spec_rule ) {
1315
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_EMPTY ] ) && ! ( $attr_spec_rule[ AMP_Rule_Spec::VALUE_URL ][ AMP_Rule_Spec::ALLOW_EMPTY ] ) && $node->hasAttribute( $attr_name ) ) {
1316
- $attr_value = $node->getAttribute( $attr_name );
1317
- if ( empty( $attr_value ) ) {
1318
- return AMP_Rule_Spec::FAIL;
1319
- }
1320
- return AMP_Rule_Spec::PASS;
1321
- }
1322
- return AMP_Rule_Spec::NOT_APPLICABLE;
1323
- }
1324
-
1325
- /**
1326
- * Check if attribute has disallowed domain value rule determine if value matches.
1327
- *
1328
- * @param DOMElement $node Node.
1329
- * @param string $attr_name Attribute name.
1330
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1331
- *
1332
- * @return string:
1333
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1334
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1335
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1336
- * is no rule for this attribute.
1337
- */
1338
- private function check_attr_spec_rule_disallowed_domain( $node, $attr_name, $attr_spec_rule ) {
1339
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::DISALLOWED_DOMAIN ] ) && $node->hasAttribute( $attr_name ) ) {
1340
- $attr_value = $node->getAttribute( $attr_name );
1341
- $url_domain = AMP_WP_Utils::parse_url( $attr_value, PHP_URL_HOST );
1342
- if ( ! empty( $url_domain ) ) {
1343
- foreach ( $attr_spec_rule[ AMP_Rule_Spec::DISALLOWED_DOMAIN ] as $disallowed_domain ) {
1344
- if ( strtolower( $url_domain ) === strtolower( $disallowed_domain ) ) {
1345
-
1346
- // Found a disallowed domain, fail validation.
1347
- return AMP_Rule_Spec::FAIL;
1348
- }
1349
- }
1350
- return AMP_Rule_Spec::PASS;
1351
- }
1352
- }
1353
- return AMP_Rule_Spec::NOT_APPLICABLE;
1354
- }
1355
-
1356
- /**
1357
- * Check if attribute has blacklisted value via regex match determine if value matches.
1358
- *
1359
- * @since 0.5
1360
- *
1361
- * @param DOMElement $node Node.
1362
- * @param string $attr_name Attribute name.
1363
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1364
- *
1365
- * @return string:
1366
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1367
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1368
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1369
- * is no rule for this attribute.
1370
- */
1371
- private function check_attr_spec_rule_blacklisted_value_regex( $node, $attr_name, $attr_spec_rule ) {
1372
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX ] ) ) {
1373
- $pattern = '/' . $attr_spec_rule[ AMP_Rule_Spec::BLACKLISTED_VALUE_REGEX ] . '/u';
1374
- if ( $node->hasAttribute( $attr_name ) ) {
1375
- $attr_value = $node->getAttribute( $attr_name );
1376
- if ( preg_match( $pattern, $attr_value ) ) {
1377
- return AMP_Rule_Spec::FAIL;
1378
- } else {
1379
- return AMP_Rule_Spec::PASS;
1380
- }
1381
- } elseif ( isset( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] ) ) {
1382
- foreach ( $attr_spec_rule[ AMP_Rule_Spec::ALTERNATIVE_NAMES ] as $alternative_name ) {
1383
- if ( $node->hasAttribute( $alternative_name ) ) {
1384
- $attr_value = $node->getAttribute( $alternative_name );
1385
- if ( preg_match( $pattern, $attr_value ) ) {
1386
- return AMP_Rule_Spec::FAIL;
1387
- } else {
1388
- return AMP_Rule_Spec::PASS;
1389
- }
1390
- }
1391
- }
1392
- }
1393
- }
1394
- return AMP_Rule_Spec::NOT_APPLICABLE;
1395
- }
1396
-
1397
- /**
1398
- * Check if attribute has valid properties.
1399
- *
1400
- * @since 0.7
1401
- *
1402
- * @param DOMElement $node Node.
1403
- * @param string $attr_name Attribute name.
1404
- * @param array[]|string[] $attr_spec_rule Attribute spec rule.
1405
- *
1406
- * @return string:
1407
- * - AMP_Rule_Spec::PASS - $attr_name has a value that matches the rule.
1408
- * - AMP_Rule_Spec::FAIL - $attr_name has a value that does *not* match rule.
1409
- * - AMP_Rule_Spec::NOT_APPLICABLE - $attr_name does not exist or there
1410
- * is no rule for this attribute.
1411
- */
1412
- private function check_attr_spec_rule_value_properties( $node, $attr_name, $attr_spec_rule ) {
1413
- if ( isset( $attr_spec_rule[ AMP_Rule_Spec::VALUE_PROPERTIES ] ) && $node->hasAttribute( $attr_name ) ) {
1414
- $properties = array();
1415
- foreach ( explode( ',', $node->getAttribute( $attr_name ) ) as $pair ) {
1416
- $pair_parts = explode( '=', $pair, 2 );
1417
- if ( 2 !== count( $pair_parts ) ) {
1418
- return 0;
1419
- }
1420
- $properties[ strtolower( $pair_parts[0] ) ] = $pair_parts[1];
1421
- }
1422
-
1423
- // Fail if there are unrecognized properties.
1424
- if ( count( array_diff( array_keys( $properties ), array_keys( $attr_spec_rule[ AMP_Rule_Spec::VALUE_PROPERTIES ] ) ) ) > 0 ) {
1425
- return AMP_Rule_Spec::FAIL;
1426
- }
1427
-
1428
- foreach ( $attr_spec_rule[ AMP_Rule_Spec::VALUE_PROPERTIES ] as $prop_name => $property_spec ) {
1429
-
1430
- // Mandatory property is missing.
1431
- if ( ! empty( $property_spec['mandatory'] ) && ! isset( $properties[ $prop_name ] ) ) {
1432
- return AMP_Rule_Spec::FAIL;
1433
- }
1434
-
1435
- if ( ! isset( $properties[ $prop_name ] ) ) {
1436
- continue;
1437
- }
1438
-
1439
- $prop_value = $properties[ $prop_name ];
1440
-
1441
- // Required value is absent, so fail.
1442
- $required_value = null;
1443
- if ( isset( $property_spec['value'] ) ) {
1444
- $required_value = $property_spec['value'];
1445
- } elseif ( isset( $property_spec['value_double'] ) ) {
1446
- $required_value = $property_spec['value_double'];
1447
- $prop_value = (double) $prop_value;
1448
- }
1449
- if ( isset( $required_value ) && $prop_value !== $required_value ) {
1450
- return AMP_Rule_Spec::FAIL;
1451
- }
1452
- }
1453
- return AMP_Rule_Spec::PASS;
1454
- }
1455
- return AMP_Rule_Spec::NOT_APPLICABLE;
1456
- }
1457
-
1458
- /**
1459
- * Determine if the supplied attribute name is allowed for AMP.
1460
- *
1461
- * @since 0.5
1462
- *
1463
- * @param string $attr_name Attribute name.
1464
- * @param array[]|string[] $attr_spec_list Attribute spec list.
1465
- * @return bool Return true if attribute name is valid for this attr_spec_list, false otherwise.
1466
- */
1467
- private function is_amp_allowed_attribute( $attr_name, $attr_spec_list ) {
1468
- if ( isset( $this->globally_allowed_attributes[ $attr_name ] ) || isset( $this->layout_allowed_attributes[ $attr_name ] ) || isset( $attr_spec_list[ $attr_name ] ) ) {
1469
- return true;
1470
- } else {
1471
- foreach ( AMP_Rule_Spec::$whitelisted_attr_regex as $whitelisted_attr_regex ) {
1472
- if ( preg_match( $whitelisted_attr_regex, $attr_name ) ) {
1473
- return true;
1474
- }
1475
- }
1476
- }
1477
-
1478
- $is_allowed_alt_name_attr = (
1479
- isset( $this->rev_alternate_attr_name_lookup[ $attr_name ] )
1480
- &&
1481
- isset( $attr_spec_list[ $this->rev_alternate_attr_name_lookup[ $attr_name ] ] )
1482
- );
1483
- if ( $is_allowed_alt_name_attr ) {
1484
- return true;
1485
- }
1486
-
1487
- return false;
1488
- }
1489
-
1490
- /**
1491
- * Determine if the supplied $node's HTML tag is allowed for AMP.
1492
- *
1493
- * @since 0.5
1494
- *
1495
- * @param DOMNode $node Node.
1496
- * @return bool Return true if the specified node's name is an AMP allowed tag, false otherwise.
1497
- */
1498
- private function is_amp_allowed_tag( $node ) {
1499
- if ( ! $node instanceof DOMElement ) {
1500
- return false;
1501
- }
1502
- /**
1503
- * Return true if node is an allowed tags or is a text or comment node.
1504
- */
1505
- return (
1506
- ( XML_TEXT_NODE === $node->nodeType ) ||
1507
- isset( $this->allowed_tags[ $node->nodeName ] ) ||
1508
- ( XML_COMMENT_NODE === $node->nodeType ) ||
1509
- ( XML_CDATA_SECTION_NODE === $node->nodeType )
1510
- );
1511
- }
1512
-
1513
- /**
1514
- * Determine if the supplied $node has a parent with the specified tag name.
1515
- *
1516
- * @since 0.5
1517
- *
1518
- * @param DOMNode $node Node.
1519
- * @param string $parent_tag_name Parent tag name.
1520
- * @return bool Return true if given node has direct parent with the given name, false otherwise.
1521
- */
1522
- private function has_parent( $node, $parent_tag_name ) {
1523
- if ( $node && $node->parentNode && ( $node->parentNode->nodeName === $parent_tag_name ) ) {
1524
- return true;
1525
- }
1526
- return false;
1527
- }
1528
-
1529
- /**
1530
- * Determine if the supplied $node has an ancestor with the specified tag name.
1531
- *
1532
- * @since 0.5
1533
- *
1534
- * @todo The $ancestor_tag_name here is not sufficient as it is not just a tag name but an entire selector that is used.
1535
- * @param DOMNode $node Node.
1536
- * @param string $ancestor_tag_name Ancestor tag name.
1537
- * @return bool Return true if given node has any ancestor with the give name, false otherwise.
1538
- */
1539
- private function has_ancestor( $node, $ancestor_tag_name ) {
1540
- if ( $this->get_ancestor_with_tag_name( $node, $ancestor_tag_name ) ) {
1541
- return true;
1542
- }
1543
- return false;
1544
- }
1545
-
1546
- /**
1547
- * Get the first ancestor node matching the specified tag name for the supplied $node.
1548
- *
1549
- * @since 0.5
1550
- *
1551
- * @param DOMNode $node Node.
1552
- * @param string $ancestor_tag_name Ancestor tag name.
1553
- * @return DOMNode|null Returns an ancestor node for the name specified, or null if not found.
1554
- */
1555
- private function get_ancestor_with_tag_name( $node, $ancestor_tag_name ) {
1556
- while ( $node && $node->parentNode ) {
1557
- $node = $node->parentNode;
1558
- if ( $node->nodeName === $ancestor_tag_name ) {
1559
- return $node;
1560
- }
1561
- }
1562
- return null;
1563
- }
1564
-
1565
- /**
1566
- * Replaces the given node with it's child nodes, if any
1567
- *
1568
- * Also adds them to the stack for processing by the sanitize() function.
1569
- *
1570
- * @since 0.3.3
1571
- *
1572
- * @param DOMNode $node Node.
1573
- */
1574
- private function replace_node_with_children( $node ) {
1575
-
1576
- if ( ! $node->hasChildNodes() || ! $node->parentNode ) {
1577
- // If node has no children or no parent, just remove the node.
1578
- $this->remove_node( $node );
1579
-
1580
- } else {
1581
- /*
1582
- * If node has children, replace it with them and push children onto stack
1583
- *
1584
- * Create a DOM fragment to hold the children
1585
- */
1586
- $fragment = $this->dom->createDocumentFragment();
1587
-
1588
- // Add all children to fragment/stack.
1589
- $child = $node->firstChild;
1590
- while ( $child ) {
1591
- $fragment->appendChild( $child );
1592
- $this->stack[] = $child;
1593
- $child = $node->firstChild;
1594
- }
1595
-
1596
- // Replace node with fragment.
1597
- $node->parentNode->replaceChild( $fragment, $node );
1598
-
1599
- }
1600
- }
1601
-
1602
- /**
1603
- * Removes a node from its parent node.
1604
- *
1605
- * If removing the node makes the parent node empty, then it will remove the parent
1606
- * too. It will Continue until a non-empty parent or the 'body' element is reached.
1607
- *
1608
- * @since 0.5
1609
- *
1610
- * @param DOMNode $node Node.
1611
- */
1612
- private function remove_node( $node ) {
1613
- /**
1614
- * Parent.
1615
- *
1616
- * @var DOMNode $parent
1617
- */
1618
- $parent = $node->parentNode;
1619
- if ( $node && $parent ) {
1620
- $this->remove_invalid_child( $node );
1621
- }
1622
- while ( $parent && ! $parent->hasChildNodes() && $this->root_element !== $parent ) {
1623
- $node = $parent;
1624
- $parent = $parent->parentNode;
1625
- if ( $parent ) {
1626
- $parent->removeChild( $node );
1627
- }
1628
- }
1629
- }
1630
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/templates/class-amp-content-sanitizer.php DELETED
@@ -1,98 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Content_Sanitizer
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Content_Sanitizer
10
- *
11
- * @since 0.4.1
12
- */
13
- class AMP_Content_Sanitizer {
14
-
15
- /**
16
- * Sanitize _content_.
17
- *
18
- * @since 0.4.1
19
- * @since 0.7 Passing return_styles=false in $global_args causes stylesheets to be returned instead of styles.
20
- *
21
- * @param string $content HTML content string or DOM document.
22
- * @param string[] $sanitizer_classes Sanitizer classes.
23
- * @param array $global_args Global args.
24
- * @return array Tuple containing sanitized HTML, scripts array, and styles array (or stylesheets, if return_styles=false is passed in $global_args).
25
- */
26
- public static function sanitize( $content, array $sanitizer_classes, $global_args = array() ) {
27
- $dom = AMP_DOM_Utils::get_dom_from_content( $content );
28
-
29
- // For back-compat.
30
- if ( ! isset( $global_args['return_styles'] ) ) {
31
- $global_args['return_styles'] = true;
32
- }
33
-
34
- $results = self::sanitize_document( $dom, $sanitizer_classes, $global_args );
35
- return array(
36
- AMP_DOM_Utils::get_content_from_dom( $dom ),
37
- $results['scripts'],
38
- empty( $global_args['return_styles'] ) ? $results['stylesheets'] : $results['styles'],
39
- );
40
- }
41
-
42
- /**
43
- * Sanitize document.
44
- *
45
- * @since 0.7
46
- *
47
- * @param DOMDocument $dom HTML document.
48
- * @param string[] $sanitizer_classes Sanitizer classes.
49
- * @param array $args Global args passed into sanitizers.
50
- * @return array {
51
- * Scripts and stylesheets needed by sanitizers.
52
- *
53
- * @type array $scripts Scripts.
54
- * @type array $stylesheets Stylesheets. If $args['return_styles'] is empty.
55
- * @type array $styles Styles. If $args['return_styles'] is not empty. For legacy purposes.
56
- * }
57
- */
58
- public static function sanitize_document( &$dom, $sanitizer_classes, $args ) {
59
- $scripts = array();
60
- $stylesheets = array();
61
- $styles = array();
62
-
63
- $return_styles = ! empty( $args['return_styles'] );
64
- unset( $args['return_styles'] );
65
- foreach ( $sanitizer_classes as $sanitizer_class => $sanitizer_args ) {
66
- if ( ! class_exists( $sanitizer_class ) ) {
67
- /* translators: %s is sanitizer class */
68
- _doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Sanitizer (%s) class does not exist', 'amp' ), esc_html( $sanitizer_class ) ), '0.4.1' );
69
- continue;
70
- }
71
-
72
- /**
73
- * Sanitizer.
74
- *
75
- * @type AMP_Base_Sanitizer $sanitizer
76
- */
77
- $sanitizer = new $sanitizer_class( $dom, array_merge( $args, $sanitizer_args ) );
78
-
79
- if ( ! is_subclass_of( $sanitizer, 'AMP_Base_Sanitizer' ) ) {
80
- /* translators: %s is sanitizer class */
81
- _doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Sanitizer (%s) must extend `AMP_Base_Sanitizer`', 'amp' ), esc_html( $sanitizer_class ) ), '0.1' );
82
- continue;
83
- }
84
-
85
- $sanitizer->sanitize();
86
-
87
- $scripts = array_merge( $scripts, $sanitizer->get_scripts() );
88
- if ( $return_styles ) {
89
- $styles = array_merge( $styles, $sanitizer->get_styles() );
90
- } else {
91
- $stylesheets = array_merge( $stylesheets, $sanitizer->get_stylesheets() );
92
- }
93
- }
94
-
95
- return compact( 'scripts', 'styles', 'stylesheets' );
96
- }
97
- }
98
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/templates/class-amp-content.php DELETED
@@ -1,192 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Content
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Content
10
- */
11
- class AMP_Content {
12
-
13
- /**
14
- * Content.
15
- *
16
- * @var string
17
- */
18
- private $content;
19
-
20
- /**
21
- * AMP content.
22
- *
23
- * @var string
24
- */
25
- private $amp_content = '';
26
-
27
- /**
28
- * AMP scripts.
29
- *
30
- * @var array
31
- */
32
- private $amp_scripts = array();
33
-
34
- /**
35
- * AMP styles.
36
- *
37
- * @var array
38
- */
39
- private $amp_styles = array();
40
-
41
- /**
42
- * Args.
43
- *
44
- * @var array
45
- */
46
- private $args = array();
47
-
48
- /**
49
- * Embed handler class names.
50
- *
51
- * @var string[]
52
- */
53
- private $embed_handler_classes = array();
54
-
55
- /**
56
- * Sanitizer class names.
57
- *
58
- * @var string[]
59
- */
60
- private $sanitizer_classes = array();
61
-
62
- /**
63
- * AMP_Content constructor.
64
- *
65
- * @param string $content Content.
66
- * @param string[] $embed_handler_classes Embed handler class names.
67
- * @param string[] $sanitizer_classes Sanitizer class names.
68
- * @param array $args Args.
69
- */
70
- public function __construct( $content, $embed_handler_classes, $sanitizer_classes, $args = array() ) {
71
- $this->content = $content;
72
- $this->args = $args;
73
- $this->embed_handler_classes = $embed_handler_classes;
74
- $this->sanitizer_classes = $sanitizer_classes;
75
-
76
- $this->transform();
77
- }
78
-
79
- /**
80
- * Get AMP content.
81
- *
82
- * @return string
83
- */
84
- public function get_amp_content() {
85
- return $this->amp_content;
86
- }
87
-
88
- /**
89
- * Get AMP scripts.
90
- *
91
- * @return array
92
- */
93
- public function get_amp_scripts() {
94
- return $this->amp_scripts;
95
- }
96
-
97
- /**
98
- * Get AMP styles.
99
- *
100
- * @return array
101
- */
102
- public function get_amp_styles() {
103
- return $this->amp_styles;
104
- }
105
-
106
- /**
107
- * Transform.
108
- */
109
- private function transform() {
110
- $content = $this->content;
111
-
112
- // First, embeds + the_content filter.
113
- $embed_handlers = $this->register_embed_handlers();
114
- $content = apply_filters( 'the_content', $content );
115
- $this->unregister_embed_handlers( $embed_handlers );
116
-
117
- // Then, sanitize to strip and/or convert non-amp content.
118
- $content = $this->sanitize( $content );
119
-
120
- $this->amp_content = $content;
121
- }
122
-
123
- /**
124
- * Add scripts.
125
- *
126
- * @param array $scripts Scripts.
127
- */
128
- private function add_scripts( $scripts ) {
129
- $this->amp_scripts = array_merge( $this->amp_scripts, $scripts );
130
- }
131
-
132
- /**
133
- * Add styles.
134
- *
135
- * @param array $styles Styles.
136
- */
137
- private function add_styles( $styles ) {
138
- $this->amp_styles = array_merge( $this->amp_styles, $styles );
139
- }
140
-
141
- /**
142
- * Register embed handlers.
143
- *
144
- * @return array
145
- */
146
- private function register_embed_handlers() {
147
- $embed_handlers = array();
148
-
149
- foreach ( $this->embed_handler_classes as $embed_handler_class => $args ) {
150
- $embed_handler = new $embed_handler_class( array_merge( $this->args, $args ) );
151
-
152
- if ( ! is_subclass_of( $embed_handler, 'AMP_Base_Embed_Handler' ) ) {
153
- /* translators: %s is embed handler */
154
- _doing_it_wrong( __METHOD__, esc_html( sprintf( __( 'Embed Handler (%s) must extend `AMP_Embed_Handler`', 'amp' ), $embed_handler_class ) ), '0.1' );
155
- continue;
156
- }
157
-
158
- $embed_handler->register_embed();
159
- $embed_handlers[] = $embed_handler;
160
- }
161
-
162
- return $embed_handlers;
163
- }
164
-
165
- /**
166
- * Unregister embed handlers.
167
- *
168
- * @param array $embed_handlers Embed handlers.
169
- */
170
- private function unregister_embed_handlers( $embed_handlers ) {
171
- foreach ( $embed_handlers as $embed_handler ) {
172
- $this->add_scripts( $embed_handler->get_scripts() );
173
- $embed_handler->unregister_embed();
174
- }
175
- }
176
-
177
- /**
178
- * Sanitize.
179
- *
180
- * @see AMP_Content_Sanitizer::sanitize()
181
- * @param string $content Content.
182
- * @return array Sanitized content.
183
- */
184
- private function sanitize( $content ) {
185
- list( $sanitized_content, $scripts, $styles ) = AMP_Content_Sanitizer::sanitize( $content, $this->sanitizer_classes, $this->args );
186
-
187
- $this->add_scripts( $scripts );
188
- $this->add_styles( $styles );
189
-
190
- return $sanitized_content;
191
- }
192
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/templates/class-amp-post-template.php DELETED
@@ -1,481 +0,0 @@
1
- <?php
2
- /**
3
- * AMP_Post_Template class.
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Post_Template
10
- *
11
- * @since 0.2
12
- */
13
- class AMP_Post_Template {
14
-
15
- /**
16
- * Site icon size.
17
- *
18
- * @since 0.2
19
- * @var int
20
- */
21
- const SITE_ICON_SIZE = 32;
22
-
23
- /**
24
- * Content max width.
25
- *
26
- * @since 0.4
27
- * @var int
28
- */
29
- const CONTENT_MAX_WIDTH = 600;
30
-
31
- /**
32
- * Default navbar background.
33
- *
34
- * Needed for 0.3 back-compat
35
- *
36
- * @since 0.4
37
- * @var string
38
- */
39
- const DEFAULT_NAVBAR_BACKGROUND = '#0a89c0';
40
-
41
- /**
42
- * Default navbar color.
43
- *
44
- * Needed for 0.3 back-compat
45
- *
46
- * @since 0.4
47
- * @var string
48
- */
49
- const DEFAULT_NAVBAR_COLOR = '#fff';
50
-
51
- /**
52
- * Template directory.
53
- *
54
- * @since 0.2
55
- * @var string
56
- */
57
- private $template_dir;
58
-
59
- /**
60
- * Post template data.
61
- *
62
- * @since 0.2
63
- * @var array
64
- */
65
- private $data;
66
-
67
- /**
68
- * Post ID.
69
- *
70
- * @since 0.2
71
- * @var int
72
- */
73
- public $ID;
74
-
75
- /**
76
- * Post.
77
- *
78
- * @since 0.2
79
- * @var WP_Post
80
- */
81
- public $post;
82
-
83
- /**
84
- * AMP_Post_Template constructor.
85
- *
86
- * @param WP_Post|int $post Post.
87
- */
88
- public function __construct( $post ) {
89
-
90
- $this->template_dir = apply_filters( 'amp_post_template_dir', AMP__DIR__ . '/templates' );
91
-
92
- if ( $post instanceof WP_Post ) {
93
- $this->post = $post;
94
- } else {
95
- $this->post = get_post( $post );
96
- }
97
-
98
- // Make sure we have a post, or bail if not.
99
- if ( is_a( $this->post, 'WP_Post' ) ) {
100
- $this->ID = $this->post->ID;
101
- } else {
102
- return;
103
- }
104
- if ( ampforwp_is_front_page() ) {
105
- $this->ID = ampforwp_get_frontpage_id();
106
- }
107
- $content_max_width = self::CONTENT_MAX_WIDTH;
108
- if ( isset( $GLOBALS['content_width'] ) && $GLOBALS['content_width'] > 0 ) {
109
- $content_max_width = $GLOBALS['content_width'];
110
- }
111
- $content_max_width = apply_filters( 'amp_content_max_width', $content_max_width );
112
-
113
- $this->data = array(
114
- 'content_max_width' => $content_max_width,
115
-
116
- 'document_title' => function_exists( 'wp_get_document_title' ) ? wp_get_document_title() : wp_title( '', false ), // Back-compat with 4.3.
117
- 'canonical_url' => get_permalink( $this->ID ),
118
- 'home_url' => home_url(),
119
- 'blog_name' => get_bloginfo( 'name' ),
120
-
121
- 'html_tag_attributes' => array(),
122
- 'body_class' => '',
123
-
124
- 'site_icon_url' => apply_filters( 'amp_site_icon_url', function_exists( 'get_site_icon_url' ) ? get_site_icon_url( self::SITE_ICON_SIZE ) : '' ),
125
- 'placeholder_image_url' => amp_get_asset_url( 'images/placeholder-icon.png' ),
126
-
127
- 'featured_image' => false,
128
- 'comments_link_url' => false,
129
- 'comments_link_text' => false,
130
-
131
- 'amp_runtime_script' => 'https://cdn.ampproject.org/v0.js',
132
- 'amp_component_scripts' => array(),
133
-
134
- 'customizer_settings' => array(),
135
-
136
- 'font_urls' => array(
137
- 'merriweather' => 'https://fonts.googleapis.com/css?family=Merriweather:400,400italic,700,700italic',
138
- ),
139
-
140
- 'post_amp_styles' => array(),
141
-
142
- 'amp_analytics' => amp_add_custom_analytics(),
143
- );
144
-
145
- $this->build_post_content();
146
- $this->build_post_data();
147
- $this->build_customizer_settings();
148
- $this->build_html_tag_attributes();
149
-
150
- /**
151
- * Filters AMP template data.
152
- *
153
- * @since 0.2
154
- *
155
- * @param array $data Template data.
156
- * @param WP_Post $post Post.
157
- */
158
- $this->data = apply_filters( 'amp_post_template_data', $this->data, $this->post );
159
- }
160
-
161
- /**
162
- * Getter.
163
- *
164
- * @param string $property Property name.
165
- * @param mixed $default Default value.
166
- *
167
- * @return mixed Value.
168
- */
169
- public function get( $property, $default = null ) {
170
- if ( isset( $this->data[ $property ] ) ) {
171
- return $this->data[ $property ];
172
- } else {
173
- /* translators: %s is key name */
174
- _doing_it_wrong( __METHOD__, esc_html( sprintf( __( 'Called for non-existent key ("%s").', 'amp' ), $property ) ), '0.1' );
175
- }
176
-
177
- return $default;
178
- }
179
-
180
- /**
181
- * Get customizer setting.
182
- *
183
- * @param string $name Name.
184
- * @param mixed $default Default value.
185
- * @return mixed value.
186
- */
187
- public function get_customizer_setting( $name, $default = null ) {
188
- $settings = $this->get( 'customizer_settings' );
189
- if ( ! empty( $settings[ $name ] ) ) {
190
- return $settings[ $name ];
191
- }
192
-
193
- return $default;
194
- }
195
-
196
- /**
197
- * Load and print the template parts for the given post.
198
- */
199
- public function load() {
200
- global $wp_query;
201
- $template = is_page() || $wp_query->is_posts_page ? 'page' : 'single';
202
- $this->load_parts( array( $template ) );
203
- }
204
-
205
- /**
206
- * Load template parts.
207
- *
208
- * @param string[] $templates Templates.
209
- */
210
- public function load_parts( $templates ) {
211
- foreach ( $templates as $template ) {
212
- $file = $this->get_template_path( $template );
213
- $this->verify_and_include( $file, $template );
214
- }
215
- }
216
-
217
- /**
218
- * Get template path.
219
- *
220
- * @param string $template Template name.
221
- * @return string Template path.
222
- */
223
- private function get_template_path( $template ) {
224
- return sprintf( '%s/%s.php', $this->template_dir, $template );
225
- }
226
-
227
- /**
228
- * Add data.
229
- *
230
- * @param array $data Data.
231
- */
232
- private function add_data( $data ) {
233
- $this->data = array_merge( $this->data, $data );
234
- }
235
-
236
- /**
237
- * Add data by key.
238
- *
239
- * @param string $key Key.
240
- * @param mixed $value Value.
241
- */
242
- private function add_data_by_key( $key, $value ) {
243
- $this->data[ $key ] = $value;
244
- }
245
-
246
- /**
247
- * Merge data for key.
248
- *
249
- * @param string $key Key.
250
- * @param mixed $value Value.
251
- */
252
- private function merge_data_for_key( $key, $value ) {
253
- if ( is_array( $this->data[ $key ] ) ) {
254
- $this->data[ $key ] = array_merge( $this->data[ $key ], $value );
255
- } else {
256
- $this->add_data_by_key( $key, $value );
257
- }
258
- }
259
-
260
- /**
261
- * Build post data.
262
- *
263
- * @since 0.2
264
- */
265
- private function build_post_data() {
266
- $post_title = get_the_title( $this->ID );
267
- $post_publish_timestamp = get_the_date( 'U', $this->ID );
268
- $post_modified_timestamp = get_post_modified_time( 'U', false, $this->post );
269
- $post_author = get_userdata( $this->post->post_author );
270
-
271
- $this->add_data(
272
- array(
273
- 'post' => $this->post,
274
- 'post_id' => $this->ID,
275
- 'post_title' => $post_title,
276
- 'post_publish_timestamp' => $post_publish_timestamp,
277
- 'post_modified_timestamp' => $post_modified_timestamp,
278
- 'post_author' => $post_author,
279
- )
280
- );
281
-
282
- $this->build_post_featured_image();
283
- $this->build_post_commments_data();
284
- }
285
-
286
- /**
287
- * Buuild post comments data.
288
- */
289
- private function build_post_commments_data() {
290
- if ( ! post_type_supports( $this->post->post_type, 'comments' ) ) {
291
- return;
292
- }
293
-
294
- $comments_open = comments_open( $this->ID );
295
-
296
- // Don't show link if close and no comments.
297
- if ( ! $comments_open
298
- && ! $this->post->comment_count ) {
299
- return;
300
- }
301
-
302
- $comments_link_url = get_comments_link( $this->ID );
303
- $comments_link_text = $comments_open
304
- ? __( 'Leave a Comment', 'amp' )
305
- : __( 'View Comments', 'amp' );
306
-
307
- $this->add_data(
308
- array(
309
- 'comments_link_url' => $comments_link_url,
310
- 'comments_link_text' => $comments_link_text,
311
- )
312
- );
313
- }
314
-
315
- /**
316
- * Build post content.
317
- */
318
- private function build_post_content() {
319
- if( !empty($this->post->post_content) && false === ampforwp_is_home() && false === is_archive() ){
320
- $post_content = $this->post->post_content;
321
- $post_content = apply_filters( 'ampforwp_post_content_filter', $post_content );
322
- $amp_content = new AMP_Content(
323
- $post_content,
324
- amp_get_content_embed_handlers( $this->post ),
325
- amp_get_content_sanitizers( $this->post ),
326
- array(
327
- 'content_max_width' => $this->get( 'content_max_width' ),
328
- )
329
- );
330
-
331
- $this->add_data_by_key( 'post_amp_content', $amp_content->get_amp_content() );
332
- $this->merge_data_for_key( 'amp_component_scripts', $amp_content->get_amp_scripts() );
333
- $this->merge_data_for_key( 'post_amp_styles', $amp_content->get_amp_styles() );
334
- }
335
- }
336
-
337
- /**
338
- * Build post featured image.
339
- */
340
- private function build_post_featured_image() {
341
- $post_id = $this->ID;
342
- $featured_html = get_the_post_thumbnail( $post_id, 'large' );
343
-
344
- // Skip featured image if no featured image is available.
345
- if ( ! $featured_html ) {
346
- return;
347
- }
348
-
349
- $featured_id = get_post_thumbnail_id( $post_id );
350
-
351
- // If an image with the same ID as the featured image exists in the content, skip the featured image markup.
352
- // Prevents duplicate images, which is especially problematic for photo blogs.
353
- // A bit crude but it's fast and should cover most cases.
354
- $post_content = $this->post->post_content;
355
- if ( true !== apply_filters('ampforwp_allow_featured_image', false) && ( false !== strpos( $post_content, 'wp-image-' . $featured_id ) || false !== strpos( $post_content, 'attachment_' . $featured_id ) ) ) {
356
- return;
357
- }
358
-
359
- $featured_image = get_post( $featured_id );
360
-
361
- list( $sanitized_html, $featured_scripts, $featured_styles ) = AMP_Content_Sanitizer::sanitize(
362
- $featured_html,
363
- amp_get_content_sanitizers( $this->post ),
364
- array(
365
- 'content_max_width' => $this->get( 'content_max_width' ),
366
- )
367
- );
368
-
369
- $this->add_data_by_key(
370
- 'featured_image', array(
371
- 'amp_html' => $sanitized_html,
372
- 'caption' => $featured_image->post_excerpt,
373
- )
374
- );
375
-
376
- if ( $featured_scripts ) {
377
- $this->merge_data_for_key( 'amp_component_scripts', $featured_scripts );
378
- }
379
-
380
- if ( $featured_styles ) {
381
- $this->merge_data_for_key( 'post_amp_styles', $featured_styles );
382
- }
383
- }
384
-
385
- /**
386
- * Build customizer settings.
387
- */
388
- private function build_customizer_settings() {
389
- $settings = AMP_Customizer_Settings::get_settings();
390
-
391
- /**
392
- * Filter AMP Customizer settings.
393
- *
394
- * Inject your Customizer settings here to make them accessible via the getter in your custom style.php template.
395
- *
396
- * Example:
397
- *
398
- * echo esc_html( $this->get_customizer_setting( 'your_setting_key', 'your_default_value' ) );
399
- *
400
- * @since 0.4
401
- *
402
- * @param array $settings Array of AMP Customizer settings.
403
- * @param WP_Post $post Current post object.
404
- */
405
- $this->add_data_by_key( 'customizer_settings', apply_filters( 'amp_post_template_customizer_settings', $settings, $this->post ) );
406
- }
407
-
408
- /**
409
- * Build HTML tag attributes.
410
- */
411
- private function build_html_tag_attributes() {
412
- $attributes = array();
413
-
414
- if ( function_exists( 'is_rtl' ) && is_rtl() ) {
415
- $attributes['dir'] = 'rtl';
416
- }
417
-
418
- $lang = get_bloginfo( 'language' );
419
- if ( $lang ) {
420
- $attributes['lang'] = $lang;
421
- }
422
-
423
- $this->add_data_by_key( 'html_tag_attributes', $attributes );
424
- }
425
-
426
- /**
427
- * Verify and include.
428
- *
429
- * @param string $file File.
430
- * @param string $template_type Template type.
431
- */
432
- private function verify_and_include( $file, $template_type ) {
433
- $located_file = $this->locate_template( $file );
434
- if ( $located_file ) {
435
- $file = $located_file;
436
- }
437
-
438
- $file = apply_filters( 'amp_post_template_file', $file, $template_type, $this->post );
439
- if ( ! $this->is_valid_template( $file ) ) {
440
- /* translators: %1$s is template file, %2$s is 'WP_CONTENT_DIR' string. */
441
- _doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Path validation for template (%1$s) failed. Path cannot traverse and must be located in `%2$s`.', 'amp' ), esc_html( $file ), 'WP_CONTENT_DIR' ), '0.1' );
442
- return;
443
- }
444
-
445
- do_action( 'amp_post_template_include_' . $template_type, $this );
446
- include $file;
447
- }
448
-
449
- /**
450
- * Locate template.
451
- *
452
- * @param string $file File.
453
- * @return string The template filename if one is located.
454
- */
455
- private function locate_template( $file ) {
456
- $search_file = sprintf( 'amp/%s', basename( $file ) );
457
- return locate_template( array( $search_file ), false );
458
- }
459
-
460
- /**
461
- * Is valid template.
462
- *
463
- * @param string $template Template name.
464
- * @return bool Whether valid.
465
- */
466
- private function is_valid_template( $template ) {
467
- if ( false !== strpos( $template, '..' ) ) {
468
- return false;
469
- }
470
-
471
- if ( false !== strpos( $template, './' ) ) {
472
- return false;
473
- }
474
-
475
- if ( ! file_exists( $template ) ) {
476
- return false;
477
- }
478
-
479
- return true;
480
- }
481
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/utils/class-amp-validation-utils.php DELETED
@@ -1,1848 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Validation_Utils
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Validation_Utils
10
- *
11
- * @since 0.7
12
- */
13
- class AMP_Validation_Utils {
14
-
15
- /**
16
- * Query var that triggers validation.
17
- *
18
- * @var string
19
- */
20
- const VALIDATE_QUERY_VAR = 'amp_validate';
21
-
22
- /**
23
- * Query var that enables validation debug mode, to disable removal of invalid elements/attributes.
24
- *
25
- * @var string
26
- */
27
- const DEBUG_QUERY_VAR = 'amp_debug';
28
-
29
- /**
30
- * Query var for cache-busting.
31
- *
32
- * @var string
33
- */
34
- const CACHE_BUST_QUERY_VAR = 'amp_cache_bust';
35
-
36
- /**
37
- * The slug of the post type to store AMP errors.
38
- *
39
- * @var string
40
- */
41
- const POST_TYPE_SLUG = 'amp_validation_error';
42
-
43
- /**
44
- * The key in the response for the sources that have invalid output.
45
- *
46
- * @var string
47
- */
48
- const SOURCES_INVALID_OUTPUT = 'sources_with_invalid_output';
49
-
50
- /**
51
- * Validation code for an invalid element.
52
- *
53
- * @var string
54
- */
55
- const INVALID_ELEMENT_CODE = 'invalid_element';
56
-
57
- /**
58
- * Validation code for an invalid attribute.
59
- *
60
- * @var string
61
- */
62
- const INVALID_ATTRIBUTE_CODE = 'invalid_attribute';
63
-
64
- /**
65
- * Validation code for when script is enqueued (which is not allowed).
66
- *
67
- * @var string
68
- */
69
- const ENQUEUED_SCRIPT_CODE = 'enqueued_script';
70
-
71
- /**
72
- * The meta key for the AMP URL where the error occurred.
73
- *
74
- * @var string
75
- */
76
- const AMP_URL_META = 'amp_url';
77
-
78
- /**
79
- * The key for removed elements.
80
- *
81
- * @var string
82
- */
83
- const REMOVED_ELEMENTS = 'removed_elements';
84
-
85
- /**
86
- * The key for removed attributes.
87
- *
88
- * @var string
89
- */
90
- const REMOVED_ATTRIBUTES = 'removed_attributes';
91
-
92
- /**
93
- * The key for removed sources.
94
- *
95
- * @var string
96
- */
97
- const REMOVED_SOURCES = 'removed_sources';
98
-
99
- /**
100
- * The action to recheck URLs for AMP validity.
101
- *
102
- * @var string
103
- */
104
- const RECHECK_ACTION = 'amp_recheck';
105
-
106
- /**
107
- * The query arg for whether there are remaining errors after rechecking URLs.
108
- *
109
- * @var string
110
- */
111
- const REMAINING_ERRORS = 'amp_remaining_errors';
112
-
113
- /**
114
- * The query arg for the number of URLs tested.
115
- *
116
- * @var string
117
- */
118
- const URLS_TESTED = 'amp_urls_tested';
119
-
120
- /**
121
- * The nonce action for rechecking a URL.
122
- *
123
- * @var string
124
- */
125
- const NONCE_ACTION = 'amp_recheck_';
126
-
127
- /**
128
- * Transient key to store validation errors when activating a plugin.
129
- *
130
- * @var string
131
- */
132
- const PLUGIN_ACTIVATION_VALIDATION_ERRORS_TRANSIENT_KEY = 'amp_plugin_activation_validation_errors';
133
-
134
- /**
135
- * The name of the side meta box on the CPT post.php page.
136
- *
137
- * @var string
138
- */
139
- const STATUS_META_BOX = 'amp_validation_status';
140
-
141
- /**
142
- * The name of the side meta box on the CPT post.php page.
143
- *
144
- * @var string
145
- */
146
- const VALIDATION_ERRORS_META_BOX = 'amp_validation_errors';
147
-
148
- /**
149
- * The errors encountered when validating.
150
- *
151
- * @var array[][] {
152
- * @type string $code Error code.
153
- * @type string $node_name Name of removed node.
154
- * @type string $parent_name Name of parent node.
155
- * }
156
- */
157
- public static $validation_errors = array();
158
-
159
- /**
160
- * Sources that enqueue each script.
161
- *
162
- * @var array
163
- */
164
- public static $enqueued_script_sources = array();
165
-
166
- /**
167
- * Sources that enqueue each style.
168
- *
169
- * @var array
170
- */
171
- public static $enqueued_style_sources = array();
172
-
173
- /**
174
- * Post IDs for posts that have been updated which need to be re-validated.
175
- *
176
- * @var int[]
177
- */
178
- public static $posts_pending_frontend_validation = array();
179
-
180
- /**
181
- * Current sources gathered for a given hook currently being run.
182
- *
183
- * @see AMP_Validation_Utils::wrap_hook_callbacks()
184
- * @see AMP_Validation_Utils::decorate_filter_source()
185
- * @var array[]
186
- */
187
- protected static $current_hook_source_stack = array();
188
-
189
- /**
190
- * Hook source stack.
191
- *
192
- * This has to be public for the sake of PHP 5.3.
193
- *
194
- * @since 0.7
195
- * @var array[]
196
- */
197
- public static $hook_source_stack = array();
198
-
199
- /**
200
- * Add the actions.
201
- *
202
- * @return void
203
- */
204
- public static function init() {
205
- if ( current_theme_supports( 'amp' ) ) {
206
- add_action( 'init', array( __CLASS__, 'register_post_type' ) );
207
- add_filter( 'dashboard_glance_items', array( __CLASS__, 'filter_dashboard_glance_items' ) );
208
- add_action( 'rightnow_end', array( __CLASS__, 'print_dashboard_glance_styles' ) );
209
- add_action( 'save_post', array( __CLASS__, 'handle_save_post_prompting_validation' ), 10, 2 );
210
- }
211
-
212
- add_action( 'edit_form_top', array( __CLASS__, 'print_edit_form_validation_status' ), 10, 2 );
213
- add_action( 'all_admin_notices', array( __CLASS__, 'plugin_notice' ) );
214
- add_filter( 'manage_' . self::POST_TYPE_SLUG . '_posts_columns', array( __CLASS__, 'add_post_columns' ) );
215
- add_action( 'manage_posts_custom_column', array( __CLASS__, 'output_custom_column' ), 10, 2 );
216
- add_filter( 'post_row_actions', array( __CLASS__, 'filter_row_actions' ), 10, 2 );
217
- add_filter( 'bulk_actions-edit-' . self::POST_TYPE_SLUG, array( __CLASS__, 'add_bulk_action' ), 10, 2 );
218
- add_filter( 'handle_bulk_actions-edit-' . self::POST_TYPE_SLUG, array( __CLASS__, 'handle_bulk_action' ), 10, 3 );
219
- add_action( 'admin_notices', array( __CLASS__, 'remaining_error_notice' ) );
220
- add_action( 'post_action_' . self::RECHECK_ACTION, array( __CLASS__, 'handle_inline_recheck' ) );
221
- add_action( 'admin_menu', array( __CLASS__, 'remove_publish_meta_box' ) );
222
- add_action( 'admin_menu', array( __CLASS__, 'add_admin_menu_validation_status_count' ) );
223
- add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_boxes' ) );
224
-
225
- // Actions and filters involved in validation.
226
- add_action( 'activate_plugin', function() {
227
- if ( ! has_action( 'shutdown', array( __CLASS__, 'validate_after_plugin_activation' ) ) ) {
228
- add_action( 'shutdown', array( __CLASS__, 'validate_after_plugin_activation' ) ); // Shutdown so all plugins will have been activated.
229
- }
230
- } );
231
- }
232
-
233
- /**
234
- * Add count of how many validation error posts there are to the admin menu.
235
- */
236
- public static function add_admin_menu_validation_status_count() {
237
- global $submenu;
238
- if ( ! isset( $submenu[ AMP_Options_Manager::OPTION_NAME ] ) ) {
239
- return;
240
- }
241
- $count = wp_count_posts( self::POST_TYPE_SLUG );
242
- if ( empty( $count->publish ) ) {
243
- return;
244
- }
245
- foreach ( $submenu[ AMP_Options_Manager::OPTION_NAME ] as &$submenu_item ) {
246
- if ( 'edit.php?post_type=' . self::POST_TYPE_SLUG === $submenu_item[2] ) {
247
- $submenu_item[0] .= ' <span class="awaiting-mod"><span class="pending-count">' . esc_html( $count->publish ) . '</span></span>';
248
- break;
249
- }
250
- }
251
- }
252
-
253
- /**
254
- * Filter At a Glance items add AMP Validation Errors.
255
- *
256
- * @param array $items At a glance items.
257
- * @return array Items.
258
- */
259
- public static function filter_dashboard_glance_items( $items ) {
260
- $counts = wp_count_posts( self::POST_TYPE_SLUG );
261
- if ( ! empty( $counts->publish ) ) {
262
- $items[] = sprintf(
263
- '<a class="amp-validation-errors" href="%s">%s</a>',
264
- esc_url( admin_url( 'edit.php?post_type=' . self::POST_TYPE_SLUG ) ),
265
- esc_html( sprintf(
266
- /* translators: %s is the validation error count */
267
- _n( '%s AMP Validation Error', '%s AMP Validation Errors', $counts->publish, 'amp' ),
268
- $counts->publish
269
- ) )
270
- );
271
- }
272
- return $items;
273
- }
274
-
275
- /**
276
- * Print styles for the At a Glance widget.
277
- */
278
- public static function print_dashboard_glance_styles() {
279
- ?>
280
- <style>
281
- #dashboard_right_now .amp-validation-errors {
282
- color: #a00;
283
- }
284
- #dashboard_right_now .amp-validation-errors:before {
285
- content: "\f534";
286
- }
287
- #dashboard_right_now .amp-validation-errors:hover {
288
- color: #dc3232;
289
- border: none;
290
- }
291
- </style>
292
- <?php
293
- }
294
-
295
- /**
296
- * Add hooks for doing validation during preprocessing/sanitizing.
297
- */
298
- public static function add_validation_hooks() {
299
- self::wrap_widget_callbacks();
300
-
301
- add_action( 'all', array( __CLASS__, 'wrap_hook_callbacks' ) );
302
- $wrapped_filters = array( 'the_content', 'the_excerpt' );
303
- foreach ( $wrapped_filters as $wrapped_filter ) {
304
- add_filter( $wrapped_filter, array( __CLASS__, 'decorate_filter_source' ), PHP_INT_MAX );
305
- }
306
-
307
- add_filter( 'do_shortcode_tag', array( __CLASS__, 'decorate_shortcode_source' ), -1, 2 );
308
- add_filter( 'amp_content_sanitizers', array( __CLASS__, 'add_validation_callback' ) );
309
- }
310
-
311
- /**
312
- * Handle save_post action to queue re-validation of the post on the frontend.
313
- *
314
- * @see AMP_Validation_Utils::validate_queued_posts_on_frontend()
315
- * @param int $post_id Post ID.
316
- * @param WP_Post $post Post.
317
- */
318
- public static function handle_save_post_prompting_validation( $post_id, $post ) {
319
- $should_validate_post = (
320
- is_post_type_viewable( $post->post_type )
321
- &&
322
- ! wp_is_post_autosave( $post )
323
- &&
324
- ! wp_is_post_revision( $post )
325
- );
326
- if ( $should_validate_post ) {
327
- self::$posts_pending_frontend_validation[] = $post_id;
328
-
329
- // The reason for shutdown is to ensure that all postmeta changes have been saved, including whether AMP is enabled.
330
- if ( ! has_action( 'shutdown', array( __CLASS__, 'validate_queued_posts_on_frontend' ) ) ) {
331
- add_action( 'shutdown', array( __CLASS__, 'validate_queued_posts_on_frontend' ) );
332
- }
333
- }
334
- }
335
-
336
- /**
337
- * Validate the posts pending frontend validation.
338
- *
339
- * @see AMP_Validation_Utils::handle_save_post_prompting_validation()
340
- */
341
- public static function validate_queued_posts_on_frontend() {
342
- $posts = array_filter(
343
- array_map( 'get_post', self::$posts_pending_frontend_validation ),
344
- function( $post ) {
345
- return $post && post_supports_amp( $post ) && 'trash' !== $post->post_status;
346
- }
347
- );
348
-
349
- // @todo Only validate the first and then queue the rest in WP Cron?
350
- foreach ( $posts as $post ) {
351
- $url = amp_get_permalink( $post->ID );
352
- if ( ! $url ) {
353
- continue;
354
- }
355
-
356
- $validation_errors = self::validate_url( $url );
357
- if ( is_wp_error( $validation_errors ) ) {
358
- continue;
359
- }
360
-
361
- self::store_validation_errors( $validation_errors, $url );
362
- }
363
- }
364
-
365
- /**
366
- * Processes markup, to determine AMP validity.
367
- *
368
- * Passes $markup through the AMP sanitizers.
369
- * Also passes a 'validation_error_callback' to keep track of stripped attributes and nodes.
370
- *
371
- * @param string $markup The markup to process.
372
- * @return string Sanitized markup.
373
- */
374
- public static function process_markup( $markup ) {
375
- AMP_Theme_Support::register_content_embed_handlers();
376
-
377
- /** This filter is documented in wp-includes/post-template.php */
378
- $markup = apply_filters( 'the_content', $markup );
379
- $args = array(
380
- 'content_max_width' => ! empty( $content_width ) ? $content_width : AMP_Post_Template::CONTENT_MAX_WIDTH,
381
- 'validation_error_callback' => 'AMP_Validation_Utils::add_validation_error',
382
- );
383
-
384
- $results = AMP_Content_Sanitizer::sanitize( $markup, amp_get_content_sanitizers(), $args );
385
- return $results[0];
386
- }
387
-
388
- /**
389
- * Whether the user has the required capability.
390
- *
391
- * Checks for permissions before validating.
392
- *
393
- * @return boolean $has_cap Whether the current user has the capability.
394
- */
395
- public static function has_cap() {
396
- return current_user_can( 'edit_posts' );
397
- }
398
-
399
- /**
400
- * Add validation error.
401
- *
402
- * @param array $data {
403
- * Data.
404
- *
405
- * @type string $code Error code.
406
- * @type DOMElement|DOMNode $node The removed node.
407
- * }
408
- */
409
- public static function add_validation_error( array $data ) {
410
- $node = null;
411
-
412
- if ( isset( $data['node'] ) && $data['node'] instanceof DOMNode ) {
413
- $node = $data['node'];
414
- unset( $data['node'] );
415
- $data['node_name'] = $node->nodeName;
416
- $data['sources'] = self::locate_sources( $node );
417
- if ( $node->parentNode ) {
418
- $data['parent_name'] = $node->parentNode->nodeName;
419
- }
420
- }
421
-
422
- if ( $node instanceof DOMElement ) {
423
- if ( ! isset( $data['code'] ) ) {
424
- $data['code'] = self::INVALID_ELEMENT_CODE;
425
- }
426
- $data['node_attributes'] = array();
427
- foreach ( $node->attributes as $attribute ) {
428
- $data['node_attributes'][ $attribute->nodeName ] = $attribute->nodeValue;
429
- }
430
-
431
- $is_enqueued_link = (
432
- 'link' === $node->nodeName
433
- &&
434
- preg_match( '/(?P<handle>.+)-css$/', (string) $node->getAttribute( 'id' ), $matches )
435
- &&
436
- isset( self::$enqueued_style_sources[ $matches['handle'] ] )
437
- );
438
- if ( $is_enqueued_link ) {
439
- $data['sources'] = self::$enqueued_style_sources[ $matches['handle'] ];
440
- }
441
- } elseif ( $node instanceof DOMAttr ) {
442
- if ( ! isset( $data['code'] ) ) {
443
- $data['code'] = self::INVALID_ATTRIBUTE_CODE;
444
- }
445
- $data['element_attributes'] = array();
446
- if ( $node->parentNode && $node->parentNode->hasAttributes() ) {
447
- foreach ( $node->parentNode->attributes as $attribute ) {
448
- $data['element_attributes'][ $attribute->nodeName ] = $attribute->nodeValue;
449
- }
450
- }
451
- }
452
-
453
- if ( ! isset( $data['code'] ) ) {
454
- $data['code'] = 'unknown';
455
- }
456
-
457
- self::$validation_errors[] = $data;
458
- }
459
-
460
- /**
461
- * Gets the AMP validation response.
462
- *
463
- * Returns the current validation errors the sanitizers found in rendering the page.
464
- *
465
- * @param array $validation_errors Validation errors.
466
- * @return array The AMP validity of the markup.
467
- */
468
- public static function summarize_validation_errors( $validation_errors ) {
469
- $results = array();
470
- $removed_elements = array();
471
- $removed_attributes = array();
472
- $invalid_sources = array();
473
- foreach ( $validation_errors as $validation_error ) {
474
- $code = isset( $validation_error['code'] ) ? $validation_error['code'] : null;
475
-
476
- if ( self::INVALID_ELEMENT_CODE === $code ) {
477
- if ( ! isset( $removed_elements[ $validation_error['node_name'] ] ) ) {
478
- $removed_elements[ $validation_error['node_name'] ] = 0;
479
- }
480
- $removed_elements[ $validation_error['node_name'] ] += 1;
481
- } elseif ( self::INVALID_ATTRIBUTE_CODE === $code ) {
482
- if ( ! isset( $removed_attributes[ $validation_error['node_name'] ] ) ) {
483
- $removed_attributes[ $validation_error['node_name'] ] = 0;
484
- }
485
- $removed_attributes[ $validation_error['node_name'] ] += 1;
486
- }
487
-
488
- if ( ! empty( $validation_error['sources'] ) ) {
489
- $source = array_pop( $validation_error['sources'] );
490
-
491
- if ( isset( $source['type'], $source['name'] ) ) {
492
- $invalid_sources[ $source['type'] ][] = $source['name'];
493
- }
494
- }
495
- }
496
-
497
- $results = array_merge(
498
- array(
499
- self::SOURCES_INVALID_OUTPUT => $invalid_sources,
500
- ),
501
- compact(
502
- 'removed_elements',
503
- 'removed_attributes'
504
- ),
505
- $results );
506
-
507
- return $results;
508
- }
509
-
510
- /**
511
- * Reset the stored removed nodes and attributes.
512
- *
513
- * After testing if the markup is valid,
514
- * these static values will remain.
515
- * So reset them in case another test is needed.
516
- *
517
- * @return void
518
- */
519
- public static function reset_validation_results() {
520
- self::$validation_errors = array();
521
- self::$enqueued_style_sources = array();
522
- self::$enqueued_script_sources = array();
523
- }
524
-
525
- /**
526
- * Checks the AMP validity of the post content.
527
- *
528
- * If it's not valid AMP, it displays an error message above the 'Classic' editor.
529
- *
530
- * @param WP_Post $post The updated post.
531
- * @return void
532
- */
533
- public static function print_edit_form_validation_status( $post ) {
534
- if ( ! post_supports_amp( $post ) || ! self::has_cap() ) {
535
- return;
536
- }
537
-
538
- $url = null;
539
- $validation_status_post = null;
540
- $validation_errors = array();
541
-
542
- // Incorporate frontend validation status if there is a known URL for the post.
543
- if ( is_post_type_viewable( $post->post_type ) ) {
544
- $url = amp_get_permalink( $post->ID );
545
-
546
- $validation_status_post = self::get_validation_status_post( $url );
547
- if ( $validation_status_post ) {
548
- $data = json_decode( $validation_status_post->post_content, true );
549
- if ( is_array( $data ) ) {
550
- $validation_errors = array_merge( $validation_errors, $data );
551
- }
552
- }
553
- }
554
-
555
- // If no results from URL are available, validate post content outside frontend context.
556
- if ( empty( $validation_errors ) && post_type_supports( $post->post_type, 'editor' ) ) {
557
- self::process_markup( $post->post_content );
558
- $validation_errors = array_merge(
559
- $validation_errors,
560
- self::$validation_errors
561
- );
562
- self::reset_validation_results();
563
-
564
- // Make sure original post is restored after applying shortcodes which could change it.
565
- $GLOBALS['post'] = $post; // WPCS: override ok.
566
- setup_postdata( $post );
567
- }
568
-
569
- if ( empty( $validation_errors ) ) {
570
- return;
571
- }
572
-
573
- echo '<div class="notice notice-warning">';
574
- echo '<p>';
575
- esc_html_e( 'Warning: There is content which fails AMP validation; it will be stripped when served as AMP.', 'amp' );
576
- if ( $validation_status_post || $url ) {
577
- if ( $validation_status_post ) {
578
- echo sprintf(
579
- ' <a href="%s" target="_blank">%s</a>',
580
- esc_url( get_edit_post_link( $validation_status_post ) ),
581
- esc_html__( 'Details', 'amp' )
582
- );
583
- }
584
- if ( $url ) {
585
- if ( $validation_status_post ) {
586
- echo ' | ';
587
- }
588
- echo sprintf(
589
- ' <a href="%s" aria-label="%s" target="_blank">%s</a>',
590
- esc_url( self::get_debug_url( $url ) ),
591
- esc_attr__( 'Validate URL on frontend but without invalid elements/attributes removed', 'amp' ),
592
- esc_html__( 'Debug', 'amp' )
593
- );
594
- }
595
- }
596
- echo '</p>';
597
-
598
- $results = self::summarize_validation_errors( array_unique( $validation_errors, SORT_REGULAR ) );
599
- $removed_sets = array();
600
- if ( ! empty( $results[ self::REMOVED_ELEMENTS ] ) && is_array( $results[ self::REMOVED_ELEMENTS ] ) ) {
601
- $removed_sets[] = array(
602
- 'label' => __( 'Invalid elements:', 'amp' ),
603
- 'names' => array_map( 'sanitize_key', $results[ self::REMOVED_ELEMENTS ] ),
604
- );
605
- }
606
- if ( ! empty( $results[ self::REMOVED_ATTRIBUTES ] ) && is_array( $results[ self::REMOVED_ATTRIBUTES ] ) ) {
607
- $removed_sets[] = array(
608
- 'label' => __( 'Invalid attributes:', 'amp' ),
609
- 'names' => array_map( 'sanitize_key', $results[ self::REMOVED_ATTRIBUTES ] ),
610
- );
611
- }
612
- // @todo There are other kinds of errors other than REMOVED_ELEMENTS and REMOVED_ATTRIBUTES.
613
- foreach ( $removed_sets as $removed_set ) {
614
- printf( '<p>%s ', esc_html( $removed_set['label'] ) );
615
- self::output_removed_set( $removed_set['names'] );
616
- echo '</p>';
617
- }
618
-
619
- echo '</div>';
620
- }
621
-
622
- /**
623
- * Get source start comment.
624
- *
625
- * @param array $source Source data.
626
- * @param bool $is_start Whether the comment is the start or end.
627
- * @return string HTML Comment.
628
- */
629
- public static function get_source_comment( array $source, $is_start = true ) {
630
- unset( $source['reflection'] );
631
- return sprintf(
632
- '<!--%samp-source-stack %s-->',
633
- $is_start ? '' : '/',
634
- str_replace( '--', '', wp_json_encode( $source ) )
635
- );
636
- }
637
-
638
- /**
639
- * Parse source comment.
640
- *
641
- * @param DOMComment $comment Comment.
642
- * @return array|null Parsed source or null if not a source comment.
643
- */
644
- public static function parse_source_comment( DOMComment $comment ) {
645
- if ( ! preg_match( '#^\s*(?P<closing>/)?amp-source-stack\s+(?P<args>{.+})\s*$#s', $comment->nodeValue, $matches ) ) {
646
- return null;
647
- }
648
-
649
- $source = json_decode( $matches['args'], true );
650
- $closing = ! empty( $matches['closing'] );
651
-
652
- return compact( 'source', 'closing' );
653
- }
654
-
655
- /**
656
- * Walk back tree to find the open sources.
657
- *
658
- * @param DOMNode $node Node to look for.
659
- * @return array[][] {
660
- * The data of the removed sources (theme, plugin, or mu-plugin).
661
- *
662
- * @type string $name The name of the source.
663
- * @type string $type The type of the source.
664
- * }
665
- */
666
- public static function locate_sources( DOMNode $node ) {
667
- $xpath = new DOMXPath( $node->ownerDocument );
668
- $comments = $xpath->query( 'preceding::comment()[ starts-with( ., "amp-source-stack" ) or starts-with( ., "/amp-source-stack" ) ]', $node );
669
- $sources = array();
670
- foreach ( $comments as $comment ) {
671
- $parsed_comment = self::parse_source_comment( $comment );
672
- if ( ! $parsed_comment ) {
673
- continue;
674
- }
675
- if ( $parsed_comment['closing'] ) {
676
- array_pop( $sources );
677
- } else {
678
- $sources[] = $parsed_comment['source'];
679
- }
680
- }
681
- return $sources;
682
- }
683
-
684
- /**
685
- * Remove source comments.
686
- *
687
- * @param DOMDocument $dom Document.
688
- */
689
- public static function remove_source_comments( $dom ) {
690
- $xpath = new DOMXPath( $dom );
691
- $comments = array();
692
- foreach ( $xpath->query( '//comment()[ starts-with( ., "amp-source-stack" ) or starts-with( ., "/amp-source-stack" ) ]' ) as $comment ) {
693
- if ( self::parse_source_comment( $comment ) ) {
694
- $comments[] = $comment;
695
- }
696
- }
697
- foreach ( $comments as $comment ) {
698
- $comment->parentNode->removeChild( $comment );
699
- }
700
- }
701
-
702
- /**
703
- * Wrap callbacks for registered widgets to keep track of queued assets and the source for anything printed for validation.
704
- *
705
- * @global array $wp_filter
706
- * @return void
707
- */
708
- public static function wrap_widget_callbacks() {
709
- global $wp_registered_widgets;
710
- foreach ( $wp_registered_widgets as $widget_id => &$registered_widget ) {
711
- $source = self::get_source( $registered_widget['callback'] );
712
- if ( ! $source ) {
713
- continue;
714
- }
715
- $source['widget_id'] = $widget_id;
716
-
717
- $function = $registered_widget['callback'];
718
- $accepted_args = 2; // For the $instance and $args arguments.
719
- $callback = compact( 'function', 'accepted_args', 'source' );
720
-
721
- $registered_widget['callback'] = self::wrapped_callback( $callback );
722
- }
723
- }
724
-
725
- /**
726
- * Wrap filter/action callback functions for a given hook.
727
- *
728
- * Wrapped callback functions are reset to their original functions after invocation.
729
- * This runs at the 'all' action. The shutdown hook is excluded.
730
- *
731
- * @global WP_Hook[] $wp_filter
732
- * @param string $hook Hook name for action or filter.
733
- * @return void
734
- */
735
- public static function wrap_hook_callbacks( $hook ) {
736
- global $wp_filter;
737
-
738
- if ( ! isset( $wp_filter[ $hook ] ) || 'shutdown' === $hook ) {
739
- return;
740
- }
741
-
742
- self::$current_hook_source_stack[ $hook ] = array();
743
- foreach ( $wp_filter[ $hook ]->callbacks as $priority => &$callbacks ) {
744
- foreach ( $callbacks as &$callback ) {
745
- $source = self::get_source( $callback['function'] );
746
- if ( ! $source ) {
747
- continue;
748
- }
749
-
750
- $reflection = $source['reflection'];
751
- unset( $source['reflection'] ); // Omit from stored source.
752
-
753
- // Add hook to stack for decorate_filter_source to read from.
754
- self::$current_hook_source_stack[ $hook ][] = $source;
755
-
756
- /*
757
- * A current limitation with wrapping callbacks is that the wrapped function cannot have
758
- * any parameters passed by reference. Without this the result is:
759
- *
760
- * > PHP Warning: Parameter 1 to wp_default_styles() expected to be a reference, value given.
761
- */
762
- if ( self::has_parameters_passed_by_reference( $reflection ) ) {
763
- continue;
764
- }
765
-
766
- $source['hook'] = $hook;
767
- $original_function = $callback['function'];
768
- $wrapped_callback = self::wrapped_callback( array_merge(
769
- $callback,
770
- compact( 'priority', 'source', 'hook' )
771
- ) );
772
-
773
- $callback['function'] = function() use ( &$callback, $wrapped_callback, $original_function ) {
774
- $callback['function'] = $original_function; // Restore original.
775
- return call_user_func_array( $wrapped_callback, func_get_args() );
776
- };
777
- }
778
- }
779
- }
780
-
781
- /**
782
- * Determine whether the given reflection method/function has params passed by reference.
783
- *
784
- * @since 0.7
785
- * @param ReflectionFunction|ReflectionMethod $reflection Reflection.
786
- * @return bool Whether there are parameters passed by reference.
787
- */
788
- protected static function has_parameters_passed_by_reference( $reflection ) {
789
- foreach ( $reflection->getParameters() as $parameter ) {
790
- if ( $parameter->isPassedByReference() ) {
791
- return true;
792
- }
793
- }
794
- return false;
795
- }
796
-
797
- /**
798
- * Filters the output created by a shortcode callback.
799
- *
800
- * @since 0.7
801
- *
802
- * @param string $output Shortcode output.
803
- * @param string $tag Shortcode name.
804
- * @return string Output.
805
- * @global array $shortcode_tags
806
- */
807
- public static function decorate_shortcode_source( $output, $tag ) {
808
- global $shortcode_tags;
809
- if ( ! isset( $shortcode_tags[ $tag ] ) ) {
810
- return $output;
811
- }
812
- $source = self::get_source( $shortcode_tags[ $tag ] );
813
- if ( empty( $source ) ) {
814
- return $output;
815
- }
816
- $source['shortcode'] = $tag;
817
-
818
- $output = implode( '', array(
819
- self::get_source_comment( $source, true ),
820
- $output,
821
- self::get_source_comment( $source, false ),
822
- ) );
823
- return $output;
824
- }
825
-
826
- /**
827
- * Wraps output of a filter to add source stack comments.
828
- *
829
- * @todo Duplicate with AMP_Validation_Utils::wrap_buffer_with_source_comments()?
830
- * @param string $value Value.
831
- * @return string Value wrapped in source comments.
832
- */
833
- public static function decorate_filter_source( $value ) {
834
-
835
- // Abort if the output is not a string and it doesn't contain any HTML tags.
836
- if ( ! is_string( $value ) || ! preg_match( '/<.+?>/s', $value ) ) {
837
- return $value;
838
- }
839
-
840
- $post = get_post();
841
- $source = array(
842
- 'hook' => current_filter(),
843
- 'filter' => true,
844
- );
845
- if ( $post ) {
846
- $source['post_id'] = $post->ID;
847
- $source['post_type'] = $post->post_type;
848
- }
849
- if ( isset( self::$current_hook_source_stack[ current_filter() ] ) ) {
850
- $sources = self::$current_hook_source_stack[ current_filter() ];
851
- array_pop( $sources ); // Remove self.
852
- $source['sources'] = $sources;
853
- }
854
- return implode( '', array(
855
- self::get_source_comment( $source, true ),
856
- $value,
857
- self::get_source_comment( $source, false ),
858
- ) );
859
- }
860
-
861
- /**
862
- * Gets the plugin or theme of the callback, if one exists.
863
- *
864
- * @param string|array $callback The callback for which to get the plugin.
865
- * @return array|null {
866
- * The source data.
867
- *
868
- * @type string $type Source type (core, plugin, mu-plugin, or theme).
869
- * @type string $name Source name.
870
- * @type string $function Normalized function name.
871
- * @type ReflectionMethod|ReflectionFunction $reflection
872
- * }
873
- */
874
- public static function get_source( $callback ) {
875
- $reflection = null;
876
- $class_name = null; // Because ReflectionMethod::getDeclaringClass() can return a parent class.
877
- try {
878
- if ( is_string( $callback ) && is_callable( $callback ) ) {
879
- // The $callback is a function or static method.
880
- $exploded_callback = explode( '::', $callback, 2 );
881
- if ( 2 === count( $exploded_callback ) ) {
882
- $class_name = $exploded_callback[0];
883
- $reflection = new ReflectionMethod( $exploded_callback[0], $exploded_callback[1] );
884
- } else {
885
- $reflection = new ReflectionFunction( $callback );
886
- }
887
- } elseif ( is_array( $callback ) && isset( $callback[0], $callback[1] ) && method_exists( $callback[0], $callback[1] ) ) {
888
- // The $callback is a method.
889
- if ( is_string( $callback[0] ) ) {
890
- $class_name = $callback[0];
891
- } elseif ( is_object( $callback[0] ) ) {
892
- $class_name = get_class( $callback[0] );
893
- }
894
- $reflection = new ReflectionMethod( $callback[0], $callback[1] );
895
- } elseif ( is_object( $callback ) && ( 'Closure' === get_class( $callback ) ) ) {
896
- $reflection = new ReflectionFunction( $callback );
897
- }
898
- } catch ( Exception $e ) {
899
- return null;
900
- }
901
-
902
- if ( ! $reflection ) {
903
- return null;
904
- }
905
-
906
- $source = compact( 'reflection' );
907
-
908
- $file = $reflection->getFileName();
909
- if ( $file ) {
910
- $file = wp_normalize_path( $file );
911
- $slug_pattern = '([^/]+)';
912
- if ( preg_match( ':' . preg_quote( trailingslashit( wp_normalize_path( WP_PLUGIN_DIR ) ), ':' ) . $slug_pattern . ':s', $file, $matches ) ) {
913
- $source['type'] = 'plugin';
914
- $source['name'] = $matches[1];
915
- } elseif ( preg_match( ':' . preg_quote( trailingslashit( wp_normalize_path( get_theme_root() ) ), ':' ) . $slug_pattern . ':s', $file, $matches ) ) {
916
- $source['type'] = 'theme';
917
- $source['name'] = $matches[1];
918
- } elseif ( preg_match( ':' . preg_quote( trailingslashit( wp_normalize_path( WPMU_PLUGIN_DIR ) ), ':' ) . $slug_pattern . ':s', $file, $matches ) ) {
919
- $source['type'] = 'mu-plugin';
920
- $source['name'] = $matches[1];
921
- } elseif ( preg_match( ':' . preg_quote( trailingslashit( wp_normalize_path( ABSPATH ) ), ':' ) . '(wp-admin|wp-includes)/:s', $file, $matches ) ) {
922
- $source['type'] = 'core';
923
- $source['name'] = $matches[1];
924
- }
925
- }
926
-
927
- if ( $class_name ) {
928
- $source['function'] = $class_name . '::' . $reflection->getName();
929
- } else {
930
- $source['function'] = $reflection->getName();
931
- }
932
-
933
- return $source;
934
- }
935
-
936
- /**
937
- * Check whether or not output buffering is currently possible.
938
- *
939
- * This is to guard against a fatal error: "ob_start(): Cannot use output buffering in output buffering display handlers".
940
- *
941
- * @return bool Whether output buffering is allowed.
942
- */
943
- public static function can_output_buffer() {
944
-
945
- // Output buffering for validation can only be done while overall output buffering is being done for the response.
946
- if ( ! AMP_Theme_Support::is_output_buffering() ) {
947
- return false;
948
- }
949
-
950
- // Abort when in shutdown since output has finished, when we're likely in the overall output buffering display handler.
951
- if ( did_action( 'shutdown' ) ) {
952
- return false;
953
- }
954
-
955
- // Check if any functions in call stack are output buffering display handlers.
956
- $called_functions = array();
957
- if ( defined( 'DEBUG_BACKTRACE_IGNORE_ARGS' ) ) {
958
- $arg = DEBUG_BACKTRACE_IGNORE_ARGS; // phpcs:ignore PHPCompatibility.PHP.NewConstants.debug_backtrace_ignore_argsFound
959
- } else {
960
- $arg = false;
961
- }
962
- $backtrace = debug_backtrace( $arg ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace -- Only way to find out if we are in a buffering display handler.
963
- foreach ( $backtrace as $call_stack ) {
964
- $called_functions[] = '{closure}' === $call_stack['function'] ? 'Closure::__invoke' : $call_stack['function'];
965
- }
966
- return 0 === count( array_intersect( ob_list_handlers(), $called_functions ) );
967
- }
968
-
969
- /**
970
- * Wraps a callback in comments if it outputs markup.
971
- *
972
- * If the sanitizer removes markup,
973
- * this indicates which plugin it was from.
974
- * The call_user_func_array() logic is mainly copied from WP_Hook:apply_filters().
975
- *
976
- * @param array $callback {
977
- * The callback data.
978
- *
979
- * @type callable $function
980
- * @type int $accepted_args
981
- * @type array $source
982
- * }
983
- * @return closure $wrapped_callback The callback, wrapped in comments.
984
- */
985
- public static function wrapped_callback( $callback ) {
986
- return function() use ( $callback ) {
987
- global $wp_styles, $wp_scripts;
988
-
989
- $function = $callback['function'];
990
- $accepted_args = $callback['accepted_args'];
991
- $args = func_get_args();
992
-
993
- $before_styles_enqueued = array();
994
- if ( isset( $wp_styles ) && isset( $wp_styles->queue ) ) {
995
- $before_styles_enqueued = $wp_styles->queue;
996
- }
997
- $before_scripts_enqueued = array();
998
- if ( isset( $wp_scripts ) && isset( $wp_scripts->queue ) ) {
999
- $before_scripts_enqueued = $wp_scripts->queue;
1000
- }
1001
-
1002
- // Wrap the markup output of (action) hooks in source comments.
1003
- AMP_Validation_Utils::$hook_source_stack[] = $callback['source'];
1004
- $has_buffer_started = false;
1005
- if ( AMP_Validation_Utils::can_output_buffer() ) {
1006
- $has_buffer_started = ob_start( array( __CLASS__, 'wrap_buffer_with_source_comments' ) );
1007
- }
1008
- $result = call_user_func_array( $function, array_slice( $args, 0, intval( $accepted_args ) ) );
1009
- if ( $has_buffer_started ) {
1010
- ob_end_flush();
1011
- }
1012
- array_pop( AMP_Validation_Utils::$hook_source_stack );
1013
-
1014
- // Keep track of which source enqueued the styles.
1015
- if ( isset( $wp_styles ) && isset( $wp_styles->queue ) ) {
1016
- foreach ( array_diff( $wp_styles->queue, $before_styles_enqueued ) as $handle ) {
1017
- AMP_Validation_Utils::$enqueued_style_sources[ $handle ][] = $callback['source'];
1018
- }
1019
- }
1020
-
1021
- // Keep track of which source enqueued the scripts, and immediately report validity .
1022
- if ( isset( $wp_scripts ) && isset( $wp_scripts->queue ) ) {
1023
- foreach ( array_diff( $wp_scripts->queue, $before_scripts_enqueued ) as $handle ) {
1024
- AMP_Validation_Utils::$enqueued_script_sources[ $handle ][] = $callback['source'];
1025
-
1026
- // Flag all scripts not loaded from the AMP CDN as validation errors.
1027
- if ( isset( $wp_scripts->registered[ $handle ] ) && 0 !== strpos( $wp_scripts->registered[ $handle ]->src, 'https://cdn.ampproject.org/' ) ) {
1028
- self::add_validation_error( array(
1029
- 'code' => self::ENQUEUED_SCRIPT_CODE,
1030
- 'handle' => $handle,
1031
- 'dependency' => $wp_scripts->registered[ $handle ],
1032
- 'sources' => array(
1033
- $callback['source'],
1034
- ),
1035
- ) );
1036
- }
1037
- }
1038
- }
1039
-
1040
- return $result;
1041
- };
1042
- }
1043
-
1044
- /**
1045
- * Wrap output buffer with source comments.
1046
- *
1047
- * A key reason for why this is a method and not a closure is so that
1048
- * the can_output_buffer method will be able to identify it by name.
1049
- *
1050
- * @since 0.7
1051
- * @todo Is duplicate of \AMP_Validation_Utils::decorate_filter_source()?
1052
- *
1053
- * @param string $output Output buffer.
1054
- * @return string Output buffer conditionally wrapped with source comments.
1055
- */
1056
- public static function wrap_buffer_with_source_comments( $output ) {
1057
- if ( empty( self::$hook_source_stack ) ) {
1058
- return $output;
1059
- }
1060
-
1061
- $source = self::$hook_source_stack[ count( self::$hook_source_stack ) - 1 ];
1062
-
1063
- // Wrap output that contains HTML tags (as opposed to actions that trigger in HTML attributes).
1064
- if ( ! empty( $output ) && preg_match( '/<.+?>/s', $output ) ) {
1065
- $output = implode( '', array(
1066
- self::get_source_comment( $source, true ),
1067
- $output,
1068
- self::get_source_comment( $source, false ),
1069
- ) );
1070
- }
1071
- return $output;
1072
- }
1073
-
1074
- /**
1075
- * Output a removed set, each wrapped in <code></code>.
1076
- *
1077
- * @param array[][] $set {
1078
- * The removed elements to output.
1079
- *
1080
- * @type string $name The name of the source.
1081
- * @type string $count The number that were invalid.
1082
- * }
1083
- * @return void
1084
- */
1085
- protected static function output_removed_set( $set ) {
1086
- $items = array();
1087
- foreach ( $set as $name => $count ) {
1088
- if ( 1 === intval( $count ) ) {
1089
- $items[] = sprintf( '<code>%s</code>', esc_html( $name ) );
1090
- } else {
1091
- $items[] = sprintf( '<code>%s</code> (%d)', esc_html( $name ), $count );
1092
- }
1093
- }
1094
- echo implode( ', ', $items ); // WPCS: XSS OK.
1095
- }
1096
-
1097
- /**
1098
- * Whether to validate the front end response.
1099
- *
1100
- * Either the user has the capability and the query var is present.
1101
- *
1102
- * @return boolean Whether to validate.
1103
- */
1104
- public static function should_validate_response() {
1105
- return self::has_cap() && isset( $_GET[ self::VALIDATE_QUERY_VAR ] ); // WPCS: CSRF ok.
1106
- }
1107
-
1108
- /**
1109
- * Finalize validation.
1110
- *
1111
- * @param DOMDocument $dom Document.
1112
- * @param array $args {
1113
- * Args.
1114
- *
1115
- * @type bool $remove_source_comments Whether source comments should be removed. Defaults to true.
1116
- * @type bool $append_validation_status_comment Whether the validation errors should be appended as an HTML comment. Defaults to true.
1117
- * }
1118
- */
1119
- public static function finalize_validation( DOMDocument $dom, $args = array() ) {
1120
- $args = array_merge(
1121
- array(
1122
- 'remove_source_comments' => true,
1123
- 'append_validation_status_comment' => true,
1124
- ),
1125
- $args
1126
- );
1127
-
1128
- if ( $args['remove_source_comments'] ) {
1129
- self::remove_source_comments( $dom );
1130
- }
1131
-
1132
- if ( $args['append_validation_status_comment'] ) {
1133
- $encoded = wp_json_encode( self::$validation_errors, 128 /* JSON_PRETTY_PRINT */ );
1134
- $encoded = str_replace( '--', '\u002d\u002d', $encoded ); // Prevent "--" in strings from breaking out of HTML comments.
1135
- $comment = $dom->createComment( 'AMP_VALIDATION_ERRORS:' . $encoded . "\n" );
1136
- $dom->documentElement->appendChild( $comment );
1137
- }
1138
- }
1139
-
1140
- /**
1141
- * Adds the validation callback if front-end validation is needed.
1142
- *
1143
- * @param array $sanitizers The AMP sanitizers.
1144
- * @return array $sanitizers The filtered AMP sanitizers.
1145
- */
1146
- public static function add_validation_callback( $sanitizers ) {
1147
- foreach ( $sanitizers as $sanitizer => $args ) {
1148
- $sanitizers[ $sanitizer ] = array_merge(
1149
- $args,
1150
- array(
1151
- 'validation_error_callback' => __CLASS__ . '::add_validation_error',
1152
- )
1153
- );
1154
- }
1155
- return $sanitizers;
1156
- }
1157
-
1158
- /**
1159
- * Registers the post type to store the validation errors.
1160
- *
1161
- * @return void.
1162
- */
1163
- public static function register_post_type() {
1164
- $post_type = register_post_type(
1165
- self::POST_TYPE_SLUG,
1166
- array(
1167
- 'labels' => array(
1168
- 'name' => _x( 'Validation Status', 'post type general name', 'amp' ),
1169
- 'singular_name' => __( 'validation error', 'amp' ),
1170
- 'not_found' => __( 'No validation errors found', 'amp' ),
1171
- 'not_found_in_trash' => __( 'No validation errors found in trash', 'amp' ),
1172
- 'search_items' => __( 'Search statuses', 'amp' ),
1173
- 'edit_item' => __( 'Validation Status', 'amp' ),
1174
- ),
1175
- 'supports' => false,
1176
- 'public' => false,
1177
- 'show_ui' => true,
1178
- 'show_in_menu' => AMP_Options_Manager::OPTION_NAME,
1179
- )
1180
- );
1181
-
1182
- // Hide the add new post link.
1183
- $post_type->cap->create_posts = 'do_not_allow';
1184
- }
1185
-
1186
- /**
1187
- * Stores the validation errors.
1188
- *
1189
- * After the preprocessors run, this gets the validation response if the query var is present.
1190
- * It then stores the response in a custom post type.
1191
- * If there's already an error post for the URL, but there's no error anymore, it deletes it.
1192
- *
1193
- * @param array $validation_errors Validation errors.
1194
- * @param string $url URL on which the validation errors occurred.
1195
- * @return int|null $post_id The post ID of the custom post type used, or null.
1196
- * @global WP $wp
1197
- */
1198
- public static function store_validation_errors( $validation_errors, $url ) {
1199
- $post_for_this_url = self::get_validation_status_post( $url );
1200
-
1201
- // Since there are no validation errors and there is an existing $existing_post_id, just delete the post.
1202
- if ( empty( $validation_errors ) ) {
1203
- if ( $post_for_this_url ) {
1204
- wp_delete_post( $post_for_this_url->ID, true );
1205
- }
1206
- return null;
1207
- }
1208
-
1209
- $encoded_errors = wp_json_encode( $validation_errors );
1210
- $post_name = md5( $encoded_errors );
1211
-
1212
- // If the post name is unchanged then the errors are the same and there is nothing to do.
1213
- if ( $post_for_this_url && $post_for_this_url->post_name === $post_name ) {
1214
- return $post_for_this_url->ID;
1215
- }
1216
-
1217
- // If there already exists a post for the given validation errors, just amend the $url to the existing post.
1218
- $post_for_other_url = get_page_by_path( $post_name, OBJECT, self::POST_TYPE_SLUG );
1219
- if ( ! $post_for_other_url ) {
1220
- $post_for_other_url = get_page_by_path( $post_name . '__trashed', OBJECT, self::POST_TYPE_SLUG );
1221
- }
1222
- if ( $post_for_other_url ) {
1223
- if ( 'trash' === $post_for_other_url->post_status ) {
1224
- wp_untrash_post( $post_for_other_url->ID );
1225
- }
1226
- if ( ! in_array( $url, get_post_meta( $post_for_other_url->ID, self::AMP_URL_META, false ), true ) ) {
1227
- add_post_meta( $post_for_other_url->ID, self::AMP_URL_META, wp_slash( $url ), false );
1228
- }
1229
- return $post_for_other_url->ID;
1230
- }
1231
-
1232
- // Otherwise, create a new validation status post, or update the existing one.
1233
- $post_id = wp_insert_post( wp_slash( array(
1234
- 'ID' => $post_for_this_url ? $post_for_this_url->ID : null,
1235
- 'post_type' => self::POST_TYPE_SLUG,
1236
- 'post_title' => $url,
1237
- 'post_name' => $post_name,
1238
- 'post_content' => $encoded_errors,
1239
- 'post_status' => 'publish',
1240
- ) ) );
1241
- if ( ! $post_id ) {
1242
- return null;
1243
- }
1244
- if ( ! in_array( $url, get_post_meta( $post_id, self::AMP_URL_META, false ), true ) ) {
1245
- add_post_meta( $post_id, self::AMP_URL_META, wp_slash( $url ), false );
1246
- }
1247
- return $post_id;
1248
- }
1249
-
1250
- /**
1251
- * Gets the existing custom post that stores errors for the $url, if it exists.
1252
- *
1253
- * @param string $url The URL of the post.
1254
- * @return WP_Post|null The post of the existing custom post, or null.
1255
- */
1256
- public static function get_validation_status_post( $url ) {
1257
- if ( ! post_type_exists( self::POST_TYPE_SLUG ) ) {
1258
- return null;
1259
- }
1260
- $query = new WP_Query( array(
1261
- 'post_type' => self::POST_TYPE_SLUG,
1262
- 'post_status' => 'publish',
1263
- 'posts_per_page' => 1,
1264
- 'meta_query' => array(
1265
- array(
1266
- 'key' => self::AMP_URL_META,
1267
- 'value' => $url,
1268
- ),
1269
- ),
1270
- ) );
1271
- return array_shift( $query->posts );
1272
- }
1273
-
1274
- /**
1275
- * Validates the latest published post.
1276
- *
1277
- * @return array|WP_Error The validation errors, or WP_Error.
1278
- */
1279
- public static function validate_after_plugin_activation() {
1280
- $url = amp_admin_get_preview_permalink();
1281
- if ( ! $url ) {
1282
- return new WP_Error( 'no_published_post_url_available' );
1283
- }
1284
- $validation_errors = self::validate_url( $url );
1285
- if ( is_array( $validation_errors ) && count( $validation_errors ) > 0 ) {
1286
- self::store_validation_errors( $validation_errors, $url );
1287
- set_transient( self::PLUGIN_ACTIVATION_VALIDATION_ERRORS_TRANSIENT_KEY, $validation_errors, 60 );
1288
- } else {
1289
- delete_transient( self::PLUGIN_ACTIVATION_VALIDATION_ERRORS_TRANSIENT_KEY );
1290
- }
1291
- return $validation_errors;
1292
- }
1293
-
1294
- /**
1295
- * Validates a given URL.
1296
- *
1297
- * The validation errors will be stored in the validation status custom post type,
1298
- * as well as in a transient.
1299
- *
1300
- * @param string $url The URL to validate.
1301
- * @return array|WP_Error The validation errors, or WP_Error on error.
1302
- */
1303
- public static function validate_url( $url ) {
1304
- $validation_url = add_query_arg(
1305
- array(
1306
- self::VALIDATE_QUERY_VAR => 1,
1307
- self::CACHE_BUST_QUERY_VAR => wp_rand(),
1308
- ),
1309
- $url
1310
- );
1311
-
1312
- $r = wp_remote_get( $validation_url, array(
1313
- 'cookies' => wp_unslash( $_COOKIE ),
1314
- 'sslverify' => false,
1315
- 'headers' => array(
1316
- 'Cache-Control' => 'no-cache',
1317
- ),
1318
- ) );
1319
- if ( is_wp_error( $r ) ) {
1320
- return $r;
1321
- }
1322
- if ( wp_remote_retrieve_response_code( $r ) >= 400 ) {
1323
- return new WP_Error(
1324
- wp_remote_retrieve_response_code( $r ),
1325
- wp_remote_retrieve_response_message( $r )
1326
- );
1327
- }
1328
- $response = wp_remote_retrieve_body( $r );
1329
- if ( ! preg_match( '#</body>.*?<!--\s*AMP_VALIDATION_ERRORS\s*:\s*(\[.*?\])\s*-->#s', $response, $matches ) ) {
1330
- return new WP_Error( 'response_comment_absent' );
1331
- }
1332
- $validation_errors = json_decode( $matches[1], true );
1333
- if ( ! is_array( $validation_errors ) ) {
1334
- return new WP_Error( 'malformed_json_validation_errors' );
1335
- }
1336
-
1337
- return $validation_errors;
1338
- }
1339
-
1340
- /**
1341
- * On activating a plugin, display a notice if a plugin causes an AMP validation error.
1342
- *
1343
- * @return void
1344
- */
1345
- public static function plugin_notice() {
1346
- global $pagenow;
1347
- if ( ( 'plugins.php' === $pagenow ) && ( ! empty( $_GET['activate'] ) || ! empty( $_GET['activate-multi'] ) ) ) { // WPCS: CSRF ok.
1348
- $validation_errors = get_transient( self::PLUGIN_ACTIVATION_VALIDATION_ERRORS_TRANSIENT_KEY );
1349
- if ( empty( $validation_errors ) || ! is_array( $validation_errors ) ) {
1350
- return;
1351
- }
1352
- delete_transient( self::PLUGIN_ACTIVATION_VALIDATION_ERRORS_TRANSIENT_KEY );
1353
- $errors = self::summarize_validation_errors( $validation_errors );
1354
- $invalid_plugins = isset( $errors[ self::SOURCES_INVALID_OUTPUT ]['plugin'] ) ? array_unique( $errors[ self::SOURCES_INVALID_OUTPUT ]['plugin'] ) : null;
1355
- if ( isset( $invalid_plugins ) ) {
1356
- $reported_plugins = array();
1357
- foreach ( $invalid_plugins as $plugin ) {
1358
- $reported_plugins[] = sprintf( '<code>%s</code>', esc_html( $plugin ) );
1359
- }
1360
-
1361
- $more_details_link = sprintf(
1362
- '<a href="%s">%s</a>',
1363
- esc_url( add_query_arg(
1364
- 'post_type',
1365
- self::POST_TYPE_SLUG,
1366
- admin_url( 'edit.php' )
1367
- ) ),
1368
- __( 'More details', 'amp' )
1369
- );
1370
- printf(
1371
- '<div class="notice notice-warning is-dismissible"><p>%s %s %s</p><button type="button" class="notice-dismiss"><span class="screen-reader-text">%s</span></button></div>',
1372
- esc_html( _n( 'Warning: The following plugin may be incompatible with AMP:', 'Warning: The following plugins may be incompatible with AMP: ', count( $invalid_plugins ), 'amp' ) ),
1373
- implode( ', ', $reported_plugins ),
1374
- $more_details_link,
1375
- esc_html__( 'Dismiss this notice.', 'amp' )
1376
- ); // WPCS: XSS ok.
1377
- }
1378
- }
1379
- }
1380
-
1381
- /**
1382
- * Adds post columns to the UI for the validation errors.
1383
- *
1384
- * @param array $columns The post columns.
1385
- * @return array $columns The new post columns.
1386
- */
1387
- public static function add_post_columns( $columns ) {
1388
- $columns = array_merge(
1389
- $columns,
1390
- array(
1391
- 'url_count' => esc_html__( 'Count', 'amp' ),
1392
- self::REMOVED_ELEMENTS => esc_html__( 'Removed Elements', 'amp' ),
1393
- self::REMOVED_ATTRIBUTES => esc_html__( 'Removed Attributes', 'amp' ),
1394
- self::SOURCES_INVALID_OUTPUT => esc_html__( 'Incompatible Sources', 'amp' ),
1395
- )
1396
- );
1397
-
1398
- // Move date to end.
1399
- if ( isset( $columns['date'] ) ) {
1400
- $date = $columns['date'];
1401
- unset( $columns['date'] );
1402
- $columns['date'] = $date;
1403
- }
1404
-
1405
- return $columns;
1406
- }
1407
-
1408
- /**
1409
- * Outputs custom columns in the /wp-admin UI for the AMP validation errors.
1410
- *
1411
- * @param string $column_name The name of the column.
1412
- * @param int $post_id The ID of the post for the column.
1413
- * @return void
1414
- */
1415
- public static function output_custom_column( $column_name, $post_id ) {
1416
- $post = get_post( $post_id );
1417
- if ( self::POST_TYPE_SLUG !== $post->post_type ) {
1418
- return;
1419
- }
1420
- $validation_errors = json_decode( $post->post_content, true );
1421
- if ( ! is_array( $validation_errors ) ) {
1422
- return;
1423
- }
1424
- $errors = self::summarize_validation_errors( $validation_errors );
1425
- $urls = get_post_meta( $post_id, self::AMP_URL_META, false );
1426
-
1427
- switch ( $column_name ) {
1428
- case 'url_count':
1429
- echo count( $urls );
1430
- break;
1431
- case self::REMOVED_ELEMENTS:
1432
- if ( ! empty( $errors[ self::REMOVED_ELEMENTS ] ) ) {
1433
- self::output_removed_set( $errors[ self::REMOVED_ELEMENTS ] );
1434
- } else {
1435
- esc_html_e( '--', 'amp' );
1436
- }
1437
- break;
1438
- case self::REMOVED_ATTRIBUTES:
1439
- if ( ! empty( $errors[ self::REMOVED_ATTRIBUTES ] ) ) {
1440
- self::output_removed_set( $errors[ self::REMOVED_ATTRIBUTES ] );
1441
- } else {
1442
- esc_html_e( '--', 'amp' );
1443
- }
1444
- break;
1445
- case self::SOURCES_INVALID_OUTPUT:
1446
- if ( isset( $errors[ self::SOURCES_INVALID_OUTPUT ] ) ) {
1447
- $sources = array();
1448
- foreach ( $errors[ self::SOURCES_INVALID_OUTPUT ] as $type => $names ) {
1449
- foreach ( array_unique( $names ) as $name ) {
1450
- $sources[] = sprintf( '%s: <code>%s</code>', esc_html( $type ), esc_html( $name ) );
1451
- }
1452
- }
1453
- echo implode( ', ', $sources ); // WPCS: XSS ok.
1454
- }
1455
- break;
1456
- }
1457
- }
1458
-
1459
- /**
1460
- * Adds a 'Recheck' link to the edit.php row actions.
1461
- *
1462
- * The logic to add the new action is mainly copied from WP_Posts_List_Table::handle_row_actions().
1463
- *
1464
- * @param array $actions The actions in the edit.php page.
1465
- * @param WP_Post $post The post for the actions.
1466
- * @return array $actions The filtered actions.
1467
- */
1468
- public static function filter_row_actions( $actions, $post ) {
1469
- if ( self::POST_TYPE_SLUG !== $post->post_type ) {
1470
- return $actions;
1471
- }
1472
-
1473
- $actions['edit'] = sprintf(
1474
- '<a href="%s">%s</a>',
1475
- esc_url( get_edit_post_link( $post ) ),
1476
- esc_html__( 'Details', 'amp' )
1477
- );
1478
- unset( $actions['inline hide-if-no-js'] );
1479
- $url = get_post_meta( $post->ID, self::AMP_URL_META, true );
1480
-
1481
- if ( ! empty( $url ) ) {
1482
- $actions[ self::RECHECK_ACTION ] = self::get_recheck_link( $post, get_edit_post_link( $post->ID, 'raw' ), $url );
1483
- $actions[ self::DEBUG_QUERY_VAR ] = sprintf(
1484
- '<a href="%s" aria-label="%s">%s</a>',
1485
- esc_url( self::get_debug_url( $url ) ),
1486
- esc_attr__( 'Validate URL on frontend but without invalid elements/attributes removed', 'amp' ),
1487
- esc_html__( 'Debug', 'amp' )
1488
- );
1489
- }
1490
-
1491
- return $actions;
1492
- }
1493
-
1494
- /**
1495
- * Adds a 'Recheck' bulk action to the edit.php page.
1496
- *
1497
- * @param array $actions The bulk actions in the edit.php page.
1498
- * @return array $actions The filtered bulk actions.
1499
- */
1500
- public static function add_bulk_action( $actions ) {
1501
- unset( $actions['edit'] );
1502
- $actions[ self::RECHECK_ACTION ] = esc_html__( 'Recheck', 'amp' );
1503
- return $actions;
1504
- }
1505
-
1506
- /**
1507
- * Handles the 'Recheck' bulk action on the edit.php page.
1508
- *
1509
- * @param string $redirect The URL of the redirect.
1510
- * @param string $action The action.
1511
- * @param array $items The items on which to take the action.
1512
- * @return string $redirect The filtered URL of the redirect.
1513
- */
1514
- public static function handle_bulk_action( $redirect, $action, $items ) {
1515
- if ( self::RECHECK_ACTION !== $action ) {
1516
- return $redirect;
1517
- }
1518
- $remaining_invalid_urls = array();
1519
- foreach ( $items as $item ) {
1520
- $url = get_post_meta( $item, self::AMP_URL_META, true );
1521
- if ( empty( $url ) ) {
1522
- continue;
1523
- }
1524
-
1525
- $validation_errors = self::validate_url( $url );
1526
- if ( ! is_array( $validation_errors ) ) {
1527
- continue;
1528
- }
1529
-
1530
- self::store_validation_errors( $validation_errors, $url );
1531
- if ( ! empty( $validation_errors ) ) {
1532
- $remaining_invalid_urls[] = $url;
1533
- }
1534
- }
1535
-
1536
- // Get the URLs that still have errors after rechecking.
1537
- $args = array(
1538
- self::URLS_TESTED => count( $items ),
1539
- self::REMAINING_ERRORS => empty( $remaining_invalid_urls ) ? '0' : '1',
1540
- );
1541
-
1542
- return add_query_arg( $args, $redirect );
1543
- }
1544
-
1545
- /**
1546
- * Outputs an admin notice after rechecking URL(s) on the custom post page.
1547
- *
1548
- * @return void
1549
- */
1550
- public static function remaining_error_notice() {
1551
- if ( ! isset( $_GET[ self::REMAINING_ERRORS ] ) || self::POST_TYPE_SLUG !== get_current_screen()->post_type ) { // WPCS: CSRF ok.
1552
- return;
1553
- }
1554
-
1555
- $count_urls_tested = isset( $_GET[ self::URLS_TESTED ] ) ? intval( $_GET[ self::URLS_TESTED ] ) : 1; // WPCS: CSRF ok.
1556
- $errors_remain = ! empty( $_GET[ self::REMAINING_ERRORS ] ); // WPCS: CSRF ok.
1557
- if ( $errors_remain ) {
1558
- $class = 'notice-warning';
1559
- $message = _n( 'The rechecked URL still has validation errors.', 'The rechecked URLs still have validation errors.', $count_urls_tested, 'amp' );
1560
- } else {
1561
- $message = _n( 'The rechecked URL has no validation errors.', 'The rechecked URLs have no validation errors.', $count_urls_tested, 'amp' );
1562
- $class = 'updated';
1563
- }
1564
-
1565
- printf(
1566
- '<div class="notice is-dismissible %s"><p>%s</p><button type="button" class="notice-dismiss"><span class="screen-reader-text">%s</span></button></div>',
1567
- esc_attr( $class ),
1568
- esc_html( $message ),
1569
- esc_html__( 'Dismiss this notice.', 'amp' )
1570
- );
1571
- }
1572
-
1573
- /**
1574
- * Handles clicking 'recheck' on the inline post actions.
1575
- *
1576
- * @param int $post_id The post ID of the recheck.
1577
- * @return void
1578
- */
1579
- public static function handle_inline_recheck( $post_id ) {
1580
- check_admin_referer( self::NONCE_ACTION . $post_id );
1581
- $url = get_post_meta( $post_id, self::AMP_URL_META, true );
1582
- if ( isset( $_GET['recheck_url'] ) ) {
1583
- $url = wp_validate_redirect( wp_unslash( $_GET['recheck_url'] ) );
1584
- }
1585
- $validation_errors = self::validate_url( $url );
1586
- $remaining_errors = true;
1587
- if ( is_array( $validation_errors ) ) {
1588
- self::store_validation_errors( $validation_errors, $url );
1589
- $remaining_errors = ! empty( $validation_errors );
1590
- }
1591
-
1592
- $redirect = wp_get_referer();
1593
- if ( ! $redirect || empty( $validation_errors ) ) {
1594
- // If there are no remaining errors and the post was deleted, redirect to edit.php instead of post.php.
1595
- $redirect = add_query_arg(
1596
- 'post_type',
1597
- self::POST_TYPE_SLUG,
1598
- admin_url( 'edit.php' )
1599
- );
1600
- }
1601
- $args = array(
1602
- self::URLS_TESTED => '1',
1603
- self::REMAINING_ERRORS => $remaining_errors ? '1' : '0',
1604
- );
1605
- wp_safe_redirect( add_query_arg( $args, $redirect ) );
1606
- exit();
1607
- }
1608
-
1609
- /**
1610
- * Removes the 'Publish' meta box from the CPT post.php page.
1611
- *
1612
- * @return void
1613
- */
1614
- public static function remove_publish_meta_box() {
1615
- remove_meta_box( 'submitdiv', self::POST_TYPE_SLUG, 'side' );
1616
- }
1617
-
1618
- /**
1619
- * Adds the meta boxes to the CPT post.php page.
1620
- *
1621
- * @return void
1622
- */
1623
- public static function add_meta_boxes() {
1624
- add_meta_box( self::VALIDATION_ERRORS_META_BOX, __( 'Validation Errors', 'amp' ), array( __CLASS__, 'print_validation_errors_meta_box' ), self::POST_TYPE_SLUG, 'normal' );
1625
- add_meta_box( self::STATUS_META_BOX, __( 'Status', 'amp' ), array( __CLASS__, 'print_status_meta_box' ), self::POST_TYPE_SLUG, 'side' );
1626
- }
1627
-
1628
- /**
1629
- * Outputs the markup of the side meta box in the CPT post.php page.
1630
- *
1631
- * This is partially copied from meta-boxes.php.
1632
- * Adds 'Published on,' and links to move to trash and recheck.
1633
- *
1634
- * @param WP_Post $post The post for which to output the box.
1635
- * @return void
1636
- */
1637
- public static function print_status_meta_box( $post ) {
1638
- $redirect_url = add_query_arg(
1639
- 'post',
1640
- $post->ID,
1641
- admin_url( 'post.php' )
1642
- );
1643
-
1644
- echo '<div id="submitpost" class="submitbox">';
1645
- /* translators: Meta box date format */
1646
- $date_format = __( 'M j, Y @ H:i', 'default' );
1647
- echo '<div class="curtime misc-pub-section"><span id="timestamp">';
1648
- /* translators: %s: The date this was published */
1649
- printf( __( 'Published on: <b>%s</b>', 'amp' ), esc_html( date_i18n( $date_format, strtotime( $post->post_date ) ) ) ); // WPCS: XSS ok.
1650
- echo '</span></div>';
1651
- printf( '<div class="misc-pub-section"><a class="submitdelete deletion" href="%s">%s</a></div>', esc_url( get_delete_post_link( $post->ID ) ), esc_html__( 'Move to Trash', 'default' ) );
1652
-
1653
- echo '<div class="misc-pub-section">';
1654
- echo self::get_recheck_link( $post, $redirect_url ); // WPCS: XSS ok.
1655
- $url = get_post_meta( $post->ID, self::AMP_URL_META, true );
1656
- if ( $url ) {
1657
- printf(
1658
- ' | <a href="%s" aria-label="%s">%s</a>',
1659
- esc_url( self::get_debug_url( $url ) ),
1660
- esc_attr__( 'Validate URL on frontend but without invalid elements/attributes removed', 'amp' ),
1661
- esc_html__( 'Debug', 'amp' )
1662
- ); // WPCS: XSS ok.
1663
- }
1664
- echo '</div>';
1665
-
1666
- echo '</div><!-- /submitpost -->';
1667
- }
1668
-
1669
- /**
1670
- * Outputs the full meta box on the CPT post.php page.
1671
- *
1672
- * This displays the errors stored in the post content.
1673
- * These are output as stored, but using <details> elements.
1674
- *
1675
- * @param WP_Post $post The post for which to output the box.
1676
- * @return void
1677
- */
1678
- public static function print_validation_errors_meta_box( $post ) {
1679
- $errors = json_decode( $post->post_content, true );
1680
- $urls = get_post_meta( $post->ID, self::AMP_URL_META, false );
1681
- ?>
1682
- <style>
1683
- .amp-validation-errors .detailed {
1684
- margin-left: 30px;
1685
- }
1686
- .amp-validation-errors .amp-recheck {
1687
- float: right;
1688
- }
1689
- </style>
1690
- <div class="amp-validation-errors">
1691
- <ul>
1692
- <?php foreach ( $errors as $error ) : ?>
1693
- <?php
1694
- $collasped_details = array();
1695
- ?>
1696
- <li>
1697
- <details open>
1698
- <summary><code><?php echo esc_html( $error['code'] ); ?></code></summary>
1699
- <ul class="detailed">
1700
- <?php if ( self::INVALID_ELEMENT_CODE === $error['code'] ) : ?>
1701
- <li>
1702
- <details open>
1703
- <summary><?php esc_html_e( 'Removed:', 'amp' ); ?></summary>
1704
- <code class="detailed">
1705
- <?php
1706
- if ( isset( $error['parent_name'] ) ) {
1707
- echo esc_html( sprintf( '<%s …>', $error['parent_name'] ) );
1708
- }
1709
- ?>
1710
- <mark>
1711
- <?php
1712
- echo esc_html( sprintf( '<%s', $error['node_name'] ) );
1713
- if ( isset( $error['node_attributes'] ) ) {
1714
- foreach ( $error['node_attributes'] as $key => $value ) {
1715
- printf( ' %s="%s"', esc_html( $key ), esc_html( $value ) );
1716
- }
1717
- }
1718
- echo esc_html( '>…' );
1719
- ?>
1720
- </mark>
1721
- </code>
1722
- </details>
1723
- <?php
1724
- $collasped_details[] = 'node_attributes';
1725
- $collasped_details[] = 'node_name';
1726
- $collasped_details[] = 'parent_name';
1727
- ?>
1728
- </li>
1729
- <?php elseif ( self::INVALID_ATTRIBUTE_CODE === $error['code'] ) : ?>
1730
- <li>
1731
- <details open>
1732
- <summary><?php esc_html_e( 'Removed:', 'amp' ); ?></summary>
1733
- <code class="detailed">
1734
- <?php
1735
- if ( isset( $error['parent_name'] ) ) {
1736
- echo esc_html( sprintf( '<%s', $error['parent_name'] ) );
1737
- }
1738
- foreach ( $error['element_attributes'] as $key => $value ) {
1739
- if ( $key === $error['node_name'] ) {
1740
- echo '<mark>';
1741
- }
1742
- printf( ' %s="%s"', esc_html( $key ), esc_html( $value ) );
1743
- if ( $key === $error['node_name'] ) {
1744
- echo '</mark>';
1745
- }
1746
- }
1747
- echo esc_html( '>' );
1748
- ?>
1749
- </code>
1750
- </details>
1751
- <?php
1752
- $collasped_details[] = 'parent_name';
1753
- $collasped_details[] = 'element_attributes';
1754
- $collasped_details[] = 'node_name';
1755
- ?>
1756
- </li>
1757
- <?php endif; ?>
1758
- <?php unset( $error['code'] ); ?>
1759
- <?php foreach ( $error as $key => $value ) : ?>
1760
- <li>
1761
- <details <?php echo ! in_array( $key, $collasped_details, true ) ? 'open' : ''; ?>>
1762
- <summary><code><?php echo esc_html( $key ); ?></code></summary>
1763
- <div class="detailed">
1764
- <?php if ( is_string( $value ) ) : ?>
1765
- <?php echo esc_html( $value ); ?>
1766
- <?php else : ?>
1767
- <pre><?php echo esc_html( wp_json_encode( $value, 128 /* JSON_PRETTY_PRINT */ | 64 /* JSON_UNESCAPED_SLASHES */ ) ); ?></pre>
1768
- <?php endif; ?>
1769
- </div>
1770
- </details>
1771
- </li>
1772
- <?php endforeach; ?>
1773
- </ul>
1774
- </details>
1775
- </li>
1776
- <?php endforeach; ?>
1777
- </ul>
1778
- <hr>
1779
- <h3><?php esc_html_e( 'URLs', 'amp' ); ?></h3>
1780
- <ul>
1781
- <?php foreach ( $urls as $url ) : ?>
1782
- <li>
1783
- <a href="<?php echo esc_url( $url ); ?>"><?php echo esc_url( $url ); ?></a>
1784
- <span class="amp-recheck">
1785
- <?php echo self::get_recheck_link( $post, get_edit_post_link( $post->ID, 'raw' ), $url ); // WPCS: XSS ok. ?>
1786
- |
1787
- <?php
1788
- printf(
1789
- '<a href="%s" aria-label="%s">%s</a>',
1790
- esc_url( self::get_debug_url( $url ) ),
1791
- esc_attr__( 'Validate URL on frontend but without invalid elements/attributes removed', 'amp' ),
1792
- esc_html__( 'Debug', 'amp' )
1793
- )
1794
- ?>
1795
- </span>
1796
- </li>
1797
- <?php endforeach; ?>
1798
- </ul>
1799
- </div>
1800
- <?php
1801
- }
1802
-
1803
- /**
1804
- * Get validation debug UR:.
1805
- *
1806
- * @param string $url URL to to validate and debug.
1807
- * @return string Debug URL.
1808
- */
1809
- public static function get_debug_url( $url ) {
1810
- return add_query_arg(
1811
- array(
1812
- self::VALIDATE_QUERY_VAR => 1,
1813
- self::DEBUG_QUERY_VAR => 1,
1814
- ),
1815
- $url
1816
- ) . '#development=1';
1817
- }
1818
-
1819
- /**
1820
- * Gets the link to recheck the post for AMP validity.
1821
- *
1822
- * Appends a query var to $redirect_url.
1823
- * On clicking the link, it checks if errors still exist for $post.
1824
- *
1825
- * @param WP_Post $post The post storing the validation error.
1826
- * @param string $redirect_url The URL of the redirect.
1827
- * @param string $recheck_url The URL to check. Optional.
1828
- * @return string $link The link to recheck the post.
1829
- */
1830
- public static function get_recheck_link( $post, $redirect_url, $recheck_url = null ) {
1831
- return sprintf(
1832
- '<a href="%s" aria-label="%s">%s</a>',
1833
- wp_nonce_url(
1834
- add_query_arg(
1835
- array(
1836
- 'action' => self::RECHECK_ACTION,
1837
- 'recheck_url' => $recheck_url,
1838
- ),
1839
- $redirect_url
1840
- ),
1841
- self::NONCE_ACTION . $post->ID
1842
- ),
1843
- esc_html__( 'Recheck the URL for AMP validity', 'amp' ),
1844
- esc_html__( 'Recheck', 'amp' )
1845
- );
1846
- }
1847
-
1848
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/widgets/class-amp-widget-archives.php DELETED
@@ -1,103 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Widget_Archives
4
- *
5
- * @since 0.7.0
6
- * @package AMP
7
- */
8
-
9
- /**
10
- * Class AMP_Widget_Archives
11
- *
12
- * @since 0.7.0
13
- * @package AMP
14
- */
15
- class AMP_Widget_Archives extends WP_Widget_Archives {
16
-
17
- /**
18
- * Echoes the markup of the widget.
19
- *
20
- * Mainly copied from WP_Widget_Archives::widget()
21
- * Changes include:
22
- * An id for the <form>.
23
- * More escaping.
24
- * The dropdown is now filtered with 'wp_dropdown_cats.'
25
- * This enables adding an 'on' attribute, with the id of the form.
26
- * So changing the dropdown value will redirect to the category page, with valid AMP.
27
- *
28
- * @since 0.7.0
29
- *
30
- * @param array $args Widget display data.
31
- * @param array $instance Data for widget.
32
- * @return void.
33
- */
34
- public function widget( $args, $instance ) {
35
- if ( ! is_amp_endpoint() ) {
36
- parent::widget( $args, $instance );
37
- return;
38
- }
39
-
40
- $c = ! empty( $instance['count'] ) ? '1' : '0';
41
- $d = ! empty( $instance['dropdown'] ) ? '1' : '0';
42
-
43
- /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
44
- $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? __( 'Archives', 'default' ) : $instance['title'], $instance, $this->id_base );
45
- echo wp_kses_post( $args['before_widget'] );
46
- if ( $title ) :
47
- echo wp_kses_post( $args['before_title'] . $title . $args['after_title'] );
48
- endif;
49
-
50
- if ( $d ) :
51
- $dropdown_id = "{$this->id_base}-dropdown-{$this->number}";
52
- ?>
53
- <form action="<?php echo esc_url( home_url() ); ?>" method="get" target="_top">
54
- <label class="screen-reader-text" for="<?php echo esc_attr( $dropdown_id ); ?>"><?php echo esc_html( $title ); ?></label>
55
- <select id="<?php echo esc_attr( $dropdown_id ); ?>" name="archive-dropdown" on="change:AMP.navigateTo(url=event.value)">
56
- <?php
57
-
58
- /** This filter is documented in wp-includes/widgets/class-wp-widget-archives.php */
59
- $dropdown_args = apply_filters( 'widget_archives_dropdown_args', array(
60
- 'type' => 'monthly',
61
- 'format' => 'option',
62
- 'show_post_count' => $c,
63
- ) );
64
-
65
- switch ( $dropdown_args['type'] ) {
66
- case 'yearly':
67
- $label = __( 'Select Year', 'default' );
68
- break;
69
- case 'monthly':
70
- $label = __( 'Select Month', 'default' );
71
- break;
72
- case 'daily':
73
- $label = __( 'Select Day', 'default' );
74
- break;
75
- case 'weekly':
76
- $label = __( 'Select Week', 'default' );
77
- break;
78
- default:
79
- $label = __( 'Select Post', 'default' );
80
- break;
81
- }
82
- ?>
83
- <option value=""><?php echo esc_attr( $label ); ?></option>
84
- <?php wp_get_archives( $dropdown_args ); ?>
85
- </select>
86
- </form>
87
- <?php else : ?>
88
- <ul>
89
- <?php
90
-
91
- /** This filter is documented in wp-includes/widgets/class-wp-widget-archives.php */
92
- wp_get_archives( apply_filters( 'widget_archives_args', array(
93
- 'type' => 'monthly',
94
- 'show_post_count' => $c,
95
- ) ) );
96
- ?>
97
- </ul>
98
- <?php
99
- endif;
100
- echo wp_kses_post( $args['after_widget'] );
101
- }
102
-
103
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/widgets/class-amp-widget-categories.php DELETED
@@ -1,91 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Widget_Categories
4
- *
5
- * @since 0.7.0
6
- * @package AMP
7
- */
8
-
9
- /**
10
- * Class AMP_Widget_Categories
11
- *
12
- * @since 0.7.0
13
- * @package AMP
14
- */
15
- class AMP_Widget_Categories extends WP_Widget_Categories {
16
-
17
- /**
18
- * Echoes the markup of the widget.
19
- *
20
- * Mainly copied from WP_Widget_Categories::widget()
21
- * There's now an id for the <form>.
22
- * And the dropdown is now filtered with 'wp_dropdown_cats.'
23
- * This enables adding an 'on' attribute, with the id of the form.
24
- * So changing the dropdown value will redirect to the category page, with valid AMP.
25
- *
26
- * @since 0.7.0
27
- *
28
- * @param array $args Widget display data.
29
- * @param array $instance Data for widget.
30
- * @return void
31
- */
32
- public function widget( $args, $instance ) {
33
- if ( ! is_amp_endpoint() ) {
34
- parent::widget( $args, $instance );
35
- return;
36
- }
37
-
38
- static $first_dropdown = true;
39
- $title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Categories', 'default' );
40
- /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
41
- $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
42
- $c = ! empty( $instance['count'] ) ? '1' : '0';
43
- $h = ! empty( $instance['hierarchical'] ) ? '1' : '0';
44
- $d = ! empty( $instance['dropdown'] ) ? '1' : '0';
45
- echo wp_kses_post( $args['before_widget'] );
46
- if ( $title ) {
47
- echo wp_kses_post( $args['before_title'] . $title . $args['after_title'] );
48
- }
49
- $cat_args = array(
50
- 'orderby' => 'name',
51
- 'show_count' => $c,
52
- 'hierarchical' => $h,
53
- );
54
- if ( $d ) :
55
- $form_id = sprintf( 'widget-categories-dropdown-%d', $this->number );
56
- printf( '<form action="%s" method="get" target="_top" id="%s">', esc_url( home_url() ), esc_attr( $form_id ) );
57
- $dropdown_id = ( $first_dropdown ) ? 'cat' : "{$this->id_base}-dropdown-{$this->number}";
58
- $first_dropdown = false;
59
- echo '<label class="screen-reader-text" for="' . esc_attr( $dropdown_id ) . '">' . esc_html( $title ) . '</label>';
60
- $cat_args['show_option_none'] = __( 'Select Category', 'default' );
61
- $cat_args['id'] = $dropdown_id;
62
-
63
- $dropdown = wp_dropdown_categories( array_merge(
64
- /** This filter is documented in wp-includes/widgets/class-wp-widget-categories.php */
65
- apply_filters( 'widget_categories_dropdown_args', $cat_args, $instance ),
66
- array( 'echo' => false )
67
- ) );
68
- $dropdown = preg_replace(
69
- '/(?<=<select\b)/',
70
- sprintf( '<select on="change:%s.submit"', esc_attr( $form_id ) ),
71
- $dropdown,
72
- 1
73
- );
74
- echo $dropdown; // WPCS: XSS OK.
75
- echo '</form>';
76
- else :
77
- ?>
78
- <ul>
79
- <?php
80
- $cat_args['title_li'] = '';
81
-
82
- /** This filter is documented in wp-includes/widgets/class-wp-widget-categories.php */
83
- wp_list_categories( apply_filters( 'widget_categories_args', $cat_args, $instance ) );
84
- ?>
85
- </ul>
86
- <?php
87
- endif;
88
- echo wp_kses_post( $args['after_widget'] );
89
- }
90
-
91
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/widgets/class-amp-widget-media-video.php DELETED
@@ -1,33 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Widget_Media_Video
4
- *
5
- * @since 0.7.0
6
- * @package AMP
7
- */
8
-
9
- if ( class_exists( 'WP_Widget_Media_Video' ) ) {
10
- /**
11
- * Class AMP_Widget_Media_Video
12
- *
13
- * @since 0.7.0
14
- * @package AMP
15
- */
16
- class AMP_Widget_Media_Video extends WP_Widget_Media_Video {
17
-
18
- /**
19
- * Overrides the parent callback that strips width and height values.
20
- *
21
- * @param string $html Video shortcode HTML output.
22
- * @return string HTML Output.
23
- */
24
- public function inject_video_max_width_style( $html ) {
25
- if ( is_amp_endpoint() ) {
26
- return $html;
27
- }
28
- return parent::inject_video_max_width_style( $html );
29
- }
30
-
31
- }
32
-
33
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/widgets/class-amp-widget-recent-comments.php DELETED
@@ -1,38 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Widget_Recent_Comments
4
- *
5
- * @since 0.7.0
6
- * @package AMP
7
- */
8
-
9
- /**
10
- * Class AMP_Widget_Recent_Comments
11
- *
12
- * @since 0.7.0
13
- * @package AMP
14
- */
15
- class AMP_Widget_Recent_Comments extends WP_Widget_Recent_Comments {
16
-
17
- /**
18
- * Instantiates the widget, and prevents inline styling.
19
- *
20
- * @since 0.7.0
21
- */
22
- public function __construct() {
23
- parent::__construct();
24
- add_filter( 'wp_head', array( $this, 'remove_head_style_in_amp' ), 0 );
25
- }
26
-
27
- /**
28
- * Prevent recent comments widget style from printing in AMP,
29
- *
30
- * @since 0.7.0
31
- */
32
- public function remove_head_style_in_amp() {
33
- if ( is_amp_endpoint() ) {
34
- add_filter( 'show_recent_comments_widget_style', '__return_false' );
35
- }
36
- }
37
-
38
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/includes/widgets/class-amp-widget-text.php DELETED
@@ -1,33 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Widget_Text
4
- *
5
- * @since 0.7.0
6
- * @package AMP
7
- */
8
-
9
- if ( class_exists( 'WP_Widget_Text' ) ) {
10
- /**
11
- * Class AMP_Widget_Text
12
- *
13
- * @since 0.7.0
14
- * @package AMP
15
- */
16
- class AMP_Widget_Text extends WP_Widget_Text {
17
-
18
- /**
19
- * Overrides the parent callback that strips width and height attributes.
20
- *
21
- * @param array $matches The matches returned from preg_replace_callback().
22
- * @return string $html The markup, unaltered.
23
- */
24
- public function inject_video_max_width_style( $matches ) {
25
- if ( is_amp_endpoint() ) {
26
- return $matches[0];
27
- }
28
- return parent::inject_video_max_width_style( $matches );
29
- }
30
-
31
- }
32
-
33
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/templates/admin/amp-status.php DELETED
@@ -1,71 +0,0 @@
1
- <?php
2
- /**
3
- * AMP status option in the submit meta box.
4
- *
5
- * @package AMP
6
- */
7
-
8
- // Check referrer.
9
- if ( ! ( $this instanceof AMP_Post_Meta_Box ) ) {
10
- return;
11
- }
12
-
13
- /**
14
- * Inherited template vars.
15
- *
16
- * @var array $labels Labels for enabled or disabled.
17
- * @var string $status Enabled or disabled.
18
- * @var array $errors Support errors.
19
- */
20
- ?>
21
- <div class="misc-pub-section misc-amp-status">
22
- <span class="amp-icon"></span>
23
- <?php esc_html_e( 'AMP:', 'amp' ); ?>
24
- <strong class="amp-status-text"><?php echo esc_html( $labels[ $status ] ); ?></strong>
25
- <a href="#amp_status" class="edit-amp-status hide-if-no-js" role="button">
26
- <span aria-hidden="true"><?php esc_html_e( 'Edit', 'amp' ); ?></span>
27
- <span class="screen-reader-text"><?php esc_html_e( 'Edit Status', 'amp' ); ?></span>
28
- </a>
29
- <div id="amp-status-select" class="hide-if-js" data-amp-status="<?php echo esc_attr( $status ); ?>">
30
- <?php if ( empty( $errors ) ) : ?>
31
- <fieldset>
32
- <input id="amp-status-enabled" type="radio" name="<?php echo esc_attr( self::STATUS_INPUT_NAME ); ?>" value="<?php echo esc_attr( self::ENABLED_STATUS ); ?>" <?php checked( self::ENABLED_STATUS, $status ); ?>>
33
- <label for="amp-status-enabled" class="selectit"><?php echo esc_html( $labels['enabled'] ); ?></label>
34
- <br />
35
- <input id="amp-status-disabled" type="radio" name="<?php echo esc_attr( self::STATUS_INPUT_NAME ); ?>" value="<?php echo esc_attr( self::DISABLED_STATUS ); ?>" <?php checked( self::DISABLED_STATUS, $status ); ?>>
36
- <label for="amp-status-disabled" class="selectit"><?php echo esc_html( $labels['disabled'] ); ?></label>
37
- <br />
38
- <?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_NAME ); ?>
39
- </fieldset>
40
- <?php else : ?>
41
- <div class="inline notice notice-warning notice-alt">
42
- <p>
43
- <?php
44
- $support_errors_codes = AMP_Post_Type_Support::get_support_errors( $post );
45
- $support_errors = array();
46
- if ( in_array( 'password-protected', $support_errors_codes, true ) ) {
47
- $support_errors[] = __( 'AMP cannot be enabled on password protected posts.', 'amp' );
48
- }
49
- if ( in_array( 'post-type-support', $support_errors_codes, true ) ) {
50
- /* translators: %s is URL to AMP settings screen */
51
- $support_errors[] = wp_kses_post( sprintf( __( 'AMP cannot be enabled because this <a href="%s">post type does not support it</a>.', 'amp' ), admin_url( 'admin.php?page=amp-options' ) ) );
52
- }
53
- if ( in_array( 'skip-post', $support_errors_codes, true ) ) {
54
- $support_errors[] = __( 'A plugin or theme has disabled AMP support.', 'amp' );
55
- }
56
- if ( count( array_diff( $support_errors_codes, array( 'page-on-front', 'page-for-posts', 'password-protected', 'post-type-support', 'skip-post' ) ) ) > 0 ) {
57
- $support_errors[] = __( 'Unavailable for an unknown reason.', 'amp' );
58
- }
59
- echo implode( ' ', $support_errors ); // WPCS: xss ok.
60
- ?>
61
- </p>
62
- </div>
63
- <?php endif; ?>
64
- <div class="amp-status-actions">
65
- <?php if ( empty( $errors ) ) : ?>
66
- <a href="#amp_status" class="save-amp-status hide-if-no-js button"><?php esc_html_e( 'OK', 'amp' ); ?></a>
67
- <?php endif; ?>
68
- <a href="#amp_status" class="cancel-amp-status hide-if-no-js button-cancel"><?php esc_html_e( 'Cancel', 'amp' ); ?></a>
69
- </div>
70
- </div>
71
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/templates/header.php DELETED
@@ -1,14 +0,0 @@
1
- <?php
2
- /**
3
- * Header template part.
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Context.
10
- *
11
- * @var AMP_Post_Template $this
12
- */
13
-
14
- $this->load_parts( array( 'header-bar' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/templates/html-end.php DELETED
@@ -1,18 +0,0 @@
1
- <?php
2
- /**
3
- * HTML end template part.
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Context.
10
- *
11
- * @var AMP_Post_Template $this
12
- */
13
- ?>
14
-
15
- <?php do_action( 'amp_post_template_footer', $this ); ?>
16
-
17
- </body>
18
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/templates/html-start.php DELETED
@@ -1,26 +0,0 @@
1
- <?php
2
- /**
3
- * HTML start template part.
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Context.
10
- *
11
- * @var AMP_Post_Template $this
12
- */
13
- ?>
14
- <!doctype html>
15
- <html amp <?php echo AMP_HTML_Utils::build_attributes_string( $this->get( 'html_tag_attributes' ) ); // WPCS: XSS ok. ?>>
16
- <head>
17
- <meta charset="utf-8">
18
- <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
19
- <?php do_action( 'amp_post_template_head', $this ); ?>
20
- <style amp-custom>
21
- <?php $this->load_parts( array( 'style' ) ); ?>
22
- <?php do_action( 'amp_post_template_css', $this ); ?>
23
- </style>
24
- </head>
25
-
26
- <body class="<?php echo esc_attr( $this->get( 'body_class' ) ); ?>">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/templates/page.php DELETED
@@ -1,34 +0,0 @@
1
- <?php
2
- /**
3
- * Page view template.
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Context.
10
- *
11
- * @var AMP_Post_Template $this
12
- */
13
-
14
- $this->load_parts( array( 'html-start' ) );
15
- ?>
16
-
17
- <?php $this->load_parts( array( 'header' ) ); ?>
18
-
19
- <article class="amp-wp-article">
20
- <header class="amp-wp-article-header">
21
- <h1 class="amp-wp-title"><?php echo esc_html( $this->get( 'post_title' ) ); ?></h1>
22
- </header>
23
-
24
- <?php $this->load_parts( array( 'featured-image' ) ); ?>
25
-
26
- <div class="amp-wp-article-content">
27
- <?php echo $this->get( 'post_amp_content' ); // WPCS: XSS ok. Handled in AMP_Content::transform(). ?>
28
- </div>
29
- </article>
30
-
31
- <?php $this->load_parts( array( 'footer' ) ); ?>
32
-
33
- <?php
34
- $this->load_parts( array( 'html-end' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/wpcom-helper.php DELETED
@@ -1,237 +0,0 @@
1
- <?php
2
- /**
3
- * WPCOM-specific things.
4
- *
5
- * @todo Move this into Jetpack. See https://github.com/Automattic/amp-wp/issues/1021
6
- * @package AMP
7
- */
8
-
9
- add_action( 'pre_amp_render_post', 'jetpack_amp_disable_the_content_filters' );
10
-
11
- // Disable admin menu.
12
- add_filter( 'amp_options_menu_is_enabled', '__return_false', 9999 );
13
-
14
- /**
15
- * Disable the_content filters for Jetpack.
16
- *
17
- * @since 0.3
18
- */
19
- function jetpack_amp_disable_the_content_filters() {
20
- add_filter( 'post_flair_disable', '__return_true', 99 );
21
- add_filter( 'videopress_show_2015_player', '__return_true' );
22
- add_filter( 'protected_embeds_use_form_post', '__return_false' );
23
-
24
- remove_filter( 'the_title', 'widont' );
25
-
26
- remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
27
- remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'maybe_create_links' ), 100 );
28
- }
29
-
30
- add_action( 'amp_post_template_head', 'jetpack_amp_add_og_tags' );
31
-
32
- /**
33
- * Add Open Graph tags.
34
- *
35
- * @since 0.3
36
- */
37
- function jetpack_amp_add_og_tags() {
38
- if ( function_exists( 'jetpack_og_tags' ) ) {
39
- jetpack_og_tags();
40
- }
41
- }
42
-
43
- add_filter( 'amp_post_template_metadata', 'jetpack_amp_post_template_metadata', 10, 2 );
44
-
45
- /**
46
- * Add publisher and image metadata.
47
- *
48
- * @since 0.3
49
- *
50
- * @param array $metadata Metadata array.
51
- * @param WP_Post $post Post.
52
- * @return array Modified metadata array.
53
- */
54
- function jetpack_amp_post_template_metadata( $metadata, $post ) {
55
- if ( isset( $metadata['publisher'] ) && ! isset( $metadata['publisher']['logo'] ) ) {
56
- $metadata = wpcom_amp_add_blavatar_to_metadata( $metadata );
57
- }
58
-
59
- if ( ! isset( $metadata['image'] ) ) {
60
- $metadata = wpcom_amp_add_image_to_metadata( $metadata, $post );
61
- }
62
-
63
- return $metadata;
64
- }
65
-
66
- /**
67
- * Add blavatar to metadata.
68
- *
69
- * @since 0.3
70
- *
71
- * @param array $metadata Metadata.
72
- * @return array Metadata.
73
- */
74
- function wpcom_amp_add_blavatar_to_metadata( $metadata ) {
75
- if ( ! function_exists( 'blavatar_domain' ) ) {
76
- return $metadata;
77
- }
78
-
79
- $size = 60;
80
-
81
- $metadata['publisher']['logo'] = array(
82
- '@type' => 'ImageObject',
83
- 'url' => blavatar_url( blavatar_domain( site_url() ), 'img', $size, staticize_subdomain( 'https://wordpress.com/i/favicons/apple-touch-icon-60x60.png' ) ),
84
- 'width' => $size,
85
- 'height' => $size,
86
- );
87
-
88
- return $metadata;
89
- }
90
-
91
- /**
92
- * Add image to metadata.
93
- *
94
- * @since 0.3.2
95
- *
96
- * @param array $metadata Metadata.
97
- * @param WP_Post $post Post.
98
- * @return array Metadata.
99
- */
100
- function wpcom_amp_add_image_to_metadata( $metadata, $post ) {
101
- if ( ! class_exists( 'Jetpack_PostImages' ) ) {
102
- return wpcom_amp_add_fallback_image_to_metadata( $metadata );
103
- }
104
-
105
- $image = Jetpack_PostImages::get_image( $post->ID, array(
106
- 'fallback_to_avatars' => true,
107
- 'avatar_size' => 200,
108
- // AMP already attempts these.
109
- 'from_thumbnail' => false,
110
- 'from_attachment' => false,
111
- ) );
112
-
113
- if ( empty( $image ) ) {
114
- return wpcom_amp_add_fallback_image_to_metadata( $metadata );
115
- }
116
-
117
- if ( ! isset( $image['src_width'] ) ) {
118
- $dimensions = wpcom_amp_extract_image_dimensions_from_getimagesize( array(
119
- $image['src'] => false,
120
- ) );
121
-
122
- if ( false !== $dimensions[ $image['src'] ] ) {
123
- $image['src_width'] = $dimensions['width'];
124
- $image['src_height'] = $dimensions['height'];
125
- }
126
- }
127
-
128
- $metadata['image'] = array(
129
- '@type' => 'ImageObject',
130
- 'url' => $image['src'],
131
- 'width' => $image['src_width'],
132
- 'height' => $image['src_height'],
133
- );
134
-
135
- return $metadata;
136
- }
137
-
138
- /**
139
- * Add fallback image to metadata.
140
- *
141
- * @since 0.3.2
142
- *
143
- * @param array $metadata Metadata.
144
- * @return array Metadata.
145
- */
146
- function wpcom_amp_add_fallback_image_to_metadata( $metadata ) {
147
- $metadata['image'] = array(
148
- '@type' => 'ImageObject',
149
- 'url' => staticize_subdomain( 'https://wordpress.com/i/blank.jpg' ),
150
- 'width' => 200,
151
- 'height' => 200,
152
- );
153
-
154
- return $metadata;
155
- }
156
-
157
- add_action( 'amp_extract_image_dimensions_batch_callbacks_registered', 'wpcom_amp_extract_image_dimensions_batch_add_custom_callbacks' );
158
-
159
- /**
160
- * Add hooks to extract image dimensions.
161
- *
162
- * @since 0.5
163
- */
164
- function wpcom_amp_extract_image_dimensions_batch_add_custom_callbacks() {
165
- // If images are being served from Photon or WP.com files, try extracting the size using querystring.
166
- add_action( 'amp_extract_image_dimensions_batch', 'wpcom_amp_extract_image_dimensions_from_querystring', 9, 1 ); // Hook in before the default extractors.
167
-
168
- // Uses a special wpcom lib (wpcom_getimagesize) to extract dimensions as a last resort if we weren't able to figure them out.
169
- add_action( 'amp_extract_image_dimensions_batch', 'wpcom_amp_extract_image_dimensions_from_getimagesize', 99, 1 ); // Our last resort, so run late.
170
-
171
- // The wpcom override obviates this one, so take it out.
172
- remove_filter( 'amp_extract_image_dimensions_batch', array( 'AMP_Image_Dimension_Extractor', 'extract_by_downloading_images' ), 999 );
173
- }
174
-
175
- /**
176
- * Extract image dimensions from query string.
177
- *
178
- * @since 0.5
179
- *
180
- * @param array $dimensions Dimensions.
181
- * @return array Dimensions.
182
- */
183
- function wpcom_amp_extract_image_dimensions_from_querystring( $dimensions ) {
184
- foreach ( $dimensions as $url => $value ) {
185
-
186
- if ( is_array( $value ) ) {
187
- continue;
188
- }
189
-
190
- $host = wp_parse_url( $url, PHP_URL_HOST );
191
- if ( ! wp_endswith( $host, '.wp.com' ) && ! wp_endswith( $host, '.files.wordpress.com' ) ) {
192
- continue;
193
- }
194
-
195
- parse_str( wp_parse_url( $url, PHP_URL_QUERY ), $query );
196
- $w = isset( $query['w'] ) ? absint( $query['w'] ) : false;
197
- $h = isset( $query['h'] ) ? absint( $query['h'] ) : false;
198
-
199
- if ( false !== $w && false !== $h ) {
200
- $dimensions[ $url ] = array(
201
- 'width' => $w,
202
- 'height' => $h,
203
- );
204
- }
205
- }
206
- return $dimensions;
207
- }
208
-
209
- /**
210
- * Extract image dimensions via wpcom/imagesize.
211
- *
212
- * @since 0.5
213
- *
214
- * @param array $dimensions Dimensions.
215
- * @return array Dimensions.
216
- */
217
- function wpcom_amp_extract_image_dimensions_from_getimagesize( $dimensions ) {
218
- if ( ! function_exists( 'require_lib' ) ) {
219
- return $dimensions;
220
- }
221
- require_lib( 'wpcom/imagesize' );
222
-
223
- foreach ( $dimensions as $url => $value ) {
224
- if ( is_array( $value ) ) {
225
- continue;
226
- }
227
- $result = wpcom_getimagesize( $url );
228
- if ( is_array( $result ) ) {
229
- $dimensions[ $url ] = array(
230
- 'width' => $result[0],
231
- 'height' => $result[1],
232
- );
233
- }
234
- }
235
-
236
- return $dimensions;
237
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/wpcom/class-amp-polldaddy-embed.php DELETED
@@ -1,101 +0,0 @@
1
- <?php
2
- /**
3
- * Class WPCOM_AMP_Polldaddy_Embed
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class WPCOM_AMP_Polldaddy_Embed
10
- */
11
- class WPCOM_AMP_Polldaddy_Embed extends AMP_Base_Embed_Handler {
12
-
13
- /**
14
- * Register embed.
15
- */
16
- public function register_embed() {
17
- add_shortcode( 'polldaddy', array( $this, 'shortcode' ) );
18
- add_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10, 3 );
19
- }
20
-
21
- /**
22
- * Unregister embed.
23
- */
24
- public function unregister_embed() {
25
- remove_shortcode( 'polldaddy' );
26
- remove_filter( 'embed_oembed_html', array( $this, 'filter_embed_oembed_html' ), 10 );
27
- }
28
-
29
- /**
30
- * Shortcode.
31
- *
32
- * @param array $attr Shortcode attributes.
33
- * @return string Shortcode.
34
- * @global WP_Embed $wp_embed
35
- */
36
- public function shortcode( $attr ) {
37
- global $wp_embed;
38
-
39
- $output = '';
40
- $url = 'https://polldaddy.com/';
41
- if ( ! empty( $attr['poll'] ) ) {
42
- $url .= 'poll/' . $attr['poll'] . '/';
43
- } elseif ( ! empty( $attr['survey'] ) ) {
44
- $url .= 's/' . $attr['survey'] . '/';
45
- }
46
-
47
- if ( ! empty( $attr['title'] ) ) {
48
- $output = $this->render_link( $url, $attr['title'] );
49
- } elseif ( $url ) {
50
- $output = $wp_embed->shortcode( $attr, $url );
51
- }
52
-
53
- return $output;
54
- }
55
-
56
- /**
57
- * Filter oEmbed HTML for PollDaddy to for AMP output.
58
- *
59
- * @param string $cache Cache for oEmbed.
60
- * @param string $url Embed URL.
61
- * @param array $attr Shortcode attributes.
62
- * @return string Embed.
63
- */
64
- public function filter_embed_oembed_html( $cache, $url, $attr ) {
65
- $parsed_url = wp_parse_url( $url );
66
- if ( false === strpos( $parsed_url['host'], 'polldaddy.com' ) ) {
67
- return $cache;
68
- }
69
-
70
- $output = '';
71
-
72
- // Poll oEmbed responses include noscript.
73
- if ( preg_match( '#<noscript>(.+?)</noscript>#', $cache, $matches ) ) {
74
- $output = $matches[1];
75
- }
76
-
77
- if ( empty( $output ) ) {
78
- if ( ! empty( $attr['title'] ) ) {
79
- $name = $attr['title'];
80
- } elseif ( false !== strpos( $url, 'polldaddy.com/s' ) ) {
81
- $name = __( 'View Survey', 'amp' );
82
- } else {
83
- $name = __( 'View Poll', 'amp' );
84
- }
85
- $output = $this->render_link( $url, $name );
86
- }
87
-
88
- return $output;
89
- }
90
-
91
- /**
92
- * Render poll/survey link.
93
- *
94
- * @param string $url Link URL.
95
- * @param string $title Link Text.
96
- * @return string Link.
97
- */
98
- private function render_link( $url, $title ) {
99
- return sprintf( '<p><a href="' . esc_url( $url ) . '">' . esc_html( $title ) . '</a></p>' );
100
- }
101
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/amp/wpcom/shortcodes.php DELETED
@@ -1,20 +0,0 @@
1
- <?php
2
- /**
3
- * Shortcode functions for WordPress.com.
4
- *
5
- * @package AMP
6
- */
7
-
8
- _deprecated_file( __FILE__, '0.6' );
9
-
10
- /**
11
- * Add custom embeds for WordPress.com.
12
- *
13
- * @deprecated Now PollDaddy is supported in core AMP.
14
- * @param array $embed_handler_classes Embed handler classes.
15
- * @return mixed
16
- */
17
- function wpcom_amp_add_custom_embeds( $embed_handler_classes ) {
18
- _deprecated_function( __FUNCTION__, '0.6' );
19
- return $embed_handler_classes;
20
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/vendor-compatibility.php DELETED
@@ -1,342 +0,0 @@
1
- <?php
2
- add_action('plugins_loaded', function(){
3
- if(!is_admin()){
4
- add_filter("ampforwp_update_autoload_class", 'ampforwp_update_class',10,2);
5
-
6
- add_action("wp",'ampforwp_enable_support_for_otherpages');
7
-
8
- add_filter("ampforwp_content_sanitizers", 'content_sanitizers_remove_blacklist', 999);
9
- add_filter("amp_content_sanitizers", 'content_sanitizers_remove_blacklist', 999);
10
- add_filter('amp_content_embed_handlers', 'ampforwp_modified_embed_handlers');
11
- add_filter( 'amp_post_status_default_enabled', 'ampforwp_post_status' );
12
- add_filter( 'amp_post_template_file', 'ampforwp_custom_template', 10, 3 );
13
- add_filter( 'amp_get_permalink', 'ampforwp_change_end_point' );
14
- add_filter('amp_post_template_data', 'ampforwp_post_template_data');
15
- }
16
- });
17
-
18
- add_action('init','ampforwp_modifying_front_page_query');
19
- function ampforwp_modifying_front_page_query() {
20
- remove_action( 'parse_query', 'amp_correct_query_when_is_front_page',10 );
21
- add_action( 'parse_query', 'ampforwp_correct_query_front_page',15 );
22
- }
23
-
24
- function ampforwp_correct_query_front_page(WP_Query $query){
25
-
26
- if ( start_non_amp_to_amp_conversion()) {
27
- return false;
28
- }
29
- if ( false !== $query->get( amp_get_slug(), false ) ) {
30
- global $redux_builder_amp;
31
- $amp_frontpage_id = $amp_frontpage = '';
32
- if ( isset($redux_builder_amp['amp-frontpage-select-option']) && $redux_builder_amp['amp-frontpage-select-option'] ) {
33
- $amp_frontpage = true;
34
- }
35
- $amp_home_id = 0;
36
- if (ampforwp_is_blog() ) {
37
- $amp_home_id = ampforwp_get_blog_details('id');
38
- }
39
- if ( 'page' === get_option( 'show_on_front' ) ) {
40
- $amp_frontpage_id = get_option( 'page_on_front' );
41
- }
42
- // Frontpage id should be assigned
43
- if ( ampforwp_is_front_page() ) {
44
- $amp_frontpage_id = ampforwp_get_frontpage_id();
45
- }
46
- $is_front_page_query = (
47
- $query->is_main_query()
48
- &&
49
- $query->is_home()
50
- &&
51
- // Is query not yet fixed up to be front page.
52
- ! $query->is_front_page()
53
- &&
54
- // is Homepage support enabeld from options panel
55
- $amp_frontpage
56
- &&
57
- // See line in WP_Query::parse_query() at <https://github.com/WordPress/wordpress-develop/blob/0baa8ae/src/wp-includes/class-wp-query.php#L961>.
58
- 0 === count( array_diff( array_keys( wp_parse_args( $query->query ) ), array( amp_get_slug(), 'preview', 'page', 'paged', 'cpage' ) ) )
59
- );
60
-
61
- if ( $is_front_page_query ) {
62
- $query->is_home = false;
63
- $query->is_page = true;
64
- $query->is_singular = true;
65
- $query->set( 'page_id', $amp_frontpage_id );
66
- }
67
- elseif(ampforwp_is_blog() || ampforwp_is_home() ) {
68
- $query->is_home = true;
69
- $query->set( 'page_id', $amp_home_id );
70
- }
71
-
72
- }
73
- else{
74
- $query->set( 'amp', false );
75
- }
76
- }
77
-
78
- /*
79
- * is_archive() || is_search() Support added after 0.7 vendor amp
80
- */
81
- function ampforwp_enable_support_for_otherpages(){
82
- if ( start_non_amp_to_amp_conversion()) {
83
- return ;
84
- }
85
- global $redux_builder_amp;
86
- $is_amp_endpoint_needed = ampforwp_is_amp_endpoint();
87
- $hide_cats_amp = '';
88
- $hide_cats_amp = is_category_amp_disabled();
89
- $support_for_archives = '';
90
-
91
- if ( isset($redux_builder_amp['ampforwp-amp-convert-to-wp']) && $redux_builder_amp['ampforwp-amp-convert-to-wp'] && ampforwp_is_non_amp() ) {
92
- add_action( 'wp_head', 'ampforwp_home_archive_rel_canonical', 1 );
93
- }
94
- if( (isset($redux_builder_amp['ampforwp-archive-support']) && $redux_builder_amp['ampforwp-archive-support']) && is_archive() ){
95
- $support_for_archives = true;
96
- }
97
- else{
98
- $support_for_archives = false;
99
- }
100
- $amp_frontpage_id = ampforwp_get_frontpage_id();
101
-
102
- if( ( ($support_for_archives && !$hide_cats_amp) || is_search() || is_front_page() || ampforwp_is_blog() || ampforwp_is_home() || is_404() ) && $is_amp_endpoint_needed ){
103
- remove_action( 'template_redirect', 'amp_render' );
104
- if ( is_front_page() && $amp_frontpage_id ) {
105
- $amp_frontpage_post = get_post($amp_frontpage_id);
106
- amp_render_post($amp_frontpage_post);
107
- }
108
- elseif(is_404()){
109
- $fourofour = get_post(2);
110
- amp_render_post($fourofour);
111
- }
112
- else
113
- amp_render_post(0);
114
- exit;
115
- }
116
- }
117
-
118
- // Sanitizers
119
- function content_sanitizers_remove_blacklist($sanitizer_classes){
120
- global $redux_builder_amp;
121
- // Whitelist sanitizer
122
- if(isset($sanitizer_classes['AMP_Blacklist_Sanitizer'])) {
123
- unset($sanitizer_classes['AMP_Blacklist_Sanitizer']);
124
- $sanitizer_classes['AMP_Tag_And_Attribute_Sanitizer']= array();
125
- }
126
- if(isset($sanitizer_classes['AMP_Base_Sanitizer'])) {
127
- unset($sanitizer_classes['AMP_Base_Sanitizer']);
128
- }
129
- // New image sanitizer For Lightbox and FooGallery support
130
- if( isset( $sanitizer_classes['AMP_Img_Sanitizer']) ) {
131
- require_once( AMPFORWP_PLUGIN_DIR. 'classes/class-ampforwp-img-sanitizer.php' );
132
- unset($sanitizer_classes['AMP_Img_Sanitizer']);
133
- $sanitizer_classes['AMPforWP_Img_Sanitizer']= array();
134
- }
135
- // New Iframe sanitizer to allow popups
136
- if(isset( $sanitizer_classes['AMP_Iframe_Sanitizer'] ) ) {
137
- require_once( AMPFORWP_PLUGIN_DIR. 'classes/class-ampforwp-iframe-sanitizer.php' );
138
- unset($sanitizer_classes['AMP_Iframe_Sanitizer']);
139
- $sanitizer_classes['AMPforWP_Iframe_Sanitizer']= array();
140
- }
141
- return $sanitizer_classes;
142
- }
143
-
144
- // Embed Handlers
145
- function ampforwp_modified_embed_handlers($handlers){
146
- // New Gallery Embed Handler for Gallery with Captions
147
- if(isset($handlers['AMP_Gallery_Embed_Handler'])) {
148
- require_once(AMPFORWP_PLUGIN_DIR. 'classes/class-ampforwp-gallery-embed.php');
149
- unset($handlers['AMP_Gallery_Embed_Handler']);
150
- $handlers['AMPforWP_Gallery_Embed_Handler'] = array();
151
- }
152
- // New Vimeo Embed Handler
153
- if (isset($handlers['AMP_Vimeo_Embed_Handler'])) {
154
- require_once(AMPFORWP_PLUGIN_DIR. 'classes/class-ampforwp-vimeo-embed.php');
155
- unset($handlers['AMP_Vimeo_Embed_Handler']);
156
- $handlers['AMPforWP_Vimeo_Embed_Handler'] = array();
157
- }
158
- return $handlers;
159
- }
160
-
161
-
162
-
163
- function ampforwp_post_status($enabled){
164
- global $redux_builder_amp, $post;
165
- if ( ( is_single() && 'post' === $post->post_type && ! $redux_builder_amp['amp-on-off-for-all-posts'] ) || ( is_page() && ! $redux_builder_amp['amp-on-off-for-all-pages'] ) ){
166
- $enabled = false;
167
- }
168
- if( ( ampforwp_is_home() || ampforwp_is_front_page() ) && ! $redux_builder_amp['ampforwp-homepage-on-off-support'] ){
169
- // returning false will redirect the homepage to the last post
170
- // Redirect the Homepage from here itself
171
- wp_safe_redirect( get_bloginfo('url'), 301 );
172
- exit;
173
- }
174
- return $enabled;
175
- }
176
-
177
- // Template Overriding for Home, Blog, FrontPage , Archives and Search
178
- function ampforwp_custom_template( $file, $type, $post ) {
179
- if ( current_theme_supports( 'amp' ) || start_non_amp_to_amp_conversion() ) {
180
- return $file;
181
- }
182
- global $redux_builder_amp, $wp_query;
183
- $slug = array();
184
- $current_url_in_pieces = array();
185
- $ampforwp_custom_post_page = ampforwp_custom_post_page();
186
- if ( 'single' === $type ) {
187
- // Homepage
188
- if ( ampforwp_is_home() ) {
189
- $file = AMPFORWP_PLUGIN_DIR . '/templates/design-manager/design-'. ampforwp_design_selector() .'/index.php';
190
- }
191
- // Archive Pages
192
- if ( is_archive() && $redux_builder_amp['ampforwp-archive-support'] ) {
193
-
194
- $file = AMPFORWP_PLUGIN_DIR . '/templates/design-manager/design-'. ampforwp_design_selector() .'/archive.php';
195
- }
196
- // Search pages
197
- if ( is_search() &&
198
- ( $redux_builder_amp['amp-design-1-search-feature'] ||
199
- $redux_builder_amp['amp-design-2-search-feature'] ||
200
- $redux_builder_amp['amp-design-3-search-feature'] )
201
- ) {
202
- $file = AMPFORWP_PLUGIN_DIR . '/templates/design-manager/design-'. ampforwp_design_selector() .'/search.php';
203
- }
204
- // FrontPage
205
- if ( ampforwp_is_front_page() ) {
206
- $file = AMPFORWP_PLUGIN_DIR . '/templates/design-manager/design-'. ampforwp_design_selector() .'/frontpage.php';
207
- }
208
- }
209
-
210
- // Polylang compatibility
211
- // For Frontpage
212
- if ( 'single' === $type && ampforwp_polylang_front_page() && true == $redux_builder_amp['amp-frontpage-select-option'] ) {
213
- $file = AMPFORWP_PLUGIN_DIR . '/templates/design-manager/design-'. ampforwp_design_selector() .'/frontpage.php';
214
- }
215
- if( 'page' === $type ) {
216
- // pages
217
- if ( is_page() ) {
218
- $file = AMPFORWP_PLUGIN_DIR . '/templates/design-manager/design-'. ampforwp_design_selector() .'/single.php';
219
- }
220
- // Blog
221
- if ( ampforwp_is_blog() ) {
222
- $file = AMPFORWP_PLUGIN_DIR . '/templates/design-manager/design-'. ampforwp_design_selector() .'/index.php';
223
- }
224
- // FrontPage
225
- if ( ampforwp_is_front_page() ) {
226
- $file = AMPFORWP_PLUGIN_DIR . '/templates/design-manager/design-'. ampforwp_design_selector() .'/frontpage.php';
227
- }
228
-
229
- }
230
- return $file;
231
- }
232
-
233
-
234
-
235
- // End-point (?amp) and correct amphtml for pages after 0.7
236
- function ampforwp_change_end_point($url){
237
- global $redux_builder_amp;
238
- $post_id = get_the_ID();
239
- $amp_url = $url;
240
- if( is_page() && is_post_type_hierarchical( get_post_type( $post_id ) )){
241
- $amp_url = remove_query_arg( 'amp', $amp_url );
242
- $amp_url = trailingslashit( $amp_url );
243
- $amp_url = user_trailingslashit( $amp_url . AMPFORWP_AMP_QUERY_VAR );
244
- }
245
- if(isset($redux_builder_amp['amp-core-end-point']) && $redux_builder_amp['amp-core-end-point']){
246
- $amp_url = get_permalink();
247
- $amp_url = add_query_arg(AMPFORWP_AMP_QUERY_VAR,'',$amp_url);
248
- }
249
- return $amp_url;
250
- }
251
-
252
- /*
253
- * Function Check wp theme will convert as AMP theme or not
254
- * Its @return true when Convert option Enabled
255
- */
256
- function start_non_amp_to_amp_conversion(){
257
- global $redux_builder_amp;
258
- if(
259
- isset( $redux_builder_amp['amp-design-type-selection'] )
260
- && 'amp-converter' == $redux_builder_amp['amp-design-type-selection']
261
- ){
262
- $url_path = trim(parse_url(add_query_arg(array()), PHP_URL_PATH), '/');
263
- $pos = strpos($url_path, amp_get_slug());
264
- if(false!== $pos){
265
- return true;
266
- }
267
- return false;
268
- }
269
- return false;
270
- }
271
-
272
- // Integer value for date, more info: #1241
273
- function ampforwp_post_template_data( $data ) {
274
- // post publish timestamp. Integer value for date, more info: #1241
275
- $data['post_publish_timestamp'] = intval($data['post_publish_timestamp']);
276
- // Placeholder Image. for more info: #1310
277
- $data['placeholder_image_url'] = AMPFORWP_IMAGE_DIR. '/placeholder-icon.png';
278
-
279
- return $data;
280
- }
281
-
282
-
283
- function ampforwp_update_class($classList, $currentClass){
284
- $updateClass = array('AMP_Theme_Support',
285
- 'AMP_Tag_And_Attribute_Sanitizer',
286
- 'AMP_Style_Sanitizer',
287
- 'AMP_Allowed_Tags_Generated',
288
- );
289
- if(!in_array($currentClass, $updateClass)){
290
- return true;
291
- }
292
- switch ($currentClass) {
293
- case 'AMP_Theme_Support':
294
- if ( file_exists( AMPFORWP_PLUGIN_DIR .'/includes/vendor/vendor-files/vendor/autoload.php' ) ) {
295
- require_once AMPFORWP_PLUGIN_DIR .'/includes/vendor/vendor-files/vendor/autoload.php';
296
- }
297
- require AMPFORWP_PLUGIN_DIR . "/includes/vendor/vendor-files/class-amp-theme-support.php";
298
- //AMP_Response_Headers
299
- require AMPFORWP_PLUGIN_DIR . "/includes/vendor/vendor-files/class-amp-response-headers.php";
300
- //AMP_Core_Theme_Sanitizer
301
- require AMPFORWP_PLUGIN_DIR . "/includes/vendor/vendor-files/sanitizer/class-amp-core-theme-sanitizer.php";
302
- break;
303
- case "AMP_Tag_And_Attribute_Sanitizer":
304
- require AMPFORWP_PLUGIN_DIR . "/includes/vendor/vendor-files/sanitizer/class-amp-tag-and-attribute-sanitizer.php";
305
- break;
306
- case "AMP_Style_Sanitizer":
307
- require AMPFORWP_PLUGIN_DIR . "/includes/vendor/vendor-files/sanitizer/class-amp-style-sanitizer.php";
308
- break;
309
- case "AMP_Allowed_Tags_Generated":
310
- require AMPFORWP_PLUGIN_DIR . "/includes/vendor/vendor-files/class-amp-allowed-tags-generated.php";
311
- break;
312
- default:
313
- # code...
314
- break;
315
- }
316
- return false;
317
- }
318
-
319
-
320
- if(!function_exists('ampforwp_isexternal')){
321
- function ampforwp_isexternal($url) {
322
- $components = parse_url($url);
323
- if ( empty($components['host']) ) return false; // we will treat url like '/relative.php' as relative
324
- if ( strcasecmp($components['host'], $_SERVER['HTTP_HOST']) === 0 ) return false; // url host looks exactly like the local host
325
- return strrpos(strtolower($components['host']), $_SERVER['HTTP_HOST']) !== strlen($components['host']) - strlen($_SERVER['HTTP_HOST']); // check if the url host is a subdomain
326
- }//Function function_exists
327
- }// ampforwp_isexternal function_exists close
328
-
329
- if(!function_exists('ampforwp_findInternalUrl')){
330
- function ampforwp_findInternalUrl($url){
331
- if(!ampforwp_isexternal($url) && strpos($url, amp_get_slug())=== False){
332
- if(strpos($url, "#")!==false){
333
- $url = explode("#",$url);
334
- $url = trailingslashit($url[0]).user_trailingslashit(amp_get_slug()).'#'.$url[1];
335
- }else{
336
- $url = trailingslashit($url).user_trailingslashit(amp_get_slug());
337
- }
338
- return $url;
339
- }
340
- return $url;
341
- }// function Close
342
- }// function_exists ampforwp_findInternalUrl close
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/vendor-files/class-amp-allowed-tags-generated.php DELETED
@@ -1,10822 +0,0 @@
1
- <?php
2
- /**
3
- * Generated by amphtml-update.py - do not edit.
4
- *
5
- * This is a list of HTML tags and attributes that are allowed by the
6
- * AMP specification. Note that tag names have been converted to lowercase.
7
- *
8
- * Note: This file only contains tags that are relevant to the `body` of
9
- * an AMP page. To include additional elements modify the variable
10
- * `mandatory_parent_blacklist` in the amp_wp_build.py script.
11
- *
12
- * phpcs:ignoreFile
13
- */
14
- class AMP_Allowed_Tags_Generated {
15
-
16
- private static $spec_file_revision = 595;
17
- private static $minimum_validator_revision_required = 322;
18
-
19
- private static $allowed_tags = array(
20
- 'a' => array(
21
- array(
22
- 'attr_spec_list' => array(
23
- '[href]' => array(),
24
- 'border' => array(),
25
- 'download' => array(),
26
- 'href' => array(
27
- 'blacklisted_value_regex' => '__amp_source_origin',
28
- 'value_url' => array(
29
- 'allow_empty' => true,
30
- 'allow_relative' => true,
31
- 'allowed_protocol' => array(
32
- 'ftp',
33
- 'geo',
34
- 'http',
35
- 'https',
36
- 'mailto',
37
- 'maps',
38
- 'bbmi',
39
- 'fb-messenger',
40
- 'intent',
41
- 'line',
42
- 'skype',
43
- 'sms',
44
- 'snapchat',
45
- 'tel',
46
- 'tg',
47
- 'threema',
48
- 'twitter',
49
- 'viber',
50
- 'whatsapp',
51
- ),
52
- ),
53
- ),
54
- 'hreflang' => array(),
55
- 'media' => array(),
56
- 'name' => array(),
57
- 'referrerpolicy' => array(),
58
- 'rel' => array(
59
- 'blacklisted_value_regex' => '(^|\\s)(components|dns-prefetch|import|manifest|preconnect|prefetch|preload|prerender|serviceworker|stylesheet|subresource|)(\\s|$)',
60
- ),
61
- 'role' => array(),
62
- 'tabindex' => array(),
63
- 'target' => array(
64
- 'value_regex' => '(_blank|_self|_top)',
65
- ),
66
- 'type' => array(
67
- 'value_casei' => 'text/html',
68
- ),
69
- ),
70
- 'tag_spec' => array(
71
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#links',
72
- ),
73
- ),
74
- ),
75
- 'abbr' => array(
76
- array(
77
- 'attr_spec_list' => array(),
78
- 'tag_spec' => array(),
79
- ),
80
- ),
81
- 'acronym' => array(
82
- array(
83
- 'attr_spec_list' => array(),
84
- 'tag_spec' => array(),
85
- ),
86
- ),
87
- 'address' => array(
88
- array(
89
- 'attr_spec_list' => array(),
90
- 'tag_spec' => array(),
91
- ),
92
- ),
93
- 'amp-3q-player' => array(
94
- array(
95
- 'attr_spec_list' => array(
96
- 'autoplay' => array(
97
- 'value' => '',
98
- ),
99
- 'data-id' => array(
100
- 'mandatory' => true,
101
- ),
102
- 'media' => array(),
103
- 'noloading' => array(
104
- 'value' => '',
105
- ),
106
- ),
107
- 'tag_spec' => array(
108
- 'requires_extension' => array(
109
- 'amp-3q-player',
110
- ),
111
- ),
112
- ),
113
- ),
114
- 'amp-accordion' => array(
115
- array(
116
- 'attr_spec_list' => array(
117
- 'disable-session-states' => array(
118
- 'value' => '',
119
- ),
120
- 'expand-single-section' => array(
121
- 'value' => '',
122
- ),
123
- ),
124
- 'tag_spec' => array(
125
- 'requires_extension' => array(
126
- 'amp-accordion',
127
- ),
128
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-accordion',
129
- ),
130
- ),
131
- ),
132
- 'amp-ad' => array(
133
- array(
134
- 'attr_spec_list' => array(
135
- 'alt' => array(),
136
- 'json' => array(),
137
- 'media' => array(),
138
- 'noloading' => array(
139
- 'value' => '',
140
- ),
141
- 'rtc-config' => array(),
142
- 'src' => array(
143
- 'blacklisted_value_regex' => '__amp_source_origin',
144
- 'value_url' => array(
145
- 'allow_relative' => true,
146
- 'allowed_protocol' => array(
147
- 'https',
148
- ),
149
- ),
150
- ),
151
- 'template' => array(),
152
- 'type' => array(
153
- 'mandatory' => true,
154
- ),
155
- ),
156
- 'tag_spec' => array(
157
- 'also_requires_tag_warning' => array(
158
- 'amp-ad extension .js script',
159
- ),
160
- 'disallowed_ancestor' => array(
161
- 'amp-app-banner',
162
- ),
163
- 'requires_extension' => array(
164
- 'amp-ad',
165
- ),
166
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
167
- ),
168
- ),
169
- array(
170
- 'attr_spec_list' => array(
171
- 'alt' => array(),
172
- 'data-multi-size' => array(
173
- 'dispatch_key' => 2,
174
- 'mandatory' => true,
175
- 'value' => '',
176
- ),
177
- 'json' => array(),
178
- 'media' => array(),
179
- 'noloading' => array(
180
- 'value' => '',
181
- ),
182
- 'rtc-config' => array(),
183
- 'src' => array(
184
- 'blacklisted_value_regex' => '__amp_source_origin',
185
- 'value_url' => array(
186
- 'allow_relative' => true,
187
- 'allowed_protocol' => array(
188
- 'https',
189
- ),
190
- ),
191
- ),
192
- 'type' => array(
193
- 'mandatory' => true,
194
- ),
195
- ),
196
- 'tag_spec' => array(
197
- 'also_requires_tag_warning' => array(
198
- 'amp-ad extension .js script',
199
- ),
200
- 'disallowed_ancestor' => array(
201
- 'amp-app-banner',
202
- 'amp-carousel',
203
- 'amp-fx-flying-carpet',
204
- 'amp-lightbox',
205
- 'amp-sticky-ad',
206
- ),
207
- 'requires_extension' => array(
208
- 'amp-ad',
209
- ),
210
- 'spec_name' => 'amp-ad with data-multi-size attribute',
211
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
212
- ),
213
- ),
214
- array(
215
- 'attr_spec_list' => array(
216
- 'alt' => array(),
217
- 'data-enable-refresh' => array(
218
- 'dispatch_key' => 2,
219
- 'mandatory' => true,
220
- 'value' => '',
221
- ),
222
- 'json' => array(),
223
- 'media' => array(),
224
- 'noloading' => array(
225
- 'value' => '',
226
- ),
227
- 'src' => array(
228
- 'blacklisted_value_regex' => '__amp_source_origin',
229
- 'value_url' => array(
230
- 'allow_relative' => true,
231
- 'allowed_protocol' => array(
232
- 'https',
233
- ),
234
- ),
235
- ),
236
- 'type' => array(
237
- 'mandatory' => true,
238
- ),
239
- ),
240
- 'tag_spec' => array(
241
- 'also_requires_tag_warning' => array(
242
- 'amp-ad extension .js script',
243
- ),
244
- 'disallowed_ancestor' => array(
245
- 'amp-app-banner',
246
- 'amp-fx-flying-carpet',
247
- 'amp-lightbox',
248
- ),
249
- 'requires_extension' => array(
250
- 'amp-ad',
251
- ),
252
- 'spec_name' => 'amp-ad with data-enable-refresh attribute',
253
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
254
- ),
255
- ),
256
- ),
257
- 'amp-analytics' => array(
258
- array(
259
- 'attr_spec_list' => array(
260
- 'config' => array(
261
- 'blacklisted_value_regex' => '__amp_source_origin',
262
- 'value_url' => array(
263
- 'allow_empty' => true,
264
- 'allow_relative' => true,
265
- 'allowed_protocol' => array(
266
- 'https',
267
- ),
268
- ),
269
- ),
270
- 'type' => array(),
271
- ),
272
- 'tag_spec' => array(
273
- 'requires_extension' => array(
274
- 'amp-analytics',
275
- ),
276
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-analytics',
277
- ),
278
- ),
279
- ),
280
- 'amp-anim' => array(
281
- array(
282
- 'attr_spec_list' => array(
283
- 'alt' => array(),
284
- 'attribution' => array(),
285
- 'controls' => array(),
286
- 'media' => array(),
287
- 'noloading' => array(
288
- 'value' => '',
289
- ),
290
- 'src' => array(
291
- 'alternative_names' => array(
292
- 'srcset',
293
- ),
294
- 'blacklisted_value_regex' => '__amp_source_origin',
295
- 'mandatory' => true,
296
- 'value_url' => array(
297
- 'allow_relative' => true,
298
- 'allowed_protocol' => array(
299
- 'data',
300
- 'http',
301
- 'https',
302
- ),
303
- ),
304
- ),
305
- ),
306
- 'tag_spec' => array(
307
- 'requires_extension' => array(
308
- 'amp-anim',
309
- ),
310
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-anim',
311
- ),
312
- ),
313
- ),
314
- 'amp-animation' => array(
315
- array(
316
- 'attr_spec_list' => array(
317
- 'media' => array(),
318
- 'noloading' => array(
319
- 'value' => '',
320
- ),
321
- 'trigger' => array(
322
- 'value' => 'visibility',
323
- ),
324
- ),
325
- 'tag_spec' => array(
326
- 'requires_extension' => array(
327
- 'amp-animation',
328
- ),
329
- ),
330
- ),
331
- ),
332
- 'amp-apester-media' => array(
333
- array(
334
- 'attr_spec_list' => array(
335
- 'data-apester-channel-token' => array(
336
- 'value_regex' => '[0-9a-zA-Z]+',
337
- ),
338
- 'data-apester-media-id' => array(
339
- 'value_regex' => '[0-9a-zA-Z]+',
340
- ),
341
- 'media' => array(),
342
- 'noloading' => array(
343
- 'value' => '',
344
- ),
345
- ),
346
- 'tag_spec' => array(
347
- 'requires_extension' => array(
348
- 'amp-apester-media',
349
- ),
350
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-apester-media',
351
- ),
352
- ),
353
- ),
354
- 'amp-app-banner' => array(
355
- array(
356
- 'attr_spec_list' => array(
357
- 'id' => array(
358
- 'mandatory' => true,
359
- ),
360
- 'media' => array(),
361
- 'noloading' => array(
362
- 'value' => '',
363
- ),
364
- ),
365
- 'tag_spec' => array(
366
- 'mandatory_parent' => 'body',
367
- 'requires_extension' => array(
368
- 'amp-app-banner',
369
- ),
370
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-app-banner',
371
- 'unique' => true,
372
- ),
373
- ),
374
- ),
375
- 'amp-audio' => array(
376
- array(
377
- 'attr_spec_list' => array(
378
- 'album' => array(),
379
- 'artist' => array(),
380
- 'artwork' => array(),
381
- 'autoplay' => array(
382
- 'value' => '',
383
- ),
384
- 'controls' => array(),
385
- 'controlslist' => array(),
386
- 'loop' => array(
387
- 'value' => '',
388
- ),
389
- 'media' => array(),
390
- 'muted' => array(
391
- 'value' => '',
392
- ),
393
- 'noloading' => array(
394
- 'value' => '',
395
- ),
396
- 'preload' => array(
397
- 'value_regex_casei' => '(auto|metadata|none|)',
398
- ),
399
- 'src' => array(
400
- 'blacklisted_value_regex' => '__amp_source_origin',
401
- 'value_url' => array(
402
- 'allow_relative' => true,
403
- 'allowed_protocol' => array(
404
- 'https',
405
- ),
406
- ),
407
- ),
408
- ),
409
- 'tag_spec' => array(
410
- 'disallowed_ancestor' => array(
411
- 'amp-story',
412
- ),
413
- 'requires_extension' => array(
414
- 'amp-audio',
415
- ),
416
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
417
- ),
418
- ),
419
- array(
420
- 'attr_spec_list' => array(
421
- 'album' => array(),
422
- 'artist' => array(),
423
- 'artwork' => array(),
424
- 'autoplay' => array(
425
- 'mandatory' => true,
426
- 'value' => '',
427
- ),
428
- 'controls' => array(),
429
- 'controlslist' => array(),
430
- 'loop' => array(
431
- 'value' => '',
432
- ),
433
- 'media' => array(),
434
- 'muted' => array(
435
- 'value' => '',
436
- ),
437
- 'noloading' => array(
438
- 'value' => '',
439
- ),
440
- 'src' => array(
441
- 'blacklisted_value_regex' => '__amp_source_origin',
442
- 'value_url' => array(
443
- 'allow_relative' => true,
444
- 'allowed_protocol' => array(
445
- 'https',
446
- ),
447
- ),
448
- ),
449
- ),
450
- 'tag_spec' => array(
451
- 'mandatory_ancestor' => 'amp-story',
452
- 'requires_extension' => array(
453
- 'amp-audio',
454
- ),
455
- 'spec_name' => 'amp-story >> amp-audio',
456
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
457
- ),
458
- ),
459
- ),
460
- 'amp-auto-ads' => array(
461
- array(
462
- 'attr_spec_list' => array(
463
- 'media' => array(),
464
- 'noloading' => array(
465
- 'value' => '',
466
- ),
467
- 'type' => array(
468
- 'mandatory' => true,
469
- ),
470
- ),
471
- 'tag_spec' => array(
472
- 'mandatory_parent' => 'body',
473
- 'requires_extension' => array(
474
- 'amp-auto-ads',
475
- ),
476
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-auto-ads',
477
- ),
478
- ),
479
- ),
480
- 'amp-beopinion' => array(
481
- array(
482
- 'attr_spec_list' => array(
483
- 'data-account' => array(
484
- 'mandatory' => true,
485
- 'value_regex_casei' => '[0-9a-f]{24}',
486
- ),
487
- 'data-content' => array(
488
- 'value_regex_casei' => '[0-9a-f]{24}',
489
- ),
490
- 'data-my-content' => array(
491
- 'value_regex' => '0|1',
492
- ),
493
- 'data-name' => array(),
494
- 'media' => array(),
495
- 'noloading' => array(
496
- 'value' => '',
497
- ),
498
- ),
499
- 'tag_spec' => array(
500
- 'requires_extension' => array(
501
- 'amp-beopinion',
502
- ),
503
- ),
504
- ),
505
- ),
506
- 'amp-bind-macro' => array(
507
- array(
508
- 'attr_spec_list' => array(
509
- 'arguments' => array(),
510
- 'expression' => array(
511
- 'mandatory' => true,
512
- ),
513
- 'id' => array(
514
- 'mandatory' => true,
515
- ),
516
- ),
517
- 'tag_spec' => array(
518
- 'requires_extension' => array(
519
- 'amp-bind',
520
- ),
521
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind',
522
- ),
523
- ),
524
- ),
525
- 'amp-bodymovin-animation' => array(
526
- array(
527
- 'attr_spec_list' => array(
528
- 'loop' => array(
529
- 'value_regex_casei' => '(false|number|true)',
530
- ),
531
- 'noautoplay' => array(
532
- 'value' => '',
533
- ),
534
- 'src' => array(
535
- 'mandatory' => true,
536
- 'value_url' => array(
537
- 'allow_relative' => false,
538
- 'allowed_protocol' => array(
539
- 'https',
540
- ),
541
- ),
542
- ),
543
- ),
544
- 'tag_spec' => array(
545
- 'requires_extension' => array(
546
- 'amp-bodymovin-animation',
547
- ),
548
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bodymovin-animation',
549
- ),
550
- ),
551
- ),
552
- 'amp-brid-player' => array(
553
- array(
554
- 'attr_spec_list' => array(
555
- 'autoplay' => array(),
556
- 'data-outstream' => array(
557
- 'value_regex' => '[0-9]+',
558
- ),
559
- 'data-partner' => array(
560
- 'mandatory' => true,
561
- 'value_regex' => '[0-9]+',
562
- ),
563
- 'data-player' => array(
564
- 'mandatory' => true,
565
- 'value_regex' => '[0-9]+',
566
- ),
567
- 'data-playlist' => array(
568
- 'value_regex' => '[0-9]+',
569
- ),
570
- 'data-video' => array(
571
- 'value_regex' => '[0-9]+',
572
- ),
573
- 'media' => array(),
574
- 'noloading' => array(
575
- 'value' => '',
576
- ),
577
- ),
578
- 'tag_spec' => array(
579
- 'requires_extension' => array(
580
- 'amp-brid-player',
581
- ),
582
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-brid-player',
583
- ),
584
- ),
585
- ),
586
- 'amp-brightcove' => array(
587
- array(
588
- 'attr_spec_list' => array(
589
- '[data-account]' => array(),
590
- '[data-embed]' => array(),
591
- '[data-player-id]' => array(),
592
- '[data-player]' => array(),
593
- '[data-playlist-id]' => array(),
594
- '[data-video-id]' => array(),
595
- 'data-account' => array(
596
- 'mandatory' => true,
597
- ),
598
- 'media' => array(),
599
- 'noloading' => array(
600
- 'value' => '',
601
- ),
602
- ),
603
- 'tag_spec' => array(
604
- 'requires_extension' => array(
605
- 'amp-brightcove',
606
- ),
607
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-brightcove',
608
- ),
609
- ),
610
- ),
611
- 'amp-byside-content' => array(
612
- array(
613
- 'attr_spec_list' => array(
614
- 'data-label' => array(
615
- 'mandatory' => true,
616
- ),
617
- 'data-webcare-id' => array(
618
- 'mandatory' => true,
619
- ),
620
- 'media' => array(),
621
- 'noloading' => array(
622
- 'value' => '',
623
- ),
624
- ),
625
- 'tag_spec' => array(
626
- 'requires_extension' => array(
627
- 'amp-byside-content',
628
- ),
629
- ),
630
- ),
631
- ),
632
- 'amp-call-tracking' => array(
633
- array(
634
- 'attr_spec_list' => array(
635
- 'config' => array(
636
- 'blacklisted_value_regex' => '__amp_source_origin',
637
- 'mandatory' => true,
638
- 'value_url' => array(
639
- 'allow_relative' => false,
640
- 'allowed_protocol' => array(
641
- 'https',
642
- ),
643
- ),
644
- ),
645
- 'media' => array(),
646
- 'noloading' => array(
647
- 'value' => '',
648
- ),
649
- ),
650
- 'tag_spec' => array(
651
- 'requires_extension' => array(
652
- 'amp-call-tracking',
653
- ),
654
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-call-tracking',
655
- ),
656
- ),
657
- ),
658
- 'amp-carousel' => array(
659
- array(
660
- 'attr_spec_list' => array(
661
- '[slide]' => array(),
662
- 'arrows' => array(
663
- 'value' => '',
664
- ),
665
- 'autoplay' => array(
666
- 'value' => '',
667
- ),
668
- 'controls' => array(),
669
- 'delay' => array(
670
- 'value_regex' => '[0-9]+',
671
- ),
672
- 'dots' => array(
673
- 'value' => '',
674
- ),
675
- 'lightbox' => array(),
676
- 'lightbox-exclude' => array(
677
- 'value' => '',
678
- ),
679
- 'lightbox-thumbnail-id' => array(
680
- 'value_regex_casei' => '^[a-z][a-z\\d_-]*',
681
- ),
682
- 'loop' => array(
683
- 'value' => '',
684
- ),
685
- 'media' => array(),
686
- 'noloading' => array(
687
- 'value' => '',
688
- ),
689
- 'type' => array(
690
- 'value_regex' => 'slides|carousel',
691
- ),
692
- ),
693
- 'tag_spec' => array(
694
- 'requires_extension' => array(
695
- 'amp-carousel',
696
- ),
697
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-carousel',
698
- ),
699
- ),
700
- ),
701
- 'amp-consent' => array(
702
- array(
703
- 'attr_spec_list' => array(
704
- 'media' => array(),
705
- 'noloading' => array(
706
- 'value' => '',
707
- ),
708
- ),
709
- 'tag_spec' => array(
710
- 'requires_extension' => array(
711
- 'amp-consent',
712
- ),
713
- 'unique' => true,
714
- ),
715
- ),
716
- ),
717
- 'amp-dailymotion' => array(
718
- array(
719
- 'attr_spec_list' => array(
720
- 'autoplay' => array(),
721
- 'data-endscreen-enable' => array(
722
- 'value_regex' => 'true|false',
723
- ),
724
- 'data-info' => array(
725
- 'value_regex' => 'true|false',
726
- ),
727
- 'data-mute' => array(
728
- 'value_regex' => 'true|false',
729
- ),
730
- 'data-sharing-enable' => array(
731
- 'value_regex' => 'true|false',
732
- ),
733
- 'data-start' => array(
734
- 'value_regex' => '[0-9]+',
735
- ),
736
- 'data-ui-highlight' => array(
737
- 'value_regex_casei' => '([0-9a-f]{3}){1,2}',
738
- ),
739
- 'data-ui-logo' => array(
740
- 'value_regex' => 'true|false',
741
- ),
742
- 'data-videoid' => array(
743
- 'mandatory' => true,
744
- 'value_regex_casei' => '[a-z0-9]+',
745
- ),
746
- 'media' => array(),
747
- 'noloading' => array(
748
- 'value' => '',
749
- ),
750
- ),
751
- 'tag_spec' => array(
752
- 'requires_extension' => array(
753
- 'amp-dailymotion',
754
- ),
755
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-dailymotion',
756
- ),
757
- ),
758
- ),
759
- 'amp-date-picker' => array(
760
- array(
761
- 'attr_spec_list' => array(
762
- 'allow-blocked-ranges' => array(
763
- 'value' => '',
764
- ),
765
- 'blocked' => array(),
766
- 'day-size' => array(
767
- 'value_regex' => '[0-9]+',
768
- ),
769
- 'first-day-of-week' => array(
770
- 'value_regex' => '[0-6]',
771
- ),
772
- 'format' => array(),
773
- 'fullscreen' => array(
774
- 'value' => '',
775
- ),
776
- 'highlighted' => array(),
777
- 'input-selector' => array(),
778
- 'locale' => array(),
779
- 'max' => array(),
780
- 'media' => array(),
781
- 'min' => array(),
782
- 'mode' => array(
783
- 'value_casei' => 'static',
784
- ),
785
- 'month-format' => array(),
786
- 'noloading' => array(
787
- 'value' => '',
788
- ),
789
- 'number-of-months' => array(
790
- 'value_regex' => '[0-9]+',
791
- ),
792
- 'open-after-clear' => array(
793
- 'value' => '',
794
- ),
795
- 'open-after-select' => array(
796
- 'value' => '',
797
- ),
798
- 'src' => array(
799
- 'blacklisted_value_regex' => '__amp_source_origin',
800
- 'value_url' => array(
801
- 'allow_relative' => true,
802
- 'allowed_protocol' => array(
803
- 'https',
804
- ),
805
- ),
806
- ),
807
- 'type' => array(
808
- 'value_casei' => 'single',
809
- ),
810
- 'week-day-format' => array(),
811
- ),
812
- 'tag_spec' => array(
813
- 'requires_extension' => array(
814
- 'amp-date-picker',
815
- ),
816
- 'spec_name' => 'amp-date-picker[type=single][mode=static]',
817
- ),
818
- ),
819
- array(
820
- 'attr_spec_list' => array(
821
- 'allow-blocked-ranges' => array(
822
- 'value' => '',
823
- ),
824
- 'blocked' => array(),
825
- 'day-size' => array(
826
- 'value_regex' => '[0-9]+',
827
- ),
828
- 'first-day-of-week' => array(
829
- 'value_regex' => '[0-6]',
830
- ),
831
- 'format' => array(),
832
- 'highlighted' => array(),
833
- 'input-selector' => array(),
834
- 'locale' => array(),
835
- 'max' => array(),
836
- 'media' => array(),
837
- 'min' => array(),
838
- 'mode' => array(
839
- 'mandatory' => true,
840
- 'value_casei' => 'overlay',
841
- ),
842
- 'month-format' => array(),
843
- 'noloading' => array(
844
- 'value' => '',
845
- ),
846
- 'number-of-months' => array(
847
- 'value_regex' => '[0-9]+',
848
- ),
849
- 'open-after-clear' => array(
850
- 'value' => '',
851
- ),
852
- 'open-after-select' => array(
853
- 'value' => '',
854
- ),
855
- 'src' => array(
856
- 'blacklisted_value_regex' => '__amp_source_origin',
857
- 'value_url' => array(
858
- 'allow_relative' => true,
859
- 'allowed_protocol' => array(
860
- 'https',
861
- ),
862
- ),
863
- ),
864
- 'type' => array(
865
- 'value_casei' => 'single',
866
- ),
867
- 'week-day-format' => array(),
868
- ),
869
- 'tag_spec' => array(
870
- 'requires_extension' => array(
871
- 'amp-date-picker',
872
- ),
873
- 'spec_name' => 'amp-date-picker[type=single][mode=overlay]',
874
- ),
875
- ),
876
- array(
877
- 'attr_spec_list' => array(
878
- 'allow-blocked-ranges' => array(
879
- 'value' => '',
880
- ),
881
- 'blocked' => array(),
882
- 'day-size' => array(
883
- 'value_regex' => '[0-9]+',
884
- ),
885
- 'end-input-selector' => array(),
886
- 'first-day-of-week' => array(
887
- 'value_regex' => '[0-6]',
888
- ),
889
- 'format' => array(),
890
- 'fullscreen' => array(
891
- 'value' => '',
892
- ),
893
- 'highlighted' => array(),
894
- 'locale' => array(),
895
- 'max' => array(),
896
- 'media' => array(),
897
- 'min' => array(),
898
- 'mode' => array(
899
- 'value_casei' => 'static',
900
- ),
901
- 'month-format' => array(),
902
- 'noloading' => array(
903
- 'value' => '',
904
- ),
905
- 'number-of-months' => array(
906
- 'value_regex' => '[0-9]+',
907
- ),
908
- 'open-after-clear' => array(
909
- 'value' => '',
910
- ),
911
- 'open-after-select' => array(
912
- 'value' => '',
913
- ),
914
- 'src' => array(
915
- 'blacklisted_value_regex' => '__amp_source_origin',
916
- 'value_url' => array(
917
- 'allow_relative' => true,
918
- 'allowed_protocol' => array(
919
- 'https',
920
- ),
921
- ),
922
- ),
923
- 'start-input-selector' => array(),
924
- 'type' => array(
925
- 'mandatory' => true,
926
- 'value_casei' => 'range',
927
- ),
928
- 'week-day-format' => array(),
929
- ),
930
- 'tag_spec' => array(
931
- 'requires_extension' => array(
932
- 'amp-date-picker',
933
- ),
934
- 'spec_name' => 'amp-date-picker[type=range][mode=static]',
935
- ),
936
- ),
937
- array(
938
- 'attr_spec_list' => array(
939
- 'allow-blocked-ranges' => array(
940
- 'value' => '',
941
- ),
942
- 'blocked' => array(),
943
- 'day-size' => array(
944
- 'value_regex' => '[0-9]+',
945
- ),
946
- 'end-input-selector' => array(),
947
- 'first-day-of-week' => array(
948
- 'value_regex' => '[0-6]',
949
- ),
950
- 'format' => array(),
951
- 'highlighted' => array(),
952
- 'locale' => array(),
953
- 'max' => array(),
954
- 'media' => array(),
955
- 'min' => array(),
956
- 'mode' => array(
957
- 'mandatory' => true,
958
- 'value_casei' => 'overlay',
959
- ),
960
- 'month-format' => array(),
961
- 'noloading' => array(
962
- 'value' => '',
963
- ),
964
- 'number-of-months' => array(
965
- 'value_regex' => '[0-9]+',
966
- ),
967
- 'open-after-clear' => array(
968
- 'value' => '',
969
- ),
970
- 'open-after-select' => array(
971
- 'value' => '',
972
- ),
973
- 'src' => array(
974
- 'blacklisted_value_regex' => '__amp_source_origin',
975
- 'value_url' => array(
976
- 'allow_relative' => true,
977
- 'allowed_protocol' => array(
978
- 'https',
979
- ),
980
- ),
981
- ),
982
- 'start-input-selector' => array(),
983
- 'type' => array(
984
- 'mandatory' => true,
985
- 'value_casei' => 'range',
986
- ),
987
- 'week-day-format' => array(),
988
- ),
989
- 'tag_spec' => array(
990
- 'requires_extension' => array(
991
- 'amp-date-picker',
992
- ),
993
- 'spec_name' => 'amp-date-picker[type=range][mode=overlay]',
994
- ),
995
- ),
996
- ),
997
- 'amp-document-recommendations' => array(
998
- array(
999
- 'attr_spec_list' => array(),
1000
- 'tag_spec' => array(
1001
- 'mandatory_parent' => 'body',
1002
- 'requires_extension' => array(
1003
- 'amp-document-recommendations',
1004
- ),
1005
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-document-recommendations',
1006
- ),
1007
- ),
1008
- ),
1009
- 'amp-embed' => array(
1010
- array(
1011
- 'attr_spec_list' => array(
1012
- 'alt' => array(),
1013
- 'json' => array(),
1014
- 'media' => array(),
1015
- 'noloading' => array(
1016
- 'value' => '',
1017
- ),
1018
- 'rtc-config' => array(),
1019
- 'src' => array(
1020
- 'blacklisted_value_regex' => '__amp_source_origin',
1021
- 'value_url' => array(
1022
- 'allow_relative' => true,
1023
- 'allowed_protocol' => array(
1024
- 'https',
1025
- ),
1026
- ),
1027
- ),
1028
- 'template' => array(),
1029
- 'type' => array(
1030
- 'mandatory' => true,
1031
- ),
1032
- ),
1033
- 'tag_spec' => array(
1034
- 'also_requires_tag_warning' => array(
1035
- 'amp-ad extension .js script',
1036
- ),
1037
- 'disallowed_ancestor' => array(
1038
- 'amp-app-banner',
1039
- ),
1040
- 'requires_extension' => array(
1041
- 'amp-ad',
1042
- ),
1043
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
1044
- ),
1045
- ),
1046
- array(
1047
- 'attr_spec_list' => array(
1048
- 'alt' => array(),
1049
- 'data-multi-size' => array(
1050
- 'dispatch_key' => 2,
1051
- 'mandatory' => true,
1052
- 'value' => '',
1053
- ),
1054
- 'json' => array(),
1055
- 'media' => array(),
1056
- 'noloading' => array(
1057
- 'value' => '',
1058
- ),
1059
- 'rtc-config' => array(),
1060
- 'src' => array(
1061
- 'blacklisted_value_regex' => '__amp_source_origin',
1062
- 'value_url' => array(
1063
- 'allow_relative' => true,
1064
- 'allowed_protocol' => array(
1065
- 'https',
1066
- ),
1067
- ),
1068
- ),
1069
- 'type' => array(
1070
- 'mandatory' => true,
1071
- ),
1072
- ),
1073
- 'tag_spec' => array(
1074
- 'also_requires_tag_warning' => array(
1075
- 'amp-ad extension .js script',
1076
- ),
1077
- 'disallowed_ancestor' => array(
1078
- 'amp-app-banner',
1079
- 'amp-carousel',
1080
- 'amp-fx-flying-carpet',
1081
- 'amp-lightbox',
1082
- 'amp-sticky-ad',
1083
- ),
1084
- 'requires_extension' => array(
1085
- 'amp-ad',
1086
- ),
1087
- 'spec_name' => 'amp-embed with data-multi-size attribute',
1088
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
1089
- ),
1090
- ),
1091
- ),
1092
- 'amp-experiment' => array(
1093
- array(
1094
- 'attr_spec_list' => array(),
1095
- 'tag_spec' => array(
1096
- 'requires_extension' => array(
1097
- 'amp-experiment',
1098
- ),
1099
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-experiment',
1100
- 'unique' => true,
1101
- ),
1102
- ),
1103
- ),
1104
- 'amp-facebook' => array(
1105
- array(
1106
- 'attr_spec_list' => array(
1107
- 'data-href' => array(
1108
- 'mandatory' => true,
1109
- ),
1110
- 'media' => array(),
1111
- 'noloading' => array(
1112
- 'value' => '',
1113
- ),
1114
- ),
1115
- 'tag_spec' => array(
1116
- 'requires_extension' => array(
1117
- 'amp-facebook',
1118
- ),
1119
- ),
1120
- ),
1121
- ),
1122
- 'amp-facebook-comments' => array(
1123
- array(
1124
- 'attr_spec_list' => array(
1125
- 'data-href' => array(
1126
- 'mandatory' => true,
1127
- ),
1128
- 'media' => array(),
1129
- 'noloading' => array(
1130
- 'value' => '',
1131
- ),
1132
- ),
1133
- 'tag_spec' => array(
1134
- 'requires_extension' => array(
1135
- 'amp-facebook-comments',
1136
- ),
1137
- ),
1138
- ),
1139
- ),
1140
- 'amp-facebook-like' => array(
1141
- array(
1142
- 'attr_spec_list' => array(
1143
- 'data-href' => array(
1144
- 'mandatory' => true,
1145
- 'value_url' => array(
1146
- 'allow_relative' => false,
1147
- 'allowed_protocol' => array(
1148
- 'http',
1149
- 'https',
1150
- ),
1151
- ),
1152
- ),
1153
- 'media' => array(),
1154
- 'noloading' => array(
1155
- 'value' => '',
1156
- ),
1157
- ),
1158
- 'tag_spec' => array(
1159
- 'requires_extension' => array(
1160
- 'amp-facebook-like',
1161
- ),
1162
- ),
1163
- ),
1164
- ),
1165
- 'amp-facebook-page' => array(
1166
- array(
1167
- 'attr_spec_list' => array(
1168
- 'data-href' => array(
1169
- 'mandatory' => true,
1170
- 'value_url' => array(
1171
- 'allow_relative' => false,
1172
- 'allowed_protocol' => array(
1173
- 'http',
1174
- 'https',
1175
- ),
1176
- ),
1177
- ),
1178
- 'media' => array(),
1179
- 'noloading' => array(
1180
- 'value' => '',
1181
- ),
1182
- ),
1183
- 'tag_spec' => array(
1184
- 'requires_extension' => array(
1185
- 'amp-facebook-page',
1186
- ),
1187
- ),
1188
- ),
1189
- ),
1190
- 'amp-fit-text' => array(
1191
- array(
1192
- 'attr_spec_list' => array(
1193
- 'max-font-size' => array(),
1194
- 'media' => array(),
1195
- 'min-font-size' => array(),
1196
- 'noloading' => array(
1197
- 'value' => '',
1198
- ),
1199
- ),
1200
- 'tag_spec' => array(
1201
- 'requires_extension' => array(
1202
- 'amp-fit-text',
1203
- ),
1204
- ),
1205
- ),
1206
- ),
1207
- 'amp-font' => array(
1208
- array(
1209
- 'attr_spec_list' => array(
1210
- 'font-family' => array(
1211
- 'mandatory' => true,
1212
- ),
1213
- 'font-style' => array(),
1214
- 'font-variant' => array(),
1215
- 'font-weight' => array(),
1216
- 'media' => array(),
1217
- 'noloading' => array(
1218
- 'value' => '',
1219
- ),
1220
- 'on-error-add-class' => array(),
1221
- 'on-error-remove-class' => array(),
1222
- 'on-load-add-class' => array(),
1223
- 'on-load-remove-class' => array(),
1224
- 'timeout' => array(
1225
- 'value_regex' => '[0-9]+',
1226
- ),
1227
- ),
1228
- 'tag_spec' => array(
1229
- 'requires_extension' => array(
1230
- 'amp-font',
1231
- ),
1232
- ),
1233
- ),
1234
- ),
1235
- 'amp-fx-flying-carpet' => array(
1236
- array(
1237
- 'attr_spec_list' => array(
1238
- 'height' => array(
1239
- 'mandatory' => true,
1240
- ),
1241
- 'media' => array(),
1242
- 'noloading' => array(
1243
- 'value' => '',
1244
- ),
1245
- ),
1246
- 'tag_spec' => array(
1247
- 'requires_extension' => array(
1248
- 'amp-fx-flying-carpet',
1249
- ),
1250
- ),
1251
- ),
1252
- ),
1253
- 'amp-gfycat' => array(
1254
- array(
1255
- 'attr_spec_list' => array(
1256
- 'data-gfyid' => array(
1257
- 'mandatory' => true,
1258
- ),
1259
- 'media' => array(),
1260
- 'noautoplay' => array(
1261
- 'value' => '',
1262
- ),
1263
- 'noloading' => array(
1264
- 'value' => '',
1265
- ),
1266
- ),
1267
- 'tag_spec' => array(
1268
- 'requires_extension' => array(
1269
- 'amp-gfycat',
1270
- ),
1271
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-gfycat',
1272
- ),
1273
- ),
1274
- ),
1275
- 'amp-gist' => array(
1276
- array(
1277
- 'attr_spec_list' => array(
1278
- 'data-gistid' => array(
1279
- 'mandatory' => true,
1280
- ),
1281
- 'media' => array(),
1282
- 'noloading' => array(
1283
- 'value' => '',
1284
- ),
1285
- ),
1286
- 'tag_spec' => array(
1287
- 'requires_extension' => array(
1288
- 'amp-gist',
1289
- ),
1290
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-gist',
1291
- ),
1292
- ),
1293
- ),
1294
- 'amp-hulu' => array(
1295
- array(
1296
- 'attr_spec_list' => array(
1297
- 'data-eid' => array(
1298
- 'mandatory' => true,
1299
- ),
1300
- 'media' => array(),
1301
- 'noloading' => array(
1302
- 'value' => '',
1303
- ),
1304
- ),
1305
- 'tag_spec' => array(
1306
- 'requires_extension' => array(
1307
- 'amp-hulu',
1308
- ),
1309
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-hulu',
1310
- ),
1311
- ),
1312
- ),
1313
- 'amp-iframe' => array(
1314
- array(
1315
- 'attr_spec_list' => array(
1316
- '[src]' => array(),
1317
- 'allow' => array(),
1318
- 'allowfullscreen' => array(
1319
- 'value' => '',
1320
- ),
1321
- 'allowpaymentrequest' => array(
1322
- 'value' => '',
1323
- ),
1324
- 'allowtransparency' => array(
1325
- 'value' => '',
1326
- ),
1327
- 'frameborder' => array(
1328
- 'value_regex' => '0|1',
1329
- ),
1330
- 'media' => array(),
1331
- 'noloading' => array(
1332
- 'value' => '',
1333
- ),
1334
- 'referrerpolicy' => array(),
1335
- 'resizable' => array(
1336
- 'value' => '',
1337
- ),
1338
- 'sandbox' => array(),
1339
- 'scrolling' => array(
1340
- 'value_regex' => 'auto|yes|no',
1341
- ),
1342
- 'src' => array(
1343
- 'blacklisted_value_regex' => '__amp_source_origin',
1344
- 'value_url' => array(
1345
- 'allow_relative' => true,
1346
- 'allowed_protocol' => array(
1347
- 'data',
1348
- 'https',
1349
- ),
1350
- ),
1351
- ),
1352
- 'srcdoc' => array(),
1353
- ),
1354
- 'tag_spec' => array(
1355
- 'requires_extension' => array(
1356
- 'amp-iframe',
1357
- ),
1358
- ),
1359
- ),
1360
- ),
1361
- 'amp-ima-video' => array(
1362
- array(
1363
- 'attr_spec_list' => array(
1364
- 'autoplay' => array(
1365
- 'value' => '',
1366
- ),
1367
- 'data-src' => array(
1368
- 'blacklisted_value_regex' => '__amp_source_origin',
1369
- 'value_url' => array(
1370
- 'allow_relative' => true,
1371
- 'allowed_protocol' => array(
1372
- 'https',
1373
- ),
1374
- ),
1375
- ),
1376
- 'data-tag' => array(
1377
- 'mandatory' => true,
1378
- 'value_url' => array(
1379
- 'allow_relative' => true,
1380
- 'allowed_protocol' => array(
1381
- 'https',
1382
- ),
1383
- ),
1384
- ),
1385
- 'media' => array(),
1386
- 'noloading' => array(
1387
- 'value' => '',
1388
- ),
1389
- ),
1390
- 'tag_spec' => array(
1391
- 'requires_extension' => array(
1392
- 'amp-ima-video',
1393
- ),
1394
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ima-video',
1395
- ),
1396
- ),
1397
- ),
1398
- 'amp-image-lightbox' => array(
1399
- array(
1400
- 'attr_spec_list' => array(
1401
- 'controls' => array(),
1402
- 'media' => array(),
1403
- 'noloading' => array(
1404
- 'value' => '',
1405
- ),
1406
- ),
1407
- 'tag_spec' => array(
1408
- 'requires_extension' => array(
1409
- 'amp-image-lightbox',
1410
- ),
1411
- ),
1412
- ),
1413
- ),
1414
- 'amp-img' => array(
1415
- array(
1416
- 'attr_spec_list' => array(
1417
- '[alt]' => array(),
1418
- '[attribution]' => array(),
1419
- '[src]' => array(),
1420
- '[srcset]' => array(),
1421
- 'alt' => array(),
1422
- 'attribution' => array(),
1423
- 'lightbox' => array(),
1424
- 'lightbox-exclude' => array(
1425
- 'value' => '',
1426
- ),
1427
- 'lightbox-thumbnail-id' => array(
1428
- 'value_regex_casei' => '^[a-z][a-z\\d_-]*',
1429
- ),
1430
- 'media' => array(),
1431
- 'noloading' => array(
1432
- 'value' => '',
1433
- ),
1434
- 'placeholder' => array(),
1435
- 'src' => array(
1436
- 'alternative_names' => array(
1437
- 'srcset',
1438
- ),
1439
- 'blacklisted_value_regex' => '__amp_source_origin',
1440
- 'mandatory' => true,
1441
- 'value_url' => array(
1442
- 'allow_relative' => true,
1443
- 'allowed_protocol' => array(
1444
- 'data',
1445
- 'http',
1446
- 'https',
1447
- ),
1448
- ),
1449
- ),
1450
- ),
1451
- 'tag_spec' => array(
1452
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-img',
1453
- ),
1454
- ),
1455
- ),
1456
- 'amp-imgur' => array(
1457
- array(
1458
- 'attr_spec_list' => array(
1459
- 'data-imgur-id' => array(
1460
- 'mandatory' => true,
1461
- ),
1462
- 'media' => array(),
1463
- 'noloading' => array(
1464
- 'value' => '',
1465
- ),
1466
- ),
1467
- 'tag_spec' => array(
1468
- 'requires_extension' => array(
1469
- 'amp-imgur',
1470
- ),
1471
- ),
1472
- ),
1473
- ),
1474
- 'amp-instagram' => array(
1475
- array(
1476
- 'attr_spec_list' => array(
1477
- 'alt' => array(),
1478
- 'data-shortcode' => array(
1479
- 'mandatory' => true,
1480
- ),
1481
- 'media' => array(),
1482
- 'noloading' => array(
1483
- 'value' => '',
1484
- ),
1485
- ),
1486
- 'tag_spec' => array(
1487
- 'requires_extension' => array(
1488
- 'amp-instagram',
1489
- ),
1490
- ),
1491
- ),
1492
- ),
1493
- 'amp-install-serviceworker' => array(
1494
- array(
1495
- 'attr_spec_list' => array(
1496
- 'data-iframe-src' => array(
1497
- 'blacklisted_value_regex' => '__amp_source_origin',
1498
- 'value_url' => array(
1499
- 'allow_relative' => true,
1500
- 'allowed_protocol' => array(
1501
- 'https',
1502
- ),
1503
- ),
1504
- ),
1505
- 'src' => array(
1506
- 'blacklisted_value_regex' => '__amp_source_origin',
1507
- 'mandatory' => true,
1508
- 'value_url' => array(
1509
- 'allow_relative' => true,
1510
- 'allowed_protocol' => array(
1511
- 'https',
1512
- ),
1513
- ),
1514
- ),
1515
- ),
1516
- 'tag_spec' => array(
1517
- 'requires_extension' => array(
1518
- 'amp-install-serviceworker',
1519
- ),
1520
- ),
1521
- ),
1522
- ),
1523
- 'amp-izlesene' => array(
1524
- array(
1525
- 'attr_spec_list' => array(
1526
- 'data-videoid' => array(
1527
- 'mandatory' => true,
1528
- 'value_regex' => '[0-9]+',
1529
- ),
1530
- 'media' => array(),
1531
- 'noloading' => array(
1532
- 'value' => '',
1533
- ),
1534
- ),
1535
- 'tag_spec' => array(
1536
- 'requires_extension' => array(
1537
- 'amp-izlesene',
1538
- ),
1539
- ),
1540
- ),
1541
- ),
1542
- 'amp-jwplayer' => array(
1543
- array(
1544
- 'attr_spec_list' => array(
1545
- 'data-media-id' => array(
1546
- 'value_regex_casei' => '[0-9a-z]{8}',
1547
- ),
1548
- 'data-player-id' => array(
1549
- 'mandatory' => true,
1550
- 'value_regex_casei' => '[0-9a-z]{8}',
1551
- ),
1552
- 'data-playlist-id' => array(
1553
- 'value_regex_casei' => '[0-9a-z]{8}',
1554
- ),
1555
- ),
1556
- 'tag_spec' => array(
1557
- 'requires_extension' => array(
1558
- 'amp-jwplayer',
1559
- ),
1560
- ),
1561
- ),
1562
- ),
1563
- 'amp-kaltura-player' => array(
1564
- array(
1565
- 'attr_spec_list' => array(
1566
- 'data-partner' => array(
1567
- 'mandatory' => true,
1568
- ),
1569
- 'media' => array(),
1570
- 'noloading' => array(
1571
- 'value' => '',
1572
- ),
1573
- ),
1574
- 'tag_spec' => array(
1575
- 'requires_extension' => array(
1576
- 'amp-kaltura-player',
1577
- ),
1578
- ),
1579
- ),
1580
- ),
1581
- 'amp-layout' => array(
1582
- array(
1583
- 'attr_spec_list' => array(
1584
- 'media' => array(),
1585
- 'noloading' => array(
1586
- 'value' => '',
1587
- ),
1588
- ),
1589
- 'tag_spec' => array(
1590
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-layout',
1591
- ),
1592
- ),
1593
- ),
1594
- 'amp-lightbox' => array(
1595
- array(
1596
- 'attr_spec_list' => array(
1597
- 'controls' => array(),
1598
- 'from' => array(),
1599
- 'media' => array(),
1600
- 'noloading' => array(
1601
- 'value' => '',
1602
- ),
1603
- 'scrollable' => array(),
1604
- ),
1605
- 'tag_spec' => array(
1606
- 'requires_extension' => array(
1607
- 'amp-lightbox',
1608
- ),
1609
- ),
1610
- ),
1611
- ),
1612
- 'amp-list' => array(
1613
- array(
1614
- 'attr_spec_list' => array(
1615
- '[src]' => array(),
1616
- '[state]' => array(),
1617
- 'credentials' => array(),
1618
- 'items' => array(),
1619
- 'max-items' => array(),
1620
- 'media' => array(),
1621
- 'noloading' => array(
1622
- 'value' => '',
1623
- ),
1624
- 'reset-on-refresh' => array(
1625
- 'value' => '',
1626
- ),
1627
- 'single-item' => array(),
1628
- 'src' => array(
1629
- 'blacklisted_value_regex' => '__amp_source_origin',
1630
- 'mandatory' => true,
1631
- 'value_url' => array(
1632
- 'allow_relative' => true,
1633
- 'allowed_protocol' => array(
1634
- 'https',
1635
- ),
1636
- ),
1637
- ),
1638
- 'template' => array(),
1639
- ),
1640
- 'tag_spec' => array(
1641
- 'requires_extension' => array(
1642
- 'amp-list',
1643
- ),
1644
- ),
1645
- ),
1646
- array(
1647
- 'attr_spec_list' => array(
1648
- '[src]' => array(
1649
- 'mandatory' => true,
1650
- ),
1651
- 'credentials' => array(),
1652
- 'items' => array(),
1653
- 'max-items' => array(),
1654
- 'media' => array(),
1655
- 'noloading' => array(
1656
- 'value' => '',
1657
- ),
1658
- 'single-item' => array(),
1659
- 'src' => array(
1660
- 'blacklisted_value_regex' => '__amp_source_origin',
1661
- 'value_url' => array(
1662
- 'allow_relative' => true,
1663
- 'allowed_protocol' => array(
1664
- 'https',
1665
- ),
1666
- ),
1667
- ),
1668
- 'template' => array(),
1669
- ),
1670
- 'tag_spec' => array(
1671
- 'requires_extension' => array(
1672
- 'amp-list',
1673
- ),
1674
- 'spec_name' => 'AMP-LIST [SRC]',
1675
- ),
1676
- ),
1677
- ),
1678
- 'amp-live-list' => array(
1679
- array(
1680
- 'attr_spec_list' => array(
1681
- 'data-max-items-per-page' => array(
1682
- 'mandatory' => true,
1683
- 'value_regex' => '\\d+',
1684
- ),
1685
- 'data-poll-interval' => array(
1686
- 'value_regex' => '\\d{5,}',
1687
- ),
1688
- 'disabled' => array(
1689
- 'value' => '',
1690
- ),
1691
- 'id' => array(
1692
- 'mandatory' => true,
1693
- ),
1694
- 'sort' => array(
1695
- 'value_regex' => 'ascending',
1696
- ),
1697
- ),
1698
- 'tag_spec' => array(
1699
- 'requires_extension' => array(
1700
- 'amp-live-list',
1701
- ),
1702
- ),
1703
- ),
1704
- ),
1705
- 'amp-mathml' => array(
1706
- array(
1707
- 'attr_spec_list' => array(
1708
- 'data-formula' => array(
1709
- 'mandatory' => true,
1710
- ),
1711
- 'inline' => array(),
1712
- 'media' => array(),
1713
- 'noloading' => array(
1714
- 'value' => '',
1715
- ),
1716
- ),
1717
- 'tag_spec' => array(
1718
- 'requires_extension' => array(
1719
- 'amp-mathml',
1720
- ),
1721
- ),
1722
- ),
1723
- ),
1724
- 'amp-nexxtv-player' => array(
1725
- array(
1726
- 'attr_spec_list' => array(
1727
- 'data-client' => array(
1728
- 'mandatory' => true,
1729
- ),
1730
- 'data-mediaid' => array(
1731
- 'mandatory' => true,
1732
- 'value_regex' => '[^=/?:]+',
1733
- ),
1734
- 'data-mode' => array(
1735
- 'value_regex' => 'api|static',
1736
- ),
1737
- 'data-origin' => array(
1738
- 'value_url' => array(
1739
- 'allow_empty' => true,
1740
- 'allowed_protocol' => array(
1741
- 'https',
1742
- 'http',
1743
- ),
1744
- ),
1745
- ),
1746
- 'data-streamtype' => array(
1747
- 'value_regex' => 'album|audio|live|playlist|playlist-marked|video',
1748
- ),
1749
- 'media' => array(),
1750
- 'noloading' => array(
1751
- 'value' => '',
1752
- ),
1753
- ),
1754
- 'tag_spec' => array(
1755
- 'requires_extension' => array(
1756
- 'amp-nexxtv-player',
1757
- ),
1758
- ),
1759
- ),
1760
- ),
1761
- 'amp-o2-player' => array(
1762
- array(
1763
- 'attr_spec_list' => array(
1764
- 'data-bcid' => array(
1765
- 'mandatory' => true,
1766
- ),
1767
- 'data-pid' => array(
1768
- 'mandatory' => true,
1769
- ),
1770
- 'media' => array(),
1771
- 'noloading' => array(
1772
- 'value' => '',
1773
- ),
1774
- ),
1775
- 'tag_spec' => array(
1776
- 'requires_extension' => array(
1777
- 'amp-o2-player',
1778
- ),
1779
- ),
1780
- ),
1781
- ),
1782
- 'amp-ooyala-player' => array(
1783
- array(
1784
- 'attr_spec_list' => array(
1785
- 'data-embedcode' => array(
1786
- 'mandatory' => true,
1787
- ),
1788
- 'data-pcode' => array(
1789
- 'mandatory' => true,
1790
- ),
1791
- 'data-playerid' => array(
1792
- 'mandatory' => true,
1793
- ),
1794
- 'media' => array(),
1795
- 'noloading' => array(
1796
- 'value' => '',
1797
- ),
1798
- ),
1799
- 'tag_spec' => array(
1800
- 'requires_extension' => array(
1801
- 'amp-ooyala-player',
1802
- ),
1803
- ),
1804
- ),
1805
- ),
1806
- 'amp-pinterest' => array(
1807
- array(
1808
- 'attr_spec_list' => array(
1809
- 'alt' => array(),
1810
- 'data-do' => array(
1811
- 'mandatory' => true,
1812
- ),
1813
- 'media' => array(),
1814
- 'noloading' => array(
1815
- 'value' => '',
1816
- ),
1817
- ),
1818
- 'tag_spec' => array(
1819
- 'requires_extension' => array(
1820
- 'amp-pinterest',
1821
- ),
1822
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-pinterest',
1823
- ),
1824
- ),
1825
- ),
1826
- 'amp-pixel' => array(
1827
- array(
1828
- 'attr_spec_list' => array(
1829
- 'allow-ssr-img' => array(),
1830
- 'media' => array(),
1831
- 'noloading' => array(
1832
- 'value' => '',
1833
- ),
1834
- 'referrerpolicy' => array(
1835
- 'value' => 'no-referrer',
1836
- ),
1837
- 'src' => array(
1838
- 'blacklisted_value_regex' => '__amp_source_origin',
1839
- 'mandatory' => true,
1840
- 'value_url' => array(
1841
- 'allow_empty' => true,
1842
- 'allow_relative' => true,
1843
- 'allowed_protocol' => array(
1844
- 'https',
1845
- ),
1846
- ),
1847
- ),
1848
- ),
1849
- 'tag_spec' => array(
1850
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-pixel',
1851
- ),
1852
- ),
1853
- ),
1854
- 'amp-playbuzz' => array(
1855
- array(
1856
- 'attr_spec_list' => array(
1857
- 'data-comments' => array(
1858
- 'value_regex_casei' => '(false|true)',
1859
- ),
1860
- 'data-item' => array(),
1861
- 'data-item-info' => array(
1862
- 'value_regex_casei' => '(false|true)',
1863
- ),
1864
- 'data-share-buttons' => array(
1865
- 'value_regex_casei' => '(false|true)',
1866
- ),
1867
- 'media' => array(),
1868
- 'noloading' => array(
1869
- 'value' => '',
1870
- ),
1871
- 'src' => array(),
1872
- ),
1873
- 'tag_spec' => array(
1874
- 'requires_extension' => array(
1875
- 'amp-playbuzz',
1876
- ),
1877
- ),
1878
- ),
1879
- ),
1880
- 'amp-position-observer' => array(
1881
- array(
1882
- 'attr_spec_list' => array(
1883
- 'intersection-ratios' => array(
1884
- 'value_regex' => '^([0]*?\\.\\d*$|1$|0$)|([0]*?\\.\\d*|1|0)\\s{1}([0]*?\\.\\d*$|1$|0$)',
1885
- ),
1886
- 'media' => array(),
1887
- 'noloading' => array(
1888
- 'value' => '',
1889
- ),
1890
- 'target' => array(),
1891
- 'viewport-margins' => array(
1892
- 'value_regex' => '^(\\d+$|\\d+px$|\\d+vh$)|((\\d+|\\d+px|\\d+vh)\\s{1}(\\d+$|\\d+px$|\\d+vh$))',
1893
- ),
1894
- ),
1895
- 'tag_spec' => array(
1896
- 'requires_extension' => array(
1897
- 'amp-position-observer',
1898
- ),
1899
- ),
1900
- ),
1901
- ),
1902
- 'amp-reach-player' => array(
1903
- array(
1904
- 'attr_spec_list' => array(
1905
- 'data-embed-id' => array(
1906
- 'mandatory' => true,
1907
- 'value_regex' => '[0-9a-z-]+',
1908
- ),
1909
- 'media' => array(),
1910
- 'noloading' => array(
1911
- 'value' => '',
1912
- ),
1913
- ),
1914
- 'tag_spec' => array(
1915
- 'requires_extension' => array(
1916
- 'amp-reach-player',
1917
- ),
1918
- ),
1919
- ),
1920
- ),
1921
- 'amp-reddit' => array(
1922
- array(
1923
- 'attr_spec_list' => array(
1924
- 'data-embedlive' => array(
1925
- 'value_regex_casei' => '(false|true)',
1926
- ),
1927
- 'data-embedparent' => array(
1928
- 'value_regex_casei' => '(false|true)',
1929
- ),
1930
- 'data-embedtype' => array(
1931
- 'mandatory' => true,
1932
- 'value_regex_casei' => '(comment|post)',
1933
- ),
1934
- 'data-src' => array(
1935
- 'mandatory' => true,
1936
- ),
1937
- 'media' => array(),
1938
- 'noloading' => array(
1939
- 'value' => '',
1940
- ),
1941
- ),
1942
- 'tag_spec' => array(
1943
- 'requires_extension' => array(
1944
- 'amp-reddit',
1945
- ),
1946
- ),
1947
- ),
1948
- ),
1949
- 'amp-riddle-quiz' => array(
1950
- array(
1951
- 'attr_spec_list' => array(
1952
- 'data-riddle-id' => array(
1953
- 'mandatory' => true,
1954
- 'value_regex' => '[0-9]+',
1955
- ),
1956
- 'media' => array(),
1957
- 'noloading' => array(
1958
- 'value' => '',
1959
- ),
1960
- ),
1961
- 'tag_spec' => array(
1962
- 'requires_extension' => array(
1963
- 'amp-riddle-quiz',
1964
- ),
1965
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-riddle-quiz',
1966
- ),
1967
- ),
1968
- ),
1969
- 'amp-selector' => array(
1970
- array(
1971
- 'attr_spec_list' => array(
1972
- '[disabled]' => array(),
1973
- '[selected]' => array(),
1974
- 'disabled' => array(
1975
- 'value' => '',
1976
- ),
1977
- 'form' => array(),
1978
- 'keyboard-select-mode' => array(
1979
- 'value_regex_casei' => 'focus|none|select',
1980
- ),
1981
- 'media' => array(),
1982
- 'multiple' => array(
1983
- 'value' => '',
1984
- ),
1985
- 'name' => array(
1986
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
1987
- ),
1988
- 'noloading' => array(
1989
- 'value' => '',
1990
- ),
1991
- ),
1992
- 'tag_spec' => array(
1993
- 'disallowed_ancestor' => array(
1994
- 'amp-selector',
1995
- ),
1996
- 'requires_extension' => array(
1997
- 'amp-selector',
1998
- ),
1999
- ),
2000
- ),
2001
- ),
2002
- 'amp-sidebar' => array(
2003
- array(
2004
- 'attr_spec_list' => array(
2005
- 'media' => array(),
2006
- 'noloading' => array(
2007
- 'value' => '',
2008
- ),
2009
- 'side' => array(
2010
- 'value_regex' => '(left|right)',
2011
- ),
2012
- ),
2013
- 'tag_spec' => array(
2014
- 'mandatory_parent' => 'body',
2015
- 'requires_extension' => array(
2016
- 'amp-sidebar',
2017
- ),
2018
- ),
2019
- ),
2020
- ),
2021
- 'amp-social-share' => array(
2022
- array(
2023
- 'attr_spec_list' => array(
2024
- 'data-share-endpoint' => array(
2025
- 'blacklisted_value_regex' => '__amp_source_origin',
2026
- 'value_url' => array(
2027
- 'allow_relative' => false,
2028
- 'allowed_protocol' => array(
2029
- 'ftp',
2030
- 'http',
2031
- 'https',
2032
- 'mailto',
2033
- 'bbmi',
2034
- 'fb-messenger',
2035
- 'intent',
2036
- 'line',
2037
- 'skype',
2038
- 'sms',
2039
- 'snapchat',
2040
- 'tel',
2041
- 'tg',
2042
- 'threema',
2043
- 'viber',
2044
- 'whatsapp',
2045
- ),
2046
- ),
2047
- ),
2048
- 'media' => array(),
2049
- 'noloading' => array(
2050
- 'value' => '',
2051
- ),
2052
- 'type' => array(
2053
- 'mandatory' => true,
2054
- ),
2055
- ),
2056
- 'tag_spec' => array(
2057
- 'requires_extension' => array(
2058
- 'amp-social-share',
2059
- ),
2060
- ),
2061
- ),
2062
- ),
2063
- 'amp-soundcloud' => array(
2064
- array(
2065
- 'attr_spec_list' => array(
2066
- 'data-color' => array(
2067
- 'value_regex_casei' => '([0-9a-f]{3}){1,2}',
2068
- ),
2069
- 'data-playlistid' => array(
2070
- 'value_regex' => '[0-9]+',
2071
- ),
2072
- 'data-secret-token' => array(
2073
- 'value_regex' => '[A-Za-z0-9_-]+',
2074
- ),
2075
- 'data-trackid' => array(
2076
- 'value_regex' => '[0-9]+',
2077
- ),
2078
- 'data-visual' => array(
2079
- 'value_regex' => 'true|false',
2080
- ),
2081
- 'media' => array(),
2082
- 'noloading' => array(
2083
- 'value' => '',
2084
- ),
2085
- ),
2086
- 'tag_spec' => array(
2087
- 'requires_extension' => array(
2088
- 'amp-soundcloud',
2089
- ),
2090
- ),
2091
- ),
2092
- ),
2093
- 'amp-springboard-player' => array(
2094
- array(
2095
- 'attr_spec_list' => array(
2096
- 'data-content-id' => array(
2097
- 'mandatory' => true,
2098
- ),
2099
- 'data-domain' => array(
2100
- 'mandatory' => true,
2101
- ),
2102
- 'data-items' => array(
2103
- 'mandatory' => true,
2104
- ),
2105
- 'data-mode' => array(
2106
- 'mandatory' => true,
2107
- 'value_regex_casei' => 'playlist|video',
2108
- ),
2109
- 'data-player-id' => array(
2110
- 'mandatory' => true,
2111
- 'value_regex_casei' => '[a-z0-9]+',
2112
- ),
2113
- 'data-site-id' => array(
2114
- 'mandatory' => true,
2115
- 'value_regex' => '[0-9]+',
2116
- ),
2117
- 'media' => array(),
2118
- 'noloading' => array(
2119
- 'value' => '',
2120
- ),
2121
- ),
2122
- 'tag_spec' => array(
2123
- 'requires_extension' => array(
2124
- 'amp-springboard-player',
2125
- ),
2126
- ),
2127
- ),
2128
- ),
2129
- 'amp-state' => array(
2130
- array(
2131
- 'attr_spec_list' => array(
2132
- '[src]' => array(),
2133
- 'credentials' => array(),
2134
- 'id' => array(
2135
- 'mandatory' => true,
2136
- ),
2137
- 'overridable' => array(),
2138
- 'src' => array(
2139
- 'blacklisted_value_regex' => '__amp_source_origin',
2140
- 'value_url' => array(
2141
- 'allow_relative' => true,
2142
- 'allowed_protocol' => array(
2143
- 'https',
2144
- ),
2145
- ),
2146
- ),
2147
- ),
2148
- 'tag_spec' => array(
2149
- 'requires_extension' => array(
2150
- 'amp-bind',
2151
- ),
2152
- 'spec_name' => 'amp-state',
2153
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind',
2154
- ),
2155
- ),
2156
- ),
2157
- 'amp-sticky-ad' => array(
2158
- array(
2159
- 'attr_spec_list' => array(
2160
- 'media' => array(),
2161
- 'noloading' => array(
2162
- 'value' => '',
2163
- ),
2164
- ),
2165
- 'tag_spec' => array(
2166
- 'disallowed_ancestor' => array(
2167
- 'amp-app-banner',
2168
- ),
2169
- 'requires_extension' => array(
2170
- 'amp-sticky-ad',
2171
- ),
2172
- 'unique' => true,
2173
- ),
2174
- ),
2175
- ),
2176
- 'amp-story' => array(
2177
- array(
2178
- 'attr_spec_list' => array(
2179
- 'background-audio' => array(
2180
- 'value_url' => array(
2181
- 'allowed_protocol' => array(
2182
- 'http',
2183
- 'https',
2184
- ),
2185
- ),
2186
- ),
2187
- 'bookend-config-src' => array(
2188
- 'value_url' => array(
2189
- 'allowed_protocol' => array(
2190
- 'http',
2191
- 'https',
2192
- ),
2193
- ),
2194
- ),
2195
- 'standalone' => array(
2196
- 'mandatory' => true,
2197
- 'value' => '',
2198
- ),
2199
- ),
2200
- 'tag_spec' => array(
2201
- 'mandatory_parent' => 'body',
2202
- 'requires_extension' => array(
2203
- 'amp-story',
2204
- ),
2205
- ),
2206
- ),
2207
- ),
2208
- 'amp-story-auto-ads' => array(
2209
- array(
2210
- 'attr_spec_list' => array(),
2211
- 'tag_spec' => array(
2212
- 'mandatory_parent' => 'amp-story',
2213
- 'requires_extension' => array(
2214
- 'amp-story-auto-ads',
2215
- ),
2216
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/extensions/amp-story/amp-story-auto-ads.md',
2217
- 'unique' => true,
2218
- ),
2219
- ),
2220
- ),
2221
- 'amp-story-cta-layer' => array(
2222
- array(
2223
- 'attr_spec_list' => array(),
2224
- 'tag_spec' => array(
2225
- 'mandatory_ancestor' => 'amp-story-page',
2226
- ),
2227
- ),
2228
- ),
2229
- 'amp-story-grid-layer' => array(
2230
- array(
2231
- 'attr_spec_list' => array(
2232
- 'template' => array(
2233
- 'mandatory' => true,
2234
- 'value_regex' => '(fill|horizontal|vertical|thirds)',
2235
- ),
2236
- ),
2237
- 'tag_spec' => array(
2238
- 'mandatory_ancestor' => 'amp-story-page',
2239
- ),
2240
- ),
2241
- ),
2242
- 'amp-story-page' => array(
2243
- array(
2244
- 'attr_spec_list' => array(
2245
- 'auto-advance-after' => array(),
2246
- 'background-audio' => array(
2247
- 'value_url' => array(
2248
- 'allowed_protocol' => array(
2249
- 'http',
2250
- 'https',
2251
- ),
2252
- ),
2253
- ),
2254
- 'id' => array(
2255
- 'mandatory' => true,
2256
- ),
2257
- ),
2258
- 'tag_spec' => array(
2259
- 'mandatory_parent' => 'amp-story',
2260
- 'requires_extension' => array(
2261
- 'amp-story',
2262
- ),
2263
- ),
2264
- ),
2265
- ),
2266
- 'amp-timeago' => array(
2267
- array(
2268
- 'attr_spec_list' => array(
2269
- 'cutoff' => array(
2270
- 'value_regex' => '\\d+',
2271
- ),
2272
- 'datetime' => array(
2273
- 'mandatory' => true,
2274
- 'value_regex' => '\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d(:[0-5]\\d(\\.\\d+)?)?(Z|[+-][0-1][0-9]:[0-5][0-9])',
2275
- ),
2276
- 'locale' => array(),
2277
- 'media' => array(),
2278
- 'noloading' => array(
2279
- 'value' => '',
2280
- ),
2281
- ),
2282
- 'tag_spec' => array(
2283
- 'requires_extension' => array(
2284
- 'amp-timeago',
2285
- ),
2286
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-timeago',
2287
- ),
2288
- ),
2289
- ),
2290
- 'amp-twitter' => array(
2291
- array(
2292
- 'attr_spec_list' => array(
2293
- 'data-tweetid' => array(
2294
- 'mandatory' => true,
2295
- ),
2296
- 'media' => array(),
2297
- 'noloading' => array(
2298
- 'value' => '',
2299
- ),
2300
- ),
2301
- 'tag_spec' => array(
2302
- 'requires_extension' => array(
2303
- 'amp-twitter',
2304
- ),
2305
- ),
2306
- ),
2307
- ),
2308
- 'amp-user-notification' => array(
2309
- array(
2310
- 'attr_spec_list' => array(
2311
- 'data-dismiss-href' => array(
2312
- 'value_url' => array(
2313
- 'allow_empty' => false,
2314
- 'allow_relative' => false,
2315
- 'allowed_protocol' => array(
2316
- 'https',
2317
- ),
2318
- ),
2319
- ),
2320
- 'data-show-if-href' => array(
2321
- 'value_url' => array(
2322
- 'allow_empty' => false,
2323
- 'allow_relative' => false,
2324
- 'allowed_protocol' => array(
2325
- 'https',
2326
- ),
2327
- ),
2328
- ),
2329
- 'enctype' => array(
2330
- 'value' => 'application/x-www-form-urlencoded',
2331
- ),
2332
- 'media' => array(),
2333
- 'noloading' => array(
2334
- 'value' => '',
2335
- ),
2336
- ),
2337
- 'tag_spec' => array(
2338
- 'requires_extension' => array(
2339
- 'amp-user-notification',
2340
- ),
2341
- ),
2342
- ),
2343
- ),
2344
- 'amp-video' => array(
2345
- array(
2346
- 'attr_spec_list' => array(
2347
- '[album]' => array(),
2348
- '[alt]' => array(),
2349
- '[artist]' => array(),
2350
- '[artwork]' => array(),
2351
- '[attribution]' => array(),
2352
- '[controls]' => array(),
2353
- '[controlslist]' => array(),
2354
- '[loop]' => array(),
2355
- '[poster]' => array(),
2356
- '[preload]' => array(),
2357
- '[src]' => array(),
2358
- '[title]' => array(),
2359
- 'album' => array(),
2360
- 'alt' => array(),
2361
- 'artist' => array(),
2362
- 'artwork' => array(),
2363
- 'attribution' => array(),
2364
- 'autoplay' => array(
2365
- 'value' => '',
2366
- ),
2367
- 'controls' => array(
2368
- 'value' => '',
2369
- ),
2370
- 'controlslist' => array(),
2371
- 'crossorigin' => array(),
2372
- 'disableremoteplayback' => array(
2373
- 'value' => '',
2374
- ),
2375
- 'lightbox' => array(),
2376
- 'lightbox-exclude' => array(
2377
- 'value' => '',
2378
- ),
2379
- 'lightbox-thumbnail-id' => array(
2380
- 'value_regex_casei' => '^[a-z][a-z\\d_-]*',
2381
- ),
2382
- 'loop' => array(
2383
- 'value' => '',
2384
- ),
2385
- 'media' => array(),
2386
- 'muted' => array(
2387
- 'value' => '',
2388
- ),
2389
- 'noloading' => array(
2390
- 'value' => '',
2391
- ),
2392
- 'placeholder' => array(),
2393
- 'poster' => array(),
2394
- 'preload' => array(
2395
- 'value_regex' => '(none|metadata|auto|)',
2396
- ),
2397
- 'src' => array(
2398
- 'blacklisted_value_regex' => '__amp_source_origin',
2399
- 'value_url' => array(
2400
- 'allow_relative' => true,
2401
- 'allowed_protocol' => array(
2402
- 'https',
2403
- ),
2404
- ),
2405
- ),
2406
- ),
2407
- 'tag_spec' => array(
2408
- 'also_requires_tag_warning' => array(
2409
- 'amp-video extension .js script',
2410
- ),
2411
- 'disallowed_ancestor' => array(
2412
- 'amp-story',
2413
- ),
2414
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
2415
- ),
2416
- ),
2417
- array(
2418
- 'attr_spec_list' => array(
2419
- '[album]' => array(),
2420
- '[alt]' => array(),
2421
- '[artist]' => array(),
2422
- '[artwork]' => array(),
2423
- '[attribution]' => array(),
2424
- '[controls]' => array(),
2425
- '[controlslist]' => array(),
2426
- '[loop]' => array(),
2427
- '[poster]' => array(),
2428
- '[preload]' => array(),
2429
- '[src]' => array(),
2430
- '[title]' => array(),
2431
- 'album' => array(),
2432
- 'alt' => array(),
2433
- 'artist' => array(),
2434
- 'artwork' => array(),
2435
- 'attribution' => array(),
2436
- 'autoplay' => array(
2437
- 'value' => '',
2438
- ),
2439
- 'controls' => array(
2440
- 'value' => '',
2441
- ),
2442
- 'controlslist' => array(),
2443
- 'crossorigin' => array(),
2444
- 'disableremoteplayback' => array(
2445
- 'value' => '',
2446
- ),
2447
- 'loop' => array(
2448
- 'value' => '',
2449
- ),
2450
- 'media' => array(),
2451
- 'muted' => array(
2452
- 'value' => '',
2453
- ),
2454
- 'noloading' => array(
2455
- 'value' => '',
2456
- ),
2457
- 'placeholder' => array(),
2458
- 'poster' => array(
2459
- 'mandatory' => true,
2460
- ),
2461
- 'preload' => array(
2462
- 'value_regex' => '(none|metadata|auto|)',
2463
- ),
2464
- 'src' => array(
2465
- 'blacklisted_value_regex' => '__amp_source_origin',
2466
- 'value_url' => array(
2467
- 'allow_relative' => true,
2468
- 'allowed_protocol' => array(
2469
- 'https',
2470
- ),
2471
- ),
2472
- ),
2473
- ),
2474
- 'tag_spec' => array(
2475
- 'mandatory_ancestor' => 'amp-story',
2476
- 'requires_extension' => array(
2477
- 'amp-video',
2478
- ),
2479
- 'spec_name' => 'amp-story >> amp-video',
2480
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
2481
- ),
2482
- ),
2483
- ),
2484
- 'amp-vimeo' => array(
2485
- array(
2486
- 'attr_spec_list' => array(
2487
- 'data-videoid' => array(
2488
- 'mandatory' => true,
2489
- 'value_regex' => '[0-9]+',
2490
- ),
2491
- 'media' => array(),
2492
- 'noloading' => array(
2493
- 'value' => '',
2494
- ),
2495
- ),
2496
- 'tag_spec' => array(
2497
- 'requires_extension' => array(
2498
- 'amp-vimeo',
2499
- ),
2500
- ),
2501
- ),
2502
- ),
2503
- 'amp-vine' => array(
2504
- array(
2505
- 'attr_spec_list' => array(
2506
- 'data-vineid' => array(
2507
- 'mandatory' => true,
2508
- ),
2509
- 'media' => array(),
2510
- 'noloading' => array(
2511
- 'value' => '',
2512
- ),
2513
- ),
2514
- 'tag_spec' => array(
2515
- 'requires_extension' => array(
2516
- 'amp-vine',
2517
- ),
2518
- ),
2519
- ),
2520
- ),
2521
- 'amp-vk' => array(
2522
- array(
2523
- 'attr_spec_list' => array(
2524
- 'data-embedtype' => array(
2525
- 'mandatory' => true,
2526
- ),
2527
- 'media' => array(),
2528
- 'noloading' => array(
2529
- 'value' => '',
2530
- ),
2531
- ),
2532
- 'tag_spec' => array(
2533
- 'requires_extension' => array(
2534
- 'amp-vk',
2535
- ),
2536
- ),
2537
- ),
2538
- ),
2539
- 'amp-web-push' => array(
2540
- array(
2541
- 'attr_spec_list' => array(
2542
- 'helper-iframe-url' => array(
2543
- 'mandatory' => true,
2544
- 'value_url' => array(
2545
- 'allow_relative' => false,
2546
- 'allowed_protocol' => array(
2547
- 'https',
2548
- ),
2549
- ),
2550
- ),
2551
- 'id' => array(
2552
- 'mandatory' => true,
2553
- 'value_regex' => 'amp-web-push',
2554
- ),
2555
- 'media' => array(),
2556
- 'noloading' => array(
2557
- 'value' => '',
2558
- ),
2559
- 'permission-dialog-url' => array(
2560
- 'mandatory' => true,
2561
- 'value_url' => array(
2562
- 'allow_relative' => false,
2563
- 'allowed_protocol' => array(
2564
- 'https',
2565
- ),
2566
- ),
2567
- ),
2568
- 'service-worker-url' => array(
2569
- 'mandatory' => true,
2570
- 'value_url' => array(
2571
- 'allow_relative' => false,
2572
- 'allowed_protocol' => array(
2573
- 'https',
2574
- ),
2575
- ),
2576
- ),
2577
- ),
2578
- 'tag_spec' => array(
2579
- 'requires_extension' => array(
2580
- 'amp-web-push',
2581
- ),
2582
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-web-push',
2583
- ),
2584
- ),
2585
- ),
2586
- 'amp-web-push-widget' => array(
2587
- array(
2588
- 'attr_spec_list' => array(
2589
- 'media' => array(),
2590
- 'noloading' => array(
2591
- 'value' => '',
2592
- ),
2593
- 'visibility' => array(
2594
- 'mandatory' => true,
2595
- 'value_regex' => '(blocked|subscribed|unsubscribed)',
2596
- ),
2597
- ),
2598
- 'tag_spec' => array(
2599
- 'requires_extension' => array(
2600
- 'amp-web-push',
2601
- ),
2602
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-web-push',
2603
- ),
2604
- ),
2605
- ),
2606
- 'amp-wistia-player' => array(
2607
- array(
2608
- 'attr_spec_list' => array(
2609
- 'data-media-hashed-id' => array(
2610
- 'mandatory' => true,
2611
- 'value_regex' => '[0-9a-zA-Z]+',
2612
- ),
2613
- 'media' => array(),
2614
- 'noloading' => array(
2615
- 'value' => '',
2616
- ),
2617
- ),
2618
- 'tag_spec' => array(
2619
- 'requires_extension' => array(
2620
- 'amp-wistia-player',
2621
- ),
2622
- ),
2623
- ),
2624
- ),
2625
- 'amp-youtube' => array(
2626
- array(
2627
- 'attr_spec_list' => array(
2628
- '[data-videoid]' => array(),
2629
- 'autoplay' => array(),
2630
- 'credentials' => array(
2631
- 'value_regex_casei' => '(include|omit)',
2632
- ),
2633
- 'data-live-channelid' => array(
2634
- 'value_regex' => '[^=/?:]+',
2635
- ),
2636
- 'data-videoid' => array(
2637
- 'value_regex' => '[^=/?:]+',
2638
- ),
2639
- 'lightbox' => array(),
2640
- 'lightbox-exclude' => array(
2641
- 'value' => '',
2642
- ),
2643
- 'lightbox-thumbnail-id' => array(
2644
- 'value_regex_casei' => '^[a-z][a-z\\d_-]*',
2645
- ),
2646
- 'media' => array(),
2647
- 'noloading' => array(
2648
- 'value' => '',
2649
- ),
2650
- ),
2651
- 'tag_spec' => array(
2652
- 'requires_extension' => array(
2653
- 'amp-youtube',
2654
- ),
2655
- ),
2656
- ),
2657
- ),
2658
- 'article' => array(
2659
- array(
2660
- 'attr_spec_list' => array(),
2661
- 'tag_spec' => array(),
2662
- ),
2663
- ),
2664
- 'aside' => array(
2665
- array(
2666
- 'attr_spec_list' => array(),
2667
- 'tag_spec' => array(),
2668
- ),
2669
- ),
2670
- 'audio' => array(
2671
- array(
2672
- 'attr_spec_list' => array(
2673
- 'autoplay' => array(),
2674
- 'controls' => array(),
2675
- 'loop' => array(),
2676
- 'muted' => array(),
2677
- 'preload' => array(),
2678
- 'src' => array(
2679
- 'blacklisted_value_regex' => '__amp_source_origin',
2680
- 'value_url' => array(
2681
- 'allow_relative' => false,
2682
- 'allowed_protocol' => array(
2683
- 'data',
2684
- 'https',
2685
- ),
2686
- ),
2687
- ),
2688
- ),
2689
- 'tag_spec' => array(
2690
- 'mandatory_ancestor' => 'noscript',
2691
- 'mandatory_ancestor_suggested_alternative' => 'amp-audio',
2692
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
2693
- ),
2694
- ),
2695
- ),
2696
- 'b' => array(
2697
- array(
2698
- 'attr_spec_list' => array(),
2699
- 'tag_spec' => array(),
2700
- ),
2701
- ),
2702
- 'base' => array(
2703
- array(
2704
- 'attr_spec_list' => array(
2705
- 'href' => array(
2706
- 'value' => '/',
2707
- ),
2708
- 'target' => array(
2709
- 'value_regex_casei' => '(_blank|_self|_top)',
2710
- ),
2711
- ),
2712
- 'tag_spec' => array(
2713
- 'mandatory_parent' => 'head',
2714
- 'unique' => true,
2715
- ),
2716
- ),
2717
- ),
2718
- 'bdi' => array(
2719
- array(
2720
- 'attr_spec_list' => array(),
2721
- 'tag_spec' => array(),
2722
- ),
2723
- ),
2724
- 'bdo' => array(
2725
- array(
2726
- 'attr_spec_list' => array(
2727
- 'dir' => array(),
2728
- ),
2729
- 'tag_spec' => array(),
2730
- ),
2731
- ),
2732
- 'big' => array(
2733
- array(
2734
- 'attr_spec_list' => array(),
2735
- 'tag_spec' => array(),
2736
- ),
2737
- ),
2738
- 'blockquote' => array(
2739
- array(
2740
- 'attr_spec_list' => array(
2741
- 'align' => array(),
2742
- 'cite' => array(
2743
- 'blacklisted_value_regex' => '__amp_source_origin',
2744
- 'value_url' => array(
2745
- 'allow_empty' => true,
2746
- 'allow_relative' => true,
2747
- 'allowed_protocol' => array(
2748
- 'http',
2749
- 'https',
2750
- ),
2751
- ),
2752
- ),
2753
- ),
2754
- 'tag_spec' => array(),
2755
- ),
2756
- ),
2757
- 'body' => array(
2758
- array(
2759
- 'attr_spec_list' => array(),
2760
- 'tag_spec' => array(
2761
- 'mandatory' => true,
2762
- 'mandatory_parent' => 'html',
2763
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
2764
- 'unique' => true,
2765
- ),
2766
- ),
2767
- ),
2768
- 'br' => array(
2769
- array(
2770
- 'attr_spec_list' => array(),
2771
- 'tag_spec' => array(),
2772
- ),
2773
- ),
2774
- 'button' => array(
2775
- array(
2776
- 'attr_spec_list' => array(
2777
- '[disabled]' => array(),
2778
- '[type]' => array(),
2779
- '[value]' => array(),
2780
- 'disabled' => array(
2781
- 'value' => '',
2782
- ),
2783
- 'name' => array(
2784
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
2785
- ),
2786
- 'role' => array(),
2787
- 'tabindex' => array(),
2788
- 'type' => array(),
2789
- 'value' => array(),
2790
- ),
2791
- 'tag_spec' => array(),
2792
- ),
2793
- array(
2794
- 'attr_spec_list' => array(
2795
- 'name' => array(
2796
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
2797
- ),
2798
- 'open-button' => array(
2799
- 'value' => '',
2800
- ),
2801
- 'role' => array(),
2802
- 'tabindex' => array(),
2803
- 'type' => array(),
2804
- 'value' => array(),
2805
- ),
2806
- 'tag_spec' => array(
2807
- 'mandatory_ancestor' => 'amp-app-banner',
2808
- 'spec_name' => 'amp-app-banner button[open-button]',
2809
- ),
2810
- ),
2811
- ),
2812
- 'caption' => array(
2813
- array(
2814
- 'attr_spec_list' => array(),
2815
- 'tag_spec' => array(),
2816
- ),
2817
- ),
2818
- 'center' => array(
2819
- array(
2820
- 'attr_spec_list' => array(),
2821
- 'tag_spec' => array(),
2822
- ),
2823
- ),
2824
- 'circle' => array(
2825
- array(
2826
- 'attr_spec_list' => array(
2827
- 'alignment-baseline' => array(),
2828
- 'baseline-shift' => array(),
2829
- 'clip' => array(),
2830
- 'clip-path' => array(),
2831
- 'clip-rule' => array(),
2832
- 'color' => array(),
2833
- 'color-interpolation' => array(),
2834
- 'color-interpolation-filters' => array(),
2835
- 'color-profile' => array(),
2836
- 'color-rendering' => array(),
2837
- 'cursor' => array(),
2838
- 'cx' => array(),
2839
- 'cy' => array(),
2840
- 'direction' => array(),
2841
- 'display' => array(),
2842
- 'dominant-baseline' => array(),
2843
- 'enable-background' => array(),
2844
- 'externalresourcesrequired' => array(),
2845
- 'fill' => array(),
2846
- 'fill-opacity' => array(),
2847
- 'fill-rule' => array(),
2848
- 'filter' => array(),
2849
- 'flood-color' => array(),
2850
- 'flood-opacity' => array(),
2851
- 'font-family' => array(),
2852
- 'font-size' => array(),
2853
- 'font-size-adjust' => array(),
2854
- 'font-stretch' => array(),
2855
- 'font-style' => array(),
2856
- 'font-variant' => array(),
2857
- 'font-weight' => array(),
2858
- 'glyph-orientation-horizontal' => array(),
2859
- 'glyph-orientation-vertical' => array(),
2860
- 'image-rendering' => array(),
2861
- 'kerning' => array(),
2862
- 'letter-spacing' => array(),
2863
- 'lighting-color' => array(),
2864
- 'marker-end' => array(),
2865
- 'marker-mid' => array(),
2866
- 'marker-start' => array(),
2867
- 'mask' => array(),
2868
- 'opacity' => array(),
2869
- 'overflow' => array(),
2870
- 'pointer-events' => array(),
2871
- 'r' => array(),
2872
- 'requiredextensions' => array(),
2873
- 'requiredfeatures' => array(),
2874
- 'shape-rendering' => array(),
2875
- 'sketch:type' => array(),
2876
- 'stop-color' => array(),
2877
- 'stop-opacity' => array(),
2878
- 'stroke' => array(),
2879
- 'stroke-dasharray' => array(),
2880
- 'stroke-dashoffset' => array(),
2881
- 'stroke-linecap' => array(),
2882
- 'stroke-linejoin' => array(),
2883
- 'stroke-miterlimit' => array(),
2884
- 'stroke-opacity' => array(),
2885
- 'stroke-width' => array(),
2886
- 'style' => array(
2887
- 'blacklisted_value_regex' => '!important',
2888
- ),
2889
- 'systemlanguage' => array(),
2890
- 'text-anchor' => array(),
2891
- 'text-decoration' => array(),
2892
- 'text-rendering' => array(),
2893
- 'transform' => array(),
2894
- 'unicode-bidi' => array(),
2895
- 'vector-effect' => array(),
2896
- 'visibility' => array(),
2897
- 'word-spacing' => array(),
2898
- 'writing-mode' => array(),
2899
- 'xml:lang' => array(),
2900
- 'xml:space' => array(),
2901
- 'xmlns' => array(),
2902
- 'xmlns:xlink' => array(),
2903
- ),
2904
- 'tag_spec' => array(
2905
- 'mandatory_ancestor' => 'svg',
2906
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
2907
- ),
2908
- ),
2909
- ),
2910
- 'cite' => array(
2911
- array(
2912
- 'attr_spec_list' => array(),
2913
- 'tag_spec' => array(),
2914
- ),
2915
- ),
2916
- 'clippath' => array(
2917
- array(
2918
- 'attr_spec_list' => array(
2919
- 'alignment-baseline' => array(),
2920
- 'baseline-shift' => array(),
2921
- 'clip' => array(),
2922
- 'clip-path' => array(),
2923
- 'clip-rule' => array(),
2924
- 'clippathunits' => array(),
2925
- 'color' => array(),
2926
- 'color-interpolation' => array(),
2927
- 'color-interpolation-filters' => array(),
2928
- 'color-profile' => array(),
2929
- 'color-rendering' => array(),
2930
- 'cursor' => array(),
2931
- 'direction' => array(),
2932
- 'display' => array(),
2933
- 'dominant-baseline' => array(),
2934
- 'enable-background' => array(),
2935
- 'externalresourcesrequired' => array(),
2936
- 'fill' => array(),
2937
- 'fill-opacity' => array(),
2938
- 'fill-rule' => array(),
2939
- 'filter' => array(),
2940
- 'flood-color' => array(),
2941
- 'flood-opacity' => array(),
2942
- 'font-family' => array(),
2943
- 'font-size' => array(),
2944
- 'font-size-adjust' => array(),
2945
- 'font-stretch' => array(),
2946
- 'font-style' => array(),
2947
- 'font-variant' => array(),
2948
- 'font-weight' => array(),
2949
- 'glyph-orientation-horizontal' => array(),
2950
- 'glyph-orientation-vertical' => array(),
2951
- 'image-rendering' => array(),
2952
- 'kerning' => array(),
2953
- 'letter-spacing' => array(),
2954
- 'lighting-color' => array(),
2955
- 'marker-end' => array(),
2956
- 'marker-mid' => array(),
2957
- 'marker-start' => array(),
2958
- 'mask' => array(),
2959
- 'opacity' => array(),
2960
- 'overflow' => array(),
2961
- 'pointer-events' => array(),
2962
- 'requiredextensions' => array(),
2963
- 'requiredfeatures' => array(),
2964
- 'shape-rendering' => array(),
2965
- 'stop-color' => array(),
2966
- 'stop-opacity' => array(),
2967
- 'stroke' => array(),
2968
- 'stroke-dasharray' => array(),
2969
- 'stroke-dashoffset' => array(),
2970
- 'stroke-linecap' => array(),
2971
- 'stroke-linejoin' => array(),
2972
- 'stroke-miterlimit' => array(),
2973
- 'stroke-opacity' => array(),
2974
- 'stroke-width' => array(),
2975
- 'style' => array(
2976
- 'blacklisted_value_regex' => '!important',
2977
- ),
2978
- 'systemlanguage' => array(),
2979
- 'text-anchor' => array(),
2980
- 'text-decoration' => array(),
2981
- 'text-rendering' => array(),
2982
- 'transform' => array(),
2983
- 'unicode-bidi' => array(),
2984
- 'vector-effect' => array(),
2985
- 'visibility' => array(),
2986
- 'word-spacing' => array(),
2987
- 'writing-mode' => array(),
2988
- 'xml:lang' => array(),
2989
- 'xml:space' => array(),
2990
- 'xmlns' => array(),
2991
- 'xmlns:xlink' => array(),
2992
- ),
2993
- 'tag_spec' => array(
2994
- 'mandatory_ancestor' => 'svg',
2995
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
2996
- ),
2997
- ),
2998
- ),
2999
- 'code' => array(
3000
- array(
3001
- 'attr_spec_list' => array(),
3002
- 'tag_spec' => array(),
3003
- ),
3004
- ),
3005
- 'col' => array(
3006
- array(
3007
- 'attr_spec_list' => array(
3008
- 'span' => array(),
3009
- ),
3010
- 'tag_spec' => array(),
3011
- ),
3012
- ),
3013
- 'colgroup' => array(
3014
- array(
3015
- 'attr_spec_list' => array(
3016
- 'span' => array(),
3017
- ),
3018
- 'tag_spec' => array(),
3019
- ),
3020
- ),
3021
- 'data' => array(
3022
- array(
3023
- 'attr_spec_list' => array(),
3024
- 'tag_spec' => array(),
3025
- ),
3026
- ),
3027
- 'datalist' => array(
3028
- array(
3029
- 'attr_spec_list' => array(),
3030
- 'tag_spec' => array(
3031
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
3032
- ),
3033
- ),
3034
- ),
3035
- 'dd' => array(
3036
- array(
3037
- 'attr_spec_list' => array(),
3038
- 'tag_spec' => array(),
3039
- ),
3040
- ),
3041
- 'defs' => array(
3042
- array(
3043
- 'attr_spec_list' => array(
3044
- 'alignment-baseline' => array(),
3045
- 'baseline-shift' => array(),
3046
- 'clip' => array(),
3047
- 'clip-path' => array(),
3048
- 'clip-rule' => array(),
3049
- 'color' => array(),
3050
- 'color-interpolation' => array(),
3051
- 'color-interpolation-filters' => array(),
3052
- 'color-profile' => array(),
3053
- 'color-rendering' => array(),
3054
- 'cursor' => array(),
3055
- 'direction' => array(),
3056
- 'display' => array(),
3057
- 'dominant-baseline' => array(),
3058
- 'enable-background' => array(),
3059
- 'externalresourcesrequired' => array(),
3060
- 'fill' => array(),
3061
- 'fill-opacity' => array(),
3062
- 'fill-rule' => array(),
3063
- 'filter' => array(),
3064
- 'flood-color' => array(),
3065
- 'flood-opacity' => array(),
3066
- 'font-family' => array(),
3067
- 'font-size' => array(),
3068
- 'font-size-adjust' => array(),
3069
- 'font-stretch' => array(),
3070
- 'font-style' => array(),
3071
- 'font-variant' => array(),
3072
- 'font-weight' => array(),
3073
- 'glyph-orientation-horizontal' => array(),
3074
- 'glyph-orientation-vertical' => array(),
3075
- 'image-rendering' => array(),
3076
- 'kerning' => array(),
3077
- 'letter-spacing' => array(),
3078
- 'lighting-color' => array(),
3079
- 'marker-end' => array(),
3080
- 'marker-mid' => array(),
3081
- 'marker-start' => array(),
3082
- 'mask' => array(),
3083
- 'opacity' => array(),
3084
- 'overflow' => array(),
3085
- 'pointer-events' => array(),
3086
- 'requiredextensions' => array(),
3087
- 'requiredfeatures' => array(),
3088
- 'shape-rendering' => array(),
3089
- 'stop-color' => array(),
3090
- 'stop-opacity' => array(),
3091
- 'stroke' => array(),
3092
- 'stroke-dasharray' => array(),
3093
- 'stroke-dashoffset' => array(),
3094
- 'stroke-linecap' => array(),
3095
- 'stroke-linejoin' => array(),
3096
- 'stroke-miterlimit' => array(),
3097
- 'stroke-opacity' => array(),
3098
- 'stroke-width' => array(),
3099
- 'style' => array(
3100
- 'blacklisted_value_regex' => '!important',
3101
- ),
3102
- 'systemlanguage' => array(),
3103
- 'text-anchor' => array(),
3104
- 'text-decoration' => array(),
3105
- 'text-rendering' => array(),
3106
- 'transform' => array(),
3107
- 'unicode-bidi' => array(),
3108
- 'vector-effect' => array(),
3109
- 'visibility' => array(),
3110
- 'word-spacing' => array(),
3111
- 'writing-mode' => array(),
3112
- 'xml:lang' => array(),
3113
- 'xml:space' => array(),
3114
- 'xmlns' => array(),
3115
- 'xmlns:xlink' => array(),
3116
- ),
3117
- 'tag_spec' => array(
3118
- 'mandatory_ancestor' => 'svg',
3119
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3120
- ),
3121
- ),
3122
- ),
3123
- 'del' => array(
3124
- array(
3125
- 'attr_spec_list' => array(
3126
- 'cite' => array(
3127
- 'blacklisted_value_regex' => '__amp_source_origin',
3128
- 'value_url' => array(
3129
- 'allow_empty' => true,
3130
- 'allow_relative' => true,
3131
- 'allowed_protocol' => array(
3132
- 'http',
3133
- 'https',
3134
- ),
3135
- ),
3136
- ),
3137
- 'datetime' => array(),
3138
- ),
3139
- 'tag_spec' => array(),
3140
- ),
3141
- ),
3142
- 'desc' => array(
3143
- array(
3144
- 'attr_spec_list' => array(
3145
- 'style' => array(
3146
- 'blacklisted_value_regex' => '!important',
3147
- ),
3148
- 'xml:lang' => array(),
3149
- 'xml:space' => array(),
3150
- 'xmlns' => array(),
3151
- 'xmlns:xlink' => array(),
3152
- ),
3153
- 'tag_spec' => array(
3154
- 'mandatory_ancestor' => 'svg',
3155
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3156
- ),
3157
- ),
3158
- ),
3159
- 'dfn' => array(
3160
- array(
3161
- 'attr_spec_list' => array(),
3162
- 'tag_spec' => array(),
3163
- ),
3164
- ),
3165
- 'dir' => array(
3166
- array(
3167
- 'attr_spec_list' => array(),
3168
- 'tag_spec' => array(),
3169
- ),
3170
- ),
3171
- 'div' => array(
3172
- array(
3173
- 'attr_spec_list' => array(
3174
- 'align' => array(),
3175
- ),
3176
- 'tag_spec' => array(),
3177
- ),
3178
- array(
3179
- 'attr_spec_list' => array(
3180
- 'align' => array(),
3181
- 'submitting' => array(
3182
- 'dispatch_key' => 1,
3183
- 'mandatory' => true,
3184
- ),
3185
- ),
3186
- 'tag_spec' => array(
3187
- 'mandatory_parent' => 'form',
3188
- 'spec_name' => 'FORM > DIV [submitting]',
3189
- ),
3190
- ),
3191
- array(
3192
- 'attr_spec_list' => array(
3193
- 'align' => array(),
3194
- 'submit-success' => array(
3195
- 'mandatory' => true,
3196
- ),
3197
- ),
3198
- 'tag_spec' => array(
3199
- 'mandatory_parent' => 'form',
3200
- 'spec_name' => 'FORM > DIV [submit-success]',
3201
- ),
3202
- ),
3203
- array(
3204
- 'attr_spec_list' => array(
3205
- 'align' => array(),
3206
- 'submit-success' => array(
3207
- 'mandatory' => true,
3208
- ),
3209
- 'template' => array(
3210
- 'mandatory' => true,
3211
- ),
3212
- ),
3213
- 'tag_spec' => array(
3214
- 'mandatory_parent' => 'form',
3215
- 'spec_name' => 'FORM > DIV [submit-success][template]',
3216
- ),
3217
- ),
3218
- array(
3219
- 'attr_spec_list' => array(
3220
- 'align' => array(),
3221
- 'submit-error' => array(
3222
- 'mandatory' => true,
3223
- ),
3224
- ),
3225
- 'tag_spec' => array(
3226
- 'mandatory_parent' => 'form',
3227
- 'spec_name' => 'FORM > DIV [submit-error]',
3228
- ),
3229
- ),
3230
- array(
3231
- 'attr_spec_list' => array(
3232
- 'align' => array(),
3233
- 'submit-error' => array(
3234
- 'mandatory' => true,
3235
- ),
3236
- 'template' => array(
3237
- 'mandatory' => true,
3238
- ),
3239
- ),
3240
- 'tag_spec' => array(
3241
- 'mandatory_parent' => 'form',
3242
- 'spec_name' => 'FORM > DIV [submit-error][template]',
3243
- ),
3244
- ),
3245
- ),
3246
- 'dl' => array(
3247
- array(
3248
- 'attr_spec_list' => array(),
3249
- 'tag_spec' => array(),
3250
- ),
3251
- ),
3252
- 'dt' => array(
3253
- array(
3254
- 'attr_spec_list' => array(),
3255
- 'tag_spec' => array(),
3256
- ),
3257
- ),
3258
- 'ellipse' => array(
3259
- array(
3260
- 'attr_spec_list' => array(
3261
- 'alignment-baseline' => array(),
3262
- 'baseline-shift' => array(),
3263
- 'clip' => array(),
3264
- 'clip-path' => array(),
3265
- 'clip-rule' => array(),
3266
- 'color' => array(),
3267
- 'color-interpolation' => array(),
3268
- 'color-interpolation-filters' => array(),
3269
- 'color-profile' => array(),
3270
- 'color-rendering' => array(),
3271
- 'cursor' => array(),
3272
- 'cx' => array(),
3273
- 'cy' => array(),
3274
- 'direction' => array(),
3275
- 'display' => array(),
3276
- 'dominant-baseline' => array(),
3277
- 'enable-background' => array(),
3278
- 'externalresourcesrequired' => array(),
3279
- 'fill' => array(),
3280
- 'fill-opacity' => array(),
3281
- 'fill-rule' => array(),
3282
- 'filter' => array(),
3283
- 'flood-color' => array(),
3284
- 'flood-opacity' => array(),
3285
- 'font-family' => array(),
3286
- 'font-size' => array(),
3287
- 'font-size-adjust' => array(),
3288
- 'font-stretch' => array(),
3289
- 'font-style' => array(),
3290
- 'font-variant' => array(),
3291
- 'font-weight' => array(),
3292
- 'glyph-orientation-horizontal' => array(),
3293
- 'glyph-orientation-vertical' => array(),
3294
- 'image-rendering' => array(),
3295
- 'kerning' => array(),
3296
- 'letter-spacing' => array(),
3297
- 'lighting-color' => array(),
3298
- 'marker-end' => array(),
3299
- 'marker-mid' => array(),
3300
- 'marker-start' => array(),
3301
- 'mask' => array(),
3302
- 'opacity' => array(),
3303
- 'overflow' => array(),
3304
- 'pointer-events' => array(),
3305
- 'requiredextensions' => array(),
3306
- 'requiredfeatures' => array(),
3307
- 'rx' => array(),
3308
- 'ry' => array(),
3309
- 'shape-rendering' => array(),
3310
- 'sketch:type' => array(),
3311
- 'stop-color' => array(),
3312
- 'stop-opacity' => array(),
3313
- 'stroke' => array(),
3314
- 'stroke-dasharray' => array(),
3315
- 'stroke-dashoffset' => array(),
3316
- 'stroke-linecap' => array(),
3317
- 'stroke-linejoin' => array(),
3318
- 'stroke-miterlimit' => array(),
3319
- 'stroke-opacity' => array(),
3320
- 'stroke-width' => array(),
3321
- 'style' => array(
3322
- 'blacklisted_value_regex' => '!important',
3323
- ),
3324
- 'systemlanguage' => array(),
3325
- 'text-anchor' => array(),
3326
- 'text-decoration' => array(),
3327
- 'text-rendering' => array(),
3328
- 'transform' => array(),
3329
- 'unicode-bidi' => array(),
3330
- 'vector-effect' => array(),
3331
- 'visibility' => array(),
3332
- 'word-spacing' => array(),
3333
- 'writing-mode' => array(),
3334
- 'xml:lang' => array(),
3335
- 'xml:space' => array(),
3336
- 'xmlns' => array(),
3337
- 'xmlns:xlink' => array(),
3338
- ),
3339
- 'tag_spec' => array(
3340
- 'mandatory_ancestor' => 'svg',
3341
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3342
- ),
3343
- ),
3344
- ),
3345
- 'em' => array(
3346
- array(
3347
- 'attr_spec_list' => array(),
3348
- 'tag_spec' => array(),
3349
- ),
3350
- ),
3351
- 'fecolormatrix' => array(
3352
- array(
3353
- 'attr_spec_list' => array(
3354
- 'alignment-baseline' => array(),
3355
- 'baseline-shift' => array(),
3356
- 'clip' => array(),
3357
- 'clip-path' => array(),
3358
- 'clip-rule' => array(),
3359
- 'color' => array(),
3360
- 'color-interpolation' => array(),
3361
- 'color-interpolation-filters' => array(),
3362
- 'color-profile' => array(),
3363
- 'color-rendering' => array(),
3364
- 'cursor' => array(),
3365
- 'direction' => array(),
3366
- 'display' => array(),
3367
- 'dominant-baseline' => array(),
3368
- 'enable-background' => array(),
3369
- 'fill' => array(),
3370
- 'fill-opacity' => array(),
3371
- 'fill-rule' => array(),
3372
- 'filter' => array(),
3373
- 'flood-color' => array(),
3374
- 'flood-opacity' => array(),
3375
- 'font-family' => array(),
3376
- 'font-size' => array(),
3377
- 'font-size-adjust' => array(),
3378
- 'font-stretch' => array(),
3379
- 'font-style' => array(),
3380
- 'font-variant' => array(),
3381
- 'font-weight' => array(),
3382
- 'glyph-orientation-horizontal' => array(),
3383
- 'glyph-orientation-vertical' => array(),
3384
- 'height' => array(),
3385
- 'image-rendering' => array(),
3386
- 'in' => array(),
3387
- 'kerning' => array(),
3388
- 'letter-spacing' => array(),
3389
- 'lighting-color' => array(),
3390
- 'marker-end' => array(),
3391
- 'marker-mid' => array(),
3392
- 'marker-start' => array(),
3393
- 'mask' => array(),
3394
- 'opacity' => array(),
3395
- 'overflow' => array(),
3396
- 'pointer-events' => array(),
3397
- 'result' => array(),
3398
- 'shape-rendering' => array(),
3399
- 'stop-color' => array(),
3400
- 'stop-opacity' => array(),
3401
- 'stroke' => array(),
3402
- 'stroke-dasharray' => array(),
3403
- 'stroke-dashoffset' => array(),
3404
- 'stroke-linecap' => array(),
3405
- 'stroke-linejoin' => array(),
3406
- 'stroke-miterlimit' => array(),
3407
- 'stroke-opacity' => array(),
3408
- 'stroke-width' => array(),
3409
- 'style' => array(
3410
- 'blacklisted_value_regex' => '!important',
3411
- ),
3412
- 'text-anchor' => array(),
3413
- 'text-decoration' => array(),
3414
- 'text-rendering' => array(),
3415
- 'type' => array(),
3416
- 'unicode-bidi' => array(),
3417
- 'values' => array(),
3418
- 'vector-effect' => array(),
3419
- 'visibility' => array(),
3420
- 'width' => array(),
3421
- 'word-spacing' => array(),
3422
- 'writing-mode' => array(),
3423
- 'x' => array(),
3424
- 'xml:lang' => array(),
3425
- 'xml:space' => array(),
3426
- 'xmlns' => array(),
3427
- 'xmlns:xlink' => array(),
3428
- 'y' => array(),
3429
- ),
3430
- 'tag_spec' => array(
3431
- 'mandatory_ancestor' => 'svg',
3432
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3433
- ),
3434
- ),
3435
- ),
3436
- 'fecomposite' => array(
3437
- array(
3438
- 'attr_spec_list' => array(
3439
- 'alignment-baseline' => array(),
3440
- 'baseline-shift' => array(),
3441
- 'clip' => array(),
3442
- 'clip-path' => array(),
3443
- 'clip-rule' => array(),
3444
- 'color' => array(),
3445
- 'color-interpolation' => array(),
3446
- 'color-interpolation-filters' => array(),
3447
- 'color-profile' => array(),
3448
- 'color-rendering' => array(),
3449
- 'cursor' => array(),
3450
- 'direction' => array(),
3451
- 'display' => array(),
3452
- 'dominant-baseline' => array(),
3453
- 'enable-background' => array(),
3454
- 'fill' => array(),
3455
- 'fill-opacity' => array(),
3456
- 'fill-rule' => array(),
3457
- 'filter' => array(),
3458
- 'flood-color' => array(),
3459
- 'flood-opacity' => array(),
3460
- 'font-family' => array(),
3461
- 'font-size' => array(),
3462
- 'font-size-adjust' => array(),
3463
- 'font-stretch' => array(),
3464
- 'font-style' => array(),
3465
- 'font-variant' => array(),
3466
- 'font-weight' => array(),
3467
- 'glyph-orientation-horizontal' => array(),
3468
- 'glyph-orientation-vertical' => array(),
3469
- 'height' => array(),
3470
- 'image-rendering' => array(),
3471
- 'in' => array(),
3472
- 'in2' => array(),
3473
- 'k1' => array(),
3474
- 'k2' => array(),
3475
- 'k3' => array(),
3476
- 'k4' => array(),
3477
- 'kerning' => array(),
3478
- 'letter-spacing' => array(),
3479
- 'lighting-color' => array(),
3480
- 'marker-end' => array(),
3481
- 'marker-mid' => array(),
3482
- 'marker-start' => array(),
3483
- 'mask' => array(),
3484
- 'opacity' => array(),
3485
- 'operator' => array(),
3486
- 'overflow' => array(),
3487
- 'pointer-events' => array(),
3488
- 'result' => array(),
3489
- 'shape-rendering' => array(),
3490
- 'stop-color' => array(),
3491
- 'stop-opacity' => array(),
3492
- 'stroke' => array(),
3493
- 'stroke-dasharray' => array(),
3494
- 'stroke-dashoffset' => array(),
3495
- 'stroke-linecap' => array(),
3496
- 'stroke-linejoin' => array(),
3497
- 'stroke-miterlimit' => array(),
3498
- 'stroke-opacity' => array(),
3499
- 'stroke-width' => array(),
3500
- 'style' => array(
3501
- 'blacklisted_value_regex' => '!important',
3502
- ),
3503
- 'text-anchor' => array(),
3504
- 'text-decoration' => array(),
3505
- 'text-rendering' => array(),
3506
- 'unicode-bidi' => array(),
3507
- 'vector-effect' => array(),
3508
- 'visibility' => array(),
3509
- 'width' => array(),
3510
- 'word-spacing' => array(),
3511
- 'writing-mode' => array(),
3512
- 'x' => array(),
3513
- 'xml:lang' => array(),
3514
- 'xml:space' => array(),
3515
- 'xmlns' => array(),
3516
- 'xmlns:xlink' => array(),
3517
- 'y' => array(),
3518
- ),
3519
- 'tag_spec' => array(
3520
- 'mandatory_ancestor' => 'svg',
3521
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3522
- ),
3523
- ),
3524
- ),
3525
- 'feflood' => array(
3526
- array(
3527
- 'attr_spec_list' => array(
3528
- 'alignment-baseline' => array(),
3529
- 'baseline-shift' => array(),
3530
- 'clip' => array(),
3531
- 'clip-path' => array(),
3532
- 'clip-rule' => array(),
3533
- 'color' => array(),
3534
- 'color-interpolation' => array(),
3535
- 'color-interpolation-filters' => array(),
3536
- 'color-profile' => array(),
3537
- 'color-rendering' => array(),
3538
- 'cursor' => array(),
3539
- 'direction' => array(),
3540
- 'display' => array(),
3541
- 'dominant-baseline' => array(),
3542
- 'enable-background' => array(),
3543
- 'fill' => array(),
3544
- 'fill-opacity' => array(),
3545
- 'fill-rule' => array(),
3546
- 'filter' => array(),
3547
- 'flood-color' => array(),
3548
- 'flood-opacity' => array(),
3549
- 'font-family' => array(),
3550
- 'font-size' => array(),
3551
- 'font-size-adjust' => array(),
3552
- 'font-stretch' => array(),
3553
- 'font-style' => array(),
3554
- 'font-variant' => array(),
3555
- 'font-weight' => array(),
3556
- 'glyph-orientation-horizontal' => array(),
3557
- 'glyph-orientation-vertical' => array(),
3558
- 'height' => array(),
3559
- 'image-rendering' => array(),
3560
- 'kerning' => array(),
3561
- 'letter-spacing' => array(),
3562
- 'lighting-color' => array(),
3563
- 'marker-end' => array(),
3564
- 'marker-mid' => array(),
3565
- 'marker-start' => array(),
3566
- 'mask' => array(),
3567
- 'opacity' => array(),
3568
- 'overflow' => array(),
3569
- 'pointer-events' => array(),
3570
- 'result' => array(),
3571
- 'shape-rendering' => array(),
3572
- 'stop-color' => array(),
3573
- 'stop-opacity' => array(),
3574
- 'stroke' => array(),
3575
- 'stroke-dasharray' => array(),
3576
- 'stroke-dashoffset' => array(),
3577
- 'stroke-linecap' => array(),
3578
- 'stroke-linejoin' => array(),
3579
- 'stroke-miterlimit' => array(),
3580
- 'stroke-opacity' => array(),
3581
- 'stroke-width' => array(),
3582
- 'style' => array(
3583
- 'blacklisted_value_regex' => '!important',
3584
- ),
3585
- 'text-anchor' => array(),
3586
- 'text-decoration' => array(),
3587
- 'text-rendering' => array(),
3588
- 'unicode-bidi' => array(),
3589
- 'vector-effect' => array(),
3590
- 'visibility' => array(),
3591
- 'width' => array(),
3592
- 'word-spacing' => array(),
3593
- 'writing-mode' => array(),
3594
- 'x' => array(),
3595
- 'xml:lang' => array(),
3596
- 'xml:space' => array(),
3597
- 'xmlns' => array(),
3598
- 'xmlns:xlink' => array(),
3599
- 'y' => array(),
3600
- ),
3601
- 'tag_spec' => array(
3602
- 'mandatory_ancestor' => 'svg',
3603
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3604
- ),
3605
- ),
3606
- ),
3607
- 'fegaussianblur' => array(
3608
- array(
3609
- 'attr_spec_list' => array(
3610
- 'alignment-baseline' => array(),
3611
- 'baseline-shift' => array(),
3612
- 'clip' => array(),
3613
- 'clip-path' => array(),
3614
- 'clip-rule' => array(),
3615
- 'color' => array(),
3616
- 'color-interpolation' => array(),
3617
- 'color-interpolation-filters' => array(),
3618
- 'color-profile' => array(),
3619
- 'color-rendering' => array(),
3620
- 'cursor' => array(),
3621
- 'direction' => array(),
3622
- 'display' => array(),
3623
- 'dominant-baseline' => array(),
3624
- 'edgemode' => array(),
3625
- 'enable-background' => array(),
3626
- 'fill' => array(),
3627
- 'fill-opacity' => array(),
3628
- 'fill-rule' => array(),
3629
- 'filter' => array(),
3630
- 'flood-color' => array(),
3631
- 'flood-opacity' => array(),
3632
- 'font-family' => array(),
3633
- 'font-size' => array(),
3634
- 'font-size-adjust' => array(),
3635
- 'font-stretch' => array(),
3636
- 'font-style' => array(),
3637
- 'font-variant' => array(),
3638
- 'font-weight' => array(),
3639
- 'glyph-orientation-horizontal' => array(),
3640
- 'glyph-orientation-vertical' => array(),
3641
- 'height' => array(),
3642
- 'image-rendering' => array(),
3643
- 'in' => array(),
3644
- 'kerning' => array(),
3645
- 'letter-spacing' => array(),
3646
- 'lighting-color' => array(),
3647
- 'marker-end' => array(),
3648
- 'marker-mid' => array(),
3649
- 'marker-start' => array(),
3650
- 'mask' => array(),
3651
- 'opacity' => array(),
3652
- 'overflow' => array(),
3653
- 'pointer-events' => array(),
3654
- 'result' => array(),
3655
- 'shape-rendering' => array(),
3656
- 'stddeviation' => array(),
3657
- 'stop-color' => array(),
3658
- 'stop-opacity' => array(),
3659
- 'stroke' => array(),
3660
- 'stroke-dasharray' => array(),
3661
- 'stroke-dashoffset' => array(),
3662
- 'stroke-linecap' => array(),
3663
- 'stroke-linejoin' => array(),
3664
- 'stroke-miterlimit' => array(),
3665
- 'stroke-opacity' => array(),
3666
- 'stroke-width' => array(),
3667
- 'style' => array(
3668
- 'blacklisted_value_regex' => '!important',
3669
- ),
3670
- 'text-anchor' => array(),
3671
- 'text-decoration' => array(),
3672
- 'text-rendering' => array(),
3673
- 'unicode-bidi' => array(),
3674
- 'vector-effect' => array(),
3675
- 'visibility' => array(),
3676
- 'width' => array(),
3677
- 'word-spacing' => array(),
3678
- 'writing-mode' => array(),
3679
- 'x' => array(),
3680
- 'xml:lang' => array(),
3681
- 'xml:space' => array(),
3682
- 'xmlns' => array(),
3683
- 'xmlns:xlink' => array(),
3684
- 'y' => array(),
3685
- ),
3686
- 'tag_spec' => array(
3687
- 'mandatory_ancestor' => 'svg',
3688
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3689
- ),
3690
- ),
3691
- ),
3692
- 'femerge' => array(
3693
- array(
3694
- 'attr_spec_list' => array(
3695
- 'alignment-baseline' => array(),
3696
- 'baseline-shift' => array(),
3697
- 'clip' => array(),
3698
- 'clip-path' => array(),
3699
- 'clip-rule' => array(),
3700
- 'color' => array(),
3701
- 'color-interpolation' => array(),
3702
- 'color-interpolation-filters' => array(),
3703
- 'color-profile' => array(),
3704
- 'color-rendering' => array(),
3705
- 'cursor' => array(),
3706
- 'direction' => array(),
3707
- 'display' => array(),
3708
- 'dominant-baseline' => array(),
3709
- 'enable-background' => array(),
3710
- 'fill' => array(),
3711
- 'fill-opacity' => array(),
3712
- 'fill-rule' => array(),
3713
- 'filter' => array(),
3714
- 'flood-color' => array(),
3715
- 'flood-opacity' => array(),
3716
- 'font-family' => array(),
3717
- 'font-size' => array(),
3718
- 'font-size-adjust' => array(),
3719
- 'font-stretch' => array(),
3720
- 'font-style' => array(),
3721
- 'font-variant' => array(),
3722
- 'font-weight' => array(),
3723
- 'glyph-orientation-horizontal' => array(),
3724
- 'glyph-orientation-vertical' => array(),
3725
- 'height' => array(),
3726
- 'image-rendering' => array(),
3727
- 'kerning' => array(),
3728
- 'letter-spacing' => array(),
3729
- 'lighting-color' => array(),
3730
- 'marker-end' => array(),
3731
- 'marker-mid' => array(),
3732
- 'marker-start' => array(),
3733
- 'mask' => array(),
3734
- 'opacity' => array(),
3735
- 'overflow' => array(),
3736
- 'pointer-events' => array(),
3737
- 'result' => array(),
3738
- 'shape-rendering' => array(),
3739
- 'stop-color' => array(),
3740
- 'stop-opacity' => array(),
3741
- 'stroke' => array(),
3742
- 'stroke-dasharray' => array(),
3743
- 'stroke-dashoffset' => array(),
3744
- 'stroke-linecap' => array(),
3745
- 'stroke-linejoin' => array(),
3746
- 'stroke-miterlimit' => array(),
3747
- 'stroke-opacity' => array(),
3748
- 'stroke-width' => array(),
3749
- 'style' => array(
3750
- 'blacklisted_value_regex' => '!important',
3751
- ),
3752
- 'text-anchor' => array(),
3753
- 'text-decoration' => array(),
3754
- 'text-rendering' => array(),
3755
- 'unicode-bidi' => array(),
3756
- 'vector-effect' => array(),
3757
- 'visibility' => array(),
3758
- 'width' => array(),
3759
- 'word-spacing' => array(),
3760
- 'writing-mode' => array(),
3761
- 'x' => array(),
3762
- 'xml:lang' => array(),
3763
- 'xml:space' => array(),
3764
- 'xmlns' => array(),
3765
- 'xmlns:xlink' => array(),
3766
- 'y' => array(),
3767
- ),
3768
- 'tag_spec' => array(
3769
- 'mandatory_ancestor' => 'svg',
3770
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3771
- ),
3772
- ),
3773
- ),
3774
- 'femergenode' => array(
3775
- array(
3776
- 'attr_spec_list' => array(
3777
- 'in' => array(),
3778
- 'style' => array(
3779
- 'blacklisted_value_regex' => '!important',
3780
- ),
3781
- 'xml:lang' => array(),
3782
- 'xml:space' => array(),
3783
- 'xmlns' => array(),
3784
- 'xmlns:xlink' => array(),
3785
- ),
3786
- 'tag_spec' => array(
3787
- 'mandatory_ancestor' => 'svg',
3788
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3789
- ),
3790
- ),
3791
- ),
3792
- 'feoffset' => array(
3793
- array(
3794
- 'attr_spec_list' => array(
3795
- 'alignment-baseline' => array(),
3796
- 'baseline-shift' => array(),
3797
- 'clip' => array(),
3798
- 'clip-path' => array(),
3799
- 'clip-rule' => array(),
3800
- 'color' => array(),
3801
- 'color-interpolation' => array(),
3802
- 'color-interpolation-filters' => array(),
3803
- 'color-profile' => array(),
3804
- 'color-rendering' => array(),
3805
- 'cursor' => array(),
3806
- 'direction' => array(),
3807
- 'display' => array(),
3808
- 'dominant-baseline' => array(),
3809
- 'dx' => array(),
3810
- 'dy' => array(),
3811
- 'enable-background' => array(),
3812
- 'fill' => array(),
3813
- 'fill-opacity' => array(),
3814
- 'fill-rule' => array(),
3815
- 'filter' => array(),
3816
- 'flood-color' => array(),
3817
- 'flood-opacity' => array(),
3818
- 'font-family' => array(),
3819
- 'font-size' => array(),
3820
- 'font-size-adjust' => array(),
3821
- 'font-stretch' => array(),
3822
- 'font-style' => array(),
3823
- 'font-variant' => array(),
3824
- 'font-weight' => array(),
3825
- 'glyph-orientation-horizontal' => array(),
3826
- 'glyph-orientation-vertical' => array(),
3827
- 'height' => array(),
3828
- 'image-rendering' => array(),
3829
- 'in' => array(),
3830
- 'kerning' => array(),
3831
- 'letter-spacing' => array(),
3832
- 'lighting-color' => array(),
3833
- 'marker-end' => array(),
3834
- 'marker-mid' => array(),
3835
- 'marker-start' => array(),
3836
- 'mask' => array(),
3837
- 'opacity' => array(),
3838
- 'overflow' => array(),
3839
- 'pointer-events' => array(),
3840
- 'result' => array(),
3841
- 'shape-rendering' => array(),
3842
- 'stop-color' => array(),
3843
- 'stop-opacity' => array(),
3844
- 'stroke' => array(),
3845
- 'stroke-dasharray' => array(),
3846
- 'stroke-dashoffset' => array(),
3847
- 'stroke-linecap' => array(),
3848
- 'stroke-linejoin' => array(),
3849
- 'stroke-miterlimit' => array(),
3850
- 'stroke-opacity' => array(),
3851
- 'stroke-width' => array(),
3852
- 'style' => array(
3853
- 'blacklisted_value_regex' => '!important',
3854
- ),
3855
- 'text-anchor' => array(),
3856
- 'text-decoration' => array(),
3857
- 'text-rendering' => array(),
3858
- 'unicode-bidi' => array(),
3859
- 'vector-effect' => array(),
3860
- 'visibility' => array(),
3861
- 'width' => array(),
3862
- 'word-spacing' => array(),
3863
- 'writing-mode' => array(),
3864
- 'x' => array(),
3865
- 'xml:lang' => array(),
3866
- 'xml:space' => array(),
3867
- 'xmlns' => array(),
3868
- 'xmlns:xlink' => array(),
3869
- 'y' => array(),
3870
- ),
3871
- 'tag_spec' => array(
3872
- 'mandatory_ancestor' => 'svg',
3873
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
3874
- ),
3875
- ),
3876
- ),
3877
- 'fieldset' => array(
3878
- array(
3879
- 'attr_spec_list' => array(
3880
- '[disabled]' => array(),
3881
- 'disabled' => array(),
3882
- 'name' => array(
3883
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
3884
- ),
3885
- ),
3886
- 'tag_spec' => array(),
3887
- ),
3888
- ),
3889
- 'figcaption' => array(
3890
- array(
3891
- 'attr_spec_list' => array(),
3892
- 'tag_spec' => array(),
3893
- ),
3894
- ),
3895
- 'figure' => array(
3896
- array(
3897
- 'attr_spec_list' => array(),
3898
- 'tag_spec' => array(),
3899
- ),
3900
- ),
3901
- 'filter' => array(
3902
- array(
3903
- 'attr_spec_list' => array(
3904
- 'alignment-baseline' => array(),
3905
- 'baseline-shift' => array(),
3906
- 'clip' => array(),
3907
- 'clip-path' => array(),
3908
- 'clip-rule' => array(),
3909
- 'color' => array(),
3910
- 'color-interpolation' => array(),
3911
- 'color-interpolation-filters' => array(),
3912
- 'color-profile' => array(),
3913
- 'color-rendering' => array(),
3914
- 'cursor' => array(),
3915
- 'direction' => array(),
3916
- 'display' => array(),
3917
- 'dominant-baseline' => array(),
3918
- 'enable-background' => array(),
3919
- 'externalresourcesrequired' => array(),
3920
- 'fill' => array(),
3921
- 'fill-opacity' => array(),
3922
- 'fill-rule' => array(),
3923
- 'filter' => array(),
3924
- 'filterres' => array(),
3925
- 'filterunits' => array(),
3926
- 'flood-color' => array(),
3927
- 'flood-opacity' => array(),
3928
- 'font-family' => array(),
3929
- 'font-size' => array(),
3930
- 'font-size-adjust' => array(),
3931
- 'font-stretch' => array(),
3932
- 'font-style' => array(),
3933
- 'font-variant' => array(),
3934
- 'font-weight' => array(),
3935
- 'glyph-orientation-horizontal' => array(),
3936
- 'glyph-orientation-vertical' => array(),
3937
- 'height' => array(),
3938
- 'image-rendering' => array(),
3939
- 'kerning' => array(),
3940
- 'letter-spacing' => array(),
3941
- 'lighting-color' => array(),
3942
- 'marker-end' => array(),
3943
- 'marker-mid' => array(),
3944
- 'marker-start' => array(),
3945
- 'mask' => array(),
3946
- 'opacity' => array(),
3947
- 'overflow' => array(),
3948
- 'pointer-events' => array(),
3949
- 'primitiveunits' => array(),
3950
- 'shape-rendering' => array(),
3951
- 'stop-color' => array(),
3952
- 'stop-opacity' => array(),
3953
- 'stroke' => array(),
3954
- 'stroke-dasharray' => array(),
3955
- 'stroke-dashoffset' => array(),
3956
- 'stroke-linecap' => array(),
3957
- 'stroke-linejoin' => array(),
3958
- 'stroke-miterlimit' => array(),
3959
- 'stroke-opacity' => array(),
3960
- 'stroke-width' => array(),
3961
- 'style' => array(
3962
- 'blacklisted_value_regex' => '!important',
3963
- ),
3964
- 'text-anchor' => array(),
3965
- 'text-decoration' => array(),
3966
- 'text-rendering' => array(),
3967
- 'unicode-bidi' => array(),
3968
- 'vector-effect' => array(),
3969
- 'visibility' => array(),
3970
- 'width' => array(),
3971
- 'word-spacing' => array(),
3972
- 'writing-mode' => array(),
3973
- 'x' => array(),
3974
- 'xlink:actuate' => array(),
3975
- 'xlink:arcrole' => array(),
3976
- 'xlink:href' => array(
3977
- 'alternative_names' => array(
3978
- 'href',
3979
- ),
3980
- 'value_url' => array(
3981
- 'allow_empty' => false,
3982
- 'allow_relative' => true,
3983
- 'allowed_protocol' => array(
3984
- 'http',
3985
- 'https',
3986
- ),
3987
- ),
3988
- ),
3989
- 'xlink:role' => array(),
3990
- 'xlink:show' => array(),
3991
- 'xlink:title' => array(),
3992
- 'xlink:type' => array(),
3993
- 'xml:lang' => array(),
3994
- 'xml:space' => array(),
3995
- 'xmlns' => array(),
3996
- 'xmlns:xlink' => array(),
3997
- 'y' => array(),
3998
- ),
3999
- 'tag_spec' => array(
4000
- 'mandatory_ancestor' => 'svg',
4001
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4002
- ),
4003
- ),
4004
- ),
4005
- 'footer' => array(
4006
- array(
4007
- 'attr_spec_list' => array(),
4008
- 'tag_spec' => array(),
4009
- ),
4010
- ),
4011
- 'foreignobject' => array(
4012
- array(
4013
- 'attr_spec_list' => array(
4014
- 'alignment-baseline' => array(),
4015
- 'baseline-shift' => array(),
4016
- 'clip' => array(),
4017
- 'clip-path' => array(),
4018
- 'clip-rule' => array(),
4019
- 'color' => array(),
4020
- 'color-interpolation' => array(),
4021
- 'color-interpolation-filters' => array(),
4022
- 'color-profile' => array(),
4023
- 'color-rendering' => array(),
4024
- 'cursor' => array(),
4025
- 'direction' => array(),
4026
- 'display' => array(),
4027
- 'dominant-baseline' => array(),
4028
- 'enable-background' => array(),
4029
- 'externalresourcesrequired' => array(),
4030
- 'fill' => array(),
4031
- 'fill-opacity' => array(),
4032
- 'fill-rule' => array(),
4033
- 'filter' => array(),
4034
- 'flood-color' => array(),
4035
- 'flood-opacity' => array(),
4036
- 'font-family' => array(),
4037
- 'font-size' => array(),
4038
- 'font-size-adjust' => array(),
4039
- 'font-stretch' => array(),
4040
- 'font-style' => array(),
4041
- 'font-variant' => array(),
4042
- 'font-weight' => array(),
4043
- 'glyph-orientation-horizontal' => array(),
4044
- 'glyph-orientation-vertical' => array(),
4045
- 'height' => array(),
4046
- 'image-rendering' => array(),
4047
- 'kerning' => array(),
4048
- 'letter-spacing' => array(),
4049
- 'lighting-color' => array(),
4050
- 'marker-end' => array(),
4051
- 'marker-mid' => array(),
4052
- 'marker-start' => array(),
4053
- 'mask' => array(),
4054
- 'opacity' => array(),
4055
- 'overflow' => array(),
4056
- 'pointer-events' => array(),
4057
- 'requiredextensions' => array(),
4058
- 'requiredfeatures' => array(),
4059
- 'shape-rendering' => array(),
4060
- 'stop-color' => array(),
4061
- 'stop-opacity' => array(),
4062
- 'stroke' => array(),
4063
- 'stroke-dasharray' => array(),
4064
- 'stroke-dashoffset' => array(),
4065
- 'stroke-linecap' => array(),
4066
- 'stroke-linejoin' => array(),
4067
- 'stroke-miterlimit' => array(),
4068
- 'stroke-opacity' => array(),
4069
- 'stroke-width' => array(),
4070
- 'style' => array(
4071
- 'blacklisted_value_regex' => '!important',
4072
- ),
4073
- 'systemlanguage' => array(),
4074
- 'text-anchor' => array(),
4075
- 'text-decoration' => array(),
4076
- 'text-rendering' => array(),
4077
- 'transform' => array(),
4078
- 'unicode-bidi' => array(),
4079
- 'vector-effect' => array(),
4080
- 'visibility' => array(),
4081
- 'width' => array(),
4082
- 'word-spacing' => array(),
4083
- 'writing-mode' => array(),
4084
- 'x' => array(),
4085
- 'xml:lang' => array(),
4086
- 'xml:space' => array(),
4087
- 'xmlns' => array(),
4088
- 'xmlns:xlink' => array(),
4089
- 'y' => array(),
4090
- ),
4091
- 'tag_spec' => array(
4092
- 'mandatory_ancestor' => 'svg',
4093
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4094
- ),
4095
- ),
4096
- ),
4097
- 'form' => array(
4098
- array(
4099
- 'attr_spec_list' => array(
4100
- 'accept' => array(),
4101
- 'accept-charset' => array(),
4102
- 'action' => array(
4103
- 'blacklisted_value_regex' => '__amp_source_origin',
4104
- 'mandatory' => true,
4105
- 'value_url' => array(
4106
- 'allow_relative' => true,
4107
- 'allowed_protocol' => array(
4108
- 'https',
4109
- ),
4110
- ),
4111
- ),
4112
- 'action-xhr' => array(
4113
- 'blacklisted_value_regex' => '__amp_source_origin',
4114
- 'value_url' => array(
4115
- 'allow_relative' => true,
4116
- 'allowed_protocol' => array(
4117
- 'https',
4118
- ),
4119
- ),
4120
- ),
4121
- 'autocomplete' => array(),
4122
- 'custom-validation-reporting' => array(
4123
- 'value_regex' => '(show-first-on-submit|show-all-on-submit|as-you-go|interact-and-submit)',
4124
- ),
4125
- 'enctype' => array(),
4126
- 'method' => array(
4127
- 'value_casei' => 'get',
4128
- ),
4129
- 'name' => array(),
4130
- 'novalidate' => array(),
4131
- 'target' => array(
4132
- 'mandatory' => true,
4133
- 'value_regex_casei' => '(_blank|_top)',
4134
- ),
4135
- 'verify-xhr' => array(
4136
- 'blacklisted_value_regex' => '__amp_source_origin',
4137
- 'value_url' => array(
4138
- 'allow_relative' => true,
4139
- 'allowed_protocol' => array(
4140
- 'https',
4141
- ),
4142
- ),
4143
- ),
4144
- ),
4145
- 'tag_spec' => array(
4146
- 'disallowed_ancestor' => array(
4147
- 'amp-app-banner',
4148
- ),
4149
- 'requires_extension' => array(
4150
- 'amp-form',
4151
- ),
4152
- 'spec_name' => 'FORM [method=GET]',
4153
- ),
4154
- ),
4155
- array(
4156
- 'attr_spec_list' => array(
4157
- 'accept' => array(),
4158
- 'accept-charset' => array(),
4159
- 'action-xhr' => array(
4160
- 'blacklisted_value_regex' => '__amp_source_origin',
4161
- 'mandatory' => true,
4162
- 'value_url' => array(
4163
- 'allow_relative' => true,
4164
- 'allowed_protocol' => array(
4165
- 'https',
4166
- ),
4167
- ),
4168
- ),
4169
- 'autocomplete' => array(),
4170
- 'custom-validation-reporting' => array(
4171
- 'value_regex' => '(show-first-on-submit|show-all-on-submit|as-you-go)',
4172
- ),
4173
- 'enctype' => array(),
4174
- 'method' => array(
4175
- 'dispatch_key' => 2,
4176
- 'mandatory' => true,
4177
- 'value_casei' => 'post',
4178
- ),
4179
- 'name' => array(),
4180
- 'novalidate' => array(),
4181
- 'target' => array(
4182
- 'mandatory' => true,
4183
- 'value_regex_casei' => '(_blank|_top)',
4184
- ),
4185
- 'verify-xhr' => array(
4186
- 'blacklisted_value_regex' => '__amp_source_origin',
4187
- 'value_url' => array(
4188
- 'allow_relative' => true,
4189
- 'allowed_protocol' => array(
4190
- 'https',
4191
- ),
4192
- ),
4193
- ),
4194
- ),
4195
- 'tag_spec' => array(
4196
- 'disallowed_ancestor' => array(
4197
- 'amp-app-banner',
4198
- ),
4199
- 'requires_extension' => array(
4200
- 'amp-form',
4201
- ),
4202
- 'spec_name' => 'FORM [method=POST]',
4203
- ),
4204
- ),
4205
- ),
4206
- 'g' => array(
4207
- array(
4208
- 'attr_spec_list' => array(
4209
- 'alignment-baseline' => array(),
4210
- 'baseline-shift' => array(),
4211
- 'clip' => array(),
4212
- 'clip-path' => array(),
4213
- 'clip-rule' => array(),
4214
- 'color' => array(),
4215
- 'color-interpolation' => array(),
4216
- 'color-interpolation-filters' => array(),
4217
- 'color-profile' => array(),
4218
- 'color-rendering' => array(),
4219
- 'cursor' => array(),
4220
- 'direction' => array(),
4221
- 'display' => array(),
4222
- 'dominant-baseline' => array(),
4223
- 'enable-background' => array(),
4224
- 'externalresourcesrequired' => array(),
4225
- 'fill' => array(),
4226
- 'fill-opacity' => array(),
4227
- 'fill-rule' => array(),
4228
- 'filter' => array(),
4229
- 'flood-color' => array(),
4230
- 'flood-opacity' => array(),
4231
- 'font-family' => array(),
4232
- 'font-size' => array(),
4233
- 'font-size-adjust' => array(),
4234
- 'font-stretch' => array(),
4235
- 'font-style' => array(),
4236
- 'font-variant' => array(),
4237
- 'font-weight' => array(),
4238
- 'glyph-orientation-horizontal' => array(),
4239
- 'glyph-orientation-vertical' => array(),
4240
- 'image-rendering' => array(),
4241
- 'kerning' => array(),
4242
- 'letter-spacing' => array(),
4243
- 'lighting-color' => array(),
4244
- 'marker-end' => array(),
4245
- 'marker-mid' => array(),
4246
- 'marker-start' => array(),
4247
- 'mask' => array(),
4248
- 'opacity' => array(),
4249
- 'overflow' => array(),
4250
- 'pointer-events' => array(),
4251
- 'requiredextensions' => array(),
4252
- 'requiredfeatures' => array(),
4253
- 'shape-rendering' => array(),
4254
- 'stop-color' => array(),
4255
- 'stop-opacity' => array(),
4256
- 'stroke' => array(),
4257
- 'stroke-dasharray' => array(),
4258
- 'stroke-dashoffset' => array(),
4259
- 'stroke-linecap' => array(),
4260
- 'stroke-linejoin' => array(),
4261
- 'stroke-miterlimit' => array(),
4262
- 'stroke-opacity' => array(),
4263
- 'stroke-width' => array(),
4264
- 'style' => array(
4265
- 'blacklisted_value_regex' => '!important',
4266
- ),
4267
- 'systemlanguage' => array(),
4268
- 'text-anchor' => array(),
4269
- 'text-decoration' => array(),
4270
- 'text-rendering' => array(),
4271
- 'transform' => array(),
4272
- 'unicode-bidi' => array(),
4273
- 'vector-effect' => array(),
4274
- 'visibility' => array(),
4275
- 'word-spacing' => array(),
4276
- 'writing-mode' => array(),
4277
- 'xml:lang' => array(),
4278
- 'xml:space' => array(),
4279
- 'xmlns' => array(),
4280
- 'xmlns:xlink' => array(),
4281
- ),
4282
- 'tag_spec' => array(
4283
- 'mandatory_ancestor' => 'svg',
4284
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4285
- ),
4286
- ),
4287
- ),
4288
- 'glyph' => array(
4289
- array(
4290
- 'attr_spec_list' => array(
4291
- 'alignment-baseline' => array(),
4292
- 'arabic-form' => array(),
4293
- 'baseline-shift' => array(),
4294
- 'clip' => array(),
4295
- 'clip-path' => array(),
4296
- 'clip-rule' => array(),
4297
- 'color' => array(),
4298
- 'color-interpolation' => array(),
4299
- 'color-interpolation-filters' => array(),
4300
- 'color-profile' => array(),
4301
- 'color-rendering' => array(),
4302
- 'cursor' => array(),
4303
- 'd' => array(),
4304
- 'direction' => array(),
4305
- 'display' => array(),
4306
- 'dominant-baseline' => array(),
4307
- 'enable-background' => array(),
4308
- 'fill' => array(),
4309
- 'fill-opacity' => array(),
4310
- 'fill-rule' => array(),
4311
- 'filter' => array(),
4312
- 'flood-color' => array(),
4313
- 'flood-opacity' => array(),
4314
- 'font-family' => array(),
4315
- 'font-size' => array(),
4316
- 'font-size-adjust' => array(),
4317
- 'font-stretch' => array(),
4318
- 'font-style' => array(),
4319
- 'font-variant' => array(),
4320
- 'font-weight' => array(),
4321
- 'glyph-name' => array(),
4322
- 'glyph-orientation-horizontal' => array(),
4323
- 'glyph-orientation-vertical' => array(),
4324
- 'horiz-adv-x' => array(),
4325
- 'image-rendering' => array(),
4326
- 'kerning' => array(),
4327
- 'letter-spacing' => array(),
4328
- 'lighting-color' => array(),
4329
- 'marker-end' => array(),
4330
- 'marker-mid' => array(),
4331
- 'marker-start' => array(),
4332
- 'mask' => array(),
4333
- 'opacity' => array(),
4334
- 'orientation' => array(),
4335
- 'overflow' => array(),
4336
- 'pointer-events' => array(),
4337
- 'shape-rendering' => array(),
4338
- 'stop-color' => array(),
4339
- 'stop-opacity' => array(),
4340
- 'stroke' => array(),
4341
- 'stroke-dasharray' => array(),
4342
- 'stroke-dashoffset' => array(),
4343
- 'stroke-linecap' => array(),
4344
- 'stroke-linejoin' => array(),
4345
- 'stroke-miterlimit' => array(),
4346
- 'stroke-opacity' => array(),
4347
- 'stroke-width' => array(),
4348
- 'style' => array(
4349
- 'blacklisted_value_regex' => '!important',
4350
- ),
4351
- 'text-anchor' => array(),
4352
- 'text-decoration' => array(),
4353
- 'text-rendering' => array(),
4354
- 'unicode' => array(),
4355
- 'unicode-bidi' => array(),
4356
- 'vector-effect' => array(),
4357
- 'vert-adv-y' => array(),
4358
- 'vert-origin-x' => array(),
4359
- 'vert-origin-y' => array(),
4360
- 'visibility' => array(),
4361
- 'word-spacing' => array(),
4362
- 'writing-mode' => array(),
4363
- 'xml:lang' => array(),
4364
- 'xml:space' => array(),
4365
- 'xmlns' => array(),
4366
- 'xmlns:xlink' => array(),
4367
- ),
4368
- 'tag_spec' => array(
4369
- 'mandatory_ancestor' => 'svg',
4370
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4371
- ),
4372
- ),
4373
- ),
4374
- 'glyphref' => array(
4375
- array(
4376
- 'attr_spec_list' => array(
4377
- 'alignment-baseline' => array(),
4378
- 'baseline-shift' => array(),
4379
- 'clip' => array(),
4380
- 'clip-path' => array(),
4381
- 'clip-rule' => array(),
4382
- 'color' => array(),
4383
- 'color-interpolation' => array(),
4384
- 'color-interpolation-filters' => array(),
4385
- 'color-profile' => array(),
4386
- 'color-rendering' => array(),
4387
- 'cursor' => array(),
4388
- 'direction' => array(),
4389
- 'display' => array(),
4390
- 'dominant-baseline' => array(),
4391
- 'dx' => array(),
4392
- 'dy' => array(),
4393
- 'enable-background' => array(),
4394
- 'fill' => array(),
4395
- 'fill-opacity' => array(),
4396
- 'fill-rule' => array(),
4397
- 'filter' => array(),
4398
- 'flood-color' => array(),
4399
- 'flood-opacity' => array(),
4400
- 'font-family' => array(),
4401
- 'font-size' => array(),
4402
- 'font-size-adjust' => array(),
4403
- 'font-stretch' => array(),
4404
- 'font-style' => array(),
4405
- 'font-variant' => array(),
4406
- 'font-weight' => array(),
4407
- 'format' => array(),
4408
- 'glyph-orientation-horizontal' => array(),
4409
- 'glyph-orientation-vertical' => array(),
4410
- 'glyphref' => array(),
4411
- 'image-rendering' => array(),
4412
- 'kerning' => array(),
4413
- 'letter-spacing' => array(),
4414
- 'lighting-color' => array(),
4415
- 'marker-end' => array(),
4416
- 'marker-mid' => array(),
4417
- 'marker-start' => array(),
4418
- 'mask' => array(),
4419
- 'opacity' => array(),
4420
- 'overflow' => array(),
4421
- 'pointer-events' => array(),
4422
- 'shape-rendering' => array(),
4423
- 'stop-color' => array(),
4424
- 'stop-opacity' => array(),
4425
- 'stroke' => array(),
4426
- 'stroke-dasharray' => array(),
4427
- 'stroke-dashoffset' => array(),
4428
- 'stroke-linecap' => array(),
4429
- 'stroke-linejoin' => array(),
4430
- 'stroke-miterlimit' => array(),
4431
- 'stroke-opacity' => array(),
4432
- 'stroke-width' => array(),
4433
- 'style' => array(
4434
- 'blacklisted_value_regex' => '!important',
4435
- ),
4436
- 'text-anchor' => array(),
4437
- 'text-decoration' => array(),
4438
- 'text-rendering' => array(),
4439
- 'unicode-bidi' => array(),
4440
- 'vector-effect' => array(),
4441
- 'visibility' => array(),
4442
- 'word-spacing' => array(),
4443
- 'writing-mode' => array(),
4444
- 'x' => array(),
4445
- 'xlink:actuate' => array(),
4446
- 'xlink:arcrole' => array(),
4447
- 'xlink:href' => array(
4448
- 'alternative_names' => array(
4449
- 'href',
4450
- ),
4451
- 'value_url' => array(
4452
- 'allow_empty' => false,
4453
- 'allow_relative' => true,
4454
- 'allowed_protocol' => array(
4455
- 'http',
4456
- 'https',
4457
- ),
4458
- ),
4459
- ),
4460
- 'xlink:role' => array(),
4461
- 'xlink:show' => array(),
4462
- 'xlink:title' => array(),
4463
- 'xlink:type' => array(),
4464
- 'xml:lang' => array(),
4465
- 'xml:space' => array(),
4466
- 'xmlns' => array(),
4467
- 'xmlns:xlink' => array(),
4468
- 'y' => array(),
4469
- ),
4470
- 'tag_spec' => array(
4471
- 'mandatory_ancestor' => 'svg',
4472
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4473
- ),
4474
- ),
4475
- ),
4476
- 'h1' => array(
4477
- array(
4478
- 'attr_spec_list' => array(
4479
- 'align' => array(),
4480
- ),
4481
- 'tag_spec' => array(),
4482
- ),
4483
- ),
4484
- 'h2' => array(
4485
- array(
4486
- 'attr_spec_list' => array(
4487
- 'align' => array(),
4488
- ),
4489
- 'tag_spec' => array(),
4490
- ),
4491
- ),
4492
- 'h3' => array(
4493
- array(
4494
- 'attr_spec_list' => array(
4495
- 'align' => array(),
4496
- ),
4497
- 'tag_spec' => array(),
4498
- ),
4499
- ),
4500
- 'h4' => array(
4501
- array(
4502
- 'attr_spec_list' => array(
4503
- 'align' => array(),
4504
- ),
4505
- 'tag_spec' => array(),
4506
- ),
4507
- ),
4508
- 'h5' => array(
4509
- array(
4510
- 'attr_spec_list' => array(
4511
- 'align' => array(),
4512
- ),
4513
- 'tag_spec' => array(),
4514
- ),
4515
- ),
4516
- 'h6' => array(
4517
- array(
4518
- 'attr_spec_list' => array(
4519
- 'align' => array(),
4520
- ),
4521
- 'tag_spec' => array(),
4522
- ),
4523
- ),
4524
- 'head' => array(
4525
- array(
4526
- 'attr_spec_list' => array(),
4527
- 'tag_spec' => array(
4528
- 'mandatory' => true,
4529
- 'mandatory_parent' => 'html',
4530
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
4531
- 'unique' => true,
4532
- ),
4533
- ),
4534
- ),
4535
- 'header' => array(
4536
- array(
4537
- 'attr_spec_list' => array(),
4538
- 'tag_spec' => array(),
4539
- ),
4540
- ),
4541
- 'hgroup' => array(
4542
- array(
4543
- 'attr_spec_list' => array(),
4544
- 'tag_spec' => array(),
4545
- ),
4546
- ),
4547
- 'hkern' => array(
4548
- array(
4549
- 'attr_spec_list' => array(
4550
- 'g1' => array(),
4551
- 'g2' => array(),
4552
- 'k' => array(),
4553
- 'style' => array(
4554
- 'blacklisted_value_regex' => '!important',
4555
- ),
4556
- 'u1' => array(),
4557
- 'u2' => array(),
4558
- 'xml:lang' => array(),
4559
- 'xml:space' => array(),
4560
- 'xmlns' => array(),
4561
- 'xmlns:xlink' => array(),
4562
- ),
4563
- 'tag_spec' => array(
4564
- 'mandatory_ancestor' => 'svg',
4565
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4566
- ),
4567
- ),
4568
- ),
4569
- 'hr' => array(
4570
- array(
4571
- 'attr_spec_list' => array(),
4572
- 'tag_spec' => array(),
4573
- ),
4574
- ),
4575
- 'html' => array(
4576
- array(
4577
- 'attr_spec_list' => array(
4578
- '\\u26a1' => array(
4579
- 'alternative_names' => array(
4580
- 'amp',
4581
- ),
4582
- 'mandatory' => true,
4583
- 'value' => '',
4584
- ),
4585
- ),
4586
- 'tag_spec' => array(
4587
- 'mandatory' => true,
4588
- 'mandatory_parent' => '!doctype',
4589
- 'spec_name' => 'html \\u26a1 for top-level html',
4590
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
4591
- 'unique' => true,
4592
- ),
4593
- ),
4594
- ),
4595
- 'i' => array(
4596
- array(
4597
- 'attr_spec_list' => array(),
4598
- 'tag_spec' => array(),
4599
- ),
4600
- ),
4601
- 'iframe' => array(
4602
- array(
4603
- 'attr_spec_list' => array(
4604
- 'frameborder' => array(
4605
- 'value_regex' => '0|1',
4606
- ),
4607
- 'height' => array(),
4608
- 'name' => array(),
4609
- 'referrerpolicy' => array(),
4610
- 'resizable' => array(
4611
- 'value' => '',
4612
- ),
4613
- 'sandbox' => array(),
4614
- 'scrolling' => array(
4615
- 'value_regex' => 'auto|yes|no',
4616
- ),
4617
- 'src' => array(
4618
- 'blacklisted_value_regex' => '__amp_source_origin',
4619
- 'value_url' => array(
4620
- 'allow_relative' => false,
4621
- 'allowed_protocol' => array(
4622
- 'data',
4623
- 'https',
4624
- ),
4625
- ),
4626
- ),
4627
- 'srcdoc' => array(),
4628
- 'width' => array(),
4629
- ),
4630
- 'tag_spec' => array(
4631
- 'mandatory_ancestor' => 'noscript',
4632
- 'mandatory_ancestor_suggested_alternative' => 'amp-iframe',
4633
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-iframe',
4634
- ),
4635
- ),
4636
- ),
4637
- 'image' => array(
4638
- array(
4639
- 'attr_spec_list' => array(
4640
- 'alignment-baseline' => array(),
4641
- 'baseline-shift' => array(),
4642
- 'clip' => array(),
4643
- 'clip-path' => array(),
4644
- 'clip-rule' => array(),
4645
- 'color' => array(),
4646
- 'color-interpolation' => array(),
4647
- 'color-interpolation-filters' => array(),
4648
- 'color-profile' => array(),
4649
- 'color-rendering' => array(),
4650
- 'cursor' => array(),
4651
- 'direction' => array(),
4652
- 'display' => array(),
4653
- 'dominant-baseline' => array(),
4654
- 'enable-background' => array(),
4655
- 'externalresourcesrequired' => array(),
4656
- 'fill' => array(),
4657
- 'fill-opacity' => array(),
4658
- 'fill-rule' => array(),
4659
- 'filter' => array(),
4660
- 'flood-color' => array(),
4661
- 'flood-opacity' => array(),
4662
- 'font-family' => array(),
4663
- 'font-size' => array(),
4664
- 'font-size-adjust' => array(),
4665
- 'font-stretch' => array(),
4666
- 'font-style' => array(),
4667
- 'font-variant' => array(),
4668
- 'font-weight' => array(),
4669
- 'glyph-orientation-horizontal' => array(),
4670
- 'glyph-orientation-vertical' => array(),
4671
- 'height' => array(),
4672
- 'image-rendering' => array(),
4673
- 'kerning' => array(),
4674
- 'letter-spacing' => array(),
4675
- 'lighting-color' => array(),
4676
- 'marker-end' => array(),
4677
- 'marker-mid' => array(),
4678
- 'marker-start' => array(),
4679
- 'mask' => array(),
4680
- 'opacity' => array(),
4681
- 'overflow' => array(),
4682
- 'pointer-events' => array(),
4683
- 'preserveaspectratio' => array(),
4684
- 'requiredextensions' => array(),
4685
- 'requiredfeatures' => array(),
4686
- 'shape-rendering' => array(),
4687
- 'stop-color' => array(),
4688
- 'stop-opacity' => array(),
4689
- 'stroke' => array(),
4690
- 'stroke-dasharray' => array(),
4691
- 'stroke-dashoffset' => array(),
4692
- 'stroke-linecap' => array(),
4693
- 'stroke-linejoin' => array(),
4694
- 'stroke-miterlimit' => array(),
4695
- 'stroke-opacity' => array(),
4696
- 'stroke-width' => array(),
4697
- 'style' => array(
4698
- 'blacklisted_value_regex' => '!important',
4699
- ),
4700
- 'systemlanguage' => array(),
4701
- 'text-anchor' => array(),
4702
- 'text-decoration' => array(),
4703
- 'text-rendering' => array(),
4704
- 'transform' => array(),
4705
- 'unicode-bidi' => array(),
4706
- 'vector-effect' => array(),
4707
- 'visibility' => array(),
4708
- 'width' => array(),
4709
- 'word-spacing' => array(),
4710
- 'writing-mode' => array(),
4711
- 'x' => array(),
4712
- 'xlink:actuate' => array(),
4713
- 'xlink:arcrole' => array(),
4714
- 'xlink:href' => array(
4715
- 'alternative_names' => array(
4716
- 'href',
4717
- ),
4718
- 'blacklisted_value_regex' => '(^|\\s)data:image\\/svg\\+xml',
4719
- 'value_url' => array(
4720
- 'allow_empty' => false,
4721
- 'allow_relative' => true,
4722
- 'allowed_protocol' => array(
4723
- 'data',
4724
- 'http',
4725
- 'https',
4726
- ),
4727
- ),
4728
- ),
4729
- 'xlink:role' => array(),
4730
- 'xlink:show' => array(),
4731
- 'xlink:title' => array(),
4732
- 'xlink:type' => array(),
4733
- 'xml:lang' => array(),
4734
- 'xml:space' => array(),
4735
- 'xmlns' => array(),
4736
- 'xmlns:xlink' => array(),
4737
- 'y' => array(),
4738
- ),
4739
- 'tag_spec' => array(
4740
- 'mandatory_ancestor' => 'svg',
4741
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4742
- ),
4743
- ),
4744
- ),
4745
- 'img' => array(
4746
- array(
4747
- 'attr_spec_list' => array(
4748
- 'alt' => array(),
4749
- 'border' => array(),
4750
- 'height' => array(),
4751
- 'ismap' => array(),
4752
- 'longdesc' => array(
4753
- 'blacklisted_value_regex' => '__amp_source_origin',
4754
- 'value_url' => array(
4755
- 'allow_relative' => true,
4756
- 'allowed_protocol' => array(
4757
- 'http',
4758
- 'https',
4759
- ),
4760
- ),
4761
- ),
4762
- 'src' => array(
4763
- 'alternative_names' => array(
4764
- 'srcset',
4765
- ),
4766
- 'blacklisted_value_regex' => '__amp_source_origin',
4767
- 'mandatory' => true,
4768
- 'value_url' => array(
4769
- 'allow_relative' => true,
4770
- 'allowed_protocol' => array(
4771
- 'data',
4772
- 'https',
4773
- ),
4774
- ),
4775
- ),
4776
- 'width' => array(),
4777
- ),
4778
- 'tag_spec' => array(
4779
- 'mandatory_ancestor' => 'noscript',
4780
- 'mandatory_ancestor_suggested_alternative' => 'amp-img',
4781
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-img',
4782
- ),
4783
- ),
4784
- ),
4785
- 'input' => array(
4786
- array(
4787
- 'attr_spec_list' => array(
4788
- '[accept]' => array(),
4789
- '[accesskey]' => array(),
4790
- '[autocomplete]' => array(),
4791
- '[checked]' => array(),
4792
- '[disabled]' => array(),
4793
- '[height]' => array(),
4794
- '[inputmode]' => array(),
4795
- '[max]' => array(),
4796
- '[maxlength]' => array(),
4797
- '[min]' => array(),
4798
- '[minlength]' => array(),
4799
- '[multiple]' => array(),
4800
- '[pattern]' => array(),
4801
- '[placeholder]' => array(),
4802
- '[readonly]' => array(),
4803
- '[required]' => array(),
4804
- '[selectiondirection]' => array(),
4805
- '[size]' => array(),
4806
- '[spellcheck]' => array(),
4807
- '[step]' => array(),
4808
- '[type]' => array(),
4809
- '[value]' => array(),
4810
- '[width]' => array(),
4811
- 'accept' => array(),
4812
- 'accesskey' => array(),
4813
- 'autocomplete' => array(),
4814
- 'autofocus' => array(),
4815
- 'checked' => array(),
4816
- 'disabled' => array(),
4817
- 'height' => array(),
4818
- 'inputmode' => array(),
4819
- 'list' => array(),
4820
- 'max' => array(),
4821
- 'maxlength' => array(),
4822
- 'min' => array(),
4823
- 'minlength' => array(),
4824
- 'multiple' => array(),
4825
- 'name' => array(
4826
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
4827
- ),
4828
- 'pattern' => array(),
4829
- 'placeholder' => array(),
4830
- 'readonly' => array(),
4831
- 'required' => array(),
4832
- 'selectiondirection' => array(),
4833
- 'size' => array(),
4834
- 'spellcheck' => array(),
4835
- 'step' => array(),
4836
- 'tabindex' => array(),
4837
- 'type' => array(
4838
- 'blacklisted_value_regex' => '(^|\\s)(button|file|image|password|)(\\s|$)',
4839
- ),
4840
- 'value' => array(),
4841
- 'width' => array(),
4842
- ),
4843
- 'tag_spec' => array(
4844
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
4845
- ),
4846
- ),
4847
- ),
4848
- 'ins' => array(
4849
- array(
4850
- 'attr_spec_list' => array(
4851
- 'cite' => array(
4852
- 'blacklisted_value_regex' => '__amp_source_origin',
4853
- 'value_url' => array(
4854
- 'allow_empty' => true,
4855
- 'allow_relative' => true,
4856
- 'allowed_protocol' => array(
4857
- 'http',
4858
- 'https',
4859
- ),
4860
- ),
4861
- ),
4862
- 'datetime' => array(),
4863
- ),
4864
- 'tag_spec' => array(),
4865
- ),
4866
- ),
4867
- 'kbd' => array(
4868
- array(
4869
- 'attr_spec_list' => array(),
4870
- 'tag_spec' => array(),
4871
- ),
4872
- ),
4873
- 'label' => array(
4874
- array(
4875
- 'attr_spec_list' => array(
4876
- 'for' => array(),
4877
- ),
4878
- 'tag_spec' => array(
4879
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
4880
- ),
4881
- ),
4882
- ),
4883
- 'legend' => array(
4884
- array(
4885
- 'attr_spec_list' => array(),
4886
- 'tag_spec' => array(),
4887
- ),
4888
- ),
4889
- 'li' => array(
4890
- array(
4891
- 'attr_spec_list' => array(
4892
- 'value' => array(
4893
- 'value_regex' => '[0-9]*',
4894
- ),
4895
- ),
4896
- 'tag_spec' => array(),
4897
- ),
4898
- ),
4899
- 'line' => array(
4900
- array(
4901
- 'attr_spec_list' => array(
4902
- 'alignment-baseline' => array(),
4903
- 'baseline-shift' => array(),
4904
- 'clip' => array(),
4905
- 'clip-path' => array(),
4906
- 'clip-rule' => array(),
4907
- 'color' => array(),
4908
- 'color-interpolation' => array(),
4909
- 'color-interpolation-filters' => array(),
4910
- 'color-profile' => array(),
4911
- 'color-rendering' => array(),
4912
- 'cursor' => array(),
4913
- 'direction' => array(),
4914
- 'display' => array(),
4915
- 'dominant-baseline' => array(),
4916
- 'enable-background' => array(),
4917
- 'externalresourcesrequired' => array(),
4918
- 'fill' => array(),
4919
- 'fill-opacity' => array(),
4920
- 'fill-rule' => array(),
4921
- 'filter' => array(),
4922
- 'flood-color' => array(),
4923
- 'flood-opacity' => array(),
4924
- 'font-family' => array(),
4925
- 'font-size' => array(),
4926
- 'font-size-adjust' => array(),
4927
- 'font-stretch' => array(),
4928
- 'font-style' => array(),
4929
- 'font-variant' => array(),
4930
- 'font-weight' => array(),
4931
- 'glyph-orientation-horizontal' => array(),
4932
- 'glyph-orientation-vertical' => array(),
4933
- 'image-rendering' => array(),
4934
- 'kerning' => array(),
4935
- 'letter-spacing' => array(),
4936
- 'lighting-color' => array(),
4937
- 'marker-end' => array(),
4938
- 'marker-mid' => array(),
4939
- 'marker-start' => array(),
4940
- 'mask' => array(),
4941
- 'opacity' => array(),
4942
- 'overflow' => array(),
4943
- 'pointer-events' => array(),
4944
- 'requiredextensions' => array(),
4945
- 'requiredfeatures' => array(),
4946
- 'shape-rendering' => array(),
4947
- 'sketch:type' => array(),
4948
- 'stop-color' => array(),
4949
- 'stop-opacity' => array(),
4950
- 'stroke' => array(),
4951
- 'stroke-dasharray' => array(),
4952
- 'stroke-dashoffset' => array(),
4953
- 'stroke-linecap' => array(),
4954
- 'stroke-linejoin' => array(),
4955
- 'stroke-miterlimit' => array(),
4956
- 'stroke-opacity' => array(),
4957
- 'stroke-width' => array(),
4958
- 'style' => array(
4959
- 'blacklisted_value_regex' => '!important',
4960
- ),
4961
- 'systemlanguage' => array(),
4962
- 'text-anchor' => array(),
4963
- 'text-decoration' => array(),
4964
- 'text-rendering' => array(),
4965
- 'transform' => array(),
4966
- 'unicode-bidi' => array(),
4967
- 'vector-effect' => array(),
4968
- 'visibility' => array(),
4969
- 'word-spacing' => array(),
4970
- 'writing-mode' => array(),
4971
- 'x1' => array(),
4972
- 'x2' => array(),
4973
- 'xml:lang' => array(),
4974
- 'xml:space' => array(),
4975
- 'xmlns' => array(),
4976
- 'xmlns:xlink' => array(),
4977
- 'y1' => array(),
4978
- 'y2' => array(),
4979
- ),
4980
- 'tag_spec' => array(
4981
- 'mandatory_ancestor' => 'svg',
4982
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
4983
- ),
4984
- ),
4985
- ),
4986
- 'lineargradient' => array(
4987
- array(
4988
- 'attr_spec_list' => array(
4989
- 'alignment-baseline' => array(),
4990
- 'baseline-shift' => array(),
4991
- 'clip' => array(),
4992
- 'clip-path' => array(),
4993
- 'clip-rule' => array(),
4994
- 'color' => array(),
4995
- 'color-interpolation' => array(),
4996
- 'color-interpolation-filters' => array(),
4997
- 'color-profile' => array(),
4998
- 'color-rendering' => array(),
4999
- 'cursor' => array(),
5000
- 'direction' => array(),
5001
- 'display' => array(),
5002
- 'dominant-baseline' => array(),
5003
- 'enable-background' => array(),
5004
- 'externalresourcesrequired' => array(),
5005
- 'fill' => array(),
5006
- 'fill-opacity' => array(),
5007
- 'fill-rule' => array(),
5008
- 'filter' => array(),
5009
- 'flood-color' => array(),
5010
- 'flood-opacity' => array(),
5011
- 'font-family' => array(),
5012
- 'font-size' => array(),
5013
- 'font-size-adjust' => array(),
5014
- 'font-stretch' => array(),
5015
- 'font-style' => array(),
5016
- 'font-variant' => array(),
5017
- 'font-weight' => array(),
5018
- 'glyph-orientation-horizontal' => array(),
5019
- 'glyph-orientation-vertical' => array(),
5020
- 'gradienttransform' => array(),
5021
- 'gradientunits' => array(),
5022
- 'image-rendering' => array(),
5023
- 'kerning' => array(),
5024
- 'letter-spacing' => array(),
5025
- 'lighting-color' => array(),
5026
- 'marker-end' => array(),
5027
- 'marker-mid' => array(),
5028
- 'marker-start' => array(),
5029
- 'mask' => array(),
5030
- 'opacity' => array(),
5031
- 'overflow' => array(),
5032
- 'pointer-events' => array(),
5033
- 'shape-rendering' => array(),
5034
- 'spreadmethod' => array(),
5035
- 'stop-color' => array(),
5036
- 'stop-opacity' => array(),
5037
- 'stroke' => array(),
5038
- 'stroke-dasharray' => array(),
5039
- 'stroke-dashoffset' => array(),
5040
- 'stroke-linecap' => array(),
5041
- 'stroke-linejoin' => array(),
5042
- 'stroke-miterlimit' => array(),
5043
- 'stroke-opacity' => array(),
5044
- 'stroke-width' => array(),
5045
- 'style' => array(
5046
- 'blacklisted_value_regex' => '!important',
5047
- ),
5048
- 'text-anchor' => array(),
5049
- 'text-decoration' => array(),
5050
- 'text-rendering' => array(),
5051
- 'unicode-bidi' => array(),
5052
- 'vector-effect' => array(),
5053
- 'visibility' => array(),
5054
- 'word-spacing' => array(),
5055
- 'writing-mode' => array(),
5056
- 'x1' => array(),
5057
- 'x2' => array(),
5058
- 'xlink:actuate' => array(),
5059
- 'xlink:arcrole' => array(),
5060
- 'xlink:href' => array(
5061
- 'alternative_names' => array(
5062
- 'href',
5063
- ),
5064
- 'value_url' => array(
5065
- 'allow_empty' => false,
5066
- 'allow_relative' => true,
5067
- 'allowed_protocol' => array(
5068
- 'http',
5069
- 'https',
5070
- ),
5071
- ),
5072
- ),
5073
- 'xlink:role' => array(),
5074
- 'xlink:show' => array(),
5075
- 'xlink:title' => array(),
5076
- 'xlink:type' => array(),
5077
- 'xml:lang' => array(),
5078
- 'xml:space' => array(),
5079
- 'xmlns' => array(),
5080
- 'xmlns:xlink' => array(),
5081
- 'y1' => array(),
5082
- 'y2' => array(),
5083
- ),
5084
- 'tag_spec' => array(
5085
- 'mandatory_ancestor' => 'svg',
5086
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
5087
- ),
5088
- ),
5089
- ),
5090
- 'link' => array(
5091
- array(
5092
- 'attr_spec_list' => array(
5093
- 'charset' => array(
5094
- 'value_casei' => 'utf-8',
5095
- ),
5096
- 'color' => array(),
5097
- 'crossorigin' => array(),
5098
- 'href' => array(),
5099
- 'hreflang' => array(),
5100
- 'media' => array(),
5101
- 'rel' => array(
5102
- 'blacklisted_value_regex' => '(^|\\s)(canonical|components|import|manifest|preload|serviceworker|stylesheet|subresource|)(\\s|$)',
5103
- 'mandatory' => true,
5104
- ),
5105
- 'sizes' => array(),
5106
- 'target' => array(),
5107
- 'type' => array(),
5108
- ),
5109
- 'tag_spec' => array(
5110
- 'disallowed_ancestor' => array(
5111
- 'template',
5112
- ),
5113
- 'spec_name' => 'link rel=',
5114
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5115
- ),
5116
- ),
5117
- array(
5118
- 'attr_spec_list' => array(
5119
- 'charset' => array(
5120
- 'value_casei' => 'utf-8',
5121
- ),
5122
- 'color' => array(),
5123
- 'crossorigin' => array(),
5124
- 'href' => array(
5125
- 'blacklisted_value_regex' => '__amp_source_origin',
5126
- 'mandatory' => true,
5127
- 'value_url' => array(
5128
- 'allow_relative' => true,
5129
- 'allowed_protocol' => array(
5130
- 'http',
5131
- 'https',
5132
- ),
5133
- ),
5134
- ),
5135
- 'hreflang' => array(),
5136
- 'media' => array(),
5137
- 'rel' => array(
5138
- 'dispatch_key' => 2,
5139
- 'mandatory' => true,
5140
- 'value_casei' => 'canonical',
5141
- ),
5142
- 'sizes' => array(),
5143
- 'target' => array(),
5144
- 'type' => array(),
5145
- ),
5146
- 'tag_spec' => array(
5147
- 'mandatory' => true,
5148
- 'mandatory_parent' => 'head',
5149
- 'spec_name' => 'link rel=canonical',
5150
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
5151
- 'unique' => true,
5152
- ),
5153
- ),
5154
- array(
5155
- 'attr_spec_list' => array(
5156
- 'charset' => array(
5157
- 'value_casei' => 'utf-8',
5158
- ),
5159
- 'color' => array(),
5160
- 'crossorigin' => array(),
5161
- 'href' => array(
5162
- 'blacklisted_value_regex' => '__amp_source_origin',
5163
- 'mandatory' => true,
5164
- 'value_url' => array(
5165
- 'allow_relative' => true,
5166
- 'allowed_protocol' => array(
5167
- 'https',
5168
- ),
5169
- ),
5170
- ),
5171
- 'hreflang' => array(),
5172
- 'media' => array(),
5173
- 'rel' => array(
5174
- 'dispatch_key' => 2,
5175
- 'mandatory' => true,
5176
- 'value_casei' => 'manifest',
5177
- ),
5178
- 'sizes' => array(),
5179
- 'target' => array(),
5180
- 'type' => array(),
5181
- ),
5182
- 'tag_spec' => array(
5183
- 'mandatory_parent' => 'head',
5184
- 'spec_name' => 'link rel=manifest',
5185
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5186
- ),
5187
- ),
5188
- array(
5189
- 'attr_spec_list' => array(
5190
- 'as' => array(),
5191
- 'charset' => array(
5192
- 'value_casei' => 'utf-8',
5193
- ),
5194
- 'color' => array(),
5195
- 'crossorigin' => array(),
5196
- 'href' => array(),
5197
- 'hreflang' => array(),
5198
- 'media' => array(),
5199
- 'rel' => array(
5200
- 'dispatch_key' => 2,
5201
- 'mandatory' => true,
5202
- 'value_casei' => 'preload',
5203
- ),
5204
- 'sizes' => array(),
5205
- 'target' => array(),
5206
- 'type' => array(),
5207
- ),
5208
- 'tag_spec' => array(
5209
- 'disallowed_ancestor' => array(
5210
- 'template',
5211
- ),
5212
- 'spec_name' => 'link rel=preload',
5213
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5214
- ),
5215
- ),
5216
- array(
5217
- 'attr_spec_list' => array(
5218
- 'async' => array(),
5219
- 'crossorigin' => array(),
5220
- 'href' => array(
5221
- 'mandatory' => true,
5222
- 'value_regex' => 'https://cdn\\.materialdesignicons\\.com/([0-9]+\\.?)+/css/materialdesignicons\\.min\\.css|https://cloud\\.typography\\.com/[0-9]*/[0-9]*/css/fonts\\.css|https://fast\\.fonts\\.net/.*|https://fonts\\.googleapis\\.com/css\\?.*|https://fonts\\.googleapis\\.com/icon\\?.*|https://fonts\\.googleapis\\.com/earlyaccess/.*\\.css|https://maxcdn\\.bootstrapcdn\\.com/font-awesome/([0-9]+\\.?)+/css/font-awesome\\.min\\.css(\\?.*)?|https://use\\.fontawesome\\.com/releases/v([0-9]+\\.?)+/css/(all|brands|solids|fontawesome)\\.css|https://use\\.typekit\\.net/[\\w\\p{L}\\p{N}_]+\\.css',
5223
- ),
5224
- 'integrity' => array(),
5225
- 'media' => array(),
5226
- 'rel' => array(
5227
- 'dispatch_key' => 2,
5228
- 'mandatory' => true,
5229
- 'value_casei' => 'stylesheet',
5230
- ),
5231
- 'type' => array(
5232
- 'value_casei' => 'text/css',
5233
- ),
5234
- ),
5235
- 'tag_spec' => array(
5236
- 'mandatory_parent' => 'head',
5237
- 'spec_name' => 'link rel=stylesheet for fonts',
5238
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#custom-fonts',
5239
- ),
5240
- ),
5241
- array(
5242
- 'attr_spec_list' => array(
5243
- 'charset' => array(
5244
- 'value_casei' => 'utf-8',
5245
- ),
5246
- 'color' => array(),
5247
- 'crossorigin' => array(),
5248
- 'href' => array(
5249
- 'mandatory' => true,
5250
- ),
5251
- 'hreflang' => array(),
5252
- 'itemprop' => array(
5253
- 'dispatch_key' => 2,
5254
- 'mandatory' => true,
5255
- 'value_casei' => 'sameas',
5256
- ),
5257
- 'media' => array(),
5258
- 'sizes' => array(),
5259
- 'target' => array(),
5260
- 'type' => array(),
5261
- ),
5262
- 'tag_spec' => array(
5263
- 'spec_name' => 'link itemprop=sameAs',
5264
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5265
- ),
5266
- ),
5267
- array(
5268
- 'attr_spec_list' => array(
5269
- 'charset' => array(
5270
- 'value_casei' => 'utf-8',
5271
- ),
5272
- 'color' => array(),
5273
- 'crossorigin' => array(),
5274
- 'href' => array(
5275
- 'mandatory' => true,
5276
- ),
5277
- 'hreflang' => array(),
5278
- 'itemprop' => array(
5279
- 'mandatory' => true,
5280
- ),
5281
- 'media' => array(),
5282
- 'sizes' => array(),
5283
- 'target' => array(),
5284
- 'type' => array(),
5285
- ),
5286
- 'tag_spec' => array(
5287
- 'spec_name' => 'link itemprop=',
5288
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5289
- ),
5290
- ),
5291
- array(
5292
- 'attr_spec_list' => array(
5293
- 'charset' => array(
5294
- 'value_casei' => 'utf-8',
5295
- ),
5296
- 'color' => array(),
5297
- 'crossorigin' => array(),
5298
- 'href' => array(
5299
- 'mandatory' => true,
5300
- ),
5301
- 'hreflang' => array(),
5302
- 'media' => array(),
5303
- 'property' => array(
5304
- 'mandatory' => true,
5305
- ),
5306
- 'sizes' => array(),
5307
- 'target' => array(),
5308
- 'type' => array(),
5309
- ),
5310
- 'tag_spec' => array(
5311
- 'spec_name' => 'link property=',
5312
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5313
- ),
5314
- ),
5315
- ),
5316
- 'listing' => array(
5317
- array(
5318
- 'attr_spec_list' => array(),
5319
- 'tag_spec' => array(),
5320
- ),
5321
- ),
5322
- 'main' => array(
5323
- array(
5324
- 'attr_spec_list' => array(),
5325
- 'tag_spec' => array(),
5326
- ),
5327
- ),
5328
- 'mark' => array(
5329
- array(
5330
- 'attr_spec_list' => array(),
5331
- 'tag_spec' => array(),
5332
- ),
5333
- ),
5334
- 'marker' => array(
5335
- array(
5336
- 'attr_spec_list' => array(
5337
- 'alignment-baseline' => array(),
5338
- 'baseline-shift' => array(),
5339
- 'clip' => array(),
5340
- 'clip-path' => array(),
5341
- 'clip-rule' => array(),
5342
- 'color' => array(),
5343
- 'color-interpolation' => array(),
5344
- 'color-interpolation-filters' => array(),
5345
- 'color-profile' => array(),
5346
- 'color-rendering' => array(),
5347
- 'cursor' => array(),
5348
- 'direction' => array(),
5349
- 'display' => array(),
5350
- 'dominant-baseline' => array(),
5351
- 'enable-background' => array(),
5352
- 'externalresourcesrequired' => array(),
5353
- 'fill' => array(),
5354
- 'fill-opacity' => array(),
5355
- 'fill-rule' => array(),
5356
- 'filter' => array(),
5357
- 'flood-color' => array(),
5358
- 'flood-opacity' => array(),
5359
- 'font-family' => array(),
5360
- 'font-size' => array(),
5361
- 'font-size-adjust' => array(),
5362
- 'font-stretch' => array(),
5363
- 'font-style' => array(),
5364
- 'font-variant' => array(),
5365
- 'font-weight' => array(),
5366
- 'glyph-orientation-horizontal' => array(),
5367
- 'glyph-orientation-vertical' => array(),
5368
- 'image-rendering' => array(),
5369
- 'kerning' => array(),
5370
- 'letter-spacing' => array(),
5371
- 'lighting-color' => array(),
5372
- 'marker-end' => array(),
5373
- 'marker-mid' => array(),
5374
- 'marker-start' => array(),
5375
- 'markerheight' => array(),
5376
- 'markerunits' => array(),
5377
- 'markerwidth' => array(),
5378
- 'mask' => array(),
5379
- 'opacity' => array(),
5380
- 'orient' => array(),
5381
- 'overflow' => array(),
5382
- 'pointer-events' => array(),
5383
- 'preserveaspectratio' => array(),
5384
- 'refx' => array(),
5385
- 'refy' => array(),
5386
- 'shape-rendering' => array(),
5387
- 'stop-color' => array(),
5388
- 'stop-opacity' => array(),
5389
- 'stroke' => array(),
5390
- 'stroke-dasharray' => array(),
5391
- 'stroke-dashoffset' => array(),
5392
- 'stroke-linecap' => array(),
5393
- 'stroke-linejoin' => array(),
5394
- 'stroke-miterlimit' => array(),
5395
- 'stroke-opacity' => array(),
5396
- 'stroke-width' => array(),
5397
- 'style' => array(
5398
- 'blacklisted_value_regex' => '!important',
5399
- ),
5400
- 'text-anchor' => array(),
5401
- 'text-decoration' => array(),
5402
- 'text-rendering' => array(),
5403
- 'transform' => array(),
5404
- 'unicode-bidi' => array(),
5405
- 'vector-effect' => array(),
5406
- 'viewbox' => array(),
5407
- 'visibility' => array(),
5408
- 'word-spacing' => array(),
5409
- 'writing-mode' => array(),
5410
- 'xml:lang' => array(),
5411
- 'xml:space' => array(),
5412
- 'xmlns' => array(),
5413
- 'xmlns:xlink' => array(),
5414
- ),
5415
- 'tag_spec' => array(
5416
- 'mandatory_ancestor' => 'svg',
5417
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
5418
- ),
5419
- ),
5420
- ),
5421
- 'mask' => array(
5422
- array(
5423
- 'attr_spec_list' => array(
5424
- 'alignment-baseline' => array(),
5425
- 'baseline-shift' => array(),
5426
- 'clip' => array(),
5427
- 'clip-path' => array(),
5428
- 'clip-rule' => array(),
5429
- 'color' => array(),
5430
- 'color-interpolation' => array(),
5431
- 'color-interpolation-filters' => array(),
5432
- 'color-profile' => array(),
5433
- 'color-rendering' => array(),
5434
- 'cursor' => array(),
5435
- 'direction' => array(),
5436
- 'display' => array(),
5437
- 'dominant-baseline' => array(),
5438
- 'enable-background' => array(),
5439
- 'externalresourcesrequired' => array(),
5440
- 'fill' => array(),
5441
- 'fill-opacity' => array(),
5442
- 'fill-rule' => array(),
5443
- 'filter' => array(),
5444
- 'flood-color' => array(),
5445
- 'flood-opacity' => array(),
5446
- 'font-family' => array(),
5447
- 'font-size' => array(),
5448
- 'font-size-adjust' => array(),
5449
- 'font-stretch' => array(),
5450
- 'font-style' => array(),
5451
- 'font-variant' => array(),
5452
- 'font-weight' => array(),
5453
- 'glyph-orientation-horizontal' => array(),
5454
- 'glyph-orientation-vertical' => array(),
5455
- 'height' => array(),
5456
- 'image-rendering' => array(),
5457
- 'kerning' => array(),
5458
- 'letter-spacing' => array(),
5459
- 'lighting-color' => array(),
5460
- 'marker-end' => array(),
5461
- 'marker-mid' => array(),
5462
- 'marker-start' => array(),
5463
- 'mask' => array(),
5464
- 'maskcontentunits' => array(),
5465
- 'maskunits' => array(),
5466
- 'opacity' => array(),
5467
- 'overflow' => array(),
5468
- 'pointer-events' => array(),
5469
- 'requiredextensions' => array(),
5470
- 'requiredfeatures' => array(),
5471
- 'shape-rendering' => array(),
5472
- 'stop-color' => array(),
5473
- 'stop-opacity' => array(),
5474
- 'stroke' => array(),
5475
- 'stroke-dasharray' => array(),
5476
- 'stroke-dashoffset' => array(),
5477
- 'stroke-linecap' => array(),
5478
- 'stroke-linejoin' => array(),
5479
- 'stroke-miterlimit' => array(),
5480
- 'stroke-opacity' => array(),
5481
- 'stroke-width' => array(),
5482
- 'style' => array(
5483
- 'blacklisted_value_regex' => '!important',
5484
- ),
5485
- 'systemlanguage' => array(),
5486
- 'text-anchor' => array(),
5487
- 'text-decoration' => array(),
5488
- 'text-rendering' => array(),
5489
- 'unicode-bidi' => array(),
5490
- 'vector-effect' => array(),
5491
- 'visibility' => array(),
5492
- 'width' => array(),
5493
- 'word-spacing' => array(),
5494
- 'writing-mode' => array(),
5495
- 'x' => array(),
5496
- 'xml:lang' => array(),
5497
- 'xml:space' => array(),
5498
- 'xmlns' => array(),
5499
- 'xmlns:xlink' => array(),
5500
- 'y' => array(),
5501
- ),
5502
- 'tag_spec' => array(
5503
- 'mandatory_ancestor' => 'svg',
5504
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
5505
- ),
5506
- ),
5507
- ),
5508
- 'meta' => array(
5509
- array(
5510
- 'attr_spec_list' => array(
5511
- 'charset' => array(
5512
- 'dispatch_key' => 1,
5513
- 'mandatory' => true,
5514
- 'value_casei' => 'utf-8',
5515
- ),
5516
- ),
5517
- 'tag_spec' => array(
5518
- 'mandatory' => true,
5519
- 'mandatory_parent' => 'head',
5520
- 'spec_name' => 'meta charset=utf-8',
5521
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
5522
- 'unique' => true,
5523
- ),
5524
- ),
5525
- array(
5526
- 'attr_spec_list' => array(
5527
- 'content' => array(
5528
- 'mandatory' => true,
5529
- 'value_properties' => array(
5530
- 'height' => array(),
5531
- 'initial-scale' => array(),
5532
- 'maximum-scale' => array(),
5533
- 'minimum-scale' => array(
5534
- 'mandatory' => true,
5535
- 'value_double' => 1.0,
5536
- ),
5537
- 'shrink-to-fit' => array(),
5538
- 'user-scalable' => array(),
5539
- 'viewport-fit' => array(),
5540
- 'width' => array(
5541
- 'mandatory' => true,
5542
- 'value' => 'device-width',
5543
- ),
5544
- ),
5545
- ),
5546
- 'name' => array(
5547
- 'dispatch_key' => 2,
5548
- 'mandatory' => true,
5549
- 'value' => 'viewport',
5550
- ),
5551
- ),
5552
- 'tag_spec' => array(
5553
- 'mandatory' => true,
5554
- 'mandatory_parent' => 'head',
5555
- 'spec_name' => 'meta name=viewport',
5556
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
5557
- 'unique' => true,
5558
- ),
5559
- ),
5560
- array(
5561
- 'attr_spec_list' => array(
5562
- 'content' => array(
5563
- 'mandatory' => true,
5564
- 'value_properties' => array(
5565
- 'chrome' => array(
5566
- 'value' => '1',
5567
- ),
5568
- 'ie' => array(
5569
- 'value' => 'edge',
5570
- ),
5571
- ),
5572
- ),
5573
- 'http-equiv' => array(
5574
- 'dispatch_key' => 2,
5575
- 'mandatory' => true,
5576
- 'value_casei' => 'x-ua-compatible',
5577
- ),
5578
- ),
5579
- 'tag_spec' => array(
5580
- 'mandatory_ancestor' => 'head',
5581
- 'spec_name' => 'meta http-equiv=X-UA-Compatible',
5582
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5583
- ),
5584
- ),
5585
- array(
5586
- 'attr_spec_list' => array(
5587
- 'content' => array(
5588
- 'mandatory' => true,
5589
- 'value_regex' => '.*app-id=.*',
5590
- ),
5591
- 'name' => array(
5592
- 'dispatch_key' => 2,
5593
- 'mandatory' => true,
5594
- 'value_casei' => 'apple-itunes-app',
5595
- ),
5596
- ),
5597
- 'tag_spec' => array(
5598
- 'mandatory_parent' => 'head',
5599
- 'spec_name' => 'meta name=apple-itunes-app',
5600
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5601
- ),
5602
- ),
5603
- array(
5604
- 'attr_spec_list' => array(
5605
- 'content' => array(
5606
- 'mandatory' => true,
5607
- ),
5608
- 'name' => array(
5609
- 'dispatch_key' => 2,
5610
- 'mandatory' => true,
5611
- 'value_casei' => 'amp-experiments-opt-in',
5612
- ),
5613
- ),
5614
- 'tag_spec' => array(
5615
- 'mandatory_parent' => 'head',
5616
- 'spec_name' => 'meta name=amp-experiments-opt-in',
5617
- ),
5618
- ),
5619
- array(
5620
- 'attr_spec_list' => array(
5621
- 'content' => array(
5622
- 'mandatory' => true,
5623
- 'value_url' => array(
5624
- 'allowed_protocol' => array(
5625
- 'https',
5626
- ),
5627
- ),
5628
- ),
5629
- 'name' => array(
5630
- 'dispatch_key' => 2,
5631
- 'mandatory' => true,
5632
- 'value_casei' => 'amp-3p-iframe-src',
5633
- ),
5634
- ),
5635
- 'tag_spec' => array(
5636
- 'mandatory_parent' => 'head',
5637
- 'spec_name' => 'meta name=amp-3p-iframe-src',
5638
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad',
5639
- ),
5640
- ),
5641
- array(
5642
- 'attr_spec_list' => array(
5643
- 'content' => array(
5644
- 'mandatory' => true,
5645
- ),
5646
- 'name' => array(
5647
- 'dispatch_key' => 2,
5648
- 'mandatory' => true,
5649
- 'value_casei' => 'amp-experiment-token',
5650
- ),
5651
- ),
5652
- 'tag_spec' => array(
5653
- 'mandatory_parent' => 'head',
5654
- 'spec_name' => 'meta name=amp-experiment-token',
5655
- ),
5656
- ),
5657
- array(
5658
- 'attr_spec_list' => array(
5659
- 'content' => array(
5660
- 'mandatory' => true,
5661
- ),
5662
- 'name' => array(
5663
- 'dispatch_key' => 2,
5664
- 'mandatory' => true,
5665
- 'value_casei' => 'amp-link-variable-allowed-origin',
5666
- ),
5667
- ),
5668
- 'tag_spec' => array(
5669
- 'mandatory_parent' => 'head',
5670
- 'spec_name' => 'meta name=amp-link-variable-allowed-origin',
5671
- ),
5672
- ),
5673
- array(
5674
- 'attr_spec_list' => array(
5675
- 'content' => array(
5676
- 'mandatory' => true,
5677
- ),
5678
- 'name' => array(
5679
- 'dispatch_key' => 2,
5680
- 'mandatory' => true,
5681
- 'value_casei' => 'amp-google-client-id-api',
5682
- ),
5683
- ),
5684
- 'tag_spec' => array(
5685
- 'mandatory_parent' => 'head',
5686
- 'spec_name' => 'meta name=amp-google-clientid-id-api',
5687
- ),
5688
- ),
5689
- array(
5690
- 'attr_spec_list' => array(
5691
- 'name' => array(
5692
- 'dispatch_key' => 2,
5693
- 'mandatory' => true,
5694
- 'value_casei' => 'amp-ad-doubleclick-sra',
5695
- ),
5696
- ),
5697
- 'tag_spec' => array(
5698
- 'mandatory_parent' => 'head',
5699
- 'spec_name' => 'meta name=amp-ad-doubleclick-sra',
5700
- ),
5701
- ),
5702
- array(
5703
- 'attr_spec_list' => array(
5704
- 'content' => array(),
5705
- 'itemprop' => array(),
5706
- 'name' => array(
5707
- 'blacklisted_value_regex' => '(^|\\s)(amp-.*|amp4ads-.*|apple-itunes-app|content-disposition|revisit-after|viewport)(\\s|$)',
5708
- ),
5709
- 'property' => array(),
5710
- 'scheme' => array(),
5711
- ),
5712
- 'tag_spec' => array(
5713
- 'spec_name' => 'meta name= and content=',
5714
- ),
5715
- ),
5716
- array(
5717
- 'attr_spec_list' => array(
5718
- 'content' => array(
5719
- 'mandatory' => true,
5720
- 'value_casei' => 'text/html; charset=utf-8',
5721
- ),
5722
- 'http-equiv' => array(
5723
- 'dispatch_key' => 2,
5724
- 'mandatory' => true,
5725
- 'value_casei' => 'content-type',
5726
- ),
5727
- ),
5728
- 'tag_spec' => array(
5729
- 'mandatory_ancestor' => 'head',
5730
- 'spec_name' => 'meta http-equiv=Content-Type',
5731
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5732
- ),
5733
- ),
5734
- array(
5735
- 'attr_spec_list' => array(
5736
- 'content' => array(
5737
- 'mandatory' => true,
5738
- ),
5739
- 'http-equiv' => array(
5740
- 'dispatch_key' => 2,
5741
- 'mandatory' => true,
5742
- 'value_casei' => 'content-language',
5743
- ),
5744
- ),
5745
- 'tag_spec' => array(
5746
- 'mandatory_ancestor' => 'head',
5747
- 'spec_name' => 'meta http-equiv=content-language',
5748
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5749
- ),
5750
- ),
5751
- array(
5752
- 'attr_spec_list' => array(
5753
- 'content' => array(
5754
- 'mandatory' => true,
5755
- ),
5756
- 'http-equiv' => array(
5757
- 'dispatch_key' => 2,
5758
- 'mandatory' => true,
5759
- 'value_casei' => 'pics-label',
5760
- ),
5761
- ),
5762
- 'tag_spec' => array(
5763
- 'mandatory_ancestor' => 'head',
5764
- 'spec_name' => 'meta http-equiv=pics-label',
5765
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5766
- ),
5767
- ),
5768
- array(
5769
- 'attr_spec_list' => array(
5770
- 'content' => array(
5771
- 'mandatory' => true,
5772
- ),
5773
- 'http-equiv' => array(
5774
- 'dispatch_key' => 2,
5775
- 'mandatory' => true,
5776
- 'value_casei' => 'imagetoolbar',
5777
- ),
5778
- ),
5779
- 'tag_spec' => array(
5780
- 'mandatory_ancestor' => 'head',
5781
- 'spec_name' => 'meta http-equiv=imagetoolbar',
5782
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5783
- ),
5784
- ),
5785
- array(
5786
- 'attr_spec_list' => array(
5787
- 'content' => array(
5788
- 'mandatory' => true,
5789
- 'value_casei' => 'text/css',
5790
- ),
5791
- 'http-equiv' => array(
5792
- 'dispatch_key' => 2,
5793
- 'mandatory' => true,
5794
- 'value_casei' => 'content-style-type',
5795
- ),
5796
- ),
5797
- 'tag_spec' => array(
5798
- 'mandatory_ancestor' => 'head',
5799
- 'spec_name' => 'meta http-equiv=Content-Style-Type',
5800
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5801
- ),
5802
- ),
5803
- array(
5804
- 'attr_spec_list' => array(
5805
- 'content' => array(
5806
- 'mandatory' => true,
5807
- 'value_casei' => 'text/javascript',
5808
- ),
5809
- 'http-equiv' => array(
5810
- 'dispatch_key' => 2,
5811
- 'mandatory' => true,
5812
- 'value_casei' => 'content-script-type',
5813
- ),
5814
- ),
5815
- 'tag_spec' => array(
5816
- 'mandatory_ancestor' => 'head',
5817
- 'spec_name' => 'meta http-equiv=Content-Script-Type',
5818
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5819
- ),
5820
- ),
5821
- array(
5822
- 'attr_spec_list' => array(
5823
- 'content' => array(
5824
- 'mandatory' => true,
5825
- ),
5826
- 'http-equiv' => array(
5827
- 'dispatch_key' => 2,
5828
- 'mandatory' => true,
5829
- 'value_casei' => 'origin-trial',
5830
- ),
5831
- ),
5832
- 'tag_spec' => array(
5833
- 'mandatory_ancestor' => 'head',
5834
- 'spec_name' => 'meta http-equiv=origin-trial',
5835
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5836
- ),
5837
- ),
5838
- array(
5839
- 'attr_spec_list' => array(
5840
- 'content' => array(
5841
- 'mandatory' => true,
5842
- ),
5843
- 'http-equiv' => array(
5844
- 'dispatch_key' => 2,
5845
- 'mandatory' => true,
5846
- 'value_casei' => 'resource-type',
5847
- ),
5848
- ),
5849
- 'tag_spec' => array(
5850
- 'mandatory_ancestor' => 'head',
5851
- 'spec_name' => 'meta http-equiv=resource-type',
5852
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5853
- ),
5854
- ),
5855
- array(
5856
- 'attr_spec_list' => array(
5857
- 'content' => array(
5858
- 'mandatory' => true,
5859
- 'value_regex_casei' => '(off|on)',
5860
- ),
5861
- 'http-equiv' => array(
5862
- 'dispatch_key' => 2,
5863
- 'mandatory' => true,
5864
- 'value_casei' => 'x-dns-prefetch-control',
5865
- ),
5866
- ),
5867
- 'tag_spec' => array(
5868
- 'mandatory_ancestor' => 'head',
5869
- 'spec_name' => 'meta http-equiv=x-dns-prefetch-control',
5870
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags',
5871
- ),
5872
- ),
5873
- array(
5874
- 'attr_spec_list' => array(
5875
- 'content' => array(
5876
- 'mandatory' => true,
5877
- ),
5878
- 'name' => array(
5879
- 'dispatch_key' => 2,
5880
- 'mandatory' => true,
5881
- 'value_casei' => 'amp-ad-enable-refresh',
5882
- ),
5883
- ),
5884
- 'tag_spec' => array(
5885
- 'mandatory_ancestor' => 'head',
5886
- 'spec_name' => 'meta name=amp-ad-enable-refresh',
5887
- ),
5888
- ),
5889
- array(
5890
- 'attr_spec_list' => array(
5891
- 'content' => array(
5892
- 'mandatory' => true,
5893
- ),
5894
- 'name' => array(
5895
- 'dispatch_key' => 2,
5896
- 'mandatory' => true,
5897
- 'value_casei' => 'amp-to-amp-navigation',
5898
- ),
5899
- ),
5900
- 'tag_spec' => array(
5901
- 'mandatory_parent' => 'head',
5902
- 'spec_name' => 'meta name=amp-to-amp-navigation',
5903
- 'unique' => true,
5904
- ),
5905
- ),
5906
- ),
5907
- 'metadata' => array(
5908
- array(
5909
- 'attr_spec_list' => array(
5910
- 'style' => array(
5911
- 'blacklisted_value_regex' => '!important',
5912
- ),
5913
- 'xml:lang' => array(),
5914
- 'xml:space' => array(),
5915
- 'xmlns' => array(),
5916
- 'xmlns:xlink' => array(),
5917
- ),
5918
- 'tag_spec' => array(
5919
- 'mandatory_ancestor' => 'svg',
5920
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
5921
- ),
5922
- ),
5923
- ),
5924
- 'meter' => array(
5925
- array(
5926
- 'attr_spec_list' => array(
5927
- 'high' => array(),
5928
- 'low' => array(),
5929
- 'max' => array(),
5930
- 'min' => array(),
5931
- 'optimum' => array(),
5932
- 'value' => array(),
5933
- ),
5934
- 'tag_spec' => array(),
5935
- ),
5936
- ),
5937
- 'multicol' => array(
5938
- array(
5939
- 'attr_spec_list' => array(),
5940
- 'tag_spec' => array(),
5941
- ),
5942
- ),
5943
- 'nav' => array(
5944
- array(
5945
- 'attr_spec_list' => array(),
5946
- 'tag_spec' => array(),
5947
- ),
5948
- array(
5949
- 'attr_spec_list' => array(
5950
- 'toolbar' => array(
5951
- 'dispatch_key' => 1,
5952
- 'mandatory' => true,
5953
- ),
5954
- 'toolbar-target' => array(
5955
- 'mandatory' => true,
5956
- ),
5957
- ),
5958
- 'tag_spec' => array(
5959
- 'mandatory_parent' => 'amp-sidebar',
5960
- 'spec_name' => 'amp-sidebar > nav',
5961
- ),
5962
- ),
5963
- ),
5964
- 'nextid' => array(
5965
- array(
5966
- 'attr_spec_list' => array(),
5967
- 'tag_spec' => array(),
5968
- ),
5969
- ),
5970
- 'nobr' => array(
5971
- array(
5972
- 'attr_spec_list' => array(),
5973
- 'tag_spec' => array(),
5974
- ),
5975
- ),
5976
- 'noscript' => array(
5977
- array(
5978
- 'attr_spec_list' => array(),
5979
- 'tag_spec' => array(
5980
- 'mandatory' => true,
5981
- 'mandatory_parent' => 'head',
5982
- 'spec_name' => 'noscript enclosure for boilerplate',
5983
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/spec/amp-boilerplate.md',
5984
- 'unique' => true,
5985
- ),
5986
- ),
5987
- array(
5988
- 'attr_spec_list' => array(),
5989
- 'tag_spec' => array(
5990
- 'disallowed_ancestor' => array(
5991
- 'noscript',
5992
- ),
5993
- 'mandatory_ancestor' => 'body',
5994
- ),
5995
- ),
5996
- ),
5997
- 'o:p' => array(
5998
- array(
5999
- 'attr_spec_list' => array(),
6000
- 'tag_spec' => array(),
6001
- ),
6002
- ),
6003
- 'ol' => array(
6004
- array(
6005
- 'attr_spec_list' => array(
6006
- 'reversed' => array(
6007
- 'value' => '',
6008
- ),
6009
- 'start' => array(
6010
- 'value_regex' => '[0-9]*',
6011
- ),
6012
- 'type' => array(
6013
- 'value_regex' => '[1AaIi]',
6014
- ),
6015
- ),
6016
- 'tag_spec' => array(),
6017
- ),
6018
- ),
6019
- 'optgroup' => array(
6020
- array(
6021
- 'attr_spec_list' => array(
6022
- '[disabled]' => array(),
6023
- '[label]' => array(),
6024
- 'disabled' => array(),
6025
- 'label' => array(),
6026
- ),
6027
- 'tag_spec' => array(
6028
- 'mandatory_parent' => 'select',
6029
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
6030
- ),
6031
- ),
6032
- ),
6033
- 'option' => array(
6034
- array(
6035
- 'attr_spec_list' => array(
6036
- '[disabled]' => array(),
6037
- '[label]' => array(),
6038
- '[selected]' => array(),
6039
- '[value]' => array(),
6040
- 'disabled' => array(),
6041
- 'label' => array(),
6042
- 'selected' => array(),
6043
- 'value' => array(),
6044
- ),
6045
- 'tag_spec' => array(
6046
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
6047
- ),
6048
- ),
6049
- ),
6050
- 'output' => array(
6051
- array(
6052
- 'attr_spec_list' => array(
6053
- 'for' => array(),
6054
- 'form' => array(),
6055
- 'name' => array(
6056
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
6057
- ),
6058
- ),
6059
- 'tag_spec' => array(),
6060
- ),
6061
- ),
6062
- 'p' => array(
6063
- array(
6064
- 'attr_spec_list' => array(
6065
- 'align' => array(),
6066
- ),
6067
- 'tag_spec' => array(),
6068
- ),
6069
- ),
6070
- 'path' => array(
6071
- array(
6072
- 'attr_spec_list' => array(
6073
- 'alignment-baseline' => array(),
6074
- 'baseline-shift' => array(),
6075
- 'clip' => array(),
6076
- 'clip-path' => array(),
6077
- 'clip-rule' => array(),
6078
- 'color' => array(),
6079
- 'color-interpolation' => array(),
6080
- 'color-interpolation-filters' => array(),
6081
- 'color-profile' => array(),
6082
- 'color-rendering' => array(),
6083
- 'cursor' => array(),
6084
- 'd' => array(),
6085
- 'direction' => array(),
6086
- 'display' => array(),
6087
- 'dominant-baseline' => array(),
6088
- 'enable-background' => array(),
6089
- 'externalresourcesrequired' => array(),
6090
- 'fill' => array(),
6091
- 'fill-opacity' => array(),
6092
- 'fill-rule' => array(),
6093
- 'filter' => array(),
6094
- 'flood-color' => array(),
6095
- 'flood-opacity' => array(),
6096
- 'font-family' => array(),
6097
- 'font-size' => array(),
6098
- 'font-size-adjust' => array(),
6099
- 'font-stretch' => array(),
6100
- 'font-style' => array(),
6101
- 'font-variant' => array(),
6102
- 'font-weight' => array(),
6103
- 'glyph-orientation-horizontal' => array(),
6104
- 'glyph-orientation-vertical' => array(),
6105
- 'image-rendering' => array(),
6106
- 'kerning' => array(),
6107
- 'letter-spacing' => array(),
6108
- 'lighting-color' => array(),
6109
- 'marker-end' => array(),
6110
- 'marker-mid' => array(),
6111
- 'marker-start' => array(),
6112
- 'mask' => array(),
6113
- 'opacity' => array(),
6114
- 'overflow' => array(),
6115
- 'pathlength' => array(),
6116
- 'pointer-events' => array(),
6117
- 'requiredextensions' => array(),
6118
- 'requiredfeatures' => array(),
6119
- 'shape-rendering' => array(),
6120
- 'sketch:type' => array(),
6121
- 'stop-color' => array(),
6122
- 'stop-opacity' => array(),
6123
- 'stroke' => array(),
6124
- 'stroke-dasharray' => array(),
6125
- 'stroke-dashoffset' => array(),
6126
- 'stroke-linecap' => array(),
6127
- 'stroke-linejoin' => array(),
6128
- 'stroke-miterlimit' => array(),
6129
- 'stroke-opacity' => array(),
6130
- 'stroke-width' => array(),
6131
- 'style' => array(
6132
- 'blacklisted_value_regex' => '!important',
6133
- ),
6134
- 'systemlanguage' => array(),
6135
- 'text-anchor' => array(),
6136
- 'text-decoration' => array(),
6137
- 'text-rendering' => array(),
6138
- 'transform' => array(),
6139
- 'unicode-bidi' => array(),
6140
- 'vector-effect' => array(),
6141
- 'visibility' => array(),
6142
- 'word-spacing' => array(),
6143
- 'writing-mode' => array(),
6144
- 'xml:lang' => array(),
6145
- 'xml:space' => array(),
6146
- 'xmlns' => array(),
6147
- 'xmlns:xlink' => array(),
6148
- ),
6149
- 'tag_spec' => array(
6150
- 'mandatory_ancestor' => 'svg',
6151
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6152
- ),
6153
- ),
6154
- ),
6155
- 'pattern' => array(
6156
- array(
6157
- 'attr_spec_list' => array(
6158
- 'alignment-baseline' => array(),
6159
- 'baseline-shift' => array(),
6160
- 'clip' => array(),
6161
- 'clip-path' => array(),
6162
- 'clip-rule' => array(),
6163
- 'color' => array(),
6164
- 'color-interpolation' => array(),
6165
- 'color-interpolation-filters' => array(),
6166
- 'color-profile' => array(),
6167
- 'color-rendering' => array(),
6168
- 'cursor' => array(),
6169
- 'direction' => array(),
6170
- 'display' => array(),
6171
- 'dominant-baseline' => array(),
6172
- 'enable-background' => array(),
6173
- 'externalresourcesrequired' => array(),
6174
- 'fill' => array(),
6175
- 'fill-opacity' => array(),
6176
- 'fill-rule' => array(),
6177
- 'filter' => array(),
6178
- 'flood-color' => array(),
6179
- 'flood-opacity' => array(),
6180
- 'font-family' => array(),
6181
- 'font-size' => array(),
6182
- 'font-size-adjust' => array(),
6183
- 'font-stretch' => array(),
6184
- 'font-style' => array(),
6185
- 'font-variant' => array(),
6186
- 'font-weight' => array(),
6187
- 'glyph-orientation-horizontal' => array(),
6188
- 'glyph-orientation-vertical' => array(),
6189
- 'height' => array(),
6190
- 'image-rendering' => array(),
6191
- 'kerning' => array(),
6192
- 'letter-spacing' => array(),
6193
- 'lighting-color' => array(),
6194
- 'marker-end' => array(),
6195
- 'marker-mid' => array(),
6196
- 'marker-start' => array(),
6197
- 'mask' => array(),
6198
- 'opacity' => array(),
6199
- 'overflow' => array(),
6200
- 'patterncontentunits' => array(),
6201
- 'patterntransform' => array(),
6202
- 'patternunits' => array(),
6203
- 'pointer-events' => array(),
6204
- 'preserveaspectratio' => array(),
6205
- 'requiredextensions' => array(),
6206
- 'requiredfeatures' => array(),
6207
- 'shape-rendering' => array(),
6208
- 'stop-color' => array(),
6209
- 'stop-opacity' => array(),
6210
- 'stroke' => array(),
6211
- 'stroke-dasharray' => array(),
6212
- 'stroke-dashoffset' => array(),
6213
- 'stroke-linecap' => array(),
6214
- 'stroke-linejoin' => array(),
6215
- 'stroke-miterlimit' => array(),
6216
- 'stroke-opacity' => array(),
6217
- 'stroke-width' => array(),
6218
- 'style' => array(
6219
- 'blacklisted_value_regex' => '!important',
6220
- ),
6221
- 'systemlanguage' => array(),
6222
- 'text-anchor' => array(),
6223
- 'text-decoration' => array(),
6224
- 'text-rendering' => array(),
6225
- 'unicode-bidi' => array(),
6226
- 'vector-effect' => array(),
6227
- 'viewbox' => array(),
6228
- 'visibility' => array(),
6229
- 'width' => array(),
6230
- 'word-spacing' => array(),
6231
- 'writing-mode' => array(),
6232
- 'x' => array(),
6233
- 'xlink:actuate' => array(),
6234
- 'xlink:arcrole' => array(),
6235
- 'xlink:href' => array(
6236
- 'alternative_names' => array(
6237
- 'href',
6238
- ),
6239
- 'value_url' => array(
6240
- 'allow_empty' => false,
6241
- 'allow_relative' => true,
6242
- 'allowed_protocol' => array(
6243
- 'http',
6244
- 'https',
6245
- ),
6246
- ),
6247
- ),
6248
- 'xlink:role' => array(),
6249
- 'xlink:show' => array(),
6250
- 'xlink:title' => array(),
6251
- 'xlink:type' => array(),
6252
- 'xml:lang' => array(),
6253
- 'xml:space' => array(),
6254
- 'xmlns' => array(),
6255
- 'xmlns:xlink' => array(),
6256
- 'y' => array(),
6257
- ),
6258
- 'tag_spec' => array(
6259
- 'mandatory_ancestor' => 'svg',
6260
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6261
- ),
6262
- ),
6263
- ),
6264
- 'polygon' => array(
6265
- array(
6266
- 'attr_spec_list' => array(
6267
- 'alignment-baseline' => array(),
6268
- 'baseline-shift' => array(),
6269
- 'clip' => array(),
6270
- 'clip-path' => array(),
6271
- 'clip-rule' => array(),
6272
- 'color' => array(),
6273
- 'color-interpolation' => array(),
6274
- 'color-interpolation-filters' => array(),
6275
- 'color-profile' => array(),
6276
- 'color-rendering' => array(),
6277
- 'cursor' => array(),
6278
- 'direction' => array(),
6279
- 'display' => array(),
6280
- 'dominant-baseline' => array(),
6281
- 'enable-background' => array(),
6282
- 'externalresourcesrequired' => array(),
6283
- 'fill' => array(),
6284
- 'fill-opacity' => array(),
6285
- 'fill-rule' => array(),
6286
- 'filter' => array(),
6287
- 'flood-color' => array(),
6288
- 'flood-opacity' => array(),
6289
- 'font-family' => array(),
6290
- 'font-size' => array(),
6291
- 'font-size-adjust' => array(),
6292
- 'font-stretch' => array(),
6293
- 'font-style' => array(),
6294
- 'font-variant' => array(),
6295
- 'font-weight' => array(),
6296
- 'glyph-orientation-horizontal' => array(),
6297
- 'glyph-orientation-vertical' => array(),
6298
- 'image-rendering' => array(),
6299
- 'kerning' => array(),
6300
- 'letter-spacing' => array(),
6301
- 'lighting-color' => array(),
6302
- 'marker-end' => array(),
6303
- 'marker-mid' => array(),
6304
- 'marker-start' => array(),
6305
- 'mask' => array(),
6306
- 'opacity' => array(),
6307
- 'overflow' => array(),
6308
- 'pointer-events' => array(),
6309
- 'points' => array(),
6310
- 'requiredextensions' => array(),
6311
- 'requiredfeatures' => array(),
6312
- 'shape-rendering' => array(),
6313
- 'sketch:type' => array(),
6314
- 'stop-color' => array(),
6315
- 'stop-opacity' => array(),
6316
- 'stroke' => array(),
6317
- 'stroke-dasharray' => array(),
6318
- 'stroke-dashoffset' => array(),
6319
- 'stroke-linecap' => array(),
6320
- 'stroke-linejoin' => array(),
6321
- 'stroke-miterlimit' => array(),
6322
- 'stroke-opacity' => array(),
6323
- 'stroke-width' => array(),
6324
- 'style' => array(
6325
- 'blacklisted_value_regex' => '!important',
6326
- ),
6327
- 'systemlanguage' => array(),
6328
- 'text-anchor' => array(),
6329
- 'text-decoration' => array(),
6330
- 'text-rendering' => array(),
6331
- 'transform' => array(),
6332
- 'unicode-bidi' => array(),
6333
- 'vector-effect' => array(),
6334
- 'visibility' => array(),
6335
- 'word-spacing' => array(),
6336
- 'writing-mode' => array(),
6337
- 'xml:lang' => array(),
6338
- 'xml:space' => array(),
6339
- 'xmlns' => array(),
6340
- 'xmlns:xlink' => array(),
6341
- ),
6342
- 'tag_spec' => array(
6343
- 'mandatory_ancestor' => 'svg',
6344
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6345
- ),
6346
- ),
6347
- ),
6348
- 'polyline' => array(
6349
- array(
6350
- 'attr_spec_list' => array(
6351
- 'alignment-baseline' => array(),
6352
- 'baseline-shift' => array(),
6353
- 'clip' => array(),
6354
- 'clip-path' => array(),
6355
- 'clip-rule' => array(),
6356
- 'color' => array(),
6357
- 'color-interpolation' => array(),
6358
- 'color-interpolation-filters' => array(),
6359
- 'color-profile' => array(),
6360
- 'color-rendering' => array(),
6361
- 'cursor' => array(),
6362
- 'direction' => array(),
6363
- 'display' => array(),
6364
- 'dominant-baseline' => array(),
6365
- 'enable-background' => array(),
6366
- 'externalresourcesrequired' => array(),
6367
- 'fill' => array(),
6368
- 'fill-opacity' => array(),
6369
- 'fill-rule' => array(),
6370
- 'filter' => array(),
6371
- 'flood-color' => array(),
6372
- 'flood-opacity' => array(),
6373
- 'font-family' => array(),
6374
- 'font-size' => array(),
6375
- 'font-size-adjust' => array(),
6376
- 'font-stretch' => array(),
6377
- 'font-style' => array(),
6378
- 'font-variant' => array(),
6379
- 'font-weight' => array(),
6380
- 'glyph-orientation-horizontal' => array(),
6381
- 'glyph-orientation-vertical' => array(),
6382
- 'image-rendering' => array(),
6383
- 'kerning' => array(),
6384
- 'letter-spacing' => array(),
6385
- 'lighting-color' => array(),
6386
- 'marker-end' => array(),
6387
- 'marker-mid' => array(),
6388
- 'marker-start' => array(),
6389
- 'mask' => array(),
6390
- 'opacity' => array(),
6391
- 'overflow' => array(),
6392
- 'pointer-events' => array(),
6393
- 'points' => array(),
6394
- 'requiredextensions' => array(),
6395
- 'requiredfeatures' => array(),
6396
- 'shape-rendering' => array(),
6397
- 'sketch:type' => array(),
6398
- 'stop-color' => array(),
6399
- 'stop-opacity' => array(),
6400
- 'stroke' => array(),
6401
- 'stroke-dasharray' => array(),
6402
- 'stroke-dashoffset' => array(),
6403
- 'stroke-linecap' => array(),
6404
- 'stroke-linejoin' => array(),
6405
- 'stroke-miterlimit' => array(),
6406
- 'stroke-opacity' => array(),
6407
- 'stroke-width' => array(),
6408
- 'style' => array(
6409
- 'blacklisted_value_regex' => '!important',
6410
- ),
6411
- 'systemlanguage' => array(),
6412
- 'text-anchor' => array(),
6413
- 'text-decoration' => array(),
6414
- 'text-rendering' => array(),
6415
- 'transform' => array(),
6416
- 'unicode-bidi' => array(),
6417
- 'vector-effect' => array(),
6418
- 'visibility' => array(),
6419
- 'word-spacing' => array(),
6420
- 'writing-mode' => array(),
6421
- 'xml:lang' => array(),
6422
- 'xml:space' => array(),
6423
- 'xmlns' => array(),
6424
- 'xmlns:xlink' => array(),
6425
- ),
6426
- 'tag_spec' => array(
6427
- 'mandatory_ancestor' => 'svg',
6428
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6429
- ),
6430
- ),
6431
- ),
6432
- 'pre' => array(
6433
- array(
6434
- 'attr_spec_list' => array(),
6435
- 'tag_spec' => array(),
6436
- ),
6437
- ),
6438
- 'progress' => array(
6439
- array(
6440
- 'attr_spec_list' => array(
6441
- 'max' => array(),
6442
- 'value' => array(),
6443
- ),
6444
- 'tag_spec' => array(),
6445
- ),
6446
- ),
6447
- 'q' => array(
6448
- array(
6449
- 'attr_spec_list' => array(
6450
- 'cite' => array(
6451
- 'blacklisted_value_regex' => '__amp_source_origin',
6452
- 'value_url' => array(
6453
- 'allow_empty' => true,
6454
- 'allow_relative' => true,
6455
- 'allowed_protocol' => array(
6456
- 'http',
6457
- 'https',
6458
- ),
6459
- ),
6460
- ),
6461
- ),
6462
- 'tag_spec' => array(),
6463
- ),
6464
- ),
6465
- 'radialgradient' => array(
6466
- array(
6467
- 'attr_spec_list' => array(
6468
- 'alignment-baseline' => array(),
6469
- 'baseline-shift' => array(),
6470
- 'clip' => array(),
6471
- 'clip-path' => array(),
6472
- 'clip-rule' => array(),
6473
- 'color' => array(),
6474
- 'color-interpolation' => array(),
6475
- 'color-interpolation-filters' => array(),
6476
- 'color-profile' => array(),
6477
- 'color-rendering' => array(),
6478
- 'cursor' => array(),
6479
- 'cx' => array(),
6480
- 'cy' => array(),
6481
- 'direction' => array(),
6482
- 'display' => array(),
6483
- 'dominant-baseline' => array(),
6484
- 'enable-background' => array(),
6485
- 'externalresourcesrequired' => array(),
6486
- 'fill' => array(),
6487
- 'fill-opacity' => array(),
6488
- 'fill-rule' => array(),
6489
- 'filter' => array(),
6490
- 'flood-color' => array(),
6491
- 'flood-opacity' => array(),
6492
- 'font-family' => array(),
6493
- 'font-size' => array(),
6494
- 'font-size-adjust' => array(),
6495
- 'font-stretch' => array(),
6496
- 'font-style' => array(),
6497
- 'font-variant' => array(),
6498
- 'font-weight' => array(),
6499
- 'fr' => array(),
6500
- 'fx' => array(),
6501
- 'fy' => array(),
6502
- 'glyph-orientation-horizontal' => array(),
6503
- 'glyph-orientation-vertical' => array(),
6504
- 'gradienttransform' => array(),
6505
- 'gradientunits' => array(),
6506
- 'image-rendering' => array(),
6507
- 'kerning' => array(),
6508
- 'letter-spacing' => array(),
6509
- 'lighting-color' => array(),
6510
- 'marker-end' => array(),
6511
- 'marker-mid' => array(),
6512
- 'marker-start' => array(),
6513
- 'mask' => array(),
6514
- 'opacity' => array(),
6515
- 'overflow' => array(),
6516
- 'pointer-events' => array(),
6517
- 'r' => array(),
6518
- 'shape-rendering' => array(),
6519
- 'spreadmethod' => array(),
6520
- 'stop-color' => array(),
6521
- 'stop-opacity' => array(),
6522
- 'stroke' => array(),
6523
- 'stroke-dasharray' => array(),
6524
- 'stroke-dashoffset' => array(),
6525
- 'stroke-linecap' => array(),
6526
- 'stroke-linejoin' => array(),
6527
- 'stroke-miterlimit' => array(),
6528
- 'stroke-opacity' => array(),
6529
- 'stroke-width' => array(),
6530
- 'style' => array(
6531
- 'blacklisted_value_regex' => '!important',
6532
- ),
6533
- 'text-anchor' => array(),
6534
- 'text-decoration' => array(),
6535
- 'text-rendering' => array(),
6536
- 'unicode-bidi' => array(),
6537
- 'vector-effect' => array(),
6538
- 'visibility' => array(),
6539
- 'word-spacing' => array(),
6540
- 'writing-mode' => array(),
6541
- 'xlink:actuate' => array(),
6542
- 'xlink:arcrole' => array(),
6543
- 'xlink:href' => array(
6544
- 'alternative_names' => array(
6545
- 'href',
6546
- ),
6547
- 'value_url' => array(
6548
- 'allow_empty' => false,
6549
- 'allow_relative' => true,
6550
- 'allowed_protocol' => array(
6551
- 'http',
6552
- 'https',
6553
- ),
6554
- ),
6555
- ),
6556
- 'xlink:role' => array(),
6557
- 'xlink:show' => array(),
6558
- 'xlink:title' => array(),
6559
- 'xlink:type' => array(),
6560
- 'xml:lang' => array(),
6561
- 'xml:space' => array(),
6562
- 'xmlns' => array(),
6563
- 'xmlns:xlink' => array(),
6564
- ),
6565
- 'tag_spec' => array(
6566
- 'mandatory_ancestor' => 'svg',
6567
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6568
- ),
6569
- ),
6570
- ),
6571
- 'rb' => array(
6572
- array(
6573
- 'attr_spec_list' => array(),
6574
- 'tag_spec' => array(),
6575
- ),
6576
- ),
6577
- 'rect' => array(
6578
- array(
6579
- 'attr_spec_list' => array(
6580
- 'alignment-baseline' => array(),
6581
- 'baseline-shift' => array(),
6582
- 'clip' => array(),
6583
- 'clip-path' => array(),
6584
- 'clip-rule' => array(),
6585
- 'color' => array(),
6586
- 'color-interpolation' => array(),
6587
- 'color-interpolation-filters' => array(),
6588
- 'color-profile' => array(),
6589
- 'color-rendering' => array(),
6590
- 'cursor' => array(),
6591
- 'direction' => array(),
6592
- 'display' => array(),
6593
- 'dominant-baseline' => array(),
6594
- 'enable-background' => array(),
6595
- 'externalresourcesrequired' => array(),
6596
- 'fill' => array(),
6597
- 'fill-opacity' => array(),
6598
- 'fill-rule' => array(),
6599
- 'filter' => array(),
6600
- 'flood-color' => array(),
6601
- 'flood-opacity' => array(),
6602
- 'font-family' => array(),
6603
- 'font-size' => array(),
6604
- 'font-size-adjust' => array(),
6605
- 'font-stretch' => array(),
6606
- 'font-style' => array(),
6607
- 'font-variant' => array(),
6608
- 'font-weight' => array(),
6609
- 'glyph-orientation-horizontal' => array(),
6610
- 'glyph-orientation-vertical' => array(),
6611
- 'height' => array(),
6612
- 'image-rendering' => array(),
6613
- 'kerning' => array(),
6614
- 'letter-spacing' => array(),
6615
- 'lighting-color' => array(),
6616
- 'marker-end' => array(),
6617
- 'marker-mid' => array(),
6618
- 'marker-start' => array(),
6619
- 'mask' => array(),
6620
- 'opacity' => array(),
6621
- 'overflow' => array(),
6622
- 'pointer-events' => array(),
6623
- 'requiredextensions' => array(),
6624
- 'requiredfeatures' => array(),
6625
- 'rx' => array(),
6626
- 'ry' => array(),
6627
- 'shape-rendering' => array(),
6628
- 'sketch:type' => array(),
6629
- 'stop-color' => array(),
6630
- 'stop-opacity' => array(),
6631
- 'stroke' => array(),
6632
- 'stroke-dasharray' => array(),
6633
- 'stroke-dashoffset' => array(),
6634
- 'stroke-linecap' => array(),
6635
- 'stroke-linejoin' => array(),
6636
- 'stroke-miterlimit' => array(),
6637
- 'stroke-opacity' => array(),
6638
- 'stroke-width' => array(),
6639
- 'style' => array(
6640
- 'blacklisted_value_regex' => '!important',
6641
- ),
6642
- 'systemlanguage' => array(),
6643
- 'text-anchor' => array(),
6644
- 'text-decoration' => array(),
6645
- 'text-rendering' => array(),
6646
- 'transform' => array(),
6647
- 'unicode-bidi' => array(),
6648
- 'vector-effect' => array(),
6649
- 'visibility' => array(),
6650
- 'width' => array(),
6651
- 'word-spacing' => array(),
6652
- 'writing-mode' => array(),
6653
- 'x' => array(),
6654
- 'xml:lang' => array(),
6655
- 'xml:space' => array(),
6656
- 'xmlns' => array(),
6657
- 'xmlns:xlink' => array(),
6658
- 'y' => array(),
6659
- ),
6660
- 'tag_spec' => array(
6661
- 'mandatory_ancestor' => 'svg',
6662
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
6663
- ),
6664
- ),
6665
- ),
6666
- 'rp' => array(
6667
- array(
6668
- 'attr_spec_list' => array(),
6669
- 'tag_spec' => array(),
6670
- ),
6671
- ),
6672
- 'rt' => array(
6673
- array(
6674
- 'attr_spec_list' => array(),
6675
- 'tag_spec' => array(),
6676
- ),
6677
- ),
6678
- 'rtc' => array(
6679
- array(
6680
- 'attr_spec_list' => array(),
6681
- 'tag_spec' => array(),
6682
- ),
6683
- ),
6684
- 'ruby' => array(
6685
- array(
6686
- 'attr_spec_list' => array(),
6687
- 'tag_spec' => array(),
6688
- ),
6689
- ),
6690
- 's' => array(
6691
- array(
6692
- 'attr_spec_list' => array(),
6693
- 'tag_spec' => array(),
6694
- ),
6695
- ),
6696
- 'samp' => array(
6697
- array(
6698
- 'attr_spec_list' => array(),
6699
- 'tag_spec' => array(),
6700
- ),
6701
- ),
6702
- 'script' => array(
6703
- array(
6704
- 'attr_spec_list' => array(
6705
- 'async' => array(
6706
- 'mandatory' => true,
6707
- 'value' => '',
6708
- ),
6709
- 'nonce' => array(),
6710
- 'src' => array(
6711
- 'dispatch_key' => 2,
6712
- 'mandatory' => true,
6713
- 'value' => 'https://cdn.ampproject.org/v0.js',
6714
- ),
6715
- 'type' => array(
6716
- 'value_casei' => 'text/javascript',
6717
- ),
6718
- ),
6719
- 'cdata' => array(
6720
- 'blacklisted_cdata_regex' => array(
6721
- 'error_message' => 'contents',
6722
- 'regex' => '.',
6723
- ),
6724
- ),
6725
- 'tag_spec' => array(
6726
- 'mandatory' => true,
6727
- 'mandatory_parent' => 'head',
6728
- 'spec_name' => 'amphtml engine v0.js script',
6729
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup',
6730
- 'unique' => true,
6731
- ),
6732
- ),
6733
- array(
6734
- 'attr_spec_list' => array(
6735
- 'nonce' => array(),
6736
- 'type' => array(
6737
- 'dispatch_key' => 2,
6738
- 'mandatory' => true,
6739
- 'value_casei' => 'application/ld+json',
6740
- ),
6741
- ),
6742
- 'cdata' => array(
6743
- 'blacklisted_cdata_regex' => array(
6744
- 'error_message' => 'html comments',
6745
- 'regex' => '<!--',
6746
- ),
6747
- ),
6748
- 'tag_spec' => array(
6749
- 'spec_name' => 'script type=application/ld+json',
6750
- ),
6751
- ),
6752
- array(
6753
- 'attr_spec_list' => array(
6754
- 'id' => array(
6755
- 'dispatch_key' => 2,
6756
- 'mandatory' => true,
6757
- 'value_casei' => 'amp-rtc',
6758
- ),
6759
- 'nonce' => array(),
6760
- 'type' => array(
6761
- 'mandatory' => true,
6762
- 'value_casei' => 'application/json',
6763
- ),
6764
- ),
6765
- 'cdata' => array(
6766
- 'blacklisted_cdata_regex' => array(
6767
- 'error_message' => 'html comments',
6768
- 'regex' => '<!--',
6769
- ),
6770
- ),
6771
- 'tag_spec' => array(
6772
- 'mandatory_parent' => 'head',
6773
- 'spec_name' => 'script id=amp-rtc',
6774
- 'unique' => true,
6775
- ),
6776
- ),
6777
- array(
6778
- 'attr_spec_list' => array(
6779
- 'type' => array(
6780
- 'dispatch_key' => 3,
6781
- 'mandatory' => true,
6782
- 'value_casei' => 'application/json',
6783
- ),
6784
- ),
6785
- 'cdata' => array(
6786
- 'blacklisted_cdata_regex' => array(
6787
- 'error_message' => 'html comments',
6788
- 'regex' => '<!--',
6789
- ),
6790
- ),
6791
- 'tag_spec' => array(
6792
- 'mandatory_parent' => 'amp-ima-video',
6793
- 'spec_name' => 'amp-ima-video > script[type=application/json]',
6794
- ),
6795
- ),
6796
- array(
6797
- 'attr_spec_list' => array(
6798
- 'async' => array(
6799
- 'mandatory' => true,
6800
- 'value' => '',
6801
- ),
6802
- 'nonce' => array(),
6803
- 'type' => array(
6804
- 'value_casei' => 'text/javascript',
6805
- ),
6806
- ),
6807
- 'tag_spec' => array(
6808
- 'extension_spec' => array(
6809
- 'allowed_versions' => array(
6810
- '0.1',
6811
- 'latest',
6812
- ),
6813
- 'name' => 'amp-3q-player',
6814
- ),
6815
- ),
6816
- ),
6817
- array(
6818
- 'attr_spec_list' => array(
6819
- 'async' => array(
6820
- 'mandatory' => true,
6821
- 'value' => '',
6822
- ),
6823
- 'nonce' => array(),
6824
- 'type' => array(
6825
- 'value_casei' => 'text/javascript',
6826
- ),
6827
- ),
6828
- 'tag_spec' => array(
6829
- 'extension_spec' => array(
6830
- 'allowed_versions' => array(
6831
- '0.1',
6832
- 'latest',
6833
- ),
6834
- 'name' => 'amp-access-laterpay',
6835
- 'requires_usage' => 3,
6836
- ),
6837
- 'requires_extension' => array(
6838
- 'amp-access',
6839
- ),
6840
- ),
6841
- ),
6842
- array(
6843
- 'attr_spec_list' => array(
6844
- 'async' => array(
6845
- 'mandatory' => true,
6846
- 'value' => '',
6847
- ),
6848
- 'nonce' => array(),
6849
- 'type' => array(
6850
- 'value_casei' => 'text/javascript',
6851
- ),
6852
- ),
6853
- 'tag_spec' => array(
6854
- 'extension_spec' => array(
6855
- 'allowed_versions' => array(
6856
- '0.1',
6857
- 'latest',
6858
- ),
6859
- 'name' => 'amp-access-scroll',
6860
- 'requires_usage' => 3,
6861
- ),
6862
- 'requires_extension' => array(
6863
- 'amp-access',
6864
- ),
6865
- ),
6866
- ),
6867
- array(
6868
- 'attr_spec_list' => array(
6869
- 'async' => array(
6870
- 'mandatory' => true,
6871
- 'value' => '',
6872
- ),
6873
- 'nonce' => array(),
6874
- 'type' => array(
6875
- 'value_casei' => 'text/javascript',
6876
- ),
6877
- ),
6878
- 'tag_spec' => array(
6879
- 'extension_spec' => array(
6880
- 'allowed_versions' => array(
6881
- '0.1',
6882
- 'latest',
6883
- ),
6884
- 'deprecated_allow_duplicates' => true,
6885
- 'name' => 'amp-access',
6886
- 'requires_usage' => 2,
6887
- ),
6888
- ),
6889
- ),
6890
- array(
6891
- 'attr_spec_list' => array(
6892
- 'id' => array(
6893
- 'dispatch_key' => 2,
6894
- 'mandatory' => true,
6895
- 'value' => 'amp-access',
6896
- ),
6897
- 'nonce' => array(),
6898
- 'type' => array(
6899
- 'mandatory' => true,
6900
- 'value_casei' => 'application/json',
6901
- ),
6902
- ),
6903
- 'cdata' => array(
6904
- 'blacklisted_cdata_regex' => array(
6905
- 'error_message' => 'html comments',
6906
- 'regex' => '<!--',
6907
- ),
6908
- ),
6909
- 'tag_spec' => array(
6910
- 'mandatory_parent' => 'head',
6911
- 'requires_extension' => array(
6912
- 'amp-access',
6913
- 'amp-analytics',
6914
- ),
6915
- 'spec_name' => 'amp-access extension .json script',
6916
- 'unique' => true,
6917
- ),
6918
- ),
6919
- array(
6920
- 'attr_spec_list' => array(
6921
- 'async' => array(
6922
- 'mandatory' => true,
6923
- 'value' => '',
6924
- ),
6925
- 'nonce' => array(),
6926
- 'type' => array(
6927
- 'value_casei' => 'text/javascript',
6928
- ),
6929
- ),
6930
- 'tag_spec' => array(
6931
- 'extension_spec' => array(
6932
- 'allowed_versions' => array(
6933
- '0.1',
6934
- 'latest',
6935
- ),
6936
- 'deprecated_allow_duplicates' => true,
6937
- 'name' => 'amp-accordion',
6938
- 'requires_usage' => 2,
6939
- ),
6940
- ),
6941
- ),
6942
- array(
6943
- 'attr_spec_list' => array(
6944
- 'async' => array(
6945
- 'mandatory' => true,
6946
- 'value' => '',
6947
- ),
6948
- 'nonce' => array(),
6949
- 'type' => array(
6950
- 'value_casei' => 'text/javascript',
6951
- ),
6952
- ),
6953
- 'tag_spec' => array(
6954
- 'extension_spec' => array(
6955
- 'allowed_versions' => array(
6956
- '0.1',
6957
- 'latest',
6958
- ),
6959
- 'deprecated_allow_duplicates' => true,
6960
- 'name' => 'amp-ad',
6961
- 'requires_usage' => 2,
6962
- ),
6963
- 'spec_name' => 'amp-ad extension .js script',
6964
- ),
6965
- ),
6966
- array(
6967
- 'attr_spec_list' => array(
6968
- 'async' => array(
6969
- 'mandatory' => true,
6970
- 'value' => '',
6971
- ),
6972
- 'nonce' => array(),
6973
- 'type' => array(
6974
- 'value_casei' => 'text/javascript',
6975
- ),
6976
- ),
6977
- 'tag_spec' => array(
6978
- 'extension_spec' => array(
6979
- 'allowed_versions' => array(
6980
- '0.1',
6981
- 'latest',
6982
- ),
6983
- 'deprecated_allow_duplicates' => true,
6984
- 'name' => 'amp-analytics',
6985
- 'requires_usage' => 2,
6986
- ),
6987
- ),
6988
- ),
6989
- array(
6990
- 'attr_spec_list' => array(
6991
- 'nonce' => array(),
6992
- 'type' => array(
6993
- 'dispatch_key' => 3,
6994
- 'mandatory' => true,
6995
- 'value_casei' => 'application/json',
6996
- ),
6997
- ),
6998
- 'cdata' => array(
6999
- 'blacklisted_cdata_regex' => array(
7000
- 'error_message' => 'html comments',
7001
- 'regex' => '<!--',
7002
- ),
7003
- ),
7004
- 'tag_spec' => array(
7005
- 'mandatory_parent' => 'amp-analytics',
7006
- 'requires_extension' => array(
7007
- 'amp-analytics',
7008
- ),
7009
- 'spec_name' => 'amp-analytics extension .json script',
7010
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-analytics',
7011
- ),
7012
- ),
7013
- array(
7014
- 'attr_spec_list' => array(
7015
- 'async' => array(
7016
- 'mandatory' => true,
7017
- 'value' => '',
7018
- ),
7019
- 'nonce' => array(),
7020
- 'type' => array(
7021
- 'value_casei' => 'text/javascript',
7022
- ),
7023
- ),
7024
- 'tag_spec' => array(
7025
- 'extension_spec' => array(
7026
- 'allowed_versions' => array(
7027
- '0.1',
7028
- 'latest',
7029
- ),
7030
- 'deprecated_allow_duplicates' => true,
7031
- 'name' => 'amp-anim',
7032
- 'requires_usage' => 2,
7033
- ),
7034
- ),
7035
- ),
7036
- array(
7037
- 'attr_spec_list' => array(
7038
- 'async' => array(
7039
- 'mandatory' => true,
7040
- 'value' => '',
7041
- ),
7042
- 'nonce' => array(),
7043
- 'type' => array(
7044
- 'value_casei' => 'text/javascript',
7045
- ),
7046
- ),
7047
- 'tag_spec' => array(
7048
- 'extension_spec' => array(
7049
- 'allowed_versions' => array(
7050
- '0.1',
7051
- 'latest',
7052
- ),
7053
- 'name' => 'amp-animation',
7054
- ),
7055
- ),
7056
- ),
7057
- array(
7058
- 'attr_spec_list' => array(
7059
- 'nonce' => array(),
7060
- 'type' => array(
7061
- 'dispatch_key' => 3,
7062
- 'mandatory' => true,
7063
- 'value_casei' => 'application/json',
7064
- ),
7065
- ),
7066
- 'cdata' => array(
7067
- 'blacklisted_cdata_regex' => array(
7068
- 'error_message' => 'html comments',
7069
- 'regex' => '<!--',
7070
- ),
7071
- ),
7072
- 'tag_spec' => array(
7073
- 'mandatory_parent' => 'amp-animation',
7074
- 'requires_extension' => array(
7075
- 'amp-animation',
7076
- ),
7077
- 'spec_name' => 'amp-animation extension .json script',
7078
- ),
7079
- ),
7080
- array(
7081
- 'attr_spec_list' => array(
7082
- 'async' => array(
7083
- 'mandatory' => true,
7084
- 'value' => '',
7085
- ),
7086
- 'nonce' => array(),
7087
- 'type' => array(
7088
- 'value_casei' => 'text/javascript',
7089
- ),
7090
- ),
7091
- 'tag_spec' => array(
7092
- 'extension_spec' => array(
7093
- 'allowed_versions' => array(
7094
- '0.1',
7095
- 'latest',
7096
- ),
7097
- 'deprecated_allow_duplicates' => true,
7098
- 'name' => 'amp-apester-media',
7099
- 'requires_usage' => 2,
7100
- ),
7101
- ),
7102
- ),
7103
- array(
7104
- 'attr_spec_list' => array(
7105
- 'async' => array(
7106
- 'mandatory' => true,
7107
- 'value' => '',
7108
- ),
7109
- 'nonce' => array(),
7110
- 'type' => array(
7111
- 'value_casei' => 'text/javascript',
7112
- ),
7113
- ),
7114
- 'tag_spec' => array(
7115
- 'extension_spec' => array(
7116
- 'allowed_versions' => array(
7117
- '0.1',
7118
- 'latest',
7119
- ),
7120
- 'deprecated_allow_duplicates' => true,
7121
- 'name' => 'amp-app-banner',
7122
- ),
7123
- ),
7124
- ),
7125
- array(
7126
- 'attr_spec_list' => array(
7127
- 'async' => array(
7128
- 'mandatory' => true,
7129
- 'value' => '',
7130
- ),
7131
- 'nonce' => array(),
7132
- 'type' => array(
7133
- 'value_casei' => 'text/javascript',
7134
- ),
7135
- ),
7136
- 'tag_spec' => array(
7137
- 'extension_spec' => array(
7138
- 'allowed_versions' => array(
7139
- '0.1',
7140
- 'latest',
7141
- ),
7142
- 'deprecated_allow_duplicates' => true,
7143
- 'name' => 'amp-audio',
7144
- 'requires_usage' => 2,
7145
- ),
7146
- ),
7147
- ),
7148
- array(
7149
- 'attr_spec_list' => array(
7150
- 'async' => array(
7151
- 'mandatory' => true,
7152
- 'value' => '',
7153
- ),
7154
- 'nonce' => array(),
7155
- 'type' => array(
7156
- 'value_casei' => 'text/javascript',
7157
- ),
7158
- ),
7159
- 'tag_spec' => array(
7160
- 'extension_spec' => array(
7161
- 'allowed_versions' => array(
7162
- '0.1',
7163
- 'latest',
7164
- ),
7165
- 'name' => 'amp-auto-ads',
7166
- ),
7167
- ),
7168
- ),
7169
- array(
7170
- 'attr_spec_list' => array(
7171
- 'async' => array(
7172
- 'mandatory' => true,
7173
- 'value' => '',
7174
- ),
7175
- 'nonce' => array(),
7176
- 'type' => array(
7177
- 'value_casei' => 'text/javascript',
7178
- ),
7179
- ),
7180
- 'tag_spec' => array(
7181
- 'extension_spec' => array(
7182
- 'allowed_versions' => array(
7183
- '0.1',
7184
- 'latest',
7185
- ),
7186
- 'name' => 'amp-beopinion',
7187
- ),
7188
- ),
7189
- ),
7190
- array(
7191
- 'attr_spec_list' => array(
7192
- 'async' => array(
7193
- 'mandatory' => true,
7194
- 'value' => '',
7195
- ),
7196
- 'nonce' => array(),
7197
- 'type' => array(
7198
- 'value_casei' => 'text/javascript',
7199
- ),
7200
- ),
7201
- 'tag_spec' => array(
7202
- 'extension_spec' => array(
7203
- 'allowed_versions' => array(
7204
- '0.1',
7205
- 'latest',
7206
- ),
7207
- 'name' => 'amp-bind',
7208
- 'requires_usage' => 3,
7209
- ),
7210
- ),
7211
- ),
7212
- array(
7213
- 'attr_spec_list' => array(
7214
- 'nonce' => array(),
7215
- 'type' => array(
7216
- 'dispatch_key' => 3,
7217
- 'mandatory' => true,
7218
- 'value_casei' => 'application/json',
7219
- ),
7220
- ),
7221
- 'cdata' => array(
7222
- 'blacklisted_cdata_regex' => array(
7223
- 'error_message' => 'html comments',
7224
- 'regex' => '<!--',
7225
- ),
7226
- ),
7227
- 'tag_spec' => array(
7228
- 'mandatory_parent' => 'amp-state',
7229
- 'requires_extension' => array(
7230
- 'amp-bind',
7231
- ),
7232
- 'spec_name' => 'amp-bind extension .json script',
7233
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind',
7234
- ),
7235
- ),
7236
- array(
7237
- 'attr_spec_list' => array(
7238
- 'async' => array(
7239
- 'mandatory' => true,
7240
- 'value' => '',
7241
- ),
7242
- 'nonce' => array(),
7243
- 'type' => array(
7244
- 'value_casei' => 'text/javascript',
7245
- ),
7246
- ),
7247
- 'tag_spec' => array(
7248
- 'extension_spec' => array(
7249
- 'allowed_versions' => array(
7250
- '0.1',
7251
- 'latest',
7252
- ),
7253
- 'name' => 'amp-bodymovin-animation',
7254
- ),
7255
- ),
7256
- ),
7257
- array(
7258
- 'attr_spec_list' => array(
7259
- 'async' => array(
7260
- 'mandatory' => true,
7261
- 'value' => '',
7262
- ),
7263
- 'nonce' => array(),
7264
- 'type' => array(
7265
- 'value_casei' => 'text/javascript',
7266
- ),
7267
- ),
7268
- 'tag_spec' => array(
7269
- 'extension_spec' => array(
7270
- 'allowed_versions' => array(
7271
- '0.1',
7272
- 'latest',
7273
- ),
7274
- 'deprecated_allow_duplicates' => true,
7275
- 'name' => 'amp-brid-player',
7276
- 'requires_usage' => 2,
7277
- ),
7278
- ),
7279
- ),
7280
- array(
7281
- 'attr_spec_list' => array(
7282
- 'async' => array(
7283
- 'mandatory' => true,
7284
- 'value' => '',
7285
- ),
7286
- 'nonce' => array(),
7287
- 'type' => array(
7288
- 'value_casei' => 'text/javascript',
7289
- ),
7290
- ),
7291
- 'tag_spec' => array(
7292
- 'extension_spec' => array(
7293
- 'allowed_versions' => array(
7294
- '0.1',
7295
- 'latest',
7296
- ),
7297
- 'deprecated_allow_duplicates' => true,
7298
- 'name' => 'amp-brightcove',
7299
- 'requires_usage' => 2,
7300
- ),
7301
- ),
7302
- ),
7303
- array(
7304
- 'attr_spec_list' => array(
7305
- 'async' => array(
7306
- 'mandatory' => true,
7307
- 'value' => '',
7308
- ),
7309
- 'nonce' => array(),
7310
- 'type' => array(
7311
- 'value_casei' => 'text/javascript',
7312
- ),
7313
- ),
7314
- 'tag_spec' => array(
7315
- 'extension_spec' => array(
7316
- 'allowed_versions' => array(
7317
- '0.1',
7318
- 'latest',
7319
- ),
7320
- 'name' => 'amp-byside-content',
7321
- ),
7322
- ),
7323
- ),
7324
- array(
7325
- 'attr_spec_list' => array(
7326
- 'async' => array(
7327
- 'mandatory' => true,
7328
- 'value' => '',
7329
- ),
7330
- 'nonce' => array(),
7331
- 'type' => array(
7332
- 'value_casei' => 'text/javascript',
7333
- ),
7334
- ),
7335
- 'tag_spec' => array(
7336
- 'extension_spec' => array(
7337
- 'allowed_versions' => array(
7338
- '0.1',
7339
- 'latest',
7340
- ),
7341
- 'name' => 'amp-call-tracking',
7342
- 'requires_usage' => 2,
7343
- ),
7344
- ),
7345
- ),
7346
- array(
7347
- 'attr_spec_list' => array(
7348
- 'async' => array(
7349
- 'mandatory' => true,
7350
- 'value' => '',
7351
- ),
7352
- 'nonce' => array(),
7353
- 'type' => array(
7354
- 'value_casei' => 'text/javascript',
7355
- ),
7356
- ),
7357
- 'tag_spec' => array(
7358
- 'extension_spec' => array(
7359
- 'allowed_versions' => array(
7360
- '0.1',
7361
- 'latest',
7362
- ),
7363
- 'deprecated_allow_duplicates' => true,
7364
- 'name' => 'amp-carousel',
7365
- 'requires_usage' => 2,
7366
- ),
7367
- ),
7368
- ),
7369
- array(
7370
- 'attr_spec_list' => array(
7371
- 'async' => array(
7372
- 'mandatory' => true,
7373
- 'value' => '',
7374
- ),
7375
- 'nonce' => array(),
7376
- 'type' => array(
7377
- 'value_casei' => 'text/javascript',
7378
- ),
7379
- ),
7380
- 'tag_spec' => array(
7381
- 'extension_spec' => array(
7382
- 'allowed_versions' => array(
7383
- '0.1',
7384
- 'latest',
7385
- ),
7386
- 'name' => 'amp-consent',
7387
- ),
7388
- ),
7389
- ),
7390
- array(
7391
- 'attr_spec_list' => array(
7392
- 'nonce' => array(),
7393
- 'type' => array(
7394
- 'dispatch_key' => 3,
7395
- 'mandatory' => true,
7396
- 'value_casei' => 'application/json',
7397
- ),
7398
- ),
7399
- 'cdata' => array(
7400
- 'blacklisted_cdata_regex' => array(
7401
- 'error_message' => 'html comments',
7402
- 'regex' => '<!--',
7403
- ),
7404
- ),
7405
- 'tag_spec' => array(
7406
- 'mandatory_parent' => 'amp-consent',
7407
- 'requires_extension' => array(
7408
- 'amp-consent',
7409
- ),
7410
- 'spec_name' => 'amp-consent extension .json script',
7411
- 'unique' => true,
7412
- ),
7413
- ),
7414
- array(
7415
- 'attr_spec_list' => array(
7416
- 'async' => array(
7417
- 'mandatory' => true,
7418
- 'value' => '',
7419
- ),
7420
- 'nonce' => array(),
7421
- 'type' => array(
7422
- 'value_casei' => 'text/javascript',
7423
- ),
7424
- ),
7425
- 'tag_spec' => array(
7426
- 'extension_spec' => array(
7427
- 'allowed_versions' => array(
7428
- '0.1',
7429
- 'latest',
7430
- ),
7431
- 'deprecated_allow_duplicates' => true,
7432
- 'name' => 'amp-dailymotion',
7433
- 'requires_usage' => 2,
7434
- ),
7435
- ),
7436
- ),
7437
- array(
7438
- 'attr_spec_list' => array(
7439
- 'async' => array(
7440
- 'mandatory' => true,
7441
- 'value' => '',
7442
- ),
7443
- 'nonce' => array(),
7444
- 'type' => array(
7445
- 'value_casei' => 'text/javascript',
7446
- ),
7447
- ),
7448
- 'tag_spec' => array(
7449
- 'extension_spec' => array(
7450
- 'allowed_versions' => array(
7451
- '0.1',
7452
- 'latest',
7453
- ),
7454
- 'name' => 'amp-date-picker',
7455
- ),
7456
- ),
7457
- ),
7458
- array(
7459
- 'attr_spec_list' => array(),
7460
- 'tag_spec' => array(
7461
- 'extension_spec' => array(
7462
- 'allowed_versions' => array(
7463
- '0.1',
7464
- 'latest',
7465
- ),
7466
- 'name' => 'amp-document-recommendations',
7467
- ),
7468
- ),
7469
- ),
7470
- array(
7471
- 'attr_spec_list' => array(
7472
- 'recommendations' => array(
7473
- 'dispatch_key' => 3,
7474
- 'mandatory' => true,
7475
- 'value_casei' => 'application/json',
7476
- ),
7477
- ),
7478
- 'tag_spec' => array(
7479
- 'mandatory_parent' => 'amp-document-recommendations',
7480
- 'requires_extension' => array(
7481
- 'amp-document-recommendations',
7482
- ),
7483
- 'spec_name' => 'amp-document-recommendations extension .json configuration',
7484
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-document-recommendations',
7485
- ),
7486
- ),
7487
- array(
7488
- 'attr_spec_list' => array(
7489
- 'async' => array(
7490
- 'mandatory' => true,
7491
- 'value' => '',
7492
- ),
7493
- 'nonce' => array(),
7494
- 'type' => array(
7495
- 'value_casei' => 'text/javascript',
7496
- ),
7497
- ),
7498
- 'tag_spec' => array(
7499
- 'extension_spec' => array(
7500
- 'allowed_versions' => array(
7501
- '0.1',
7502
- 'latest',
7503
- ),
7504
- 'deprecated_allow_duplicates' => true,
7505
- 'name' => 'amp-dynamic-css-classes',
7506
- 'requires_usage' => 3,
7507
- ),
7508
- ),
7509
- ),
7510
- array(
7511
- 'attr_spec_list' => array(
7512
- 'async' => array(
7513
- 'mandatory' => true,
7514
- 'value' => '',
7515
- ),
7516
- 'nonce' => array(),
7517
- 'type' => array(
7518
- 'value_casei' => 'text/javascript',
7519
- ),
7520
- ),
7521
- 'tag_spec' => array(
7522
- 'extension_spec' => array(
7523
- 'allowed_versions' => array(
7524
- '0.1',
7525
- 'latest',
7526
- ),
7527
- 'deprecated_allow_duplicates' => true,
7528
- 'name' => 'amp-experiment',
7529
- 'requires_usage' => 2,
7530
- ),
7531
- ),
7532
- ),
7533
- array(
7534
- 'attr_spec_list' => array(
7535
- 'nonce' => array(),
7536
- 'type' => array(
7537
- 'dispatch_key' => 3,
7538
- 'mandatory' => true,
7539
- 'value_casei' => 'application/json',
7540
- ),
7541
- ),
7542
- 'cdata' => array(
7543
- 'blacklisted_cdata_regex' => array(
7544
- 'error_message' => 'html comments',
7545
- 'regex' => '<!--',
7546
- ),
7547
- ),
7548
- 'tag_spec' => array(
7549
- 'mandatory_parent' => 'amp-experiment',
7550
- 'spec_name' => 'amp-experiment extension .json script',
7551
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-experiment',
7552
- ),
7553
- ),
7554
- array(
7555
- 'attr_spec_list' => array(
7556
- 'async' => array(
7557
- 'mandatory' => true,
7558
- 'value' => '',
7559
- ),
7560
- 'nonce' => array(),
7561
- 'type' => array(
7562
- 'value_casei' => 'text/javascript',
7563
- ),
7564
- ),
7565
- 'tag_spec' => array(
7566
- 'extension_spec' => array(
7567
- 'allowed_versions' => array(
7568
- '0.1',
7569
- 'latest',
7570
- ),
7571
- 'name' => 'amp-facebook-comments',
7572
- ),
7573
- ),
7574
- ),
7575
- array(
7576
- 'attr_spec_list' => array(
7577
- 'async' => array(
7578
- 'mandatory' => true,
7579
- 'value' => '',
7580
- ),
7581
- 'nonce' => array(),
7582
- 'type' => array(
7583
- 'value_casei' => 'text/javascript',
7584
- ),
7585
- ),
7586
- 'tag_spec' => array(
7587
- 'extension_spec' => array(
7588
- 'allowed_versions' => array(
7589
- '0.1',
7590
- 'latest',
7591
- ),
7592
- 'name' => 'amp-facebook-like',
7593
- ),
7594
- ),
7595
- ),
7596
- array(
7597
- 'attr_spec_list' => array(
7598
- 'async' => array(
7599
- 'mandatory' => true,
7600
- 'value' => '',
7601
- ),
7602
- 'nonce' => array(),
7603
- 'type' => array(
7604
- 'value_casei' => 'text/javascript',
7605
- ),
7606
- ),
7607
- 'tag_spec' => array(
7608
- 'extension_spec' => array(
7609
- 'allowed_versions' => array(
7610
- '0.1',
7611
- 'latest',
7612
- ),
7613
- 'name' => 'amp-facebook-page',
7614
- ),
7615
- ),
7616
- ),
7617
- array(
7618
- 'attr_spec_list' => array(
7619
- 'async' => array(
7620
- 'mandatory' => true,
7621
- 'value' => '',
7622
- ),
7623
- 'nonce' => array(),
7624
- 'type' => array(
7625
- 'value_casei' => 'text/javascript',
7626
- ),
7627
- ),
7628
- 'tag_spec' => array(
7629
- 'extension_spec' => array(
7630
- 'allowed_versions' => array(
7631
- '0.1',
7632
- 'latest',
7633
- ),
7634
- 'deprecated_allow_duplicates' => true,
7635
- 'name' => 'amp-facebook',
7636
- 'requires_usage' => 2,
7637
- ),
7638
- ),
7639
- ),
7640
- array(
7641
- 'attr_spec_list' => array(
7642
- 'async' => array(
7643
- 'mandatory' => true,
7644
- 'value' => '',
7645
- ),
7646
- 'nonce' => array(),
7647
- 'type' => array(
7648
- 'value_casei' => 'text/javascript',
7649
- ),
7650
- ),
7651
- 'tag_spec' => array(
7652
- 'extension_spec' => array(
7653
- 'allowed_versions' => array(
7654
- '0.1',
7655
- 'latest',
7656
- ),
7657
- 'deprecated_allow_duplicates' => true,
7658
- 'name' => 'amp-fit-text',
7659
- 'requires_usage' => 2,
7660
- ),
7661
- ),
7662
- ),
7663
- array(
7664
- 'attr_spec_list' => array(
7665
- 'async' => array(
7666
- 'mandatory' => true,
7667
- 'value' => '',
7668
- ),
7669
- 'nonce' => array(),
7670
- 'type' => array(
7671
- 'value_casei' => 'text/javascript',
7672
- ),
7673
- ),
7674
- 'tag_spec' => array(
7675
- 'extension_spec' => array(
7676
- 'allowed_versions' => array(
7677
- '0.1',
7678
- 'latest',
7679
- ),
7680
- 'deprecated_allow_duplicates' => true,
7681
- 'name' => 'amp-font',
7682
- 'requires_usage' => 2,
7683
- ),
7684
- ),
7685
- ),
7686
- array(
7687
- 'attr_spec_list' => array(
7688
- 'async' => array(
7689
- 'mandatory' => true,
7690
- 'value' => '',
7691
- ),
7692
- 'nonce' => array(),
7693
- 'type' => array(
7694
- 'value_casei' => 'text/javascript',
7695
- ),
7696
- ),
7697
- 'tag_spec' => array(
7698
- 'extension_spec' => array(
7699
- 'allowed_versions' => array(
7700
- '0.1',
7701
- 'latest',
7702
- ),
7703
- 'deprecated_allow_duplicates' => true,
7704
- 'name' => 'amp-form',
7705
- 'requires_usage' => 2,
7706
- ),
7707
- ),
7708
- ),
7709
- array(
7710
- 'attr_spec_list' => array(
7711
- 'async' => array(
7712
- 'mandatory' => true,
7713
- 'value' => '',
7714
- ),
7715
- 'nonce' => array(),
7716
- 'type' => array(
7717
- 'value_casei' => 'text/javascript',
7718
- ),
7719
- ),
7720
- 'tag_spec' => array(
7721
- 'extension_spec' => array(
7722
- 'allowed_versions' => array(
7723
- '0.1',
7724
- 'latest',
7725
- ),
7726
- 'name' => 'amp-fx-collection',
7727
- 'requires_usage' => 3,
7728
- ),
7729
- ),
7730
- ),
7731
- array(
7732
- 'attr_spec_list' => array(
7733
- 'async' => array(
7734
- 'mandatory' => true,
7735
- 'value' => '',
7736
- ),
7737
- 'nonce' => array(),
7738
- 'type' => array(
7739
- 'value_casei' => 'text/javascript',
7740
- ),
7741
- ),
7742
- 'tag_spec' => array(
7743
- 'extension_spec' => array(
7744
- 'allowed_versions' => array(
7745
- '0.1',
7746
- 'latest',
7747
- ),
7748
- 'deprecated_allow_duplicates' => true,
7749
- 'name' => 'amp-fx-flying-carpet',
7750
- 'requires_usage' => 2,
7751
- ),
7752
- ),
7753
- ),
7754
- array(
7755
- 'attr_spec_list' => array(
7756
- 'async' => array(
7757
- 'mandatory' => true,
7758
- 'value' => '',
7759
- ),
7760
- 'nonce' => array(),
7761
- 'type' => array(
7762
- 'value_casei' => 'text/javascript',
7763
- ),
7764
- ),
7765
- 'tag_spec' => array(
7766
- 'extension_spec' => array(
7767
- 'allowed_versions' => array(
7768
- '0.1',
7769
- 'latest',
7770
- ),
7771
- 'deprecated_allow_duplicates' => true,
7772
- 'name' => 'amp-gfycat',
7773
- 'requires_usage' => 2,
7774
- ),
7775
- ),
7776
- ),
7777
- array(
7778
- 'attr_spec_list' => array(
7779
- 'async' => array(
7780
- 'mandatory' => true,
7781
- 'value' => '',
7782
- ),
7783
- 'nonce' => array(),
7784
- 'type' => array(
7785
- 'value_casei' => 'text/javascript',
7786
- ),
7787
- ),
7788
- 'tag_spec' => array(
7789
- 'extension_spec' => array(
7790
- 'allowed_versions' => array(
7791
- '0.1',
7792
- 'latest',
7793
- ),
7794
- 'name' => 'amp-gist',
7795
- ),
7796
- ),
7797
- ),
7798
- array(
7799
- 'attr_spec_list' => array(
7800
- 'async' => array(
7801
- 'mandatory' => true,
7802
- 'value' => '',
7803
- ),
7804
- 'nonce' => array(),
7805
- 'type' => array(
7806
- 'value_casei' => 'text/javascript',
7807
- ),
7808
- ),
7809
- 'tag_spec' => array(
7810
- 'extension_spec' => array(
7811
- 'allowed_versions' => array(
7812
- '0.1',
7813
- 'latest',
7814
- ),
7815
- 'name' => 'amp-hulu',
7816
- ),
7817
- ),
7818
- ),
7819
- array(
7820
- 'attr_spec_list' => array(
7821
- 'async' => array(
7822
- 'mandatory' => true,
7823
- 'value' => '',
7824
- ),
7825
- 'nonce' => array(),
7826
- 'type' => array(
7827
- 'value_casei' => 'text/javascript',
7828
- ),
7829
- ),
7830
- 'tag_spec' => array(
7831
- 'extension_spec' => array(
7832
- 'allowed_versions' => array(
7833
- '0.1',
7834
- 'latest',
7835
- ),
7836
- 'deprecated_allow_duplicates' => true,
7837
- 'name' => 'amp-iframe',
7838
- 'requires_usage' => 2,
7839
- ),
7840
- ),
7841
- ),
7842
- array(
7843
- 'attr_spec_list' => array(
7844
- 'async' => array(
7845
- 'mandatory' => true,
7846
- 'value' => '',
7847
- ),
7848
- 'nonce' => array(),
7849
- 'type' => array(
7850
- 'value_casei' => 'text/javascript',
7851
- ),
7852
- ),
7853
- 'tag_spec' => array(
7854
- 'extension_spec' => array(
7855
- 'allowed_versions' => array(
7856
- '0.1',
7857
- 'latest',
7858
- ),
7859
- 'name' => 'amp-ima-video',
7860
- ),
7861
- ),
7862
- ),
7863
- array(
7864
- 'attr_spec_list' => array(
7865
- 'async' => array(
7866
- 'mandatory' => true,
7867
- 'value' => '',
7868
- ),
7869
- 'nonce' => array(),
7870
- 'type' => array(
7871
- 'value_casei' => 'text/javascript',
7872
- ),
7873
- ),
7874
- 'tag_spec' => array(
7875
- 'extension_spec' => array(
7876
- 'allowed_versions' => array(
7877
- '0.1',
7878
- 'latest',
7879
- ),
7880
- 'deprecated_allow_duplicates' => true,
7881
- 'name' => 'amp-image-lightbox',
7882
- 'requires_usage' => 2,
7883
- ),
7884
- ),
7885
- ),
7886
- array(
7887
- 'attr_spec_list' => array(
7888
- 'async' => array(
7889
- 'mandatory' => true,
7890
- 'value' => '',
7891
- ),
7892
- 'nonce' => array(),
7893
- 'type' => array(
7894
- 'value_casei' => 'text/javascript',
7895
- ),
7896
- ),
7897
- 'tag_spec' => array(
7898
- 'extension_spec' => array(
7899
- 'allowed_versions' => array(
7900
- '0.1',
7901
- 'latest',
7902
- ),
7903
- 'name' => 'amp-imgur',
7904
- ),
7905
- ),
7906
- ),
7907
- array(
7908
- 'attr_spec_list' => array(
7909
- 'async' => array(
7910
- 'mandatory' => true,
7911
- 'value' => '',
7912
- ),
7913
- 'nonce' => array(),
7914
- 'type' => array(
7915
- 'value_casei' => 'text/javascript',
7916
- ),
7917
- ),
7918
- 'tag_spec' => array(
7919
- 'extension_spec' => array(
7920
- 'allowed_versions' => array(
7921
- '0.1',
7922
- 'latest',
7923
- ),
7924
- 'deprecated_allow_duplicates' => true,
7925
- 'name' => 'amp-instagram',
7926
- 'requires_usage' => 2,
7927
- ),
7928
- ),
7929
- ),
7930
- array(
7931
- 'attr_spec_list' => array(
7932
- 'async' => array(
7933
- 'mandatory' => true,
7934
- 'value' => '',
7935
- ),
7936
- 'nonce' => array(),
7937
- 'type' => array(
7938
- 'value_casei' => 'text/javascript',
7939
- ),
7940
- ),
7941
- 'tag_spec' => array(
7942
- 'extension_spec' => array(
7943
- 'allowed_versions' => array(
7944
- '0.1',
7945
- 'latest',
7946
- ),
7947
- 'deprecated_allow_duplicates' => true,
7948
- 'name' => 'amp-install-serviceworker',
7949
- 'requires_usage' => 2,
7950
- ),
7951
- ),
7952
- ),
7953
- array(
7954
- 'attr_spec_list' => array(
7955
- 'async' => array(
7956
- 'mandatory' => true,
7957
- 'value' => '',
7958
- ),
7959
- 'nonce' => array(),
7960
- 'type' => array(
7961
- 'value_casei' => 'text/javascript',
7962
- ),
7963
- ),
7964
- 'tag_spec' => array(
7965
- 'extension_spec' => array(
7966
- 'allowed_versions' => array(
7967
- '0.1',
7968
- 'latest',
7969
- ),
7970
- 'name' => 'amp-izlesene',
7971
- 'requires_usage' => 2,
7972
- ),
7973
- ),
7974
- ),
7975
- array(
7976
- 'attr_spec_list' => array(
7977
- 'async' => array(
7978
- 'mandatory' => true,
7979
- 'value' => '',
7980
- ),
7981
- 'nonce' => array(),
7982
- 'type' => array(
7983
- 'value_casei' => 'text/javascript',
7984
- ),
7985
- ),
7986
- 'tag_spec' => array(
7987
- 'extension_spec' => array(
7988
- 'allowed_versions' => array(
7989
- '0.1',
7990
- 'latest',
7991
- ),
7992
- 'deprecated_allow_duplicates' => true,
7993
- 'name' => 'amp-jwplayer',
7994
- 'requires_usage' => 2,
7995
- ),
7996
- ),
7997
- ),
7998
- array(
7999
- 'attr_spec_list' => array(
8000
- 'async' => array(
8001
- 'mandatory' => true,
8002
- 'value' => '',
8003
- ),
8004
- 'nonce' => array(),
8005
- 'type' => array(
8006
- 'value_casei' => 'text/javascript',
8007
- ),
8008
- ),
8009
- 'tag_spec' => array(
8010
- 'extension_spec' => array(
8011
- 'allowed_versions' => array(
8012
- '0.1',
8013
- 'latest',
8014
- ),
8015
- 'deprecated_allow_duplicates' => true,
8016
- 'name' => 'amp-kaltura-player',
8017
- 'requires_usage' => 2,
8018
- ),
8019
- ),
8020
- ),
8021
- array(
8022
- 'attr_spec_list' => array(
8023
- 'async' => array(
8024
- 'mandatory' => true,
8025
- 'value' => '',
8026
- ),
8027
- 'nonce' => array(),
8028
- 'type' => array(
8029
- 'value_casei' => 'text/javascript',
8030
- ),
8031
- ),
8032
- 'tag_spec' => array(
8033
- 'extension_spec' => array(
8034
- 'allowed_versions' => array(
8035
- '0.1',
8036
- 'latest',
8037
- ),
8038
- 'name' => 'amp-lightbox-gallery',
8039
- 'requires_usage' => 3,
8040
- ),
8041
- ),
8042
- ),
8043
- array(
8044
- 'attr_spec_list' => array(
8045
- 'async' => array(
8046
- 'mandatory' => true,
8047
- 'value' => '',
8048
- ),
8049
- 'nonce' => array(),
8050
- 'type' => array(
8051
- 'value_casei' => 'text/javascript',
8052
- ),
8053
- ),
8054
- 'tag_spec' => array(
8055
- 'extension_spec' => array(
8056
- 'allowed_versions' => array(
8057
- '0.1',
8058
- 'latest',
8059
- ),
8060
- 'deprecated_allow_duplicates' => true,
8061
- 'name' => 'amp-lightbox',
8062
- 'requires_usage' => 2,
8063
- ),
8064
- ),
8065
- ),
8066
- array(
8067
- 'attr_spec_list' => array(
8068
- 'async' => array(
8069
- 'mandatory' => true,
8070
- 'value' => '',
8071
- ),
8072
- 'nonce' => array(),
8073
- 'type' => array(
8074
- 'value_casei' => 'text/javascript',
8075
- ),
8076
- ),
8077
- 'tag_spec' => array(
8078
- 'extension_spec' => array(
8079
- 'allowed_versions' => array(
8080
- '0.1',
8081
- 'latest',
8082
- ),
8083
- 'deprecated_allow_duplicates' => true,
8084
- 'name' => 'amp-list',
8085
- 'requires_usage' => 2,
8086
- ),
8087
- ),
8088
- ),
8089
- array(
8090
- 'attr_spec_list' => array(
8091
- 'async' => array(
8092
- 'mandatory' => true,
8093
- 'value' => '',
8094
- ),
8095
- 'nonce' => array(),
8096
- 'type' => array(
8097
- 'value_casei' => 'text/javascript',
8098
- ),
8099
- ),
8100
- 'tag_spec' => array(
8101
- 'extension_spec' => array(
8102
- 'allowed_versions' => array(
8103
- '0.1',
8104
- 'latest',
8105
- ),
8106
- 'name' => 'amp-live-list',
8107
- 'requires_usage' => 2,
8108
- ),
8109
- 'mandatory_parent' => 'head',
8110
- 'unique_warning' => true,
8111
- ),
8112
- ),
8113
- array(
8114
- 'attr_spec_list' => array(
8115
- 'async' => array(
8116
- 'mandatory' => true,
8117
- 'value' => '',
8118
- ),
8119
- 'nonce' => array(),
8120
- 'type' => array(
8121
- 'value_casei' => 'text/javascript',
8122
- ),
8123
- ),
8124
- 'tag_spec' => array(
8125
- 'extension_spec' => array(
8126
- 'allowed_versions' => array(
8127
- '0.1',
8128
- 'latest',
8129
- ),
8130
- 'name' => 'amp-mathml',
8131
- ),
8132
- ),
8133
- ),
8134
- array(
8135
- 'attr_spec_list' => array(
8136
- 'async' => array(
8137
- 'mandatory' => true,
8138
- 'value' => '',
8139
- ),
8140
- 'nonce' => array(),
8141
- 'type' => array(
8142
- 'value_casei' => 'text/javascript',
8143
- ),
8144
- ),
8145
- 'tag_spec' => array(
8146
- 'extension_spec' => array(
8147
- 'allowed_versions' => array(
8148
- '0.1',
8149
- 'latest',
8150
- ),
8151
- 'deprecated_allow_duplicates' => true,
8152
- 'is_custom_template' => true,
8153
- 'name' => 'amp-mustache',
8154
- 'requires_usage' => 2,
8155
- ),
8156
- ),
8157
- ),
8158
- array(
8159
- 'attr_spec_list' => array(
8160
- 'async' => array(
8161
- 'mandatory' => true,
8162
- 'value' => '',
8163
- ),
8164
- 'nonce' => array(),
8165
- 'type' => array(
8166
- 'value_casei' => 'text/javascript',
8167
- ),
8168
- ),
8169
- 'tag_spec' => array(
8170
- 'extension_spec' => array(
8171
- 'allowed_versions' => array(
8172
- '0.1',
8173
- 'latest',
8174
- ),
8175
- 'name' => 'amp-nexxtv-player',
8176
- ),
8177
- ),
8178
- ),
8179
- array(
8180
- 'attr_spec_list' => array(
8181
- 'async' => array(
8182
- 'mandatory' => true,
8183
- 'value' => '',
8184
- ),
8185
- 'nonce' => array(),
8186
- 'type' => array(
8187
- 'value_casei' => 'text/javascript',
8188
- ),
8189
- ),
8190
- 'tag_spec' => array(
8191
- 'extension_spec' => array(
8192
- 'allowed_versions' => array(
8193
- '0.1',
8194
- 'latest',
8195
- ),
8196
- 'deprecated_allow_duplicates' => true,
8197
- 'name' => 'amp-o2-player',
8198
- 'requires_usage' => 2,
8199
- ),
8200
- ),
8201
- ),
8202
- array(
8203
- 'attr_spec_list' => array(
8204
- 'async' => array(
8205
- 'mandatory' => true,
8206
- 'value' => '',
8207
- ),
8208
- 'nonce' => array(),
8209
- 'type' => array(
8210
- 'value_casei' => 'text/javascript',
8211
- ),
8212
- ),
8213
- 'tag_spec' => array(
8214
- 'extension_spec' => array(
8215
- 'allowed_versions' => array(
8216
- '0.1',
8217
- 'latest',
8218
- ),
8219
- 'name' => 'amp-ooyala-player',
8220
- ),
8221
- ),
8222
- ),
8223
- array(
8224
- 'attr_spec_list' => array(
8225
- 'async' => array(
8226
- 'mandatory' => true,
8227
- 'value' => '',
8228
- ),
8229
- 'nonce' => array(),
8230
- 'type' => array(
8231
- 'value_casei' => 'text/javascript',
8232
- ),
8233
- ),
8234
- 'tag_spec' => array(
8235
- 'extension_spec' => array(
8236
- 'allowed_versions' => array(
8237
- '0.1',
8238
- 'latest',
8239
- ),
8240
- 'deprecated_allow_duplicates' => true,
8241
- 'name' => 'amp-pinterest',
8242
- 'requires_usage' => 2,
8243
- ),
8244
- ),
8245
- ),
8246
- array(
8247
- 'attr_spec_list' => array(
8248
- 'async' => array(
8249
- 'mandatory' => true,
8250
- 'value' => '',
8251
- ),
8252
- 'nonce' => array(),
8253
- 'type' => array(
8254
- 'value_casei' => 'text/javascript',
8255
- ),
8256
- ),
8257
- 'tag_spec' => array(
8258
- 'extension_spec' => array(
8259
- 'allowed_versions' => array(
8260
- '0.1',
8261
- 'latest',
8262
- ),
8263
- 'name' => 'amp-playbuzz',
8264
- ),
8265
- ),
8266
- ),
8267
- array(
8268
- 'attr_spec_list' => array(
8269
- 'async' => array(
8270
- 'mandatory' => true,
8271
- 'value' => '',
8272
- ),
8273
- 'nonce' => array(),
8274
- 'type' => array(
8275
- 'value_casei' => 'text/javascript',
8276
- ),
8277
- ),
8278
- 'tag_spec' => array(
8279
- 'extension_spec' => array(
8280
- 'allowed_versions' => array(
8281
- '0.1',
8282
- 'latest',
8283
- ),
8284
- 'name' => 'amp-position-observer',
8285
- ),
8286
- ),
8287
- ),
8288
- array(
8289
- 'attr_spec_list' => array(
8290
- 'async' => array(
8291
- 'mandatory' => true,
8292
- 'value' => '',
8293
- ),
8294
- 'nonce' => array(),
8295
- 'type' => array(
8296
- 'value_casei' => 'text/javascript',
8297
- ),
8298
- ),
8299
- 'tag_spec' => array(
8300
- 'extension_spec' => array(
8301
- 'allowed_versions' => array(
8302
- '0.1',
8303
- 'latest',
8304
- ),
8305
- 'deprecated_allow_duplicates' => true,
8306
- 'name' => 'amp-reach-player',
8307
- 'requires_usage' => 2,
8308
- ),
8309
- ),
8310
- ),
8311
- array(
8312
- 'attr_spec_list' => array(
8313
- 'async' => array(
8314
- 'mandatory' => true,
8315
- 'value' => '',
8316
- ),
8317
- 'nonce' => array(),
8318
- 'type' => array(
8319
- 'value_casei' => 'text/javascript',
8320
- ),
8321
- ),
8322
- 'tag_spec' => array(
8323
- 'extension_spec' => array(
8324
- 'allowed_versions' => array(
8325
- '0.1',
8326
- 'latest',
8327
- ),
8328
- 'deprecated_allow_duplicates' => true,
8329
- 'name' => 'amp-reddit',
8330
- ),
8331
- ),
8332
- ),
8333
- array(
8334
- 'attr_spec_list' => array(
8335
- 'async' => array(
8336
- 'mandatory' => true,
8337
- 'value' => '',
8338
- ),
8339
- 'nonce' => array(),
8340
- 'type' => array(
8341
- 'value_casei' => 'text/javascript',
8342
- ),
8343
- ),
8344
- 'tag_spec' => array(
8345
- 'extension_spec' => array(
8346
- 'allowed_versions' => array(
8347
- '0.1',
8348
- 'latest',
8349
- ),
8350
- 'name' => 'amp-riddle-quiz',
8351
- ),
8352
- ),
8353
- ),
8354
- array(
8355
- 'attr_spec_list' => array(
8356
- 'async' => array(
8357
- 'mandatory' => true,
8358
- 'value' => '',
8359
- ),
8360
- 'nonce' => array(),
8361
- 'type' => array(
8362
- 'value_casei' => 'text/javascript',
8363
- ),
8364
- ),
8365
- 'tag_spec' => array(
8366
- 'extension_spec' => array(
8367
- 'allowed_versions' => array(
8368
- '0.1',
8369
- 'latest',
8370
- ),
8371
- 'name' => 'amp-selector',
8372
- 'requires_usage' => 2,
8373
- ),
8374
- ),
8375
- ),
8376
- array(
8377
- 'attr_spec_list' => array(
8378
- 'async' => array(
8379
- 'mandatory' => true,
8380
- 'value' => '',
8381
- ),
8382
- 'nonce' => array(),
8383
- 'type' => array(
8384
- 'value_casei' => 'text/javascript',
8385
- ),
8386
- ),
8387
- 'tag_spec' => array(
8388
- 'extension_spec' => array(
8389
- 'allowed_versions' => array(
8390
- '0.1',
8391
- 'latest',
8392
- ),
8393
- 'deprecated_allow_duplicates' => true,
8394
- 'name' => 'amp-sidebar',
8395
- 'requires_usage' => 2,
8396
- ),
8397
- ),
8398
- ),
8399
- array(
8400
- 'attr_spec_list' => array(
8401
- 'async' => array(
8402
- 'mandatory' => true,
8403
- 'value' => '',
8404
- ),
8405
- 'nonce' => array(),
8406
- 'type' => array(
8407
- 'value_casei' => 'text/javascript',
8408
- ),
8409
- ),
8410
- 'tag_spec' => array(
8411
- 'extension_spec' => array(
8412
- 'allowed_versions' => array(
8413
- '0.1',
8414
- 'latest',
8415
- ),
8416
- 'deprecated_allow_duplicates' => true,
8417
- 'name' => 'amp-social-share',
8418
- 'requires_usage' => 2,
8419
- ),
8420
- ),
8421
- ),
8422
- array(
8423
- 'attr_spec_list' => array(
8424
- 'async' => array(
8425
- 'mandatory' => true,
8426
- 'value' => '',
8427
- ),
8428
- 'nonce' => array(),
8429
- 'type' => array(
8430
- 'value_casei' => 'text/javascript',
8431
- ),
8432
- ),
8433
- 'tag_spec' => array(
8434
- 'extension_spec' => array(
8435
- 'allowed_versions' => array(
8436
- '0.1',
8437
- 'latest',
8438
- ),
8439
- 'deprecated_allow_duplicates' => true,
8440
- 'name' => 'amp-soundcloud',
8441
- 'requires_usage' => 2,
8442
- ),
8443
- ),
8444
- ),
8445
- array(
8446
- 'attr_spec_list' => array(
8447
- 'async' => array(
8448
- 'mandatory' => true,
8449
- 'value' => '',
8450
- ),
8451
- 'nonce' => array(),
8452
- 'type' => array(
8453
- 'value_casei' => 'text/javascript',
8454
- ),
8455
- ),
8456
- 'tag_spec' => array(
8457
- 'extension_spec' => array(
8458
- 'allowed_versions' => array(
8459
- '0.1',
8460
- 'latest',
8461
- ),
8462
- 'deprecated_allow_duplicates' => true,
8463
- 'name' => 'amp-springboard-player',
8464
- 'requires_usage' => 2,
8465
- ),
8466
- ),
8467
- ),
8468
- array(
8469
- 'attr_spec_list' => array(
8470
- 'async' => array(
8471
- 'mandatory' => true,
8472
- 'value' => '',
8473
- ),
8474
- 'nonce' => array(),
8475
- 'type' => array(
8476
- 'value_casei' => 'text/javascript',
8477
- ),
8478
- ),
8479
- 'tag_spec' => array(
8480
- 'extension_spec' => array(
8481
- 'allowed_versions' => array(
8482
- '0.1',
8483
- '1.0',
8484
- 'latest',
8485
- ),
8486
- 'deprecated_versions' => array(
8487
- '0.1',
8488
- ),
8489
- 'name' => 'amp-sticky-ad',
8490
- 'requires_usage' => 2,
8491
- ),
8492
- ),
8493
- ),
8494
- array(
8495
- 'attr_spec_list' => array(
8496
- 'async' => array(
8497
- 'mandatory' => true,
8498
- 'value' => '',
8499
- ),
8500
- 'nonce' => array(),
8501
- 'type' => array(
8502
- 'value_casei' => 'text/javascript',
8503
- ),
8504
- ),
8505
- 'tag_spec' => array(
8506
- 'extension_spec' => array(
8507
- 'allowed_versions' => array(
8508
- '0.1',
8509
- 'latest',
8510
- ),
8511
- 'name' => 'amp-story-auto-ads',
8512
- ),
8513
- ),
8514
- ),
8515
- array(
8516
- 'attr_spec_list' => array(
8517
- 'nonce' => array(),
8518
- 'type' => array(
8519
- 'dispatch_key' => 3,
8520
- 'mandatory' => true,
8521
- 'value_casei' => 'application/json',
8522
- ),
8523
- ),
8524
- 'cdata' => array(
8525
- 'blacklisted_cdata_regex' => array(
8526
- 'error_message' => 'html comments',
8527
- 'regex' => '<!--',
8528
- ),
8529
- ),
8530
- 'tag_spec' => array(
8531
- 'mandatory_parent' => 'amp-story-auto-ads',
8532
- 'requires_extension' => array(
8533
- 'amp-story-auto-ads',
8534
- ),
8535
- 'spec_name' => 'amp-story-auto-ads config script',
8536
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/extensions/amp-story/amp-story-auto-ads.md',
8537
- ),
8538
- ),
8539
- array(
8540
- 'attr_spec_list' => array(
8541
- 'async' => array(
8542
- 'mandatory' => true,
8543
- 'value' => '',
8544
- ),
8545
- 'nonce' => array(),
8546
- 'type' => array(
8547
- 'value_casei' => 'text/javascript',
8548
- ),
8549
- ),
8550
- 'tag_spec' => array(
8551
- 'extension_spec' => array(
8552
- 'allowed_versions' => array(
8553
- '0.1',
8554
- 'latest',
8555
- ),
8556
- 'name' => 'amp-story',
8557
- ),
8558
- ),
8559
- ),
8560
- array(
8561
- 'attr_spec_list' => array(
8562
- 'async' => array(
8563
- 'mandatory' => true,
8564
- 'value' => '',
8565
- ),
8566
- 'nonce' => array(),
8567
- 'type' => array(
8568
- 'value_casei' => 'text/javascript',
8569
- ),
8570
- ),
8571
- 'tag_spec' => array(
8572
- 'extension_spec' => array(
8573
- 'allowed_versions' => array(
8574
- '0.1',
8575
- 'latest',
8576
- ),
8577
- 'name' => 'amp-subscriptions',
8578
- 'requires_usage' => 3,
8579
- ),
8580
- ),
8581
- ),
8582
- array(
8583
- 'attr_spec_list' => array(
8584
- 'id' => array(
8585
- 'dispatch_key' => 2,
8586
- 'mandatory' => true,
8587
- 'value' => 'amp-subscriptions',
8588
- ),
8589
- 'nonce' => array(),
8590
- 'type' => array(
8591
- 'mandatory' => true,
8592
- 'value_casei' => 'application/json',
8593
- ),
8594
- ),
8595
- 'cdata' => array(
8596
- 'blacklisted_cdata_regex' => array(
8597
- 'error_message' => 'html comments',
8598
- 'regex' => '<!--',
8599
- ),
8600
- ),
8601
- 'tag_spec' => array(
8602
- 'mandatory_parent' => 'head',
8603
- 'requires_extension' => array(
8604
- 'amp-subscriptions',
8605
- ),
8606
- 'spec_name' => 'amp-subscriptions extension .json script',
8607
- 'unique' => true,
8608
- ),
8609
- ),
8610
- array(
8611
- 'attr_spec_list' => array(
8612
- 'async' => array(
8613
- 'mandatory' => true,
8614
- 'value' => '',
8615
- ),
8616
- 'nonce' => array(),
8617
- 'type' => array(
8618
- 'value_casei' => 'text/javascript',
8619
- ),
8620
- ),
8621
- 'tag_spec' => array(
8622
- 'extension_spec' => array(
8623
- 'allowed_versions' => array(
8624
- '0.1',
8625
- 'latest',
8626
- ),
8627
- 'name' => 'amp-subscriptions-google',
8628
- 'requires_usage' => 3,
8629
- ),
8630
- 'requires_extension' => array(
8631
- 'amp-subscriptions',
8632
- ),
8633
- ),
8634
- ),
8635
- array(
8636
- 'attr_spec_list' => array(
8637
- 'async' => array(
8638
- 'mandatory' => true,
8639
- 'value' => '',
8640
- ),
8641
- 'nonce' => array(),
8642
- 'type' => array(
8643
- 'value_casei' => 'text/javascript',
8644
- ),
8645
- ),
8646
- 'tag_spec' => array(
8647
- 'extension_spec' => array(
8648
- 'allowed_versions' => array(
8649
- '0.1',
8650
- 'latest',
8651
- ),
8652
- 'name' => 'amp-timeago',
8653
- ),
8654
- ),
8655
- ),
8656
- array(
8657
- 'attr_spec_list' => array(
8658
- 'async' => array(
8659
- 'mandatory' => true,
8660
- 'value' => '',
8661
- ),
8662
- 'nonce' => array(),
8663
- 'type' => array(
8664
- 'value_casei' => 'text/javascript',
8665
- ),
8666
- ),
8667
- 'tag_spec' => array(
8668
- 'extension_spec' => array(
8669
- 'allowed_versions' => array(
8670
- '0.1',
8671
- 'latest',
8672
- ),
8673
- 'deprecated_allow_duplicates' => true,
8674
- 'name' => 'amp-twitter',
8675
- 'requires_usage' => 2,
8676
- ),
8677
- ),
8678
- ),
8679
- array(
8680
- 'attr_spec_list' => array(
8681
- 'async' => array(
8682
- 'mandatory' => true,
8683
- 'value' => '',
8684
- ),
8685
- 'nonce' => array(),
8686
- 'type' => array(
8687
- 'value_casei' => 'text/javascript',
8688
- ),
8689
- ),
8690
- 'tag_spec' => array(
8691
- 'extension_spec' => array(
8692
- 'allowed_versions' => array(
8693
- '0.1',
8694
- 'latest',
8695
- ),
8696
- 'deprecated_allow_duplicates' => true,
8697
- 'name' => 'amp-user-notification',
8698
- 'requires_usage' => 2,
8699
- ),
8700
- ),
8701
- ),
8702
- array(
8703
- 'attr_spec_list' => array(
8704
- 'async' => array(
8705
- 'mandatory' => true,
8706
- 'value' => '',
8707
- ),
8708
- 'nonce' => array(),
8709
- 'type' => array(
8710
- 'value_casei' => 'text/javascript',
8711
- ),
8712
- ),
8713
- 'tag_spec' => array(
8714
- 'extension_spec' => array(
8715
- 'allowed_versions' => array(
8716
- '0.1',
8717
- 'latest',
8718
- ),
8719
- 'name' => 'amp-video',
8720
- 'requires_usage' => 3,
8721
- ),
8722
- 'spec_name' => 'amp-video extension .js script',
8723
- ),
8724
- ),
8725
- array(
8726
- 'attr_spec_list' => array(
8727
- 'async' => array(
8728
- 'mandatory' => true,
8729
- 'value' => '',
8730
- ),
8731
- 'nonce' => array(),
8732
- 'type' => array(
8733
- 'value_casei' => 'text/javascript',
8734
- ),
8735
- ),
8736
- 'tag_spec' => array(
8737
- 'extension_spec' => array(
8738
- 'allowed_versions' => array(
8739
- '0.1',
8740
- 'latest',
8741
- ),
8742
- 'deprecated_allow_duplicates' => true,
8743
- 'name' => 'amp-vimeo',
8744
- 'requires_usage' => 2,
8745
- ),
8746
- ),
8747
- ),
8748
- array(
8749
- 'attr_spec_list' => array(
8750
- 'async' => array(
8751
- 'mandatory' => true,
8752
- 'value' => '',
8753
- ),
8754
- 'nonce' => array(),
8755
- 'type' => array(
8756
- 'value_casei' => 'text/javascript',
8757
- ),
8758
- ),
8759
- 'tag_spec' => array(
8760
- 'extension_spec' => array(
8761
- 'allowed_versions' => array(
8762
- '0.1',
8763
- 'latest',
8764
- ),
8765
- 'deprecated_allow_duplicates' => true,
8766
- 'name' => 'amp-vine',
8767
- 'requires_usage' => 2,
8768
- ),
8769
- ),
8770
- ),
8771
- array(
8772
- 'attr_spec_list' => array(
8773
- 'async' => array(
8774
- 'mandatory' => true,
8775
- 'value' => '',
8776
- ),
8777
- 'nonce' => array(),
8778
- 'type' => array(
8779
- 'value_casei' => 'text/javascript',
8780
- ),
8781
- ),
8782
- 'tag_spec' => array(
8783
- 'extension_spec' => array(
8784
- 'allowed_versions' => array(
8785
- '0.1',
8786
- 'latest',
8787
- ),
8788
- 'name' => 'amp-vk',
8789
- ),
8790
- ),
8791
- ),
8792
- array(
8793
- 'attr_spec_list' => array(
8794
- 'async' => array(
8795
- 'mandatory' => true,
8796
- 'value' => '',
8797
- ),
8798
- 'nonce' => array(),
8799
- 'type' => array(
8800
- 'value_casei' => 'text/javascript',
8801
- ),
8802
- ),
8803
- 'tag_spec' => array(
8804
- 'extension_spec' => array(
8805
- 'allowed_versions' => array(
8806
- '0.1',
8807
- 'latest',
8808
- ),
8809
- 'name' => 'amp-web-push',
8810
- ),
8811
- ),
8812
- ),
8813
- array(
8814
- 'attr_spec_list' => array(
8815
- 'async' => array(
8816
- 'mandatory' => true,
8817
- 'value' => '',
8818
- ),
8819
- 'nonce' => array(),
8820
- 'type' => array(
8821
- 'value_casei' => 'text/javascript',
8822
- ),
8823
- ),
8824
- 'tag_spec' => array(
8825
- 'extension_spec' => array(
8826
- 'allowed_versions' => array(
8827
- '0.1',
8828
- 'latest',
8829
- ),
8830
- 'name' => 'amp-wistia-player',
8831
- ),
8832
- ),
8833
- ),
8834
- array(
8835
- 'attr_spec_list' => array(
8836
- 'async' => array(
8837
- 'mandatory' => true,
8838
- 'value' => '',
8839
- ),
8840
- 'nonce' => array(),
8841
- 'type' => array(
8842
- 'value_casei' => 'text/javascript',
8843
- ),
8844
- ),
8845
- 'tag_spec' => array(
8846
- 'extension_spec' => array(
8847
- 'allowed_versions' => array(
8848
- '0.1',
8849
- 'latest',
8850
- ),
8851
- 'deprecated_allow_duplicates' => true,
8852
- 'name' => 'amp-youtube',
8853
- 'requires_usage' => 2,
8854
- ),
8855
- ),
8856
- ),
8857
- ),
8858
- 'section' => array(
8859
- array(
8860
- 'attr_spec_list' => array(),
8861
- 'tag_spec' => array(
8862
- 'disallowed_ancestor' => array(
8863
- 'amp-accordion',
8864
- ),
8865
- ),
8866
- ),
8867
- array(
8868
- 'attr_spec_list' => array(
8869
- 'expanded' => array(
8870
- 'value' => '',
8871
- ),
8872
- ),
8873
- 'tag_spec' => array(
8874
- 'mandatory_parent' => 'amp-accordion',
8875
- 'spec_name' => 'amp-accordion > section',
8876
- ),
8877
- ),
8878
- ),
8879
- 'select' => array(
8880
- array(
8881
- 'attr_spec_list' => array(
8882
- '[autofocus]' => array(),
8883
- '[disabled]' => array(),
8884
- '[multiple]' => array(),
8885
- '[required]' => array(),
8886
- '[size]' => array(),
8887
- 'autofocus' => array(),
8888
- 'disabled' => array(),
8889
- 'multiple' => array(),
8890
- 'name' => array(
8891
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
8892
- ),
8893
- 'required' => array(),
8894
- 'size' => array(),
8895
- ),
8896
- 'tag_spec' => array(
8897
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
8898
- ),
8899
- ),
8900
- ),
8901
- 'slot' => array(
8902
- array(
8903
- 'attr_spec_list' => array(
8904
- 'name' => array(),
8905
- ),
8906
- 'tag_spec' => array(),
8907
- ),
8908
- ),
8909
- 'small' => array(
8910
- array(
8911
- 'attr_spec_list' => array(),
8912
- 'tag_spec' => array(),
8913
- ),
8914
- ),
8915
- 'solidcolor' => array(
8916
- array(
8917
- 'attr_spec_list' => array(
8918
- 'alignment-baseline' => array(),
8919
- 'baseline-shift' => array(),
8920
- 'clip' => array(),
8921
- 'clip-path' => array(),
8922
- 'clip-rule' => array(),
8923
- 'color' => array(),
8924
- 'color-interpolation' => array(),
8925
- 'color-interpolation-filters' => array(),
8926
- 'color-profile' => array(),
8927
- 'color-rendering' => array(),
8928
- 'cursor' => array(),
8929
- 'direction' => array(),
8930
- 'display' => array(),
8931
- 'dominant-baseline' => array(),
8932
- 'enable-background' => array(),
8933
- 'fill' => array(),
8934
- 'fill-opacity' => array(),
8935
- 'fill-rule' => array(),
8936
- 'filter' => array(),
8937
- 'flood-color' => array(),
8938
- 'flood-opacity' => array(),
8939
- 'font-family' => array(),
8940
- 'font-size' => array(),
8941
- 'font-size-adjust' => array(),
8942
- 'font-stretch' => array(),
8943
- 'font-style' => array(),
8944
- 'font-variant' => array(),
8945
- 'font-weight' => array(),
8946
- 'glyph-orientation-horizontal' => array(),
8947
- 'glyph-orientation-vertical' => array(),
8948
- 'image-rendering' => array(),
8949
- 'kerning' => array(),
8950
- 'letter-spacing' => array(),
8951
- 'lighting-color' => array(),
8952
- 'marker-end' => array(),
8953
- 'marker-mid' => array(),
8954
- 'marker-start' => array(),
8955
- 'mask' => array(),
8956
- 'opacity' => array(),
8957
- 'overflow' => array(),
8958
- 'pointer-events' => array(),
8959
- 'shape-rendering' => array(),
8960
- 'solid-color' => array(),
8961
- 'solid-opacity' => array(),
8962
- 'stop-color' => array(),
8963
- 'stop-opacity' => array(),
8964
- 'stroke' => array(),
8965
- 'stroke-dasharray' => array(),
8966
- 'stroke-dashoffset' => array(),
8967
- 'stroke-linecap' => array(),
8968
- 'stroke-linejoin' => array(),
8969
- 'stroke-miterlimit' => array(),
8970
- 'stroke-opacity' => array(),
8971
- 'stroke-width' => array(),
8972
- 'style' => array(
8973
- 'blacklisted_value_regex' => '!important',
8974
- ),
8975
- 'text-anchor' => array(),
8976
- 'text-decoration' => array(),
8977
- 'text-rendering' => array(),
8978
- 'unicode-bidi' => array(),
8979
- 'vector-effect' => array(),
8980
- 'visibility' => array(),
8981
- 'word-spacing' => array(),
8982
- 'writing-mode' => array(),
8983
- 'xml:lang' => array(),
8984
- 'xml:space' => array(),
8985
- 'xmlns' => array(),
8986
- 'xmlns:xlink' => array(),
8987
- ),
8988
- 'tag_spec' => array(
8989
- 'mandatory_ancestor' => 'svg',
8990
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
8991
- ),
8992
- ),
8993
- ),
8994
- 'source' => array(
8995
- array(
8996
- 'attr_spec_list' => array(
8997
- '[src]' => array(),
8998
- '[type]' => array(),
8999
- 'media' => array(),
9000
- 'src' => array(
9001
- 'blacklisted_value_regex' => '__amp_source_origin',
9002
- 'value_url' => array(
9003
- 'allow_relative' => true,
9004
- 'allowed_protocol' => array(
9005
- 'https',
9006
- ),
9007
- ),
9008
- ),
9009
- 'type' => array(),
9010
- ),
9011
- 'tag_spec' => array(
9012
- 'mandatory_parent' => 'amp-video',
9013
- 'spec_name' => 'amp-video > source',
9014
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
9015
- ),
9016
- ),
9017
- array(
9018
- 'attr_spec_list' => array(
9019
- '[src]' => array(),
9020
- '[type]' => array(),
9021
- 'media' => array(),
9022
- 'src' => array(
9023
- 'blacklisted_value_regex' => '__amp_source_origin',
9024
- 'value_url' => array(
9025
- 'allow_relative' => true,
9026
- 'allowed_protocol' => array(
9027
- 'https',
9028
- ),
9029
- ),
9030
- ),
9031
- 'type' => array(),
9032
- ),
9033
- 'tag_spec' => array(
9034
- 'mandatory_parent' => 'amp-audio',
9035
- 'spec_name' => 'amp-audio > source',
9036
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
9037
- ),
9038
- ),
9039
- array(
9040
- 'attr_spec_list' => array(
9041
- 'media' => array(),
9042
- 'src' => array(
9043
- 'blacklisted_value_regex' => '__amp_source_origin',
9044
- 'mandatory' => true,
9045
- 'value_url' => array(
9046
- 'allow_relative' => true,
9047
- 'allowed_protocol' => array(
9048
- 'https',
9049
- ),
9050
- ),
9051
- ),
9052
- 'type' => array(
9053
- 'mandatory' => true,
9054
- ),
9055
- ),
9056
- 'tag_spec' => array(
9057
- 'mandatory_parent' => 'audio',
9058
- 'spec_name' => 'audio > source',
9059
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio',
9060
- ),
9061
- ),
9062
- array(
9063
- 'attr_spec_list' => array(
9064
- 'media' => array(),
9065
- 'src' => array(
9066
- 'blacklisted_value_regex' => '__amp_source_origin',
9067
- 'mandatory' => true,
9068
- 'value_url' => array(
9069
- 'allow_relative' => true,
9070
- 'allowed_protocol' => array(
9071
- 'https',
9072
- ),
9073
- ),
9074
- ),
9075
- 'type' => array(
9076
- 'mandatory' => true,
9077
- ),
9078
- ),
9079
- 'tag_spec' => array(
9080
- 'mandatory_parent' => 'video',
9081
- 'spec_name' => 'video > source',
9082
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
9083
- ),
9084
- ),
9085
- array(
9086
- 'attr_spec_list' => array(
9087
- '[src]' => array(),
9088
- '[type]' => array(),
9089
- 'media' => array(),
9090
- 'src' => array(
9091
- 'blacklisted_value_regex' => '__amp_source_origin',
9092
- 'value_url' => array(
9093
- 'allow_relative' => true,
9094
- 'allowed_protocol' => array(
9095
- 'https',
9096
- ),
9097
- ),
9098
- ),
9099
- 'type' => array(),
9100
- ),
9101
- 'tag_spec' => array(
9102
- 'mandatory_parent' => 'amp-ima-video',
9103
- 'requires_extension' => array(
9104
- 'amp-ima-video',
9105
- ),
9106
- 'spec_name' => 'amp-ima-video > source',
9107
- ),
9108
- ),
9109
- ),
9110
- 'spacer' => array(
9111
- array(
9112
- 'attr_spec_list' => array(),
9113
- 'tag_spec' => array(),
9114
- ),
9115
- ),
9116
- 'span' => array(
9117
- array(
9118
- 'attr_spec_list' => array(),
9119
- 'tag_spec' => array(),
9120
- ),
9121
- ),
9122
- 'stop' => array(
9123
- array(
9124
- 'attr_spec_list' => array(
9125
- 'offset' => array(),
9126
- 'stop-color' => array(),
9127
- 'stop-opacity' => array(),
9128
- 'style' => array(
9129
- 'blacklisted_value_regex' => '!important',
9130
- ),
9131
- ),
9132
- 'tag_spec' => array(
9133
- 'mandatory_ancestor' => 'lineargradient',
9134
- 'spec_name' => 'lineargradient > stop',
9135
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9136
- ),
9137
- ),
9138
- array(
9139
- 'attr_spec_list' => array(
9140
- 'offset' => array(),
9141
- 'stop-color' => array(),
9142
- 'stop-opacity' => array(),
9143
- 'style' => array(
9144
- 'blacklisted_value_regex' => '!important',
9145
- ),
9146
- ),
9147
- 'tag_spec' => array(
9148
- 'mandatory_ancestor' => 'radialgradient',
9149
- 'spec_name' => 'radialgradient > stop',
9150
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9151
- ),
9152
- ),
9153
- ),
9154
- 'strike' => array(
9155
- array(
9156
- 'attr_spec_list' => array(),
9157
- 'tag_spec' => array(),
9158
- ),
9159
- ),
9160
- 'strong' => array(
9161
- array(
9162
- 'attr_spec_list' => array(),
9163
- 'tag_spec' => array(),
9164
- ),
9165
- ),
9166
- 'style' => array(
9167
- array(
9168
- 'attr_spec_list' => array(
9169
- 'amp-custom' => array(
9170
- 'mandatory' => true,
9171
- 'value' => '',
9172
- ),
9173
- 'nonce' => array(),
9174
- 'type' => array(
9175
- 'value_casei' => 'text/css',
9176
- ),
9177
- ),
9178
- 'cdata' => array(
9179
- 'blacklisted_cdata_regex' => array(
9180
- 'error_message' => 'CSS !important',
9181
- 'regex' => '!important',
9182
- ),
9183
- 'css_spec' => array(
9184
- 'allowed_at_rules' => array(
9185
- 'font-face',
9186
- 'keyframes',
9187
- 'media',
9188
- 'supports',
9189
- ),
9190
- 'allowed_declarations' => array(),
9191
- 'font_url_spec' => array(
9192
- 'allow_empty' => true,
9193
- 'allow_relative' => true,
9194
- 'allowed_protocol' => array(
9195
- 'https',
9196
- 'http',
9197
- 'data',
9198
- ),
9199
- ),
9200
- 'image_url_spec' => array(
9201
- 'allow_empty' => true,
9202
- 'allow_relative' => true,
9203
- 'allowed_protocol' => array(
9204
- 'https',
9205
- 'http',
9206
- 'data',
9207
- 'absolute',
9208
- ),
9209
- ),
9210
- 'validate_keyframes' => false,
9211
- ),
9212
- 'max_bytes' => 50000,
9213
- 'max_bytes_spec_url' => 'https://www.ampproject.org/docs/reference/spec#maximum-size',
9214
- ),
9215
- 'tag_spec' => array(
9216
- 'mandatory_parent' => 'head',
9217
- 'spec_name' => 'style amp-custom',
9218
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#stylesheets',
9219
- 'unique' => true,
9220
- ),
9221
- ),
9222
- array(
9223
- 'attr_spec_list' => array(
9224
- 'amp-boilerplate' => array(
9225
- 'dispatch_key' => 3,
9226
- 'mandatory' => true,
9227
- 'value' => '',
9228
- ),
9229
- 'nonce' => array(),
9230
- ),
9231
- 'cdata' => array(
9232
- 'cdata_regex' => '\\s*body{-webkit-animation:-amp-start\\s+8s\\s+steps\\(1,end\\)\\s+0s\\s+1\\s+normal\\s+both;-moz-animation:-amp-start\\s+8s\\s+steps\\(1,end\\)\\s+0s\\s+1\\s+normal\\s+both;-ms-animation:-amp-start\\s+8s\\s+steps\\(1,end\\)\\s+0s\\s+1\\s+normal\\s+both;animation:-amp-start\\s+8s\\s+steps\\(1,end\\)\\s+0s\\s+1\\s+normal\\s+both}@-webkit-keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes\\s+-amp-start{from{visibility:hidden}to{visibility:visible}}\\s*',
9233
- ),
9234
- 'tag_spec' => array(
9235
- 'mandatory_alternatives' => 'head > style[amp-boilerplate]',
9236
- 'mandatory_parent' => 'head',
9237
- 'spec_name' => 'head > style[amp-boilerplate]',
9238
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/spec/amp-boilerplate.md',
9239
- 'unique' => true,
9240
- ),
9241
- ),
9242
- array(
9243
- 'attr_spec_list' => array(
9244
- 'amp-boilerplate' => array(
9245
- 'dispatch_key' => 3,
9246
- 'mandatory' => true,
9247
- 'value' => '',
9248
- ),
9249
- 'nonce' => array(),
9250
- ),
9251
- 'cdata' => array(
9252
- 'cdata_regex' => '\\s*body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}\\s*',
9253
- ),
9254
- 'tag_spec' => array(
9255
- 'mandatory_alternatives' => 'noscript > style[amp-boilerplate]',
9256
- 'mandatory_ancestor' => 'head',
9257
- 'mandatory_parent' => 'noscript',
9258
- 'spec_name' => 'noscript > style[amp-boilerplate]',
9259
- 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/spec/amp-boilerplate.md',
9260
- 'unique' => true,
9261
- ),
9262
- ),
9263
- array(
9264
- 'attr_spec_list' => array(
9265
- 'amp-keyframes' => array(
9266
- 'dispatch_key' => 1,
9267
- 'mandatory' => true,
9268
- 'value' => '',
9269
- ),
9270
- ),
9271
- 'cdata' => array(
9272
- 'css_spec' => array(
9273
- 'allowed_at_rules' => array(
9274
- 'keyframes',
9275
- 'media',
9276
- 'supports',
9277
- ),
9278
- 'allowed_declarations' => array(
9279
- 'animation-timing-function',
9280
- 'offset-distance',
9281
- 'opacity',
9282
- 'transform',
9283
- 'visibility',
9284
- ),
9285
- 'font_url_spec' => array(),
9286
- 'image_url_spec' => array(),
9287
- 'validate_keyframes' => true,
9288
- ),
9289
- 'max_bytes' => 500000,
9290
- 'max_bytes_spec_url' => 'https://www.ampproject.org/docs/reference/spec#keyframes-stylesheet',
9291
- ),
9292
- 'tag_spec' => array(
9293
- 'mandatory_parent' => 'body',
9294
- 'spec_name' => 'style[amp-keyframes]',
9295
- 'unique' => true,
9296
- ),
9297
- ),
9298
- ),
9299
- 'sub' => array(
9300
- array(
9301
- 'attr_spec_list' => array(),
9302
- 'tag_spec' => array(),
9303
- ),
9304
- ),
9305
- 'sup' => array(
9306
- array(
9307
- 'attr_spec_list' => array(),
9308
- 'tag_spec' => array(),
9309
- ),
9310
- ),
9311
- 'svg' => array(
9312
- array(
9313
- 'attr_spec_list' => array(
9314
- 'alignment-baseline' => array(),
9315
- 'baseline-shift' => array(),
9316
- 'clip' => array(),
9317
- 'clip-path' => array(),
9318
- 'clip-rule' => array(),
9319
- 'color' => array(),
9320
- 'color-interpolation' => array(),
9321
- 'color-interpolation-filters' => array(),
9322
- 'color-profile' => array(),
9323
- 'color-rendering' => array(),
9324
- 'contentscripttype' => array(),
9325
- 'contentstyletype' => array(),
9326
- 'cursor' => array(),
9327
- 'direction' => array(),
9328
- 'display' => array(),
9329
- 'dominant-baseline' => array(),
9330
- 'enable-background' => array(),
9331
- 'externalresourcesrequired' => array(),
9332
- 'fill' => array(),
9333
- 'fill-opacity' => array(),
9334
- 'fill-rule' => array(),
9335
- 'filter' => array(),
9336
- 'flood-color' => array(),
9337
- 'flood-opacity' => array(),
9338
- 'font-family' => array(),
9339
- 'font-size' => array(),
9340
- 'font-size-adjust' => array(),
9341
- 'font-stretch' => array(),
9342
- 'font-style' => array(),
9343
- 'font-variant' => array(),
9344
- 'font-weight' => array(),
9345
- 'glyph-orientation-horizontal' => array(),
9346
- 'glyph-orientation-vertical' => array(),
9347
- 'height' => array(),
9348
- 'image-rendering' => array(),
9349
- 'kerning' => array(),
9350
- 'letter-spacing' => array(),
9351
- 'lighting-color' => array(),
9352
- 'marker-end' => array(),
9353
- 'marker-mid' => array(),
9354
- 'marker-start' => array(),
9355
- 'mask' => array(),
9356
- 'opacity' => array(),
9357
- 'overflow' => array(),
9358
- 'pointer-events' => array(),
9359
- 'preserveaspectratio' => array(),
9360
- 'requiredextensions' => array(),
9361
- 'requiredfeatures' => array(),
9362
- 'shape-rendering' => array(),
9363
- 'stop-color' => array(),
9364
- 'stop-opacity' => array(),
9365
- 'stroke' => array(),
9366
- 'stroke-dasharray' => array(),
9367
- 'stroke-dashoffset' => array(),
9368
- 'stroke-linecap' => array(),
9369
- 'stroke-linejoin' => array(),
9370
- 'stroke-miterlimit' => array(),
9371
- 'stroke-opacity' => array(),
9372
- 'stroke-width' => array(),
9373
- 'systemlanguage' => array(),
9374
- 'text-anchor' => array(),
9375
- 'text-decoration' => array(),
9376
- 'text-rendering' => array(),
9377
- 'unicode-bidi' => array(),
9378
- 'vector-effect' => array(),
9379
- 'version' => array(
9380
- 'value_regex' => '(1.0|1.1)',
9381
- ),
9382
- 'viewbox' => array(),
9383
- 'visibility' => array(),
9384
- 'width' => array(),
9385
- 'word-spacing' => array(),
9386
- 'writing-mode' => array(),
9387
- 'x' => array(),
9388
- 'xml:lang' => array(),
9389
- 'xml:space' => array(),
9390
- 'xmlns' => array(),
9391
- 'xmlns:xlink' => array(),
9392
- 'y' => array(),
9393
- 'zoomandpan' => array(),
9394
- ),
9395
- 'tag_spec' => array(
9396
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9397
- ),
9398
- ),
9399
- ),
9400
- 'switch' => array(
9401
- array(
9402
- 'attr_spec_list' => array(
9403
- 'alignment-baseline' => array(),
9404
- 'baseline-shift' => array(),
9405
- 'clip' => array(),
9406
- 'clip-path' => array(),
9407
- 'clip-rule' => array(),
9408
- 'color' => array(),
9409
- 'color-interpolation' => array(),
9410
- 'color-interpolation-filters' => array(),
9411
- 'color-profile' => array(),
9412
- 'color-rendering' => array(),
9413
- 'cursor' => array(),
9414
- 'direction' => array(),
9415
- 'display' => array(),
9416
- 'dominant-baseline' => array(),
9417
- 'enable-background' => array(),
9418
- 'fill' => array(),
9419
- 'fill-opacity' => array(),
9420
- 'fill-rule' => array(),
9421
- 'filter' => array(),
9422
- 'flood-color' => array(),
9423
- 'flood-opacity' => array(),
9424
- 'font-family' => array(),
9425
- 'font-size' => array(),
9426
- 'font-size-adjust' => array(),
9427
- 'font-stretch' => array(),
9428
- 'font-style' => array(),
9429
- 'font-variant' => array(),
9430
- 'font-weight' => array(),
9431
- 'glyph-orientation-horizontal' => array(),
9432
- 'glyph-orientation-vertical' => array(),
9433
- 'image-rendering' => array(),
9434
- 'kerning' => array(),
9435
- 'letter-spacing' => array(),
9436
- 'lighting-color' => array(),
9437
- 'marker-end' => array(),
9438
- 'marker-mid' => array(),
9439
- 'marker-start' => array(),
9440
- 'mask' => array(),
9441
- 'opacity' => array(),
9442
- 'overflow' => array(),
9443
- 'pointer-events' => array(),
9444
- 'requiredextensions' => array(),
9445
- 'requiredfeatures' => array(),
9446
- 'shape-rendering' => array(),
9447
- 'stop-color' => array(),
9448
- 'stop-opacity' => array(),
9449
- 'stroke' => array(),
9450
- 'stroke-dasharray' => array(),
9451
- 'stroke-dashoffset' => array(),
9452
- 'stroke-linecap' => array(),
9453
- 'stroke-linejoin' => array(),
9454
- 'stroke-miterlimit' => array(),
9455
- 'stroke-opacity' => array(),
9456
- 'stroke-width' => array(),
9457
- 'style' => array(
9458
- 'blacklisted_value_regex' => '!important',
9459
- ),
9460
- 'systemlanguage' => array(),
9461
- 'text-anchor' => array(),
9462
- 'text-decoration' => array(),
9463
- 'text-rendering' => array(),
9464
- 'unicode-bidi' => array(),
9465
- 'vector-effect' => array(),
9466
- 'visibility' => array(),
9467
- 'word-spacing' => array(),
9468
- 'writing-mode' => array(),
9469
- 'xml:lang' => array(),
9470
- 'xml:space' => array(),
9471
- 'xmlns' => array(),
9472
- 'xmlns:xlink' => array(),
9473
- ),
9474
- 'tag_spec' => array(
9475
- 'mandatory_ancestor' => 'svg',
9476
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9477
- ),
9478
- ),
9479
- ),
9480
- 'symbol' => array(
9481
- array(
9482
- 'attr_spec_list' => array(
9483
- 'alignment-baseline' => array(),
9484
- 'baseline-shift' => array(),
9485
- 'clip' => array(),
9486
- 'clip-path' => array(),
9487
- 'clip-rule' => array(),
9488
- 'color' => array(),
9489
- 'color-interpolation' => array(),
9490
- 'color-interpolation-filters' => array(),
9491
- 'color-profile' => array(),
9492
- 'color-rendering' => array(),
9493
- 'cursor' => array(),
9494
- 'direction' => array(),
9495
- 'display' => array(),
9496
- 'dominant-baseline' => array(),
9497
- 'enable-background' => array(),
9498
- 'externalresourcesrequired' => array(),
9499
- 'fill' => array(),
9500
- 'fill-opacity' => array(),
9501
- 'fill-rule' => array(),
9502
- 'filter' => array(),
9503
- 'flood-color' => array(),
9504
- 'flood-opacity' => array(),
9505
- 'font-family' => array(),
9506
- 'font-size' => array(),
9507
- 'font-size-adjust' => array(),
9508
- 'font-stretch' => array(),
9509
- 'font-style' => array(),
9510
- 'font-variant' => array(),
9511
- 'font-weight' => array(),
9512
- 'glyph-orientation-horizontal' => array(),
9513
- 'glyph-orientation-vertical' => array(),
9514
- 'image-rendering' => array(),
9515
- 'kerning' => array(),
9516
- 'letter-spacing' => array(),
9517
- 'lighting-color' => array(),
9518
- 'marker-end' => array(),
9519
- 'marker-mid' => array(),
9520
- 'marker-start' => array(),
9521
- 'mask' => array(),
9522
- 'opacity' => array(),
9523
- 'overflow' => array(),
9524
- 'pointer-events' => array(),
9525
- 'preserveaspectratio' => array(),
9526
- 'shape-rendering' => array(),
9527
- 'stop-color' => array(),
9528
- 'stop-opacity' => array(),
9529
- 'stroke' => array(),
9530
- 'stroke-dasharray' => array(),
9531
- 'stroke-dashoffset' => array(),
9532
- 'stroke-linecap' => array(),
9533
- 'stroke-linejoin' => array(),
9534
- 'stroke-miterlimit' => array(),
9535
- 'stroke-opacity' => array(),
9536
- 'stroke-width' => array(),
9537
- 'style' => array(
9538
- 'blacklisted_value_regex' => '!important',
9539
- ),
9540
- 'text-anchor' => array(),
9541
- 'text-decoration' => array(),
9542
- 'text-rendering' => array(),
9543
- 'unicode-bidi' => array(),
9544
- 'vector-effect' => array(),
9545
- 'viewbox' => array(),
9546
- 'visibility' => array(),
9547
- 'word-spacing' => array(),
9548
- 'writing-mode' => array(),
9549
- 'xml:lang' => array(),
9550
- 'xml:space' => array(),
9551
- 'xmlns' => array(),
9552
- 'xmlns:xlink' => array(),
9553
- ),
9554
- 'tag_spec' => array(
9555
- 'mandatory_ancestor' => 'svg',
9556
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9557
- ),
9558
- ),
9559
- ),
9560
- 'table' => array(
9561
- array(
9562
- 'attr_spec_list' => array(
9563
- 'align' => array(),
9564
- 'bgcolor' => array(),
9565
- 'border' => array(
9566
- 'value_regex' => '0|1',
9567
- ),
9568
- 'cellpadding' => array(),
9569
- 'cellspacing' => array(),
9570
- 'sortable' => array(),
9571
- 'width' => array(),
9572
- ),
9573
- 'tag_spec' => array(),
9574
- ),
9575
- ),
9576
- 'tbody' => array(
9577
- array(
9578
- 'attr_spec_list' => array(),
9579
- 'tag_spec' => array(),
9580
- ),
9581
- ),
9582
- 'td' => array(
9583
- array(
9584
- 'attr_spec_list' => array(
9585
- 'align' => array(),
9586
- 'bgcolor' => array(),
9587
- 'colspan' => array(),
9588
- 'headers' => array(),
9589
- 'height' => array(),
9590
- 'rowspan' => array(),
9591
- 'valign' => array(),
9592
- 'width' => array(),
9593
- ),
9594
- 'tag_spec' => array(),
9595
- ),
9596
- ),
9597
- 'template' => array(
9598
- array(
9599
- 'attr_spec_list' => array(
9600
- 'type' => array(
9601
- 'mandatory' => true,
9602
- 'value' => 'amp-mustache',
9603
- ),
9604
- ),
9605
- 'tag_spec' => array(
9606
- 'disallowed_ancestor' => array(
9607
- 'template',
9608
- 'amp-story-auto-ads',
9609
- 'form > div [submit-success][template]',
9610
- 'form > div [submit-error][template]',
9611
- ),
9612
- 'requires_extension' => array(
9613
- 'amp-mustache',
9614
- ),
9615
- ),
9616
- ),
9617
- array(
9618
- 'attr_spec_list' => array(
9619
- 'type' => array(
9620
- 'mandatory' => true,
9621
- 'value' => 'amp-mustache',
9622
- ),
9623
- ),
9624
- 'tag_spec' => array(
9625
- 'mandatory_parent' => 'amp-story-auto-ads',
9626
- 'requires_extension' => array(
9627
- 'amp-mustache',
9628
- ),
9629
- 'spec_name' => 'amp-story-auto-ads > template',
9630
- ),
9631
- ),
9632
- ),
9633
- 'text' => array(
9634
- array(
9635
- 'attr_spec_list' => array(
9636
- 'alignment-baseline' => array(),
9637
- 'baseline-shift' => array(),
9638
- 'clip' => array(),
9639
- 'clip-path' => array(),
9640
- 'clip-rule' => array(),
9641
- 'color' => array(),
9642
- 'color-interpolation' => array(),
9643
- 'color-interpolation-filters' => array(),
9644
- 'color-profile' => array(),
9645
- 'color-rendering' => array(),
9646
- 'cursor' => array(),
9647
- 'direction' => array(),
9648
- 'display' => array(),
9649
- 'dominant-baseline' => array(),
9650
- 'dx' => array(),
9651
- 'dy' => array(),
9652
- 'enable-background' => array(),
9653
- 'externalresourcesrequired' => array(),
9654
- 'fill' => array(),
9655
- 'fill-opacity' => array(),
9656
- 'fill-rule' => array(),
9657
- 'filter' => array(),
9658
- 'flood-color' => array(),
9659
- 'flood-opacity' => array(),
9660
- 'font-family' => array(),
9661
- 'font-size' => array(),
9662
- 'font-size-adjust' => array(),
9663
- 'font-stretch' => array(),
9664
- 'font-style' => array(),
9665
- 'font-variant' => array(),
9666
- 'font-weight' => array(),
9667
- 'glyph-orientation-horizontal' => array(),
9668
- 'glyph-orientation-vertical' => array(),
9669
- 'image-rendering' => array(),
9670
- 'kerning' => array(),
9671
- 'lengthadjust' => array(),
9672
- 'letter-spacing' => array(),
9673
- 'lighting-color' => array(),
9674
- 'marker-end' => array(),
9675
- 'marker-mid' => array(),
9676
- 'marker-start' => array(),
9677
- 'mask' => array(),
9678
- 'opacity' => array(),
9679
- 'overflow' => array(),
9680
- 'pointer-events' => array(),
9681
- 'requiredextensions' => array(),
9682
- 'requiredfeatures' => array(),
9683
- 'rotate' => array(),
9684
- 'shape-rendering' => array(),
9685
- 'stop-color' => array(),
9686
- 'stop-opacity' => array(),
9687
- 'stroke' => array(),
9688
- 'stroke-dasharray' => array(),
9689
- 'stroke-dashoffset' => array(),
9690
- 'stroke-linecap' => array(),
9691
- 'stroke-linejoin' => array(),
9692
- 'stroke-miterlimit' => array(),
9693
- 'stroke-opacity' => array(),
9694
- 'stroke-width' => array(),
9695
- 'style' => array(
9696
- 'blacklisted_value_regex' => '!important',
9697
- ),
9698
- 'systemlanguage' => array(),
9699
- 'text-anchor' => array(),
9700
- 'text-decoration' => array(),
9701
- 'text-rendering' => array(),
9702
- 'textlength' => array(),
9703
- 'transform' => array(),
9704
- 'unicode-bidi' => array(),
9705
- 'vector-effect' => array(),
9706
- 'visibility' => array(),
9707
- 'word-spacing' => array(),
9708
- 'writing-mode' => array(),
9709
- 'x' => array(),
9710
- 'xml:lang' => array(),
9711
- 'xml:space' => array(),
9712
- 'xmlns' => array(),
9713
- 'xmlns:xlink' => array(),
9714
- 'y' => array(),
9715
- ),
9716
- 'tag_spec' => array(
9717
- 'mandatory_ancestor' => 'svg',
9718
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9719
- ),
9720
- ),
9721
- ),
9722
- 'textarea' => array(
9723
- array(
9724
- 'attr_spec_list' => array(
9725
- '[autocomplete]' => array(),
9726
- '[autofocus]' => array(),
9727
- '[cols]' => array(),
9728
- '[disabled]' => array(),
9729
- '[maxlength]' => array(),
9730
- '[minlength]' => array(),
9731
- '[placeholder]' => array(),
9732
- '[readonly]' => array(),
9733
- '[required]' => array(),
9734
- '[rows]' => array(),
9735
- '[selectiondirection]' => array(),
9736
- '[selectionend]' => array(),
9737
- '[selectionstart]' => array(),
9738
- '[spellcheck]' => array(),
9739
- '[wrap]' => array(),
9740
- 'autocomplete' => array(),
9741
- 'autofocus' => array(),
9742
- 'cols' => array(),
9743
- 'disabled' => array(),
9744
- 'maxlength' => array(),
9745
- 'minlength' => array(),
9746
- 'name' => array(
9747
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
9748
- ),
9749
- 'placeholder' => array(),
9750
- 'readonly' => array(),
9751
- 'required' => array(),
9752
- 'rows' => array(),
9753
- 'selectiondirection' => array(),
9754
- 'selectionend' => array(),
9755
- 'selectionstart' => array(),
9756
- 'spellcheck' => array(),
9757
- 'wrap' => array(),
9758
- ),
9759
- 'tag_spec' => array(
9760
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form',
9761
- ),
9762
- ),
9763
- ),
9764
- 'textpath' => array(
9765
- array(
9766
- 'attr_spec_list' => array(
9767
- 'alignment-baseline' => array(),
9768
- 'baseline-shift' => array(),
9769
- 'clip' => array(),
9770
- 'clip-path' => array(),
9771
- 'clip-rule' => array(),
9772
- 'color' => array(),
9773
- 'color-interpolation' => array(),
9774
- 'color-interpolation-filters' => array(),
9775
- 'color-profile' => array(),
9776
- 'color-rendering' => array(),
9777
- 'cursor' => array(),
9778
- 'direction' => array(),
9779
- 'display' => array(),
9780
- 'dominant-baseline' => array(),
9781
- 'enable-background' => array(),
9782
- 'externalresourcesrequired' => array(),
9783
- 'fill' => array(),
9784
- 'fill-opacity' => array(),
9785
- 'fill-rule' => array(),
9786
- 'filter' => array(),
9787
- 'flood-color' => array(),
9788
- 'flood-opacity' => array(),
9789
- 'font-family' => array(),
9790
- 'font-size' => array(),
9791
- 'font-size-adjust' => array(),
9792
- 'font-stretch' => array(),
9793
- 'font-style' => array(),
9794
- 'font-variant' => array(),
9795
- 'font-weight' => array(),
9796
- 'glyph-orientation-horizontal' => array(),
9797
- 'glyph-orientation-vertical' => array(),
9798
- 'image-rendering' => array(),
9799
- 'kerning' => array(),
9800
- 'letter-spacing' => array(),
9801
- 'lighting-color' => array(),
9802
- 'marker-end' => array(),
9803
- 'marker-mid' => array(),
9804
- 'marker-start' => array(),
9805
- 'mask' => array(),
9806
- 'method' => array(),
9807
- 'opacity' => array(),
9808
- 'overflow' => array(),
9809
- 'pointer-events' => array(),
9810
- 'requiredextensions' => array(),
9811
- 'requiredfeatures' => array(),
9812
- 'shape-rendering' => array(),
9813
- 'spacing' => array(),
9814
- 'startoffset' => array(),
9815
- 'stop-color' => array(),
9816
- 'stop-opacity' => array(),
9817
- 'stroke' => array(),
9818
- 'stroke-dasharray' => array(),
9819
- 'stroke-dashoffset' => array(),
9820
- 'stroke-linecap' => array(),
9821
- 'stroke-linejoin' => array(),
9822
- 'stroke-miterlimit' => array(),
9823
- 'stroke-opacity' => array(),
9824
- 'stroke-width' => array(),
9825
- 'style' => array(
9826
- 'blacklisted_value_regex' => '!important',
9827
- ),
9828
- 'systemlanguage' => array(),
9829
- 'text-anchor' => array(),
9830
- 'text-decoration' => array(),
9831
- 'text-rendering' => array(),
9832
- 'unicode-bidi' => array(),
9833
- 'vector-effect' => array(),
9834
- 'visibility' => array(),
9835
- 'word-spacing' => array(),
9836
- 'writing-mode' => array(),
9837
- 'xlink:actuate' => array(),
9838
- 'xlink:arcrole' => array(),
9839
- 'xlink:href' => array(
9840
- 'alternative_names' => array(
9841
- 'href',
9842
- ),
9843
- 'value_url' => array(
9844
- 'allow_empty' => false,
9845
- 'allow_relative' => true,
9846
- 'allowed_protocol' => array(
9847
- 'http',
9848
- 'https',
9849
- ),
9850
- ),
9851
- ),
9852
- 'xlink:role' => array(),
9853
- 'xlink:show' => array(),
9854
- 'xlink:title' => array(),
9855
- 'xlink:type' => array(),
9856
- 'xml:lang' => array(),
9857
- 'xml:space' => array(),
9858
- 'xmlns' => array(),
9859
- 'xmlns:xlink' => array(),
9860
- ),
9861
- 'tag_spec' => array(
9862
- 'mandatory_ancestor' => 'svg',
9863
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9864
- ),
9865
- ),
9866
- ),
9867
- 'tfoot' => array(
9868
- array(
9869
- 'attr_spec_list' => array(),
9870
- 'tag_spec' => array(),
9871
- ),
9872
- ),
9873
- 'th' => array(
9874
- array(
9875
- 'attr_spec_list' => array(
9876
- 'abbr' => array(),
9877
- 'align' => array(),
9878
- 'bgcolor' => array(),
9879
- 'colspan' => array(),
9880
- 'headers' => array(),
9881
- 'height' => array(),
9882
- 'rowspan' => array(),
9883
- 'scope' => array(),
9884
- 'sorted' => array(),
9885
- 'valign' => array(),
9886
- 'width' => array(),
9887
- ),
9888
- 'tag_spec' => array(),
9889
- ),
9890
- ),
9891
- 'thead' => array(
9892
- array(
9893
- 'attr_spec_list' => array(),
9894
- 'tag_spec' => array(),
9895
- ),
9896
- ),
9897
- 'time' => array(
9898
- array(
9899
- 'attr_spec_list' => array(
9900
- 'datetime' => array(),
9901
- ),
9902
- 'tag_spec' => array(),
9903
- ),
9904
- ),
9905
- 'title' => array(
9906
- array(
9907
- 'attr_spec_list' => array(),
9908
- 'tag_spec' => array(
9909
- 'spec_name' => 'title',
9910
- ),
9911
- ),
9912
- array(
9913
- 'attr_spec_list' => array(
9914
- 'style' => array(
9915
- 'blacklisted_value_regex' => '!important',
9916
- ),
9917
- 'xml:lang' => array(),
9918
- 'xml:space' => array(),
9919
- 'xmlns' => array(),
9920
- 'xmlns:xlink' => array(),
9921
- ),
9922
- 'tag_spec' => array(
9923
- 'mandatory_ancestor' => 'svg',
9924
- 'spec_name' => 'svg title',
9925
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
9926
- ),
9927
- ),
9928
- ),
9929
- 'tr' => array(
9930
- array(
9931
- 'attr_spec_list' => array(
9932
- 'align' => array(),
9933
- 'bgcolor' => array(),
9934
- 'height' => array(),
9935
- 'valign' => array(),
9936
- ),
9937
- 'tag_spec' => array(),
9938
- ),
9939
- ),
9940
- 'track' => array(
9941
- array(
9942
- 'attr_spec_list' => array(
9943
- 'default' => array(
9944
- 'value' => '',
9945
- ),
9946
- 'kind' => array(
9947
- 'value_regex' => '(captions|descriptions|chapters|metadata)',
9948
- ),
9949
- 'label' => array(),
9950
- 'src' => array(
9951
- 'blacklisted_value_regex' => '__amp_source_origin',
9952
- 'mandatory' => true,
9953
- 'value_url' => array(
9954
- 'allow_relative' => false,
9955
- 'allowed_protocol' => array(
9956
- 'https',
9957
- ),
9958
- ),
9959
- ),
9960
- 'srclang' => array(),
9961
- ),
9962
- 'tag_spec' => array(
9963
- 'mandatory_parent' => 'audio',
9964
- 'spec_name' => 'audio > track',
9965
- ),
9966
- ),
9967
- array(
9968
- 'attr_spec_list' => array(
9969
- 'default' => array(
9970
- 'value' => '',
9971
- ),
9972
- 'kind' => array(
9973
- 'mandatory' => true,
9974
- 'value_casei' => 'subtitles',
9975
- ),
9976
- 'label' => array(),
9977
- 'src' => array(
9978
- 'blacklisted_value_regex' => '__amp_source_origin',
9979
- 'mandatory' => true,
9980
- 'value_url' => array(
9981
- 'allow_relative' => false,
9982
- 'allowed_protocol' => array(
9983
- 'https',
9984
- ),
9985
- ),
9986
- ),
9987
- 'srclang' => array(
9988
- 'mandatory' => true,
9989
- ),
9990
- ),
9991
- 'tag_spec' => array(
9992
- 'mandatory_parent' => 'audio',
9993
- 'spec_name' => 'audio > track[kind=subtitles]',
9994
- ),
9995
- ),
9996
- array(
9997
- 'attr_spec_list' => array(
9998
- 'default' => array(
9999
- 'value' => '',
10000
- ),
10001
- 'kind' => array(
10002
- 'value_regex' => '(captions|descriptions|chapters|metadata)',
10003
- ),
10004
- 'label' => array(),
10005
- 'src' => array(
10006
- 'blacklisted_value_regex' => '__amp_source_origin',
10007
- 'mandatory' => true,
10008
- 'value_url' => array(
10009
- 'allow_relative' => false,
10010
- 'allowed_protocol' => array(
10011
- 'https',
10012
- ),
10013
- ),
10014
- ),
10015
- 'srclang' => array(),
10016
- ),
10017
- 'tag_spec' => array(
10018
- 'mandatory_parent' => 'video',
10019
- 'spec_name' => 'video > track',
10020
- ),
10021
- ),
10022
- array(
10023
- 'attr_spec_list' => array(
10024
- 'default' => array(
10025
- 'value' => '',
10026
- ),
10027
- 'kind' => array(
10028
- 'mandatory' => true,
10029
- 'value_casei' => 'subtitles',
10030
- ),
10031
- 'label' => array(),
10032
- 'src' => array(
10033
- 'blacklisted_value_regex' => '__amp_source_origin',
10034
- 'mandatory' => true,
10035
- 'value_url' => array(
10036
- 'allow_relative' => false,
10037
- 'allowed_protocol' => array(
10038
- 'https',
10039
- ),
10040
- ),
10041
- ),
10042
- 'srclang' => array(
10043
- 'mandatory' => true,
10044
- ),
10045
- ),
10046
- 'tag_spec' => array(
10047
- 'mandatory_parent' => 'video',
10048
- 'spec_name' => 'video > track[kind=subtitles]',
10049
- ),
10050
- ),
10051
- array(
10052
- 'attr_spec_list' => array(
10053
- '[label]' => array(),
10054
- '[src]' => array(),
10055
- '[srclang]' => array(),
10056
- 'default' => array(
10057
- 'value' => '',
10058
- ),
10059
- 'kind' => array(
10060
- 'value_regex' => '(captions|descriptions|chapters|metadata)',
10061
- ),
10062
- 'label' => array(),
10063
- 'src' => array(
10064
- 'blacklisted_value_regex' => '__amp_source_origin',
10065
- 'mandatory' => true,
10066
- 'value_url' => array(
10067
- 'allow_relative' => false,
10068
- 'allowed_protocol' => array(
10069
- 'https',
10070
- ),
10071
- ),
10072
- ),
10073
- 'srclang' => array(),
10074
- ),
10075
- 'tag_spec' => array(
10076
- 'mandatory_parent' => 'amp-audio',
10077
- 'spec_name' => 'amp-audio > track',
10078
- ),
10079
- ),
10080
- array(
10081
- 'attr_spec_list' => array(
10082
- '[label]' => array(),
10083
- '[src]' => array(),
10084
- '[srclang]' => array(),
10085
- 'default' => array(
10086
- 'value' => '',
10087
- ),
10088
- 'kind' => array(
10089
- 'mandatory' => true,
10090
- 'value_casei' => 'subtitles',
10091
- ),
10092
- 'label' => array(),
10093
- 'src' => array(
10094
- 'blacklisted_value_regex' => '__amp_source_origin',
10095
- 'mandatory' => true,
10096
- 'value_url' => array(
10097
- 'allow_relative' => false,
10098
- 'allowed_protocol' => array(
10099
- 'https',
10100
- ),
10101
- ),
10102
- ),
10103
- 'srclang' => array(
10104
- 'mandatory' => true,
10105
- ),
10106
- ),
10107
- 'tag_spec' => array(
10108
- 'mandatory_parent' => 'amp-audio',
10109
- 'spec_name' => 'amp-audio > track[kind=subtitles]',
10110
- ),
10111
- ),
10112
- array(
10113
- 'attr_spec_list' => array(
10114
- '[label]' => array(),
10115
- '[src]' => array(),
10116
- '[srclang]' => array(),
10117
- 'default' => array(
10118
- 'value' => '',
10119
- ),
10120
- 'kind' => array(
10121
- 'value_regex' => '(captions|descriptions|chapters|metadata)',
10122
- ),
10123
- 'label' => array(),
10124
- 'src' => array(
10125
- 'blacklisted_value_regex' => '__amp_source_origin',
10126
- 'mandatory' => true,
10127
- 'value_url' => array(
10128
- 'allow_relative' => false,
10129
- 'allowed_protocol' => array(
10130
- 'https',
10131
- ),
10132
- ),
10133
- ),
10134
- 'srclang' => array(),
10135
- ),
10136
- 'tag_spec' => array(
10137
- 'mandatory_parent' => 'amp-video',
10138
- 'spec_name' => 'amp-video > track',
10139
- ),
10140
- ),
10141
- array(
10142
- 'attr_spec_list' => array(
10143
- '[label]' => array(),
10144
- '[src]' => array(),
10145
- '[srclang]' => array(),
10146
- 'default' => array(
10147
- 'value' => '',
10148
- ),
10149
- 'kind' => array(
10150
- 'mandatory' => true,
10151
- 'value_casei' => 'subtitles',
10152
- ),
10153
- 'label' => array(),
10154
- 'src' => array(
10155
- 'blacklisted_value_regex' => '__amp_source_origin',
10156
- 'mandatory' => true,
10157
- 'value_url' => array(
10158
- 'allow_relative' => false,
10159
- 'allowed_protocol' => array(
10160
- 'https',
10161
- ),
10162
- ),
10163
- ),
10164
- 'srclang' => array(
10165
- 'mandatory' => true,
10166
- ),
10167
- ),
10168
- 'tag_spec' => array(
10169
- 'mandatory_parent' => 'amp-video',
10170
- 'spec_name' => 'amp-video > track[kind=subtitles]',
10171
- ),
10172
- ),
10173
- array(
10174
- 'attr_spec_list' => array(
10175
- '[label]' => array(),
10176
- '[src]' => array(),
10177
- '[srclang]' => array(),
10178
- 'default' => array(
10179
- 'value' => '',
10180
- ),
10181
- 'kind' => array(
10182
- 'mandatory' => true,
10183
- 'value_casei' => 'subtitles',
10184
- ),
10185
- 'label' => array(),
10186
- 'src' => array(
10187
- 'blacklisted_value_regex' => '__amp_source_origin',
10188
- 'mandatory' => true,
10189
- 'value_url' => array(
10190
- 'allow_relative' => false,
10191
- 'allowed_protocol' => array(
10192
- 'https',
10193
- ),
10194
- ),
10195
- ),
10196
- 'srclang' => array(
10197
- 'mandatory' => true,
10198
- ),
10199
- ),
10200
- 'tag_spec' => array(
10201
- 'mandatory_parent' => 'amp-ima-video',
10202
- 'spec_name' => 'amp-ima-video > track[kind=subtitles]',
10203
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ima-video',
10204
- ),
10205
- ),
10206
- ),
10207
- 'tref' => array(
10208
- array(
10209
- 'attr_spec_list' => array(
10210
- 'alignment-baseline' => array(),
10211
- 'baseline-shift' => array(),
10212
- 'clip' => array(),
10213
- 'clip-path' => array(),
10214
- 'clip-rule' => array(),
10215
- 'color' => array(),
10216
- 'color-interpolation' => array(),
10217
- 'color-interpolation-filters' => array(),
10218
- 'color-profile' => array(),
10219
- 'color-rendering' => array(),
10220
- 'cursor' => array(),
10221
- 'direction' => array(),
10222
- 'display' => array(),
10223
- 'dominant-baseline' => array(),
10224
- 'enable-background' => array(),
10225
- 'externalresourcesrequired' => array(),
10226
- 'fill' => array(),
10227
- 'fill-opacity' => array(),
10228
- 'fill-rule' => array(),
10229
- 'filter' => array(),
10230
- 'flood-color' => array(),
10231
- 'flood-opacity' => array(),
10232
- 'font-family' => array(),
10233
- 'font-size' => array(),
10234
- 'font-size-adjust' => array(),
10235
- 'font-stretch' => array(),
10236
- 'font-style' => array(),
10237
- 'font-variant' => array(),
10238
- 'font-weight' => array(),
10239
- 'glyph-orientation-horizontal' => array(),
10240
- 'glyph-orientation-vertical' => array(),
10241
- 'image-rendering' => array(),
10242
- 'kerning' => array(),
10243
- 'letter-spacing' => array(),
10244
- 'lighting-color' => array(),
10245
- 'marker-end' => array(),
10246
- 'marker-mid' => array(),
10247
- 'marker-start' => array(),
10248
- 'mask' => array(),
10249
- 'opacity' => array(),
10250
- 'overflow' => array(),
10251
- 'pointer-events' => array(),
10252
- 'requiredextensions' => array(),
10253
- 'requiredfeatures' => array(),
10254
- 'shape-rendering' => array(),
10255
- 'stop-color' => array(),
10256
- 'stop-opacity' => array(),
10257
- 'stroke' => array(),
10258
- 'stroke-dasharray' => array(),
10259
- 'stroke-dashoffset' => array(),
10260
- 'stroke-linecap' => array(),
10261
- 'stroke-linejoin' => array(),
10262
- 'stroke-miterlimit' => array(),
10263
- 'stroke-opacity' => array(),
10264
- 'stroke-width' => array(),
10265
- 'style' => array(
10266
- 'blacklisted_value_regex' => '!important',
10267
- ),
10268
- 'systemlanguage' => array(),
10269
- 'text-anchor' => array(),
10270
- 'text-decoration' => array(),
10271
- 'text-rendering' => array(),
10272
- 'unicode-bidi' => array(),
10273
- 'vector-effect' => array(),
10274
- 'visibility' => array(),
10275
- 'word-spacing' => array(),
10276
- 'writing-mode' => array(),
10277
- 'xlink:actuate' => array(),
10278
- 'xlink:arcrole' => array(),
10279
- 'xlink:href' => array(
10280
- 'alternative_names' => array(
10281
- 'href',
10282
- ),
10283
- 'value_url' => array(
10284
- 'allow_empty' => false,
10285
- 'allow_relative' => true,
10286
- 'allowed_protocol' => array(
10287
- 'http',
10288
- 'https',
10289
- ),
10290
- ),
10291
- ),
10292
- 'xlink:role' => array(),
10293
- 'xlink:show' => array(),
10294
- 'xlink:title' => array(),
10295
- 'xlink:type' => array(),
10296
- 'xml:lang' => array(),
10297
- 'xml:space' => array(),
10298
- 'xmlns' => array(),
10299
- 'xmlns:xlink' => array(),
10300
- ),
10301
- 'tag_spec' => array(
10302
- 'mandatory_ancestor' => 'svg',
10303
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10304
- ),
10305
- ),
10306
- ),
10307
- 'tspan' => array(
10308
- array(
10309
- 'attr_spec_list' => array(
10310
- 'alignment-baseline' => array(),
10311
- 'baseline-shift' => array(),
10312
- 'clip' => array(),
10313
- 'clip-path' => array(),
10314
- 'clip-rule' => array(),
10315
- 'color' => array(),
10316
- 'color-interpolation' => array(),
10317
- 'color-interpolation-filters' => array(),
10318
- 'color-profile' => array(),
10319
- 'color-rendering' => array(),
10320
- 'cursor' => array(),
10321
- 'direction' => array(),
10322
- 'display' => array(),
10323
- 'dominant-baseline' => array(),
10324
- 'dx' => array(),
10325
- 'dy' => array(),
10326
- 'enable-background' => array(),
10327
- 'externalresourcesrequired' => array(),
10328
- 'fill' => array(),
10329
- 'fill-opacity' => array(),
10330
- 'fill-rule' => array(),
10331
- 'filter' => array(),
10332
- 'flood-color' => array(),
10333
- 'flood-opacity' => array(),
10334
- 'font-family' => array(),
10335
- 'font-size' => array(),
10336
- 'font-size-adjust' => array(),
10337
- 'font-stretch' => array(),
10338
- 'font-style' => array(),
10339
- 'font-variant' => array(),
10340
- 'font-weight' => array(),
10341
- 'glyph-orientation-horizontal' => array(),
10342
- 'glyph-orientation-vertical' => array(),
10343
- 'image-rendering' => array(),
10344
- 'kerning' => array(),
10345
- 'lengthadjust' => array(),
10346
- 'letter-spacing' => array(),
10347
- 'lighting-color' => array(),
10348
- 'marker-end' => array(),
10349
- 'marker-mid' => array(),
10350
- 'marker-start' => array(),
10351
- 'mask' => array(),
10352
- 'opacity' => array(),
10353
- 'overflow' => array(),
10354
- 'pointer-events' => array(),
10355
- 'requiredextensions' => array(),
10356
- 'requiredfeatures' => array(),
10357
- 'rotate' => array(),
10358
- 'shape-rendering' => array(),
10359
- 'stop-color' => array(),
10360
- 'stop-opacity' => array(),
10361
- 'stroke' => array(),
10362
- 'stroke-dasharray' => array(),
10363
- 'stroke-dashoffset' => array(),
10364
- 'stroke-linecap' => array(),
10365
- 'stroke-linejoin' => array(),
10366
- 'stroke-miterlimit' => array(),
10367
- 'stroke-opacity' => array(),
10368
- 'stroke-width' => array(),
10369
- 'style' => array(
10370
- 'blacklisted_value_regex' => '!important',
10371
- ),
10372
- 'systemlanguage' => array(),
10373
- 'text-anchor' => array(),
10374
- 'text-decoration' => array(),
10375
- 'text-rendering' => array(),
10376
- 'textlength' => array(),
10377
- 'unicode-bidi' => array(),
10378
- 'vector-effect' => array(),
10379
- 'visibility' => array(),
10380
- 'word-spacing' => array(),
10381
- 'writing-mode' => array(),
10382
- 'x' => array(),
10383
- 'xml:lang' => array(),
10384
- 'xml:space' => array(),
10385
- 'xmlns' => array(),
10386
- 'xmlns:xlink' => array(),
10387
- 'y' => array(),
10388
- ),
10389
- 'tag_spec' => array(
10390
- 'mandatory_ancestor' => 'svg',
10391
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10392
- ),
10393
- ),
10394
- ),
10395
- 'tt' => array(
10396
- array(
10397
- 'attr_spec_list' => array(),
10398
- 'tag_spec' => array(),
10399
- ),
10400
- ),
10401
- 'u' => array(
10402
- array(
10403
- 'attr_spec_list' => array(),
10404
- 'tag_spec' => array(),
10405
- ),
10406
- ),
10407
- 'ul' => array(
10408
- array(
10409
- 'attr_spec_list' => array(),
10410
- 'tag_spec' => array(),
10411
- ),
10412
- ),
10413
- 'use' => array(
10414
- array(
10415
- 'attr_spec_list' => array(
10416
- 'alignment-baseline' => array(),
10417
- 'baseline-shift' => array(),
10418
- 'clip' => array(),
10419
- 'clip-path' => array(),
10420
- 'clip-rule' => array(),
10421
- 'color' => array(),
10422
- 'color-interpolation' => array(),
10423
- 'color-interpolation-filters' => array(),
10424
- 'color-profile' => array(),
10425
- 'color-rendering' => array(),
10426
- 'cursor' => array(),
10427
- 'direction' => array(),
10428
- 'display' => array(),
10429
- 'dominant-baseline' => array(),
10430
- 'enable-background' => array(),
10431
- 'externalresourcesrequired' => array(),
10432
- 'fill' => array(),
10433
- 'fill-opacity' => array(),
10434
- 'fill-rule' => array(),
10435
- 'filter' => array(),
10436
- 'flood-color' => array(),
10437
- 'flood-opacity' => array(),
10438
- 'font-family' => array(),
10439
- 'font-size' => array(),
10440
- 'font-size-adjust' => array(),
10441
- 'font-stretch' => array(),
10442
- 'font-style' => array(),
10443
- 'font-variant' => array(),
10444
- 'font-weight' => array(),
10445
- 'glyph-orientation-horizontal' => array(),
10446
- 'glyph-orientation-vertical' => array(),
10447
- 'height' => array(),
10448
- 'image-rendering' => array(),
10449
- 'kerning' => array(),
10450
- 'letter-spacing' => array(),
10451
- 'lighting-color' => array(),
10452
- 'marker-end' => array(),
10453
- 'marker-mid' => array(),
10454
- 'marker-start' => array(),
10455
- 'mask' => array(),
10456
- 'opacity' => array(),
10457
- 'overflow' => array(),
10458
- 'pointer-events' => array(),
10459
- 'requiredextensions' => array(),
10460
- 'requiredfeatures' => array(),
10461
- 'shape-rendering' => array(),
10462
- 'stop-color' => array(),
10463
- 'stop-opacity' => array(),
10464
- 'stroke' => array(),
10465
- 'stroke-dasharray' => array(),
10466
- 'stroke-dashoffset' => array(),
10467
- 'stroke-linecap' => array(),
10468
- 'stroke-linejoin' => array(),
10469
- 'stroke-miterlimit' => array(),
10470
- 'stroke-opacity' => array(),
10471
- 'stroke-width' => array(),
10472
- 'style' => array(
10473
- 'blacklisted_value_regex' => '!important',
10474
- ),
10475
- 'systemlanguage' => array(),
10476
- 'text-anchor' => array(),
10477
- 'text-decoration' => array(),
10478
- 'text-rendering' => array(),
10479
- 'transform' => array(),
10480
- 'unicode-bidi' => array(),
10481
- 'vector-effect' => array(),
10482
- 'visibility' => array(),
10483
- 'width' => array(),
10484
- 'word-spacing' => array(),
10485
- 'writing-mode' => array(),
10486
- 'x' => array(),
10487
- 'xlink:actuate' => array(),
10488
- 'xlink:arcrole' => array(),
10489
- 'xlink:href' => array(
10490
- 'alternative_names' => array(
10491
- 'href',
10492
- ),
10493
- 'value_url' => array(
10494
- 'allow_empty' => false,
10495
- 'allow_relative' => true,
10496
- 'allowed_protocol' => array(
10497
- 'http',
10498
- 'https',
10499
- ),
10500
- ),
10501
- ),
10502
- 'xlink:role' => array(),
10503
- 'xlink:show' => array(),
10504
- 'xlink:title' => array(),
10505
- 'xlink:type' => array(),
10506
- 'xml:lang' => array(),
10507
- 'xml:space' => array(),
10508
- 'xmlns' => array(),
10509
- 'xmlns:xlink' => array(),
10510
- 'y' => array(),
10511
- ),
10512
- 'tag_spec' => array(
10513
- 'mandatory_ancestor' => 'svg',
10514
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10515
- ),
10516
- ),
10517
- ),
10518
- 'var' => array(
10519
- array(
10520
- 'attr_spec_list' => array(),
10521
- 'tag_spec' => array(),
10522
- ),
10523
- ),
10524
- 'video' => array(
10525
- array(
10526
- 'attr_spec_list' => array(
10527
- 'autoplay' => array(),
10528
- 'controls' => array(),
10529
- 'height' => array(),
10530
- 'loop' => array(),
10531
- 'muted' => array(),
10532
- 'playsinline' => array(),
10533
- 'poster' => array(),
10534
- 'preload' => array(),
10535
- 'src' => array(
10536
- 'blacklisted_value_regex' => '__amp_source_origin',
10537
- 'value_url' => array(
10538
- 'allow_relative' => false,
10539
- 'allowed_protocol' => array(
10540
- 'data',
10541
- 'https',
10542
- ),
10543
- ),
10544
- ),
10545
- 'width' => array(),
10546
- ),
10547
- 'tag_spec' => array(
10548
- 'mandatory_ancestor' => 'noscript',
10549
- 'mandatory_ancestor_suggested_alternative' => 'amp-video',
10550
- 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video',
10551
- ),
10552
- ),
10553
- ),
10554
- 'view' => array(
10555
- array(
10556
- 'attr_spec_list' => array(
10557
- 'externalresourcesrequired' => array(),
10558
- 'preserveaspectratio' => array(),
10559
- 'style' => array(
10560
- 'blacklisted_value_regex' => '!important',
10561
- ),
10562
- 'viewbox' => array(),
10563
- 'viewtarget' => array(),
10564
- 'xml:lang' => array(),
10565
- 'xml:space' => array(),
10566
- 'xmlns' => array(),
10567
- 'xmlns:xlink' => array(),
10568
- 'zoomandpan' => array(),
10569
- ),
10570
- 'tag_spec' => array(
10571
- 'mandatory_ancestor' => 'svg',
10572
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10573
- ),
10574
- ),
10575
- ),
10576
- 'vkern' => array(
10577
- array(
10578
- 'attr_spec_list' => array(
10579
- 'g1' => array(),
10580
- 'g2' => array(),
10581
- 'k' => array(),
10582
- 'style' => array(
10583
- 'blacklisted_value_regex' => '!important',
10584
- ),
10585
- 'u1' => array(),
10586
- 'u2' => array(),
10587
- 'xml:lang' => array(),
10588
- 'xml:space' => array(),
10589
- 'xmlns' => array(),
10590
- 'xmlns:xlink' => array(),
10591
- ),
10592
- 'tag_spec' => array(
10593
- 'mandatory_ancestor' => 'svg',
10594
- 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg',
10595
- ),
10596
- ),
10597
- ),
10598
- 'wbr' => array(
10599
- array(
10600
- 'attr_spec_list' => array(),
10601
- 'tag_spec' => array(),
10602
- ),
10603
- ),
10604
- 'xmp' => array(
10605
- array(
10606
- 'attr_spec_list' => array(),
10607
- 'tag_spec' => array(),
10608
- ),
10609
- ),
10610
- );
10611
-
10612
- private static $layout_allowed_attrs = array(
10613
- '[height]' => array(),
10614
- '[width]' => array(),
10615
- 'height' => array(),
10616
- 'heights' => array(),
10617
- 'layout' => array(),
10618
- 'sizes' => array(),
10619
- 'width' => array(),
10620
- );
10621
-
10622
-
10623
- private static $globally_allowed_attrs = array(
10624
- '[aria-activedescendant]' => array(),
10625
- '[aria-atomic]' => array(),
10626
- '[aria-autocomplete]' => array(),
10627
- '[aria-busy]' => array(),
10628
- '[aria-checked]' => array(),
10629
- '[aria-controls]' => array(),
10630
- '[aria-describedby]' => array(),
10631
- '[aria-disabled]' => array(),
10632
- '[aria-dropeffect]' => array(),
10633
- '[aria-expanded]' => array(),
10634
- '[aria-flowto]' => array(),
10635
- '[aria-grabbed]' => array(),
10636
- '[aria-haspopup]' => array(),
10637
- '[aria-hidden]' => array(),
10638
- '[aria-invalid]' => array(),
10639
- '[aria-label]' => array(),
10640
- '[aria-labelledby]' => array(),
10641
- '[aria-level]' => array(),
10642
- '[aria-live]' => array(),
10643
- '[aria-multiline]' => array(),
10644
- '[aria-multiselectable]' => array(),
10645
- '[aria-orientation]' => array(),
10646
- '[aria-owns]' => array(),
10647
- '[aria-posinset]' => array(),
10648
- '[aria-pressed]' => array(),
10649
- '[aria-readonly]' => array(),
10650
- '[aria-relevant]' => array(),
10651
- '[aria-required]' => array(),
10652
- '[aria-selected]' => array(),
10653
- '[aria-setsize]' => array(),
10654
- '[aria-sort]' => array(),
10655
- '[aria-valuemax]' => array(),
10656
- '[aria-valuemin]' => array(),
10657
- '[aria-valuenow]' => array(),
10658
- '[aria-valuetext]' => array(),
10659
- '[class]' => array(),
10660
- '[hidden]' => array(),
10661
- '[text]' => array(),
10662
- 'about' => array(),
10663
- 'accesskey' => array(),
10664
- 'amp-access' => array(),
10665
- 'amp-access-behavior' => array(),
10666
- 'amp-access-hide' => array(),
10667
- 'amp-access-id' => array(),
10668
- 'amp-access-loader' => array(),
10669
- 'amp-access-loading' => array(),
10670
- 'amp-access-off' => array(),
10671
- 'amp-access-on' => array(),
10672
- 'amp-access-show' => array(),
10673
- 'amp-access-style' => array(),
10674
- 'amp-access-template' => array(),
10675
- 'amp-fx' => array(
10676
- 'value_casei' => 'parallax',
10677
- ),
10678
- 'aria-activedescendant' => array(),
10679
- 'aria-atomic' => array(),
10680
- 'aria-autocomplete' => array(),
10681
- 'aria-busy' => array(),
10682
- 'aria-checked' => array(),
10683
- 'aria-controls' => array(),
10684
- 'aria-current' => array(),
10685
- 'aria-describedby' => array(),
10686
- 'aria-disabled' => array(),
10687
- 'aria-dropeffect' => array(),
10688
- 'aria-expanded' => array(),
10689
- 'aria-flowto' => array(),
10690
- 'aria-grabbed' => array(),
10691
- 'aria-haspopup' => array(),
10692
- 'aria-hidden' => array(),
10693
- 'aria-invalid' => array(),
10694
- 'aria-label' => array(),
10695
- 'aria-labelledby' => array(),
10696
- 'aria-level' => array(),
10697
- 'aria-live' => array(),
10698
- 'aria-multiline' => array(),
10699
- 'aria-multiselectable' => array(),
10700
- 'aria-orientation' => array(),
10701
- 'aria-owns' => array(),
10702
- 'aria-posinset' => array(),
10703
- 'aria-pressed' => array(),
10704
- 'aria-readonly' => array(),
10705
- 'aria-relevant' => array(),
10706
- 'aria-required' => array(),
10707
- 'aria-selected' => array(),
10708
- 'aria-setsize' => array(),
10709
- 'aria-sort' => array(),
10710
- 'aria-valuemax' => array(),
10711
- 'aria-valuemin' => array(),
10712
- 'aria-valuenow' => array(),
10713
- 'aria-valuetext' => array(),
10714
- 'class' => array(
10715
- 'blacklisted_value_regex' => '(^|\\W)i-amphtml-',
10716
- ),
10717
- 'content' => array(),
10718
- 'datatype' => array(),
10719
- 'dir' => array(),
10720
- 'draggable' => array(),
10721
- 'fallback' => array(
10722
- 'value' => '',
10723
- ),
10724
- 'hidden' => array(
10725
- 'value' => '',
10726
- ),
10727
- 'i-amp-access-id' => array(),
10728
- 'id' => array(
10729
- 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|AMP|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|i-amphtml-\\S*|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)',
10730
- ),
10731
- 'inlist' => array(),
10732
- 'itemid' => array(),
10733
- 'itemprop' => array(),
10734
- 'itemref' => array(),
10735
- 'itemscope' => array(),
10736
- 'itemtype' => array(),
10737
- 'lang' => array(),
10738
- 'lightbox' => array(),
10739
- 'on' => array(),
10740
- 'overflow' => array(),
10741
- 'placeholder' => array(
10742
- 'value' => '',
10743
- ),
10744
- 'prefix' => array(),
10745
- 'property' => array(),
10746
- 'rel' => array(
10747
- 'blacklisted_value_regex' => '(^|\\s)(canonical|components|dns-prefetch|import|manifest|preconnect|preload|prerender|serviceworker|stylesheet|subresource)(\\s|$)',
10748
- ),
10749
- 'resource' => array(),
10750
- 'rev' => array(),
10751
- 'role' => array(),
10752
- 'subscriptions-action' => array(),
10753
- 'subscriptions-actions' => array(
10754
- 'value' => '',
10755
- ),
10756
- 'subscriptions-dialog' => array(
10757
- 'value' => '',
10758
- ),
10759
- 'subscriptions-display' => array(),
10760
- 'subscriptions-section' => array(
10761
- 'value_regex_casei' => '(actions|content|content-not-granted)',
10762
- ),
10763
- 'subscriptions-service' => array(),
10764
- 'tabindex' => array(),
10765
- 'title' => array(),
10766
- 'translate' => array(),
10767
- 'typeof' => array(),
10768
- 'validation-for' => array(),
10769
- 'visible-when-invalid' => array(
10770
- 'value_regex' => '(badInput|customError|patternMismatch|rangeOverflow|rangeUnderflow|stepMismatch|tooLong|typeMismatch|valueMissing)',
10771
- ),
10772
- 'vocab' => array(),
10773
- );
10774
-
10775
-
10776
- /**
10777
- * Get allowed tags.
10778
- *
10779
- * @since 0.5
10780
- * @return array Allowed tags.
10781
- */
10782
- public static function get_allowed_tags() {
10783
- return self::$allowed_tags;
10784
- }
10785
-
10786
- /**
10787
- * Get allowed tag.
10788
- *
10789
- * Get the rules for a single tag so that the entire data structure needn't be passed around.
10790
- *
10791
- * @since 0.7
10792
- * @param string $node_name Tag name.
10793
- * @return array|null Allowed tag, or null if the tag does not exist.
10794
- */
10795
- public static function get_allowed_tag( $node_name ) {
10796
- if ( isset( self::$allowed_tags[ $node_name ] ) ) {
10797
- return self::$allowed_tags[ $node_name ];
10798
- }
10799
- return null;
10800
- }
10801
-
10802
- /**
10803
- * Get list of globally-allowed attributes.
10804
- *
10805
- * @since 0.5
10806
- * @return array Allowed tag.
10807
- */
10808
- public static function get_allowed_attributes() {
10809
- return self::$globally_allowed_attrs;
10810
- }
10811
-
10812
- /**
10813
- * Get layout attributes.
10814
- *
10815
- * @since 0.5
10816
- * @return array Allowed tag.
10817
- */
10818
- public static function get_layout_attributes() {
10819
- return self::$layout_allowed_attrs;
10820
- }
10821
-
10822
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/vendor-files/class-amp-response-headers.php DELETED
@@ -1,88 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Response_Headers
4
- *
5
- * @since 1.0
6
- * @package AMP
7
- */
8
-
9
- /**
10
- * Class AMP_Response_Headers
11
- */
12
- class AMP_Response_Headers {
13
-
14
- /**
15
- * Headers sent (or attempted to be sent).
16
- *
17
- * @since 1.0
18
- * @see AMP_Theme_Support::send_header()
19
- * @var array[]
20
- */
21
- public static $headers_sent = array();
22
-
23
- /**
24
- * Send an HTTP response header.
25
- *
26
- * This largely exists to facilitate unit testing but it also provides a better interface for sending headers.
27
- *
28
- * @since 0.7.0
29
- *
30
- * @param string $name Header name.
31
- * @param string $value Header value.
32
- * @param array $args {
33
- * Args to header().
34
- *
35
- * @type bool $replace Whether to replace a header previously sent. Default true.
36
- * @type int $status_code Status code to send with the sent header.
37
- * }
38
- * @return bool Whether the header was sent.
39
- */
40
- public static function send_header( $name, $value, $args = array() ) {
41
- $args = array_merge(
42
- array(
43
- 'replace' => true,
44
- 'status_code' => null,
45
- ),
46
- $args
47
- );
48
-
49
- self::$headers_sent[] = array_merge( compact( 'name', 'value' ), $args );
50
- if ( headers_sent() ) {
51
- return false;
52
- }
53
-
54
- header(
55
- sprintf( '%s: %s', $name, $value ),
56
- $args['replace'],
57
- $args['status_code']
58
- );
59
- return true;
60
- }
61
-
62
- /**
63
- * Send Server-Timing header.
64
- *
65
- * @since 1.0
66
- * @todo What is the ordering in Chrome dev tools? What are the colors about?
67
- * @todo Is there a better name standardization?
68
- * @todo Is there a way to indicate nested server timings, so an outer method's own time can be seen separately from the inner method's time?
69
- *
70
- * @param string $name Name.
71
- * @param float $duration Duration. If negative, will be added to microtime( true ). Optional.
72
- * @param string $description Description. Optional.
73
- * @return bool Return value of send_header call.
74
- */
75
- public static function send_server_timing( $name, $duration = null, $description = null ) {
76
- $value = $name;
77
- if ( isset( $description ) ) {
78
- $value .= sprintf( ';desc=%s', wp_json_encode( $description ) );
79
- }
80
- if ( isset( $duration ) ) {
81
- if ( $duration < 0 ) {
82
- $duration = microtime( true ) + $duration;
83
- }
84
- $value .= sprintf( ';dur=%f', $duration * 1000 );
85
- }
86
- return self::send_header( 'Server-Timing', $value, array( 'replace' => false ) );
87
- }
88
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/vendor-files/class-amp-theme-support.php DELETED
@@ -1,1148 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Theme_Support
4
- *
5
- * @package AMP
6
- */
7
-
8
- /**
9
- * Class AMP_Theme_Support
10
- *
11
- * Callbacks for adding AMP-related things when theme support is added.
12
- */
13
- class AMP_Theme_Support {
14
-
15
- /**
16
- * Replaced with the necessary scripts depending on components used in output.
17
- *
18
- * @var string
19
- */
20
- const SCRIPTS_PLACEHOLDER = '<!-- AMP:SCRIPTS_PLACEHOLDER -->';
21
-
22
- /**
23
- * Sanitizer classes.
24
- *
25
- * @var array
26
- */
27
- protected static $sanitizer_classes = array();
28
-
29
- /**
30
- * Embed handlers.
31
- *
32
- * @var AMP_Base_Embed_Handler[]
33
- */
34
- protected static $embed_handlers = array();
35
-
36
- /**
37
- * Template types.
38
- *
39
- * @var array
40
- */
41
- protected static $template_types = array(
42
- 'paged', // Deprecated.
43
- 'index',
44
- '404',
45
- 'archive',
46
- 'author',
47
- 'category',
48
- 'tag',
49
- 'taxonomy',
50
- 'date',
51
- 'home',
52
- 'front_page',
53
- 'page',
54
- 'search',
55
- 'single',
56
- 'embed',
57
- 'singular',
58
- 'attachment',
59
- );
60
-
61
- /**
62
- * AMP-specific query vars that were purged.
63
- *
64
- * @since 0.7
65
- * @see AMP_Theme_Support::purge_amp_query_vars()
66
- * @var string[]
67
- */
68
- public static $purged_amp_query_vars = array();
69
-
70
- /**
71
- * Start time when init was called.
72
- *
73
- * @since 1.0
74
- * @var float
75
- */
76
- public static $init_start_time;
77
-
78
- /**
79
- * Initialize.
80
- *
81
- * @since 0.7
82
- */
83
- public static function init() {
84
- if ( ! start_non_amp_to_amp_conversion( ) ) { //if ( ! current_theme_supports( 'amp' ) ) { /*Changed */
85
- return;
86
- }
87
- self::$init_start_time = microtime( true );
88
-
89
- self::purge_amp_query_vars();
90
- self::handle_xhr_request();
91
-
92
- require_once AMP__DIR__ . '/includes/amp-post-template-actions.php';
93
-
94
- // Validate theme support usage.
95
- $support = get_theme_support( 'amp' );
96
- if ( WP_DEBUG && is_array( $support ) ) {
97
- $args = array_shift( $support );
98
- if ( ! is_array( $args ) ) {
99
- trigger_error( esc_html__( 'Expected AMP theme support arg to be array.', 'amp' ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
100
- } elseif ( count( array_diff( array_keys( $args ), array( 'template_dir', 'available_callback', 'comments_live_list' ) ) ) !== 0 ) {
101
- trigger_error( esc_html__( 'Expected AMP theme support to only have template_dir and/or available_callback.', 'amp' ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
102
- }
103
- }
104
-
105
- add_action( 'widgets_init', array( __CLASS__, 'register_widgets' ) );
106
-
107
- /*
108
- * Note that wp action is use instead of template_redirect because some themes/plugins output
109
- * the response at this action and then short-circuit with exit. So this is why the the preceding
110
- * action to template_redirect--the wp action--is used instead.
111
- */
112
- add_action( 'wp', array( __CLASS__, 'finish_init' ), PHP_INT_MAX );
113
- }
114
-
115
- /**
116
- * Finish initialization once query vars are set.
117
- *
118
- * @since 0.7
119
- */
120
- public static function finish_init() {
121
- /*if ( ! is_amp_endpoint() ) {
122
- // Add amphtml link when paired mode is available.
123
- if ( self::is_paired_available() ) {
124
- amp_add_frontend_actions(); // @todo This function is poor in how it requires a file that then does add_action().
125
- if ( ! has_action( 'wp_head', 'amp_frontend_add_canonical' ) ) {
126
- add_action( 'wp_head', 'amp_frontend_add_canonical' );
127
- }
128
- }
129
- return;
130
- }*/
131
- //echo "called";die;
132
- if ( amp_is_canonical() ) {
133
- self::redirect_canonical_amp();
134
- } else {
135
- self::register_paired_hooks();
136
- }
137
-
138
- self::add_hooks();
139
- self::$sanitizer_classes = amp_get_content_sanitizers();
140
- self::$embed_handlers = self::register_content_embed_handlers();
141
- }
142
-
143
- /**
144
- * Redirect to canonical URL if the AMP URL was loaded, since canonical is now AMP.
145
- *
146
- * @since 0.7
147
- */
148
- public static function redirect_canonical_amp() {
149
- if ( false !== get_query_var( amp_get_slug(), false ) ) { // Because is_amp_endpoint() now returns true if amp_is_canonical().
150
- $url = preg_replace( '#^(https?://.+?)(/.*)$#', '$1', home_url( '/' ) );
151
- if ( isset( $_SERVER['REQUEST_URI'] ) ) {
152
- $url .= wp_unslash( $_SERVER['REQUEST_URI'] );
153
- }
154
-
155
- $url = amp_remove_endpoint( $url );
156
-
157
- wp_safe_redirect( $url, 302 ); // Temporary redirect because canonical may change in future.
158
- exit;
159
- }
160
- }
161
-
162
- /**
163
- * Determines whether paired mode is available.
164
- *
165
- * When 'amp' theme support has not been added or canonical mode is enabled, then this returns false.
166
- * Returns true when there is a template_dir defined in theme support, and if a defined available_callback
167
- * returns true.
168
- *
169
- * @return bool Whether available.
170
- */
171
- public static function is_paired_available() {
172
- $support = array();//get_theme_support( 'amp' );
173
- /*if ( empty( $support ) || amp_is_canonical() ) {
174
- return false;
175
- }*/
176
- if ( is_singular() && ! post_supports_amp( get_queried_object() ) ) {
177
- return false;
178
- }
179
-
180
- $args = array_shift( $support );
181
-
182
- if ( isset( $args['available_callback'] ) && is_callable( $args['available_callback'] ) ) {
183
- return call_user_func( $args['available_callback'] );
184
- }
185
- return true;
186
- }
187
-
188
- /**
189
- * Determine whether the user is in the Customizer preview iframe.
190
- *
191
- * @since 0.7
192
- *
193
- * @return bool Whether in Customizer preview iframe.
194
- */
195
- public static function is_customize_preview_iframe() {
196
- global $wp_customize;
197
- return is_customize_preview() && $wp_customize->get_messenger_channel();
198
- }
199
-
200
- /**
201
- * Register hooks for paired mode.
202
- */
203
- public static function register_paired_hooks() {
204
- foreach ( self::$template_types as $template_type ) {
205
- add_filter( "{$template_type}_template_hierarchy", array( __CLASS__, 'filter_paired_template_hierarchy' ) );
206
- }
207
- add_filter( 'template_include', array( __CLASS__, 'filter_paired_template_include' ), 100 );
208
- }
209
-
210
- /**
211
- * Register hooks.
212
- */
213
- public static function add_hooks() {
214
-
215
- add_filter( 'amp_content_sanitizers', function( $sanitizers ) {
216
- $sanitizers['AMP_Core_Theme_Sanitizer'] = array(
217
- 'template' => get_template(),
218
- 'stylesheet' => get_stylesheet(),
219
- );
220
- return $sanitizers;
221
- } );
222
-
223
- // Remove core actions which are invalid AMP.
224
- remove_action( 'wp_head', 'wp_post_preview_js', 1 );
225
- remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
226
- remove_action( 'wp_print_styles', 'print_emoji_styles' );
227
- remove_action( 'wp_head', 'wp_oembed_add_host_js' );
228
-
229
- // Prevent MediaElement.js scripts/styles from being enqueued.
230
- add_filter( 'wp_video_shortcode_library', function() {
231
- return 'amp';
232
- } );
233
- add_filter( 'wp_audio_shortcode_library', function() {
234
- return 'amp';
235
- } );
236
-
237
- /*
238
- * Add additional markup required by AMP <https://www.ampproject.org/docs/reference/spec#required-markup>.
239
- * Note that the meta[name=viewport] is not added here because a theme may want to define one with additional
240
- * properties than included in the default configuration. If a theme doesn't include one, then the meta viewport
241
- * will be added when output buffering is finished. Note that meta charset _is_ output here because the output
242
- * buffer will need it to parse the document properly, and it must be exactly as is to be valid AMP. Nevertheless,
243
- * in this case too we should defer to the theme as well to output the meta charset because it is possible the
244
- * install is not on utf-8 and we may need to do a encoding conversion.
245
- */
246
- add_action( 'wp_print_styles', array( __CLASS__, 'print_amp_styles' ), 0 ); // Print boilerplate before theme and plugin stylesheets.
247
- add_action( 'wp_head', 'amp_add_generator_metadata', 20 );
248
-
249
- add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
250
- add_action( 'wp_enqueue_scripts', array( __CLASS__, 'dequeue_customize_preview_scripts' ), 1000 );
251
- add_filter( 'customize_partial_render', array( __CLASS__, 'filter_customize_partial_render' ) );
252
-
253
- add_action( 'wp_footer', 'amp_print_analytics' );
254
-
255
- /*
256
- * Disable admin bar because admin-bar.css (28K) and Dashicons (48K) alone
257
- * combine to surpass the 50K limit imposed for the amp-custom style.
258
- */
259
- add_filter( 'show_admin_bar', '__return_false', 100 );
260
-
261
- /*
262
- * Start output buffering at very low priority for sake of plugins and themes that use template_redirect
263
- * instead of template_include.
264
- */
265
- add_action( 'template_redirect', array( __CLASS__, 'start_output_buffering' ), 0 );
266
-
267
- // Commenting hooks.
268
- add_filter( 'wp_list_comments_args', array( __CLASS__, 'set_comments_walker' ), PHP_INT_MAX );
269
- add_filter( 'comment_form_defaults', array( __CLASS__, 'filter_comment_form_defaults' ) );
270
- add_filter( 'comment_reply_link', array( __CLASS__, 'filter_comment_reply_link' ), 10, 4 );
271
- add_filter( 'cancel_comment_reply_link', array( __CLASS__, 'filter_cancel_comment_reply_link' ), 10, 3 );
272
- add_action( 'comment_form', array( __CLASS__, 'amend_comment_form' ), 100 );
273
- remove_action( 'comment_form', 'wp_comment_form_unfiltered_html_nonce' );
274
- add_filter( 'wp_kses_allowed_html', array( __CLASS__, 'whitelist_layout_in_wp_kses_allowed_html' ), 10 );
275
-
276
- if ( AMP_Validation_Utils::should_validate_response() ) {
277
- AMP_Validation_Utils::add_validation_hooks();
278
- }
279
-
280
- // @todo Add character conversion.
281
- }
282
-
283
- /**
284
- * Remove query vars that come in requests such as for amp-live-list.
285
- *
286
- * WordPress should generally not respond differently to requests when these parameters
287
- * are present. In some cases, when a query param such as __amp_source_origin is present
288
- * then it would normally get included into pagination links generated by get_pagenum_link().
289
- * The whitelist sanitizer empties out links that contain this string as it matches the
290
- * blacklisted_value_regex. So by preemptively scrubbing any reference to these query vars
291
- * we can ensure that WordPress won't end up referencing them in any way.
292
- *
293
- * @since 0.7
294
- */
295
- public static function purge_amp_query_vars() {
296
- $query_vars = array(
297
- '__amp_source_origin',
298
- '_wp_amp_action_xhr_converted',
299
- 'amp_latest_update_time',
300
- );
301
-
302
- // Scrub input vars.
303
- foreach ( $query_vars as $query_var ) {
304
- if ( ! isset( $_GET[ $query_var ] ) ) { // phpcs:ignore
305
- continue;
306
- }
307
- self::$purged_amp_query_vars[ $query_var ] = wp_unslash( $_GET[ $query_var ] ); // phpcs:ignore
308
- unset( $_REQUEST[ $query_var ], $_GET[ $query_var ] );
309
- $scrubbed = true;
310
- }
311
-
312
- if ( isset( $scrubbed ) ) {
313
- $build_query = function( $query ) use ( $query_vars ) {
314
- $pattern = '/^(' . join( '|', $query_vars ) . ')(?==|$)/';
315
- $pairs = array();
316
- foreach ( explode( '&', $query ) as $pair ) {
317
- if ( ! preg_match( $pattern, $pair ) ) {
318
- $pairs[] = $pair;
319
- }
320
- }
321
- return join( '&', $pairs );
322
- };
323
-
324
- // Scrub QUERY_STRING.
325
- if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
326
- $_SERVER['QUERY_STRING'] = $build_query( $_SERVER['QUERY_STRING'] );
327
- }
328
-
329
- // Scrub REQUEST_URI.
330
- if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
331
- list( $path, $query ) = explode( '?', $_SERVER['REQUEST_URI'], 2 );
332
-
333
- $pairs = $build_query( $query );
334
- $_SERVER['REQUEST_URI'] = $path;
335
- if ( ! empty( $pairs ) ) {
336
- $_SERVER['REQUEST_URI'] .= "?{$pairs}";
337
- }
338
- }
339
- }
340
- $_SERVER['REQUEST_URI'] = amp_remove_endpoint( $_SERVER['REQUEST_URI'] );
341
- }
342
-
343
- /**
344
- * Hook into a POST form submissions, such as the comment form or some other form submission.
345
- *
346
- * @since 0.7.0
347
- */
348
- public static function handle_xhr_request() {
349
- $is_amp_xhr = (
350
- ! empty( self::$purged_amp_query_vars['_wp_amp_action_xhr_converted'] )
351
- &&
352
- ! empty( self::$purged_amp_query_vars['__amp_source_origin'] )
353
- &&
354
- ( ! empty( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] )
355
- );
356
- if ( ! $is_amp_xhr ) {
357
- return;
358
- }
359
-
360
- // Send AMP response header.
361
- $origin = wp_validate_redirect( wp_sanitize_redirect( esc_url_raw( self::$purged_amp_query_vars['__amp_source_origin'] ) ) );
362
- if ( $origin ) {
363
- AMP_Response_Headers::send_header( 'AMP-Access-Control-Allow-Source-Origin', $origin, array( 'replace' => true ) );
364
- }
365
-
366
- // Intercept POST requests which redirect.
367
- add_filter( 'wp_redirect', array( __CLASS__, 'intercept_post_request_redirect' ), PHP_INT_MAX );
368
-
369
- // Add special handling for redirecting after comment submission.
370
- add_filter( 'comment_post_redirect', array( __CLASS__, 'filter_comment_post_redirect' ), PHP_INT_MAX, 2 );
371
-
372
- // Add die handler for AMP error display, most likely due to problem with comment.
373
- add_filter( 'wp_die_handler', function() {
374
- return array( __CLASS__, 'handle_wp_die' );
375
- } );
376
-
377
- }
378
-
379
- /**
380
- * Strip tags that are not allowed in amp-mustache.
381
- *
382
- * @since 0.7.0
383
- *
384
- * @param string $text Text to sanitize.
385
- * @return string Sanitized text.
386
- */
387
- protected static function wp_kses_amp_mustache( $text ) {
388
- $amp_mustache_allowed_html_tags = array( 'strong', 'b', 'em', 'i', 'u', 's', 'small', 'mark', 'del', 'ins', 'sup', 'sub' );
389
- return wp_kses( $text, array_fill_keys( $amp_mustache_allowed_html_tags, array() ) );
390
- }
391
-
392
- /**
393
- * Handle comment_post_redirect to ensure page reload is done when comments_live_list is not supported, while sending back a success message when it is.
394
- *
395
- * @since 0.7.0
396
- *
397
- * @param string $url Comment permalink to redirect to.
398
- * @param WP_Comment $comment Posted comment.
399
- * @return string URL.
400
- */
401
- public static function filter_comment_post_redirect( $url, $comment ) {
402
- $theme_support = get_theme_support( 'amp' );
403
-
404
- // Cause a page refresh if amp-live-list is not implemented for comments via add_theme_support( 'amp', array( 'comments_live_list' => true ) ).
405
- if ( empty( $theme_support[0]['comments_live_list'] ) ) {
406
- /*
407
- * Add the comment ID to the URL to force AMP to refresh the page.
408
- * This is ideally a temporary workaround to deal with https://github.com/ampproject/amphtml/issues/14170
409
- */
410
- $url = add_query_arg( 'comment', $comment->comment_ID, $url );
411
-
412
- // Pass URL along to wp_redirect().
413
- return $url;
414
- }
415
-
416
- // Create a success message to display to the user.
417
- if ( '1' === (string) $comment->comment_approved ) {
418
- $message = __( 'Your comment has been posted.', 'amp' );
419
- } else {
420
- $message = __( 'Your comment is awaiting moderation.', 'default' ); // Note core string re-use.
421
- }
422
-
423
- /**
424
- * Filters the message when comment submitted success message when
425
- *
426
- * @since 0.7
427
- */
428
- $message = apply_filters( 'amp_comment_posted_message', $message, $comment );
429
-
430
- // Message will be shown in template defined by AMP_Theme_Support::amend_comment_form().
431
- wp_send_json( array(
432
- 'message' => self::wp_kses_amp_mustache( $message ),
433
- ) );
434
- }
435
-
436
- /**
437
- * New error handler for AMP form submission.
438
- *
439
- * @since 0.7.0
440
- * @see wp_die()
441
- *
442
- * @param WP_Error|string $error The error to handle.
443
- * @param string|int $title Optional. Error title. If `$message` is a `WP_Error` object,
444
- * error data with the key 'title' may be used to specify the title.
445
- * If `$title` is an integer, then it is treated as the response
446
- * code. Default empty.
447
- * @param string|array|int $args {
448
- * Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
449
- * as the response code. Default empty array.
450
- *
451
- * @type int $response The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
452
- * }
453
- */
454
- public static function handle_wp_die( $error, $title = '', $args = array() ) {
455
- if ( is_int( $title ) ) {
456
- $status_code = $title;
457
- } elseif ( is_int( $args ) ) {
458
- $status_code = $args;
459
- } elseif ( is_array( $args ) && isset( $args['response'] ) ) {
460
- $status_code = $args['response'];
461
- } else {
462
- $status_code = 500;
463
- }
464
- status_header( $status_code );
465
-
466
- if ( is_wp_error( $error ) ) {
467
- $error = $error->get_error_message();
468
- }
469
-
470
- // Message will be shown in template defined by AMP_Theme_Support::amend_comment_form().
471
- wp_send_json( array(
472
- 'error' => self::wp_kses_amp_mustache( $error ),
473
- ) );
474
- }
475
-
476
- /**
477
- * Intercept the response to a POST request.
478
- *
479
- * @since 0.7.0
480
- * @see wp_redirect()
481
- *
482
- * @param string $location The location to redirect to.
483
- */
484
- public static function intercept_post_request_redirect( $location ) {
485
-
486
- // Make sure relative redirects get made absolute.
487
- $parsed_location = array_merge(
488
- array(
489
- 'scheme' => 'https',
490
- 'host' => wp_parse_url( home_url(), PHP_URL_HOST ),
491
- 'path' => isset( $_SERVER['REQUEST_URI'] ) ? strtok( wp_unslash( $_SERVER['REQUEST_URI'] ), '?' ) : '/',
492
- ),
493
- wp_parse_url( $location )
494
- );
495
-
496
- $absolute_location = '';
497
- if ( 'https' === $parsed_location['scheme'] ) {
498
- $absolute_location .= $parsed_location['scheme'] . ':';
499
- }
500
- $absolute_location .= '//' . $parsed_location['host'];
501
- if ( isset( $parsed_location['port'] ) ) {
502
- $absolute_location .= ':' . $parsed_location['port'];
503
- }
504
- $absolute_location .= $parsed_location['path'];
505
- if ( isset( $parsed_location['query'] ) ) {
506
- $absolute_location .= '?' . $parsed_location['query'];
507
- }
508
- if ( isset( $parsed_location['fragment'] ) ) {
509
- $absolute_location .= '#' . $parsed_location['fragment'];
510
- }
511
-
512
- AMP_Response_Headers::send_header( 'AMP-Redirect-To', $absolute_location );
513
- AMP_Response_Headers::send_header( 'Access-Control-Expose-Headers', 'AMP-Redirect-To' );
514
-
515
- wp_send_json_success();
516
- }
517
-
518
- /**
519
- * Register/override widgets.
520
- *
521
- * @global WP_Widget_Factory
522
- * @return void
523
- */
524
- public static function register_widgets() {
525
- global $wp_widget_factory;
526
- foreach ( $wp_widget_factory->widgets as $registered_widget ) {
527
- $registered_widget_class_name = get_class( $registered_widget );
528
- if ( ! preg_match( '/^WP_Widget_(.+)$/', $registered_widget_class_name, $matches ) ) {
529
- continue;
530
- }
531
- $amp_class_name = 'AMP_Widget_' . $matches[1];
532
- if ( ! class_exists( $amp_class_name ) || is_a( $amp_class_name, $registered_widget_class_name ) ) {
533
- continue;
534
- }
535
-
536
- unregister_widget( $registered_widget_class_name );
537
- register_widget( $amp_class_name );
538
- }
539
- }
540
-
541
- /**
542
- * Register content embed handlers.
543
- *
544
- * This was copied from `AMP_Content::register_embed_handlers()` due to being a private method
545
- * and due to `AMP_Content` not being well suited for use in AMP canonical.
546
- *
547
- * @see AMP_Content::register_embed_handlers()
548
- * @global int $content_width
549
- * @return AMP_Base_Embed_Handler[] Handlers.
550
- */
551
- public static function register_content_embed_handlers() {
552
- global $content_width;
553
-
554
- $embed_handlers = array();
555
- foreach ( amp_get_content_embed_handlers() as $embed_handler_class => $args ) {
556
-
557
- /**
558
- * Embed handler.
559
- *
560
- * @type AMP_Base_Embed_Handler $embed_handler
561
- */
562
- $embed_handler = new $embed_handler_class( array_merge(
563
- array(
564
- 'content_max_width' => ! empty( $content_width ) ? $content_width : AMP_Post_Template::CONTENT_MAX_WIDTH, // Back-compat.
565
- ),
566
- $args
567
- ) );
568
-
569
- if ( ! is_subclass_of( $embed_handler, 'AMP_Base_Embed_Handler' ) ) {
570
- /* translators: %s is embed handler */
571
- _doing_it_wrong( __METHOD__, esc_html( sprintf( __( 'Embed Handler (%s) must extend `AMP_Embed_Handler`', 'amp' ), $embed_handler_class ) ), '0.1' );
572
- continue;
573
- }
574
-
575
- $embed_handler->register_embed();
576
- $embed_handlers[] = $embed_handler;
577
- }
578
-
579
- return $embed_handlers;
580
- }
581
-
582
- /**
583
- * Add the comments template placeholder marker
584
- *
585
- * @param array $args the args for the comments list..
586
- * @return array Args to return.
587
- */
588
- public static function set_comments_walker( $args ) {
589
- $amp_walker = new AMP_Comment_Walker();
590
- $args['walker'] = $amp_walker;
591
- return $args;
592
- }
593
-
594
- /**
595
- * Adds the form submit success and fail templates.
596
- */
597
- public static function amend_comment_form() {
598
- ?>
599
- <?php if ( is_singular() && ! amp_is_canonical() ) : ?>
600
- <input type="hidden" name="redirect_to" value="<?php echo esc_url( amp_get_permalink( get_the_ID() ) ); ?>">
601
- <?php endif; ?>
602
-
603
- <div submit-success>
604
- <template type="amp-mustache">
605
- <p>{{{message}}}</p>
606
- </template>
607
- </div>
608
- <div submit-error>
609
- <template type="amp-mustache">
610
- <p class="amp-comment-submit-error">{{{error}}}</p>
611
- </template>
612
- </div>
613
- <?php
614
- }
615
-
616
- /**
617
- * Prepends template hierarchy with template_dir for AMP paired mode templates.
618
- *
619
- * @see get_query_template()
620
- *
621
- * @param array $templates Template hierarchy.
622
- * @returns array Templates.
623
- */
624
- public static function filter_paired_template_hierarchy( $templates ) {
625
- $support = array();//get_theme_support( 'amp' );
626
- $args = array_shift( $support );
627
- if ( isset( $args['template_dir'] ) ) {
628
- $amp_templates = array();
629
- foreach ( $templates as $template ) {
630
- $amp_templates[] = $args['template_dir'] . '/' . $template;
631
- }
632
- $templates = $amp_templates;
633
- }
634
- return $templates;
635
- }
636
-
637
- /**
638
- * Redirect to the non-canonical URL when the template to include is empty.
639
- *
640
- * This is a failsafe in case an index.php is not located in the AMP template_dir,
641
- * and the available_callback fails to omit a given request from being available in AMP.
642
- *
643
- * @param string $template Template to include.
644
- * @return string Template to include.
645
- */
646
- public static function filter_paired_template_include( $template ) {
647
- if ( empty( $template ) || ! self::is_paired_available() ) {
648
- wp_safe_redirect( self::get_current_canonical_url(), 302 ); // Temporary redirect because support may come later.
649
- exit;
650
- }
651
- return $template;
652
- }
653
-
654
- /**
655
- * Get canonical URL for current request.
656
- *
657
- * @see rel_canonical()
658
- * @global WP $wp
659
- * @global WP_Rewrite $wp_rewrite
660
- * @link https://www.ampproject.org/docs/reference/spec#canon.
661
- * @link https://core.trac.wordpress.org/ticket/18660
662
- *
663
- * @return string Canonical non-AMP URL.
664
- */
665
- public static function get_current_canonical_url() {
666
- global $wp, $wp_rewrite;
667
-
668
- $url = null;
669
- if ( is_singular() ) {
670
- $url = wp_get_canonical_url();
671
- }
672
-
673
- // For non-singular queries, make use of the request URI and public query vars to determine canonical URL.
674
- if ( empty( $url ) ) {
675
- $added_query_vars = $wp->query_vars;
676
- if ( ! $wp_rewrite->permalink_structure || empty( $wp->request ) ) {
677
- $url = home_url( '/' );
678
- } else {
679
- $url = home_url( user_trailingslashit( $wp->request ) );
680
- parse_str( $wp->matched_query, $matched_query_vars );
681
- foreach ( $wp->query_vars as $key => $value ) {
682
-
683
- // Remove query vars that were matched in the rewrite rules for the request.
684
- if ( isset( $matched_query_vars[ $key ] ) ) {
685
- unset( $added_query_vars[ $key ] );
686
- }
687
- }
688
- }
689
- }
690
-
691
- if ( ! empty( $added_query_vars ) ) {
692
- $url = add_query_arg( $added_query_vars, $url );
693
- }
694
-
695
- return amp_remove_endpoint( $url );
696
- }
697
-
698
- /**
699
- * Get the ID for the amp-state.
700
- *
701
- * @since 0.7
702
- *
703
- * @param int $post_id Post ID.
704
- * @return string ID for amp-state.
705
- */
706
- public static function get_comment_form_state_id( $post_id ) {
707
- return sprintf( 'commentform_post_%d', $post_id );
708
- }
709
-
710
- /**
711
- * Filter comment form args to an element with [text] AMP binding wrap the title reply.
712
- *
713
- * @since 0.7
714
- * @see comment_form()
715
- *
716
- * @param array $args Comment form args.
717
- * @return array Filtered comment form args.
718
- */
719
- public static function filter_comment_form_defaults( $args ) {
720
- $state_id = self::get_comment_form_state_id( get_the_ID() );
721
-
722
- $text_binding = sprintf(
723
- '%s.replyToName ? %s : %s',
724
- $state_id,
725
- str_replace(
726
- '%s',
727
- sprintf( '" + %s.replyToName + "', $state_id ),
728
- wp_json_encode( $args['title_reply_to'] )
729
- ),
730
- wp_json_encode( $args['title_reply'] )
731
- );
732
-
733
- $args['title_reply_before'] .= sprintf(
734
- '<span [text]="%s">',
735
- esc_attr( $text_binding )
736
- );
737
- $args['cancel_reply_before'] = '</span>' . $args['cancel_reply_before'];
738
- return $args;
739
- }
740
-
741
- /**
742
- * Modify the comment reply link for AMP.
743
- *
744
- * @since 0.7
745
- * @see get_comment_reply_link()
746
- *
747
- * @param string $link The HTML markup for the comment reply link.
748
- * @param array $args An array of arguments overriding the defaults.
749
- * @param WP_Comment $comment The object of the comment being replied.
750
- * @return string Comment reply link.
751
- */
752
- public static function filter_comment_reply_link( $link, $args, $comment ) {
753
-
754
- // Continue to show default link to wp-login when user is not logged-in.
755
- if ( get_option( 'comment_registration' ) && ! is_user_logged_in() ) {
756
- return $link;
757
- }
758
-
759
- $state_id = self::get_comment_form_state_id( get_the_ID() );
760
- $tap_state = array(
761
- $state_id => array(
762
- 'replyToName' => $comment->comment_author,
763
- 'values' => array(
764
- 'comment_parent' => (string) $comment->comment_ID,
765
- ),
766
- ),
767
- );
768
-
769
- // @todo Figure out how to support add_below. Instead of moving the form, what about letting the form get a fixed position?
770
- $link = sprintf(
771
- '<a rel="nofollow" class="comment-reply-link" href="%s" on="%s" aria-label="%s">%s</a>',
772
- esc_attr( '#' . $args['respond_id'] ),
773
- esc_attr( sprintf( 'tap:AMP.setState( %s )', wp_json_encode( $tap_state ) ) ),
774
- esc_attr( sprintf( $args['reply_to_text'], $comment->comment_author ) ),
775
- $args['reply_text']
776
- );
777
- return $link;
778
- }
779
-
780
- /**
781
- * Filters the cancel comment reply link HTML.
782
- *
783
- * @since 0.7
784
- * @see get_cancel_comment_reply_link()
785
- *
786
- * @param string $formatted_link The HTML-formatted cancel comment reply link.
787
- * @param string $link Cancel comment reply link URL.
788
- * @param string $text Cancel comment reply link text.
789
- * @return string Cancel reply link.
790
- */
791
- public static function filter_cancel_comment_reply_link( $formatted_link, $link, $text ) {
792
- unset( $formatted_link, $link );
793
- if ( empty( $text ) ) {
794
- $text = __( 'Click here to cancel reply.', 'default' );
795
- }
796
-
797
- $state_id = self::get_comment_form_state_id( get_the_ID() );
798
- $tap_state = array(
799
- $state_id => array(
800
- 'replyToName' => '',
801
- 'values' => array(
802
- 'comment_parent' => '0',
803
- ),
804
- ),
805
- );
806
-
807
- $respond_id = 'respond'; // Hard-coded in comment_form() and default value in get_comment_reply_link().
808
- return sprintf(
809
- '<a id="cancel-comment-reply-link" href="%s" %s [hidden]="%s" on="%s">%s</a>',
810
- esc_url( remove_query_arg( 'replytocom' ) . '#' . $respond_id ),
811
- isset( $_GET['replytocom'] ) ? '' : ' hidden', // phpcs:ignore
812
- esc_attr( sprintf( '%s.values.comment_parent == "0"', self::get_comment_form_state_id( get_the_ID() ) ) ),
813
- esc_attr( sprintf( 'tap:AMP.setState( %s )', wp_json_encode( $tap_state ) ) ),
814
- esc_html( $text )
815
- );
816
- }
817
-
818
- /**
819
- * Print AMP boilerplate and custom styles.
820
- */
821
- public static function print_amp_styles() {
822
- echo amp_get_boilerplate_code() . "\n"; // WPCS: XSS OK.
823
- echo "<style amp-custom></style>\n"; // This will by populated by AMP_Style_Sanitizer.
824
- }
825
-
826
- /**
827
- * Ensure markup required by AMP <https://www.ampproject.org/docs/reference/spec#required-markup>.
828
- *
829
- * Ensure meta[charset], meta[name=viewport], and link[rel=canonical]; a the whitelist sanitizer
830
- * may have removed an illegal meta[http-equiv] or meta[name=viewport]. Core only outputs a
831
- * canonical URL by default if a singular post.
832
- *
833
- * @since 0.7
834
- * @todo All of this might be better placed inside of a sanitizer.
835
- *
836
- * @param DOMDocument $dom Doc.
837
- */
838
- public static function ensure_required_markup( DOMDocument $dom ) {
839
- $head = $dom->getElementsByTagName( 'head' )->item( 0 );
840
- if ( ! $head ) {
841
- $head = $dom->createElement( 'head' );
842
- $dom->documentElement->insertBefore( $head, $dom->documentElement->firstChild );
843
- }
844
- $meta_charset = null;
845
- $meta_viewport = null;
846
- foreach ( $head->getElementsByTagName( 'meta' ) as $meta ) {
847
- /**
848
- * Meta.
849
- *
850
- * @var DOMElement $meta
851
- */
852
- if ( $meta->hasAttribute( 'charset' ) && 'utf-8' === strtolower( $meta->getAttribute( 'charset' ) ) ) { // @todo Also look for meta[http-equiv="Content-Type"]?
853
- $meta_charset = $meta;
854
- } elseif ( 'viewport' === $meta->getAttribute( 'name' ) ) {
855
- $meta_viewport = $meta;
856
- }
857
- }
858
- if ( ! $meta_charset ) {
859
- // Warning: This probably means the character encoding needs to be converted.
860
- $meta_charset = AMP_DOM_Utils::create_node( $dom, 'meta', array(
861
- 'charset' => 'utf-8',
862
- ) );
863
- $head->insertBefore( $meta_charset, $head->firstChild );
864
- }
865
- if ( ! $meta_viewport ) {
866
- $meta_viewport = AMP_DOM_Utils::create_node( $dom, 'meta', array(
867
- 'name' => 'viewport',
868
- 'content' => 'width=device-width,minimum-scale=1',
869
- ) );
870
- $head->insertBefore( $meta_viewport, $meta_charset->nextSibling );
871
- }
872
- // Prevent schema.org duplicates.
873
- $has_schema_org_metadata = false;
874
- foreach ( $head->getElementsByTagName( 'script' ) as $script ) {
875
- if ( 'application/ld+json' === $script->getAttribute( 'type' ) && false !== strpos( $script->nodeValue, 'schema.org' ) ) {
876
- $has_schema_org_metadata = true;
877
- break;
878
- }
879
- }
880
- if ( ! $has_schema_org_metadata ) {
881
- $script = $dom->createElement( 'script', wp_json_encode( amp_get_schemaorg_metadata() ) );
882
- $script->setAttribute( 'type', 'application/ld+json' );
883
- $head->appendChild( $script );
884
- }
885
- // Ensure rel=canonical link.
886
- $rel_canonical = null;
887
- foreach ( $head->getElementsByTagName( 'link' ) as $link ) {
888
- if ( 'canonical' === $link->getAttribute( 'rel' ) ) {
889
- $rel_canonical = $link;
890
- break;
891
- }
892
- }
893
- if ( ! $rel_canonical ) {
894
- $rel_canonical = AMP_DOM_Utils::create_node( $dom, 'link', array(
895
- 'rel' => 'canonical',
896
- 'href' => self::get_current_canonical_url(),
897
- ) );
898
- $head->appendChild( $rel_canonical );
899
- }
900
- }
901
-
902
- /**
903
- * Dequeue Customizer assets which are not necessary outside the preview iframe.
904
- *
905
- * Prevent enqueueing customize-preview styles if not in customizer preview iframe.
906
- * These are only needed for when there is live editing of content, such as selective refresh.
907
- *
908
- * @since 0.7
909
- */
910
- public static function dequeue_customize_preview_scripts() {
911
-
912
- // Dequeue styles unnecessary unless in customizer preview iframe when editing (such as for edit shortcuts).
913
- if ( ! self::is_customize_preview_iframe() ) {
914
- wp_dequeue_style( 'customize-preview' );
915
- foreach ( wp_styles()->registered as $handle => $dependency ) {
916
- if ( in_array( 'customize-preview', $dependency->deps, true ) ) {
917
- wp_dequeue_style( $handle );
918
- }
919
- }
920
- }
921
- }
922
-
923
- /**
924
- * Start output buffering.
925
- *
926
- * @since 0.7
927
- * @see AMP_Theme_Support::finish_output_buffering()
928
- */
929
- public static function start_output_buffering() {
930
- /*
931
- * Disable the New Relic Browser agent on AMP responses.
932
- * This prevents the New Relic from causing invalid AMP responses due the NREUM script it injects after the meta charset:
933
- * https://docs.newrelic.com/docs/browser/new-relic-browser/troubleshooting/google-amp-validator-fails-due-3rd-party-script
934
- * Sites with New Relic will need to specially configure New Relic for AMP:
935
- * https://docs.newrelic.com/docs/browser/new-relic-browser/installation/monitor-amp-pages-new-relic-browser
936
- */
937
- if ( function_exists( 'newrelic_disable_autorum' ) ) {
938
- newrelic_disable_autorum();
939
- }
940
-
941
- ob_start();
942
-
943
- // Note that the following must be at 0 because wp_ob_end_flush_all() runs at shutdown:1.
944
- add_action( 'shutdown', array( __CLASS__, 'finish_output_buffering' ), 0 );
945
- }
946
-
947
- /**
948
- * Finish output buffering.
949
- *
950
- * @since 0.7
951
- * @see AMP_Theme_Support::start_output_buffering()
952
- */
953
- public static function finish_output_buffering() {
954
- AMP_Response_Headers::send_server_timing( 'amp_output_buffer', -self::$init_start_time, 'AMP Output Buffer' );
955
- echo self::prepare_response( ob_get_clean() ); // WPCS: xss ok.
956
- }
957
-
958
- /**
959
- * Filter rendered partial to convert to AMP.
960
- *
961
- * @see WP_Customize_Partial::render()
962
- *
963
- * @param string|mixed $partial Rendered partial.
964
- * @return string|mixed Filtered partial.
965
- * @global int $content_width
966
- */
967
- public static function filter_customize_partial_render( $partial ) {
968
- global $content_width;
969
- if ( is_string( $partial ) && preg_match( '/<\w/', $partial ) ) {
970
- $dom = AMP_DOM_Utils::get_dom_from_content( $partial );
971
- $args = array(
972
- 'content_max_width' => ! empty( $content_width ) ? $content_width : AMP_Post_Template::CONTENT_MAX_WIDTH, // Back-compat.
973
- 'use_document_element' => false,
974
- 'allow_dirty_styles' => true,
975
- 'allow_dirty_scripts' => false,
976
- );
977
- AMP_Content_Sanitizer::sanitize_document( $dom, self::$sanitizer_classes, $args ); // @todo Include script assets in response?
978
- $partial = AMP_DOM_Utils::get_content_from_dom( $dom );
979
- }
980
- return $partial;
981
- }
982
-
983
- /**
984
- * Process response to ensure AMP validity.
985
- *
986
- * @since 0.7
987
- *
988
- * @param string $response HTML document response. By default it expects a complete document.
989
- * @param array $args {
990
- * Args to send to the preprocessor/sanitizer.
991
- *
992
- * @type callable $remove_invalid_callback Function to call whenever a node is removed due to being invalid.
993
- * }
994
- * @return string AMP document response.
995
- * @global int $content_width
996
- */
997
- public static function prepare_response( $response, $args = array() ) {
998
- global $content_width;
999
-
1000
- /*
1001
- * Check if the response starts with HTML markup.
1002
- * Without this check, JSON responses will be erroneously corrupted,
1003
- * being wrapped in HTML documents.
1004
- */
1005
- if ( '<' !== substr( ltrim( $response ), 0, 1 ) ) {
1006
- return $response;
1007
- }
1008
-
1009
- // Account for case where ob_flush() was called prematurely.
1010
- if ( false === strpos( $response, '<html' ) ) {
1011
- $error = sprintf(
1012
- '<div style="color:red; background: white; padding: 0.5em; position: fixed; z-index: 100000; bottom: 0; border: dashed 1px red;">%s</div>',
1013
- wp_kses_post( __( '<strong>AMP Plugin Error</strong>: It appears that your WordPress install prematurely flushed the output buffer. You will need to disable AMP theme support until that is fixed.', 'amp' ) )
1014
- );
1015
- return $error . $response;
1016
- }
1017
-
1018
- $is_validation_debug_mode = ! empty( $_REQUEST[ AMP_Validation_Utils::DEBUG_QUERY_VAR ] ); // WPCS: csrf ok.
1019
-
1020
- $args = array_merge(
1021
- array(
1022
- 'content_max_width' => ! empty( $content_width ) ? $content_width : AMP_Post_Template::CONTENT_MAX_WIDTH, // Back-compat.
1023
- 'use_document_element' => true,
1024
- 'allow_dirty_styles' => self::is_customize_preview_iframe(), // Dirty styles only needed when editing (e.g. for edit shortcodes).
1025
- 'allow_dirty_scripts' => is_customize_preview(), // Scripts are always needed to inject changeset UUID.
1026
- 'disable_invalid_removal' => $is_validation_debug_mode,
1027
- ),
1028
- $args
1029
- );
1030
-
1031
- $dom_parse_start = microtime( true );
1032
-
1033
- /*
1034
- * Make sure that <meta charset> is present in output prior to parsing.
1035
- * Note that the meta charset is supposed to appear within the first 1024 bytes.
1036
- * See <https://www.w3.org/International/questions/qa-html-encoding-declarations>.
1037
- */
1038
- if ( ! preg_match( '#<meta[^>]+charset=#i', substr( $response, 0, 1024 ) ) ) {
1039
- $response = preg_replace(
1040
- '/(<head[^>]*>)/i',
1041
- '$1' . sprintf( '<meta charset="%s">', esc_attr( get_bloginfo( 'charset' ) ) ),
1042
- $response,
1043
- 1
1044
- );
1045
- }
1046
- $dom = AMP_DOM_Utils::get_dom( $response );
1047
-
1048
- $xpath = new DOMXPath( $dom );
1049
-
1050
- $head = $dom->getElementsByTagName( 'head' )->item( 0 );
1051
-
1052
- if ( isset( $head ) ) {
1053
- // Make sure scripts from the body get moved to the head.
1054
- foreach ( $xpath->query( '//body//script[ @custom-element or @custom-template ]' ) as $script ) {
1055
- $head->appendChild( $script );
1056
- }
1057
- }
1058
-
1059
- // Ensure the mandatory amp attribute is present on the html element, as otherwise it will be stripped entirely.
1060
- if ( ! $dom->documentElement->hasAttribute( 'amp' ) && ! $dom->documentElement->hasAttribute( '⚡️' ) ) {
1061
- $dom->documentElement->setAttribute( 'amp', '' );
1062
- }
1063
-
1064
- AMP_Response_Headers::send_server_timing( 'amp_dom_parse', -$dom_parse_start, 'AMP DOM Parse' );
1065
-
1066
- $assets = AMP_Content_Sanitizer::sanitize_document( $dom, self::$sanitizer_classes, $args );
1067
-
1068
- $dom_serialize_start = microtime( true );
1069
- self::ensure_required_markup( $dom );
1070
-
1071
- // @todo If 'utf-8' is not the blog charset, then we'll need to do some character encoding conversation or "entityification".
1072
- if ( 'utf-8' !== strtolower( get_bloginfo( 'charset' ) ) ) {
1073
- /* translators: %s is the charset of the current site */
1074
- trigger_error( esc_html( sprintf( __( 'The database has the %s encoding when it needs to be utf-8 to work with AMP.', 'amp' ), get_bloginfo( 'charset' ) ) ), E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
1075
- }
1076
-
1077
- if ( AMP_Validation_Utils::should_validate_response() ) {
1078
- AMP_Validation_Utils::finalize_validation( $dom, array(
1079
- 'remove_source_comments' => ! $is_validation_debug_mode,
1080
- ) );
1081
- }
1082
-
1083
- $response = "<!DOCTYPE html>\n";
1084
- $response .= AMP_DOM_Utils::get_content_from_dom_node( $dom, $dom->documentElement );
1085
-
1086
- $amp_scripts = $assets['scripts'];
1087
- foreach ( self::$embed_handlers as $embed_handler ) {
1088
- $amp_scripts = array_merge(
1089
- $amp_scripts,
1090
- $embed_handler->get_scripts()
1091
- );
1092
- }
1093
-
1094
- // Allow for embed handlers to override the default extension version by defining a different URL.
1095
- foreach ( $amp_scripts as $handle => $value ) {
1096
- if ( is_string( $value ) && wp_script_is( $handle, 'registered' ) ) {
1097
- wp_scripts()->registered[ $handle ]->src = $value;
1098
- }
1099
- }
1100
-
1101
- // Print all scripts, some of which may have already been printed and inject into head.
1102
- ob_start();
1103
- wp_print_scripts( array_keys( $amp_scripts ) );
1104
- $script_tags = ob_get_clean();
1105
- if ( ! empty( $script_tags ) ) {
1106
- $response = preg_replace(
1107
- '#(?=</head>)#',
1108
- $script_tags,
1109
- $response,
1110
- 1
1111
- );
1112
- }
1113
-
1114
- AMP_Response_Headers::send_server_timing( 'amp_dom_serialize', -$dom_serialize_start, 'AMP DOM Serialize' );
1115
-
1116
- return $response;
1117
- }
1118
-
1119
- /**
1120
- * Adds 'data-amp-layout' to the allowed <img> attributes for wp_kses().
1121
- *
1122
- * @since 0.7
1123
- *
1124
- * @param array $context Allowed tags and their allowed attributes.
1125
- * @return array $context Filtered allowed tags and attributes.
1126
- */
1127
- public static function whitelist_layout_in_wp_kses_allowed_html( $context ) {
1128
- if ( ! empty( $context['img']['width'] ) && ! empty( $context['img']['height'] ) ) {
1129
- $context['img']['data-amp-layout'] = true;
1130
- }
1131
-
1132
- return $context;
1133
- }
1134
-
1135
- /**
1136
- * Enqueue AMP assets if this is an AMP endpoint.
1137
- *
1138
- * @since 0.7
1139
- *
1140
- * @return void
1141
- */
1142
- public static function enqueue_assets() {
1143
- wp_enqueue_script( 'amp-runtime' );
1144
-
1145
- // Enqueue default styles expected by sanitizer.
1146
- wp_enqueue_style( 'amp-default', amp_get_asset_url( 'css/amp-default.css' ), array(), AMP__VERSION );
1147
- }
1148
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/vendor-files/sanitizer/class-amp-core-theme-sanitizer.php DELETED
@@ -1,91 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Core_Theme_Sanitizer.
4
- *
5
- * @package AMP
6
- * @since 1.0
7
- */
8
-
9
- /**
10
- * Class AMP_Core_Theme_Sanitizer
11
- *
12
- * Fixes up common issues in core themes and others.
13
- *
14
- * @since 1.0
15
- */
16
- class AMP_Core_Theme_Sanitizer extends AMP_Base_Sanitizer {
17
-
18
- /**
19
- * Config for features needed by themes.
20
- *
21
- * @var array
22
- */
23
- public $theme_features = array(
24
- 'twentyseventeen' => array(
25
- 'force_svg_support' => array(),
26
- 'force_fixed_background_support' => array(),
27
- // @todo Header video probably needs special support in the plugin generally.
28
- // @todo Header image is not styled properly. Needs layout=responsive and other things?
29
- // @todo Dequeue scripts and replace with AMP functionality where possible.
30
- ),
31
- );
32
-
33
- /**
34
- * Fix up core themes to do things in the AMP way.
35
- *
36
- * @since 1.0
37
- */
38
- public function sanitize() {
39
- $theme_features = array();
40
-
41
- // Find theme features for core theme.
42
- $theme_candidates = wp_array_slice_assoc( $this->args, array( 'stylesheet', 'template' ) );
43
- foreach ( $theme_candidates as $theme_candidate ) {
44
- if ( isset( $this->theme_features[ $theme_candidate ] ) ) {
45
- $theme_features = $this->theme_features[ $theme_candidate ];
46
- break;
47
- }
48
- }
49
-
50
- // Allow specific theme features to be requested even if the theme is not in core.
51
- if ( isset( $this->args['theme_features'] ) ) {
52
- $theme_features = array_merge( $this->args['theme_features'], $theme_features );
53
- }
54
-
55
- foreach ( $theme_features as $theme_feature => $feature_args ) {
56
- if ( method_exists( $this, $theme_feature ) ) {
57
- call_user_func( array( $this, $theme_feature ), $feature_args );
58
- }
59
- }
60
- }
61
-
62
- /**
63
- * Force SVG support, replacing no-svg class name with svg class name.
64
- *
65
- * @link https://github.com/WordPress/wordpress-develop/blob/1af1f65a21a1a697fb5f33027497f9e5ae638453/src/wp-content/themes/twentyseventeen/assets/js/global.js#L211-L213
66
- * @link https://caniuse.com/#feat=svg
67
- */
68
- public function force_svg_support() {
69
- $this->dom->documentElement->setAttribute(
70
- 'class',
71
- preg_replace(
72
- '/(^|\s)no-svg(\s|$)/',
73
- ' svg ',
74
- $this->dom->documentElement->getAttribute( 'class' )
75
- )
76
- );
77
- }
78
-
79
- /**
80
- * Force support for fixed background-attachment.
81
- *
82
- * @link https://github.com/WordPress/wordpress-develop/blob/1af1f65a21a1a697fb5f33027497f9e5ae638453/src/wp-content/themes/twentyseventeen/assets/js/global.js#L215-L217
83
- * @link https://caniuse.com/#feat=background-attachment
84
- */
85
- public function force_fixed_background_support() {
86
- $this->dom->documentElement->setAttribute(
87
- 'class',
88
- $this->dom->documentElement->getAttribute( 'class' ) . ' background-fixed'
89
- );
90
- }
91
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/vendor/vendor-files/sanitizer/class-amp-style-sanitizer.php DELETED
@@ -1,1316 +0,0 @@
1
- <?php
2
- /**
3
- * Class AMP_Style_Sanitizer
4
- *
5
- * @package AMP
6
- */
7
-
8
- use \Sabberworm\CSS\RuleSet\DeclarationBlock;
9
- use \Sabberworm\CSS\CSSList\CSSList;
10
- use \Sabberworm\CSS\Property\Selector;
11
- use \Sabberworm\CSS\RuleSet\RuleSet;
12
- use \Sabberworm\CSS\Rule\Rule;
13
- use \Sabberworm\CSS\Property\AtRule;
14
- use \Sabberworm\CSS\CSSList\KeyFrame;
15
- use \Sabberworm\CSS\RuleSet\AtRuleSet;
16
- use \Sabberworm\CSS\Property\Import;
17
- use \Sabberworm\CSS\CSSList\AtRuleBlockList;
18
- use \Sabberworm\CSS\Value\RuleValueList;
19
- use \Sabberworm\CSS\Value\URL;
20
-
21
- /**
22
- * Class AMP_Style_Sanitizer
23
- *
24
- * Collects inline styles and outputs them in the amp-custom stylesheet.
25
- */
26
- class AMP_Style_Sanitizer extends AMP_Base_Sanitizer {
27
-
28
- /**
29
- * Array of flags used to control sanitization.
30
- *
31
- * @var array {
32
- * @type string $remove_unused_rules Enum 'never', 'sometimes' (default), 'always'. If total CSS is greater than max_bytes, whether to strip selectors (and then empty rules) when they are not found to be used in doc. A validation error will be emitted when stripping happens since it is not completely safe in the case of dynamic content.
33
- * @type string[] $dynamic_element_selectors Selectors for elements (or their ancestors) which contain dynamic content; selectors containing these will not be filtered.
34
- * @type bool $use_document_element Whether the root of the document should be used rather than the body.
35
- * @type bool $require_https_src Require HTTPS URLs.
36
- * @type bool $allow_dirty_styles Allow dirty styles. This short-circuits the sanitize logic; it is used primarily in Customizer preview.
37
- * @type callable $validation_error_callback Function to call when a validation error is encountered.
38
- * }
39
- */
40
- protected $args;
41
-
42
- /**
43
- * Default args.
44
- *
45
- * @var array
46
- */
47
- protected $DEFAULT_ARGS = array(
48
- 'remove_unused_rules' => 'sometimes',
49
- 'dynamic_element_selectors' => array(
50
- 'amp-list',
51
- 'amp-live-list',
52
- '[submit-error]',
53
- '[submit-success]',
54
- ),
55
- );
56
-
57
- /**
58
- * Stylesheets.
59
- *
60
- * Values are the CSS stylesheets. Keys are MD5 hashes of the stylesheets,
61
- *
62
- * @since 0.7
63
- * @var string[]
64
- */
65
- private $stylesheets = array();
66
-
67
- /**
68
- * List of stylesheet parts prior to selector/rule removal (tree shaking).
69
- *
70
- * Keys are MD5 hashes of stylesheets.
71
- *
72
- * @since 1.0
73
- * @var array[] {
74
- * @type array $stylesheet Array of stylesheet chunked, with declaration blocks being represented as arrays.
75
- * @type DOMElement|DOMAttr $node Origin for styles.
76
- * @type array $sources Sources for the node.
77
- * @type bool $keyframes Whether an amp-keyframes.
78
- * }
79
- */
80
- private $pending_stylesheets = array();
81
-
82
- /**
83
- * Spec for style[amp-custom] cdata.
84
- *
85
- * @since 1.0
86
- * @var array
87
- */
88
- private $style_custom_cdata_spec;
89
-
90
- /**
91
- * The style[amp-custom] element.
92
- *
93
- * @var DOMElement
94
- */
95
- private $amp_custom_style_element;
96
-
97
- /**
98
- * Spec for style[amp-keyframes] cdata.
99
- *
100
- * @since 1.0
101
- * @var array
102
- */
103
- private $style_keyframes_cdata_spec;
104
-
105
- /**
106
- * Regex for allowed font stylesheet URL.
107
- *
108
- * @var string
109
- */
110
- private $allowed_font_src_regex;
111
-
112
- /**
113
- * Base URL for styles.
114
- *
115
- * Full URL with trailing slash.
116
- *
117
- * @var string
118
- */
119
- private $base_url;
120
-
121
- /**
122
- * URL of the content directory.
123
- *
124
- * @var string
125
- */
126
- private $content_url;
127
-
128
- /**
129
- * Class names used in document.
130
- *
131
- * @since 1.0
132
- * @var array
133
- */
134
- private $used_class_names = array();
135
-
136
- /**
137
- * XPath.
138
- *
139
- * @since 1.0
140
- * @var DOMXPath
141
- */
142
- private $xpath;
143
-
144
- /**
145
- * Amount of time that was spent parsing CSS.
146
- *
147
- * @since 1.0
148
- * @var float
149
- */
150
- private $parse_css_duration = 0.0;
151
-
152
- /**
153
- * AMP_Base_Sanitizer constructor.
154
- *
155
- * @since 0.7
156
- *
157
- * @param DOMDocument $dom Represents the HTML document to sanitize.
158
- * @param array $args Args.
159
- */
160
- public function __construct( DOMDocument $dom, array $args = array() ) {
161
- parent::__construct( $dom, $args );
162
-
163
- foreach ( AMP_Allowed_Tags_Generated::get_allowed_tag( 'style' ) as $spec_rule ) {
164
- if ( ! isset( $spec_rule[ AMP_Rule_Spec::TAG_SPEC ]['spec_name'] ) ) {
165
- continue;
166
- }
167
- if ( 'style[amp-keyframes]' === $spec_rule[ AMP_Rule_Spec::TAG_SPEC ]['spec_name'] ) {
168
- $this->style_keyframes_cdata_spec = $spec_rule[ AMP_Rule_Spec::CDATA ];
169
- } elseif ( 'style amp-custom' === $spec_rule[ AMP_Rule_Spec::TAG_SPEC ]['spec_name'] ) {
170
- $this->style_custom_cdata_spec = $spec_rule[ AMP_Rule_Spec::CDATA ];
171
- }
172
- }
173
-
174
- $spec_name = 'link rel=stylesheet for fonts'; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
175
- foreach ( AMP_Allowed_Tags_Generated::get_allowed_tag( 'link' ) as $spec_rule ) {
176
- if ( isset( $spec_rule[ AMP_Rule_Spec::TAG_SPEC ]['spec_name'] ) && $spec_name === $spec_rule[ AMP_Rule_Spec::TAG_SPEC ]['spec_name'] ) {
177
- $this->allowed_font_src_regex = '@^(' . $spec_rule[ AMP_Rule_Spec::ATTR_SPEC_LIST ]['href']['value_regex'] . ')$@';
178
- break;
179
- }
180
- }
181
-
182
- $guessurl = site_url();
183
- if ( ! $guessurl ) {
184
- $guessurl = wp_guess_url();
185
- }
186
- $this->base_url = $guessurl;
187
- $this->content_url = WP_CONTENT_URL;
188
- $this->xpath = new DOMXPath( $dom );
189
- }
190
-
191
- /**
192
- * Get list of CSS styles in HTML content of DOMDocument ($this->dom).
193
- *
194
- * @since 0.4
195
- * @deprecated As of 1.0, use get_stylesheets().
196
- *
197
- * @return array[] Mapping CSS selectors to array of properties, or mapping of keys starting with 'stylesheet:' with value being the stylesheet.
198
- */
199
- public function get_styles() {
200
- return array();
201
- }
202
-
203
- /**
204
- * Get stylesheets.
205
- *
206
- * @since 0.7
207
- * @returns array Values are the CSS stylesheets. Keys are MD5 hashes of the stylesheets.
208
- */
209
- public function get_stylesheets() {
210
- return $this->stylesheets;
211
- }
212
-
213
- /**
214
- * Get list of all the class names used in the document.
215
- *
216
- * @since 1.0
217
- * @return array Used class names.
218
- */
219
- private function get_used_class_names() {
220
- if ( empty( $this->used_class_names ) ) {
221
- $classes = ' ';
222
- foreach ( $this->xpath->query( '//*/@class' ) as $class_attribute ) {
223
- $classes .= ' ' . $class_attribute->nodeValue;
224
- }
225
- $this->used_class_names = array_unique( array_filter( preg_split( '/\s+/', trim( $classes ) ) ) );
226
- }
227
- return $this->used_class_names;
228
- }
229
-
230
- /**
231
- * Sanitize CSS styles within the HTML contained in this instance's DOMDocument.
232
- *
233
- * @since 0.4
234
- */
235
- public function sanitize() {
236
- $elements = array();
237
-
238
- // Do nothing if inline styles are allowed.
239
- if ( ! empty( $this->args['allow_dirty_styles'] ) ) {
240
- return;
241
- }
242
-
243
- $this->parse_css_duration = 0.0;
244
-
245
- /*
246
- * Note that xpath is used to query the DOM so that the link and style elements will be
247
- * in document order. DOMNode::compareDocumentPosition() is not yet implemented.
248
- */
249
- $xpath = $this->xpath;
250
-
251
- $lower_case = 'translate( %s, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz" )'; // In XPath 2.0 this is lower-case().
252
- $predicates = array(
253
- sprintf( '( self::style and not( @amp-boilerplate ) and ( not( @type ) or %s = "text/css" ) )', sprintf( $lower_case, '@type' ) ),
254
- sprintf( '( self::link and @href and %s = "stylesheet" )', sprintf( $lower_case, '@rel' ) ),
255
- );
256
-
257
- foreach ( $xpath->query( '//*[ ' . implode( ' or ', $predicates ) . ' ]' ) as $element ) {
258
- $elements[] = $element;
259
- }
260
-
261
- /**
262
- * Element.
263
- *
264
- * @var DOMElement $element
265
- */
266
- foreach ( $elements as $element ) {
267
- $node_name = strtolower( $element->nodeName );
268
- if ( 'style' === $node_name ) {
269
- $this->process_style_element( $element );
270
- } elseif ( 'link' === $node_name ) {
271
- $this->process_link_element( $element );
272
- }
273
- }
274
-
275
- $elements = array();
276
- foreach ( $xpath->query( '//*[ @style ]' ) as $element ) {
277
- $elements[] = $element;
278
- }
279
- foreach ( $elements as $element ) {
280
- $this->collect_inline_styles( $element );
281
- }
282
-
283
- $this->finalize_styles();
284
-
285
- $this->did_convert_elements = true;
286
-
287
- if ( $this->parse_css_duration > 0.0 ) {
288
- AMP_Response_Headers::send_server_timing( 'amp_parse_css', $this->parse_css_duration, 'AMP Parse CSS' );
289
- }
290
- }
291
-
292
- /**
293
- * Generate a URL's fully-qualified file path.
294
- *
295
- * @since 0.7
296
- * @see WP_Styles::_css_href()
297
- *
298
- * @param string $url The file URL.
299
- * @param string[] $allowed_extensions Allowed file extensions.
300
- * @return string|WP_Error Style's absolute validated filesystem path, or WP_Error when error.
301
- */
302
- public function get_validated_url_file_path( $url, $allowed_extensions = array() ) {
303
- $needs_base_url = (
304
- ! is_bool( $url )
305
- &&
306
- ! preg_match( '|^(https?:)?//|', $url )
307
- &&
308
- ! ( $this->content_url && 0 === strpos( $url, $this->content_url ) )
309
- );
310
- if ( $needs_base_url ) {
311
- $url = $this->base_url . $url;
312
- }
313
-
314
- // Strip query and fragment from URL.
315
- $url = preg_replace( ':[\?#].*$:', '', $url );
316
-
317
- // Validate file extensions.
318
- if ( ! empty( $allowed_extensions ) ) {
319
- $pattern = sprintf( '/\.(%s)$/i', implode( '|', $allowed_extensions ) );
320
- if ( ! preg_match( $pattern, $url ) ) {
321
- /* translators: %s is the file URL */
322
- return new WP_Error( 'amp_disallowed_file_extension', sprintf( __( 'Skipped file which does not have an allowed file extension (%s).', 'amp' ), $url ) );
323
- }
324
- }
325
-
326
- $includes_url = includes_url( '/' );
327
- $content_url = content_url( '/' );
328
- $admin_url = get_admin_url( null, '/' );
329
- $file_path = null;
330
- if ( 0 === strpos( $url, $content_url ) ) {
331
- $file_path = WP_CONTENT_DIR . substr( $url, strlen( $content_url ) - 1 );
332
- } elseif ( 0 === strpos( $url, $includes_url ) ) {
333
- $file_path = ABSPATH . WPINC . substr( $url, strlen( $includes_url ) - 1 );
334
- } elseif ( 0 === strpos( $url, $admin_url ) ) {
335
- $file_path = ABSPATH . 'wp-admin' . substr( $url, strlen( $admin_url ) - 1 );
336
- }
337
-
338
- if ( ! $file_path || false !== strpos( '../', $file_path ) || 0 !== validate_file( $file_path ) || ! file_exists( $file_path ) ) {
339
- /* translators: %s is file URL */
340
-
341
- //return new WP_Error( 'amp_file_path_not_found', sprintf( __( 'Unable to locate filesystem path for %s.', 'amp' ), $url ) );
342
- }
343
-
344
- return $file_path;
345
- }
346
-
347
- /**
348
- * Process style element.
349
- *
350
- * @param DOMElement $element Style element.
351
- */
352
- private function process_style_element( DOMElement $element ) {
353
-
354
- // @todo Any @keyframes rules could be removed from amp-custom and instead added to amp-keyframes.
355
- $is_keyframes = $element->hasAttribute( 'amp-keyframes' );
356
- $stylesheet = trim( $element->textContent );
357
- $cdata_spec = $is_keyframes ? $this->style_keyframes_cdata_spec : $this->style_custom_cdata_spec;
358
- if ( $stylesheet ) {
359
-
360
- $stylesheet = $this->process_stylesheet( $stylesheet, $element, array(
361
- 'allowed_at_rules' => $cdata_spec['css_spec']['allowed_at_rules'],
362
- 'property_whitelist' => $cdata_spec['css_spec']['allowed_declarations'],
363
- 'validate_keyframes' => $cdata_spec['css_spec']['validate_keyframes'],
364
- ) );
365
-
366
- $pending_stylesheet = array(
367
- 'keyframes' => $is_keyframes,
368
- 'stylesheet' => $stylesheet,
369
- 'node' => $element,
370
- );
371
- if ( ! empty( $this->args['validation_error_callback'] ) ) {
372
- $pending_stylesheet['sources'] = AMP_Validation_Utils::locate_sources( $element ); // Needed because node is removed below.
373
- }
374
- $this->pending_stylesheets[] = $pending_stylesheet;
375
- }
376
-
377
- if ( $element->hasAttribute( 'amp-custom' ) ) {
378
- if ( ! $this->amp_custom_style_element ) {
379
- $this->amp_custom_style_element = $element;
380
- } else {
381
- $element->parentNode->removeChild( $element ); // There can only be one. #highlander.
382
- }
383
- } else {
384
-
385
- // Remove from DOM since we'll be adding it to amp-custom.
386
- $element->parentNode->removeChild( $element );
387
- }
388
- }
389
-
390
- /**
391
- * Process link element.
392
- *
393
- * @param DOMElement $element Link element.
394
- */
395
- private function process_link_element( DOMElement $element ) {
396
- $href = $element->getAttribute( 'href' );
397
-
398
- // Allow font URLs.
399
- if ( $this->allowed_font_src_regex && preg_match( $this->allowed_font_src_regex, $href ) ) {
400
- return;
401
- }
402
-
403
- $css_file_path = $this->get_validated_url_file_path( $href, array( 'css', 'less', 'scss', 'sass' ) );
404
-
405
- if ( is_wp_error( $css_file_path ) ) {
406
- $this->remove_invalid_child( $element, array(
407
- 'message' => $css_file_path->get_error_message(),
408
- ) );
409
- return;
410
- }
411
- $stylesheet = '';
412
- if ( $_SERVER["SERVER_ADDR"] == '127.0.0.1' || $_SERVER["SERVER_ADDR"] == '::1' ) {
413
- $handle = fopen($css_file_path, "r");
414
- $stylesheet .= fread($handle, filesize($css_file_path));
415
- fclose($handle);
416
- }else{
417
- $stylesheet .= file_get_contents( $css_file_path ); // phpcs:ignore — It's a local filesystem path not a remote request.
418
- }
419
- // Load the CSS from the filesystem.
420
- $stylesheet = file_get_contents( $css_file_path ); // phpcs:ignore -- It's a local filesystem path not a remote request.
421
- if ( false === $stylesheet ) {
422
- $this->remove_invalid_child( $element, array(
423
- 'message' => __( 'Unable to load stylesheet from filesystem.', 'amp' ),
424
- ) );
425
- return;
426
- }
427
-
428
- // Honor the link's media attribute.
429
- $media = $element->getAttribute( 'media' );
430
- if ( $media && 'all' !== $media ) {
431
- $stylesheet = sprintf( '@media %s { %s }', $media, $stylesheet );
432
- }
433
-
434
- $stylesheet = $this->process_stylesheet( $stylesheet, $element, array(
435
- 'allowed_at_rules' => $this->style_custom_cdata_spec['css_spec']['allowed_at_rules'],
436
- 'property_whitelist' => $this->style_custom_cdata_spec['css_spec']['allowed_declarations'],
437
- 'stylesheet_url' => $href,
438
- 'stylesheet_path' => $css_file_path,
439
- ) );
440
-
441
- $pending_stylesheet = array(
442
- 'keyframes' => false,
443
- 'stylesheet' => $stylesheet,
444
- 'node' => $element,
445
- );
446
- if ( ! empty( $this->args['validation_error_callback'] ) ) {
447
- $pending_stylesheet['sources'] = AMP_Validation_Utils::locate_sources( $element ); // Needed because node is removed below.
448
- }
449
- $this->pending_stylesheets[] = $pending_stylesheet;
450
-
451
- // Remove now that styles have been processed.
452
- $element->parentNode->removeChild( $element );
453
- }
454
-
455
- /**
456
- * Process stylesheet.
457
- *
458
- * Sanitized invalid CSS properties and rules, removes rules which do not
459
- * apply to the current document, and compresses the CSS to remove whitespace and comments.
460
- *
461
- * @since 1.0
462
- *
463
- * @param string $stylesheet Stylesheet.
464
- * @param DOMElement|DOMAttr $node Element (link/style) or style attribute where the stylesheet came from.
465
- * @param array $options {
466
- * Options.
467
- *
468
- * @type bool $class_selector_tree_shaking Whether to perform tree shaking to delete rules that reference class names not extant in the current document.
469
- * @type string[] $property_whitelist Exclusively-allowed properties.
470
- * @type string[] $property_blacklist Disallowed properties.
471
- * @type bool $convert_width_to_max_width Convert width to max-width.
472
- * @type string $stylesheet_url Original URL for stylesheet when originating via link (or @import?).
473
- * @type string $stylesheet_path Original filesystem path for stylesheet when originating via link (or @import?).
474
- * @type array $allowed_at_rules Allowed @-rules.
475
- * @type bool $validate_keyframes Whether keyframes should be validated.
476
- * }
477
- * @return array Processed stylesheet parts.
478
- */
479
- private function process_stylesheet( $stylesheet, $node, $options = array() ) {
480
- $cache_impacting_options = wp_array_slice_assoc(
481
- $options,
482
- array( 'property_whitelist', 'property_blacklist', 'convert_width_to_max_width', 'stylesheet_url', 'allowed_at_rules' )
483
- );
484
-
485
- $cache_key = md5( $stylesheet . serialize( $cache_impacting_options ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
486
-
487
- $cache_group = 'amp-parsed-stylesheet-v1';
488
- if ( wp_using_ext_object_cache() ) {
489
- $parsed = wp_cache_get( $cache_key, $cache_group );
490
- } else {
491
- $parsed = get_transient( $cache_key . $cache_group );
492
- }
493
- if ( ! $parsed || ! isset( $parsed['stylesheet'] ) || ! is_array( $parsed['stylesheet'] ) ) {
494
- $parsed = $this->parse_stylesheet( $stylesheet, $options );
495
- if ( wp_using_ext_object_cache() ) {
496
- wp_cache_set( $cache_key, $parsed, $cache_group );
497
- } else {
498
- // The expiration is to ensure transient doesn't stick around forever since no LRU flushing like with external object cache.
499
- set_transient( $cache_key . $cache_group, $parsed, MONTH_IN_SECONDS );
500
- }
501
- }
502
-
503
- if ( ! empty( $this->args['validation_error_callback'] ) && ! empty( $parsed['validation_errors'] ) ) {
504
- foreach ( $parsed['validation_errors'] as $validation_error ) {
505
- call_user_func( $this->args['validation_error_callback'], array_merge( $validation_error, compact( 'node' ) ) );
506
- }
507
- }
508
-
509
- return $parsed['stylesheet'];
510
- }
511
-
512
- /**
513
- * Parse stylesheet.
514
- *
515
- * @since 1.0
516
- *
517
- * @param string $stylesheet_string Stylesheet.
518
- * @param array $options Options. See definition in \AMP_Style_Sanitizer::process_stylesheet().
519
- * @return array {
520
- * Parsed stylesheet.
521
- *
522
- * @type array $stylesheet Stylesheet parts, where arrays are tuples for declaration blocks.
523
- * @type array $validation_errors Validation errors.
524
- * }
525
- */
526
- private function parse_stylesheet( $stylesheet_string, $options = array() ) {
527
- $start_time = microtime( true );
528
-
529
- $options = array_merge(
530
- array(
531
- 'allowed_at_rules' => array(),
532
- 'convert_width_to_max_width' => false,
533
- 'property_blacklist' => array(
534
- // See <https://www.ampproject.org/docs/design/responsive/style_pages#disallowed-styles>.
535
- 'behavior',
536
- '-moz-binding',
537
- ),
538
- 'property_whitelist' => array(),
539
- 'validate_keyframes' => false,
540
- 'stylesheet_url' => null,
541
- 'stylesheet_path' => null,
542
- ),
543
- $options
544
- );
545
-
546
- $stylesheet = array();
547
- $validation_errors = array();
548
- try {
549
- $parser_settings = Sabberworm\CSS\Settings::create();
550
- $css_parser = new Sabberworm\CSS\Parser( $stylesheet_string, $parser_settings );
551
- $css_document = $css_parser->parse();
552
-
553
- if ( ! empty( $options['stylesheet_url'] ) ) {
554
- $this->real_path_urls(
555
- array_filter(
556
- $css_document->getAllValues(),
557
- function ( $value ) {
558
- return $value instanceof URL;
559
- }
560
- ),
561
- $options['stylesheet_url']
562
- );
563
- }
564
-
565
- $validation_errors = $this->process_css_list( $css_document, $options );
566
-
567
- $output_format = Sabberworm\CSS\OutputFormat::createCompact();
568
-
569
- $before_declaration_block = '/*AMP_WP_BEFORE_DECLARATION_BLOCK*/';
570
- $between_selectors = '/*AMP_WP_BETWEEN_SELECTORS*/';
571
- $after_declaration_block_selectors = '/*AMP_WP_BEFORE_DECLARATION_SELECTORS*/';
572
- $after_declaration_block = '/*AMP_WP_AFTER_DECLARATION*/';
573
-
574
- $output_format->set( 'BeforeDeclarationBlock', $before_declaration_block );
575
- $output_format->set( 'SpaceBeforeSelectorSeparator', $between_selectors );
576
- $output_format->set( 'AfterDeclarationBlockSelectors', $after_declaration_block_selectors );
577
- $output_format->set( 'AfterDeclarationBlock', $after_declaration_block );
578
-
579
- $stylesheet_string = $css_document->render( $output_format );
580
-
581
- $pattern = '#';
582
- $pattern .= '(' . preg_quote( $before_declaration_block, '#' ) . ')';
583
- $pattern .= '(.+?)';
584
- $pattern .= preg_quote( $after_declaration_block_selectors, '#' );
585
- $pattern .= '(.+?)';
586
- $pattern .= preg_quote( $after_declaration_block, '#' );
587
- $pattern .= '#s';
588
-
589
- $split_stylesheet = preg_split( $pattern, $stylesheet_string, -1, PREG_SPLIT_DELIM_CAPTURE );
590
- $length = count( $split_stylesheet );
591
- for ( $i = 0; $i < $length; $i++ ) {
592
- if ( $before_declaration_block === $split_stylesheet[ $i ] ) {
593
- $selectors = explode( $between_selectors . ',', $split_stylesheet[ ++$i ] );
594
- $declaration = $split_stylesheet[ ++$i ];
595
-
596
- $selectors_parsed = array();
597
- foreach ( $selectors as $selector ) {
598
- $classes = array();
599
-
600
- // Remove :not() to eliminate false negatives, such as with `body:not(.title-tagline-hidden) .site-branding-text`.
601
- $reduced_selector = preg_replace( '/:not\(.+?\)/', '', $selector );
602
-
603
- // Remove attribute selectors to eliminate false negative, such as with `.social-navigation a[href*="example.com"]:before`.
604
- $reduced_selector = preg_replace( '/\[\w.*?\]/', '', $reduced_selector );
605
-
606
- if ( preg_match_all( '/(?<=\.)([a-zA-Z0-9_-]+)/', $reduced_selector, $matches ) ) {
607
- $classes = $matches[0];
608
- }
609
- $selectors_parsed[ $selector ] = $classes;
610
- }
611
-
612
- $stylesheet[] = array(
613
- $selectors_parsed,
614
- $declaration,
615
- );
616
- } else {
617
- $stylesheet[] = $split_stylesheet[ $i ];
618
- }
619
- }
620
- } catch ( Exception $exception ) {
621
- $validation_errors[] = array(
622
- 'code' => 'css_parse_error',
623
- 'message' => $exception->getMessage(),
624
- );
625
- }
626
-
627
- $this->parse_css_duration += ( microtime( true ) - $start_time );
628
-
629
- return compact( 'stylesheet', 'validation_errors' );
630
- }
631
-
632
- /**
633
- * Process CSS list.
634
- *
635
- * @since 1.0
636
- *
637
- * @param CSSList $css_list CSS List.
638
- * @param array $options Options.
639
- * @return array Validation errors.
640
- */
641
- private function process_css_list( CSSList $css_list, $options ) {
642
- $validation_errors = array();
643
-
644
- foreach ( $css_list->getContents() as $css_item ) {
645
- if ( $css_item instanceof DeclarationBlock && empty( $options['validate_keyframes'] ) ) {
646
- $validation_errors = array_merge(
647
- $validation_errors,
648
- $this->process_css_declaration_block( $css_item, $css_list, $options )
649
- );
650
- } elseif ( $css_item instanceof AtRuleBlockList ) {
651
- if ( in_array( $css_item->atRuleName(), $options['allowed_at_rules'], true ) ) {
652
- $validation_errors = array_merge(
653
- $validation_errors,
654
- $this->process_css_list( $css_item, $options )
655
- );
656
- } else {
657
- $validation_errors[] = array(
658
- 'code' => 'illegal_css_at_rule',
659
- /* translators: %s is the CSS at-rule name. */
660
- 'message' => sprintf( __( 'CSS @%s rules are currently disallowed.', 'amp' ), $css_item->atRuleName() ),
661
- );
662
- $css_list->remove( $css_item );
663
- }
664
- } elseif ( $css_item instanceof Import ) {
665
- $validation_errors[] = array(
666
- 'code' => 'illegal_css_import_rule',
667
- 'message' => __( 'CSS @import is currently disallowed.', 'amp' ),
668
- );
669
- $css_list->remove( $css_item );
670
- } elseif ( $css_item instanceof AtRuleSet ) {
671
- if ( in_array( $css_item->atRuleName(), $options['allowed_at_rules'], true ) ) {
672
- $validation_errors = array_merge(
673
- $validation_errors,
674
- $this->process_css_declaration_block( $css_item, $css_list, $options )
675
- );
676
- } else {
677
- $validation_errors[] = array(
678
- 'code' => 'illegal_css_at_rule',
679
- /* translators: %s is the CSS at-rule name. */
680
- 'message' => sprintf( __( 'CSS @%s rules are currently disallowed.', 'amp' ), $css_item->atRuleName() ),
681
- );
682
- $css_list->remove( $css_item );
683
- }
684
- } elseif ( $css_item instanceof KeyFrame ) {
685
- if ( in_array( 'keyframes', $options['allowed_at_rules'], true ) ) {
686
- $validation_errors = array_merge(
687
- $validation_errors,
688
- $this->process_css_keyframes( $css_item, $options )
689
- );
690
- } else {
691
- $validation_errors[] = array(
692
- 'code' => 'illegal_css_at_rule',
693
- /* translators: %s is the CSS at-rule name. */
694
- 'message' => sprintf( __( 'CSS @%s rules are currently disallowed.', 'amp' ), $css_item->atRuleName() ),
695
- );
696
- }
697
- } elseif ( $css_item instanceof AtRule ) {
698
- $validation_errors[] = array(
699
- 'code' => 'illegal_css_at_rule',
700
- /* translators: %s is the CSS at-rule name. */
701
- 'message' => sprintf( __( 'CSS @%s rules are currently disallowed.', 'amp' ), $css_item->atRuleName() ),
702
- );
703
- $css_list->remove( $css_item );
704
- } else {
705
- $validation_errors[] = array(
706
- 'code' => 'unrecognized_css',
707
- 'message' => __( 'Unrecognized CSS removed.', 'amp' ),
708
- );
709
- $css_list->remove( $css_item );
710
- }
711
- }
712
- return $validation_errors;
713
- }
714
-
715
- /**
716
- * Convert URLs in to non-relative real-paths.
717
- *
718
- * @param URL[] $urls URLs.
719
- * @param string $stylesheet_url Stylesheet URL.
720
- */
721
- private function real_path_urls( $urls, $stylesheet_url ) {
722
- $base_url = preg_replace( ':[^/]+(\?.*)?(#.*)?$:', '', $stylesheet_url );
723
- if ( empty( $base_url ) ) {
724
- return;
725
- }
726
- foreach ( $urls as $url ) {
727
- $url_string = $url->getURL()->getString();
728
- if ( 'data:' === substr( $url_string, 0, 5 ) ) {
729
- continue;
730
- }
731
-
732
- $parsed_url = wp_parse_url( $url_string );
733
- if ( ! empty( $parsed_url['host'] ) || empty( $parsed_url['path'] ) || '/' === substr( $parsed_url['path'], 0, 1 ) ) {
734
- continue;
735
- }
736
-
737
- $relative_url = preg_replace( '#^\./#', '', $url->getURL()->getString() );
738
-
739
- $real_url = $base_url . $relative_url;
740
- do {
741
- $real_url = preg_replace( '#[^/]+/../#', '', $real_url, -1, $count );
742
- } while ( 0 !== $count );
743
-
744
- $url->getURL()->setString( $real_url );
745
- }
746
- }
747
-
748
- /**
749
- * Process CSS rule set.
750
- *
751
- * @since 1.0
752
- * @link https://www.ampproject.org/docs/design/responsive/style_pages#disallowed-styles
753
- * @link https://www.ampproject.org/docs/design/responsive/style_pages#restricted-styles
754
- *
755
- * @param RuleSet $ruleset Ruleset.
756
- * @param CSSList $css_list CSS List.
757
- * @param array $options Options.
758
- *
759
- * @return array Validation errors.
760
- */
761
- private function process_css_declaration_block( RuleSet $ruleset, CSSList $css_list, $options ) {
762
- $validation_errors = array();
763
-
764
- // Remove disallowed properties.
765
- if ( ! empty( $options['property_whitelist'] ) ) {
766
- $properties = $ruleset->getRules();
767
- foreach ( $properties as $property ) {
768
- $vendorless_property_name = preg_replace( '/^-\w+-/', '', $property->getRule() );
769
- if ( ! in_array( $vendorless_property_name, $options['property_whitelist'], true ) ) {
770
- $validation_errors[] = array(
771
- 'code' => 'illegal_css_property',
772
- 'property_name' => $property->getRule(),
773
- 'property_value' => $property->getValue(),
774
- );
775
- $ruleset->removeRule( $property->getRule() );
776
- }
777
- }
778
- } else {
779
- foreach ( $options['property_blacklist'] as $illegal_property_name ) {
780
- $properties = $ruleset->getRules( $illegal_property_name );
781
- foreach ( $properties as $property ) {
782
- $validation_errors[] = array(
783
- 'code' => 'illegal_css_property',
784
- 'property_name' => $property->getRule(),
785
- 'property_value' => $property->getValue(),
786
- );
787
- $ruleset->removeRule( $property->getRule() );
788
- }
789
- }
790
- }
791
-
792
- if ( $ruleset instanceof AtRuleSet && 'font-face' === $ruleset->atRuleName() ) {
793
- $this->process_font_face_at_rule( $ruleset, $options );
794
- }
795
-
796
- $validation_errors = array_merge(
797
- $validation_errors,
798
- $this->transform_important_qualifiers( $ruleset, $css_list )
799
- );
800
-
801
- // Convert width to max-width when requested. See <https://github.com/Automattic/amp-wp/issues/494>.
802
- if ( $options['convert_width_to_max_width'] ) {
803
- $properties = $ruleset->getRules( 'width' );
804
- foreach ( $properties as $property ) {
805
- $width_property = new Rule( 'max-width' );
806
- $width_property->setValue( $property->getValue() );
807
- $ruleset->removeRule( $property );
808
- $ruleset->addRule( $width_property, $property );
809
- }
810
- }
811
-
812
- // Remove the ruleset if it is now empty.
813
- if ( 0 === count( $ruleset->getRules() ) ) {
814
- $css_list->remove( $ruleset );
815
- }
816
- // @todo Delete rules with selectors for -amphtml- class and i-amphtml- tags.
817
- return $validation_errors;
818
- }
819
-
820
- /**
821
- * Process @font-face by making src URLs non-relative and converting data: URLs into (assumed) file URLs.
822
- *
823
- * @since 1.0
824
- *
825
- * @param AtRuleSet $ruleset Ruleset for @font-face.
826
- * @param array $options Options.
827
- */
828
- private function process_font_face_at_rule( AtRuleSet $ruleset, $options ) {
829
- $src_properties = $ruleset->getRules( 'src' );
830
- if ( empty( $src_properties ) ) {
831
- return;
832
- }
833
-
834
- foreach ( $src_properties as $src_property ) {
835
- $value = $src_property->getValue();
836
- if ( ! ( $value instanceof RuleValueList ) ) {
837
- continue;
838
- }
839
-
840
- /*
841
- * The CSS Parser parses a src such as:
842
- *
843
- * url(data:application/font-woff;...) format('woff'),
844
- * url('Genericons.ttf') format('truetype'),
845
- * url('Genericons.svg#genericonsregular') format('svg')
846
- *
847
- * As a list of components consisting of:
848
- *
849
- * URL,
850
- * RuleValueList( CSSFunction, URL ),
851
- * RuleValueList( CSSFunction, URL ),
852
- * CSSFunction
853
- *
854
- * Clearly the components here are not logically grouped. So the first step is to fix the order.
855
- */
856
- $sources = array();
857
- foreach ( $value->getListComponents() as $component ) {
858
- if ( $component instanceof RuleValueList ) {
859
- $subcomponents = $component->getListComponents();
860
- $subcomponent = array_shift( $subcomponents );
861
- if ( $subcomponent ) {
862
- if ( empty( $sources ) ) {
863
- $sources[] = array( $subcomponent );
864
- } else {
865
- $sources[ count( $sources ) - 1 ][] = $subcomponent;
866
- }
867
- }
868
- foreach ( $subcomponents as $subcomponent ) {
869
- $sources[] = array( $subcomponent );
870
- }
871
- } else {
872
- if ( empty( $sources ) ) {
873
- $sources[] = array( $component );
874
- } else {
875
- $sources[ count( $sources ) - 1 ][] = $component;
876
- }
877
- }
878
- }
879
-
880
- /**
881
- * Source URL lists.
882
- *
883
- * @var URL[] $source_file_urls
884
- * @var URL[] $source_data_urls
885
- */
886
- $source_file_urls = array();
887
- $source_data_urls = array();
888
- foreach ( $sources as $i => $source ) {
889
- if ( $source[0] instanceof URL ) {
890
- if ( 'data:' === substr( $source[0]->getURL()->getString(), 0, 5 ) ) {
891
- $source_data_urls[ $i ] = $source[0];
892
- } else {
893
- $source_file_urls[ $i ] = $source[0];
894
- }
895
- }
896
- }
897
-
898
- // Convert data: URLs into regular URLs, assuming there will be a file present (e.g. woff fonts in core themes).
899
- if ( empty( $source_file_urls ) ) {
900
- continue;
901
- }
902
- $source_file_url = current( $source_file_urls );
903
- foreach ( $source_data_urls as $i => $data_url ) {
904
- $mime_type = strtok( substr( $data_url->getURL()->getString(), 5 ), ';' );
905
- if ( ! $mime_type ) {
906
- continue;
907
- }
908
- $extension = preg_replace( ':.+/(.+-)?:', '', $mime_type );
909
- $guessed_url = preg_replace(
910
- ':(?<=\.)\w+(\?.*)?(#.*)?$:', // Match the file extension in the URL.
911
- $extension,
912
- $source_file_url->getURL()->getString(),
913
- 1,
914
- $count
915
- );
916
- if ( 1 !== $count ) {
917
- continue;
918
- }
919
-
920
- // Ensure file exists.
921
- $path = $this->get_validated_url_file_path( $guessed_url );
922
- if ( is_wp_error( $path ) ) {
923
- continue;
924
- }
925
-
926
- $data_url->getURL()->setString( $guessed_url );
927
- break;
928
- }
929
- }
930
- }
931
-
932
- /**
933
- * Process CSS keyframes.
934
- *
935
- * @since 1.0
936
- * @link https://www.ampproject.org/docs/design/responsive/style_pages#restricted-styles.
937
- * @link https://github.com/ampproject/amphtml/blob/b685a0780a7f59313666225478b2b79b463bcd0b/validator/validator-main.protoascii#L1002-L1043
938
- * @todo Tree shaking could be extended to keyframes, to omit a keyframe if it is not referenced by any rule.
939
- *
940
- * @param KeyFrame $css_list Ruleset.
941
- * @param array $options Options.
942
- * @return array Validation errors.
943
- */
944
- private function process_css_keyframes( KeyFrame $css_list, $options ) {
945
- $validation_errors = array();
946
- if ( ! empty( $options['property_whitelist'] ) ) {
947
- foreach ( $css_list->getContents() as $rules ) {
948
- if ( ! ( $rules instanceof DeclarationBlock ) ) {
949
- $validation_errors[] = array(
950
- 'code' => 'unrecognized_css',
951
- 'message' => __( 'Unrecognized CSS removed.', 'amp' ),
952
- );
953
- $css_list->remove( $rules );
954
- continue;
955
- }
956
-
957
- $validation_errors = array_merge(
958
- $validation_errors,
959
- $this->transform_important_qualifiers( $rules, $css_list )
960
- );
961
-
962
- $properties = $rules->getRules();
963
- foreach ( $properties as $property ) {
964
- $vendorless_property_name = preg_replace( '/^-\w+-/', '', $property->getRule() );
965
- if ( ! in_array( $vendorless_property_name, $options['property_whitelist'], true ) ) {
966
- $validation_errors[] = array(
967
- 'code' => 'illegal_css_property',
968
- 'property_name' => $property->getRule(),
969
- 'property_value' => $property->getValue(),
970
- );
971
- $rules->removeRule( $property->getRule() );
972
- }
973
- }
974
- }
975
- }
976
- return $validation_errors;
977
- }
978
-
979
- /**
980
- * Replace !important qualifiers with more specific rules.
981
- *
982
- * @since 1.0
983
- * @see https://www.npmjs.com/package/replace-important
984
- * @see https://www.ampproject.org/docs/fundamentals/spec#important
985
- *
986
- * @param RuleSet|DeclarationBlock $ruleset Rule set.
987
- * @param CSSList $css_list CSS List.
988
- * @return array Validation errors.
989
- */
990
- private function transform_important_qualifiers( RuleSet $ruleset, CSSList $css_list ) {
991
- $validation_errors = array();
992
- $allow_transformation = (
993
- $ruleset instanceof DeclarationBlock
994
- &&
995
- ! ( $css_list instanceof KeyFrame )
996
- );
997
-
998
- $properties = $ruleset->getRules();
999
- $importants = array();
1000
- foreach ( $properties as $property ) {
1001
- if ( $property->getIsImportant() ) {
1002
- $property->setIsImportant( false );
1003
-
1004
- // An !important doesn't make sense for rulesets that don't have selectors.
1005
- if ( $allow_transformation ) {
1006
- $importants[] = $property;
1007
- $ruleset->removeRule( $property->getRule() );
1008
- } else {
1009
- $validation_errors[] = array(
1010
- 'code' => 'illegal_css_important',
1011
- 'message' => __( 'Illegal CSS !important qualifier.', 'amp' ),
1012
- );
1013
- }
1014
- }
1015
- }
1016
- if ( ! $allow_transformation || empty( $importants ) ) {
1017
- return $validation_errors;
1018
- }
1019
-
1020
- $important_ruleset = clone $ruleset;
1021
- $important_ruleset->setSelectors( array_map(
1022
- /**
1023
- * Modify selectors to be more specific to roughly match the effect of !important.
1024
- *
1025
- * @link https://github.com/ampproject/ampstart/blob/4c21d69afdd07b4c60cd190937bda09901955829/tools/replace-important/lib/index.js#L88-L109
1026
- *
1027
- * @param Selector $old_selector Original selector.
1028
- * @return Selector The new more-specific selector.
1029
- */
1030
- function( Selector $old_selector ) {
1031
- $specific = ':not(#_)'; // Here "_" is just a short single-char ID.
1032
-
1033
- $selector_mod = str_repeat( $specific, floor( $old_selector->getSpecificity() / 100 ) );
1034
- if ( $old_selector->getSpecificity() % 100 > 0 ) {
1035
- $selector_mod .= $specific;
1036
- }
1037
- if ( $old_selector->getSpecificity() % 10 > 0 ) {
1038
- $selector_mod .= $specific;
1039
- }
1040
-
1041
- $new_selector = $old_selector->getSelector();
1042
-
1043
- // Amend the selector mod to the first element in selector if it is already the root; otherwise add new root ancestor.
1044
- if ( preg_match( '/^\s*(html|:root)\b/i', $new_selector, $matches ) ) {
1045
- $new_selector = substr( $new_selector, 0, strlen( $matches[0] ) ) . $selector_mod . substr( $new_selector, strlen( $matches[0] ) );
1046
- } else {
1047
- $new_selector = sprintf( ':root%s %s', $selector_mod, $new_selector );
1048
- }
1049
- return new Selector( $new_selector );
1050
- },
1051
- $ruleset->getSelectors()
1052
- ) );
1053
- $important_ruleset->setRules( $importants );
1054
- $css_list->append( $important_ruleset ); // @todo It would be preferable if the important ruleset were inserted adjacent to the original rule.
1055
-
1056
- return $validation_errors;
1057
- }
1058
-
1059
- /**
1060
- * Collect and store all CSS style attributes.
1061
- *
1062
- * Collects the CSS styles from within the HTML contained in this instance's DOMDocument.
1063
- *
1064
- * @see Retrieve array of styles using $this->get_styles() after calling this method.
1065
- *
1066
- * @since 0.4
1067
- * @since 0.7 Modified to use element passed by XPath query.
1068
- *
1069
- * @note Uses recursion to traverse down the tree of DOMDocument nodes.
1070
- *
1071
- * @param DOMElement $element Node.
1072
- */
1073
- private function collect_inline_styles( $element ) {
1074
- $style_attribute = $element->getAttributeNode( 'style' );
1075
- if ( ! $style_attribute || ! trim( $style_attribute->nodeValue ) ) {
1076
- return;
1077
- }
1078
-
1079
- $class = 'amp-wp-' . substr( md5( $style_attribute->nodeValue ), 0, 7 );
1080
- $root = ':root' . str_repeat( ':not(#_)', 5 ); // @todo The correctness of using "5" should be validated.
1081
- $rule = sprintf( '%s .%s { %s }', $root, $class, $style_attribute->nodeValue );
1082
-
1083
- $stylesheet = $this->process_stylesheet( $rule, $style_attribute, array(
1084
- 'convert_width_to_max_width' => true,
1085
- 'allowed_at_rules' => array(),
1086
- 'property_whitelist' => $this->style_custom_cdata_spec['css_spec']['allowed_declarations'],
1087
- ) );
1088
-
1089
- if ( empty( $stylesheet ) ) {
1090
- $element->removeAttribute( 'style' );
1091
- return;
1092
- }
1093
-
1094
- $pending_stylesheet = array(
1095
- 'stylesheet' => $stylesheet,
1096
- 'node' => $element,
1097
- 'keyframes' => false,
1098
- );
1099
- if ( ! empty( $this->args['validation_error_callback'] ) ) {
1100
- $pending_stylesheet['sources'] = AMP_Validation_Utils::locate_sources( $element ); // Needed because node is removed below.
1101
- }
1102
-
1103
- $this->pending_stylesheets[] = $pending_stylesheet;
1104
-
1105
- $element->removeAttribute( 'style' );
1106
- if ( $element->hasAttribute( 'class' ) ) {
1107
- $element->setAttribute( 'class', $element->getAttribute( 'class' ) . ' ' . $class );
1108
- } else {
1109
- $element->setAttribute( 'class', $class );
1110
- }
1111
- }
1112
-
1113
- /**
1114
- * Finalize stylesheets for style[amp-custom] and style[amp-keyframes] elements.
1115
- *
1116
- * Concatenate all pending stylesheets, remove unused rules if necessary, and add to style elements in doc.
1117
- * Combine all amp-keyframe styles and add them to the end of the body.
1118
- *
1119
- * @since 1.0
1120
- * @see https://www.ampproject.org/docs/fundamentals/spec#keyframes-stylesheet
1121
- */
1122
- private function finalize_styles() {
1123
-
1124
- $stylesheet_sets = array(
1125
- 'custom' => array(
1126
- 'total_size' => 0,
1127
- 'cdata_spec' => $this->style_custom_cdata_spec,
1128
- 'pending_stylesheets' => array(),
1129
- 'final_stylesheets' => array(),
1130
- 'remove_unused_rules' => $this->args['remove_unused_rules'],
1131
- ),
1132
- 'keyframes' => array(
1133
- 'total_size' => 0,
1134
- 'cdata_spec' => $this->style_keyframes_cdata_spec,
1135
- 'pending_stylesheets' => array(),
1136
- 'final_stylesheets' => array(),
1137
- 'remove_unused_rules' => 'never', // Not relevant.
1138
- ),
1139
- );
1140
-
1141
- // Divide pending stylesheet between custom and keyframes, and calculate size of each.
1142
- while ( ! empty( $this->pending_stylesheets ) ) {
1143
- $pending_stylesheet = array_shift( $this->pending_stylesheets );
1144
-
1145
- $set_name = ! empty( $pending_stylesheet['keyframes'] ) ? 'keyframes' : 'custom';
1146
- $size = 0;
1147
- foreach ( $pending_stylesheet['stylesheet'] as $part ) {
1148
- if ( is_string( $part ) ) {
1149
- $size += strlen( $part );
1150
- } elseif ( is_array( $part ) ) {
1151
- $size += strlen( implode( ',', array_keys( $part[0] ) ) ); // Selectors.
1152
- $size += strlen( $part[1] ); // Declaration block.
1153
- }
1154
- }
1155
- $stylesheet_sets[ $set_name ]['total_size'] += $size;
1156
- $stylesheet_sets[ $set_name ]['pending_stylesheets'][] = $pending_stylesheet;
1157
- }
1158
-
1159
- // Process the pending stylesheets.
1160
- foreach ( array_keys( $stylesheet_sets ) as $set_name ) {
1161
- $stylesheet_sets[ $set_name ] = $this->finalize_stylesheet_set( $stylesheet_sets[ $set_name ] );
1162
- }
1163
-
1164
- $this->stylesheets = $stylesheet_sets['custom']['final_stylesheets'];
1165
-
1166
- // If we're not working with the document element (e.g. for legacy post templates) then there is nothing left to do.
1167
- if ( empty( $this->args['use_document_element'] ) ) {
1168
- return;
1169
- }
1170
-
1171
- // Add style[amp-custom] to document.
1172
- if ( ! empty( $stylesheet_sets['custom']['final_stylesheets'] ) ) {
1173
-
1174
- // Ensure style[amp-custom] is present in the document.
1175
- if ( ! $this->amp_custom_style_element ) {
1176
- $this->amp_custom_style_element = $this->dom->createElement( 'style' );
1177
- $this->amp_custom_style_element->setAttribute( 'amp-custom', '' );
1178
- $head = $this->dom->getElementsByTagName( 'head' )->item( 0 );
1179
- if ( ! $head ) {
1180
- $head = $this->dom->createElement( 'head' );
1181
- $this->dom->documentElement->insertBefore( $head, $this->dom->documentElement->firstChild );
1182
- }
1183
- $head->appendChild( $this->amp_custom_style_element );
1184
- }
1185
-
1186
- $css = implode( '', $stylesheet_sets['custom']['final_stylesheets'] );
1187
-
1188
- /*
1189
- * Let the style[amp-custom] be populated with the concatenated CSS.
1190
- * !important: Updating the contents of this style element by setting textContent is not
1191
- * reliable across PHP/libxml versions, so this is why the children are removed and the
1192
- * text node is then explicitly added containing the CSS.
1193
- */
1194
- while ( $this->amp_custom_style_element->firstChild ) {
1195
- $this->amp_custom_style_element->removeChild( $this->amp_custom_style_element->firstChild );
1196
- }
1197
- $this->amp_custom_style_element->appendChild( $this->dom->createTextNode( $css ) );
1198
- }
1199
-
1200
- // Add style[amp-keyframes] to document.
1201
- if ( ! empty( $stylesheet_sets['keyframes']['final_stylesheets'] ) ) {
1202
- $body = $this->dom->getElementsByTagName( 'body' )->item( 0 );
1203
- if ( ! $body ) {
1204
- if ( ! empty( $this->args['validation_error_callback'] ) ) {
1205
- call_user_func( $this->args['validation_error_callback'], array(
1206
- 'code' => 'missing_body_element',
1207
- 'message' => __( 'amp-keyframes must be last child of body element.', 'amp' ),
1208
- ) );
1209
- }
1210
- } else {
1211
- $style_element = $this->dom->createElement( 'style' );
1212
- $style_element->setAttribute( 'amp-keyframes', '' );
1213
- $style_element->appendChild( $this->dom->createTextNode( implode( '', $stylesheet_sets['keyframes']['final_stylesheets'] ) ) );
1214
- $body->appendChild( $style_element );
1215
- }
1216
- }
1217
- }
1218
-
1219
- /**
1220
- * Finalize a stylesheet set (amp-custom or amp-keyframes).
1221
- *
1222
- * @since 1.0
1223
- *
1224
- * @param array $stylesheet_set Stylesheet set.
1225
- * @return array Finalized stylesheet set.
1226
- */
1227
- private function finalize_stylesheet_set( $stylesheet_set ) {
1228
- $is_too_much_css = $stylesheet_set['total_size'] > $stylesheet_set['cdata_spec']['max_bytes'];
1229
- $should_tree_shake = (
1230
- 'always' === $stylesheet_set['remove_unused_rules'] || (
1231
- $is_too_much_css
1232
- &&
1233
- 'sometimes' === $stylesheet_set['remove_unused_rules']
1234
- )
1235
- );
1236
-
1237
- if ( $is_too_much_css && $should_tree_shake && ! empty( $this->args['validation_error_callback'] ) ) {
1238
- call_user_func( $this->args['validation_error_callback'], array(
1239
- 'code' => 'removed_unused_css_rules',
1240
- 'message' => __( 'Too much CSS is enqueued and so seemingly irrelevant rules have been removed.', 'amp' ),
1241
- ) );
1242
- }
1243
-
1244
- $dynamic_selector_pattern = null;
1245
- if ( $should_tree_shake && ! empty( $this->args['dynamic_element_selectors'] ) ) {
1246
- $dynamic_selector_pattern = '#' . implode( '|', array_map(
1247
- function( $selector ) {
1248
- return preg_quote( $selector, '#' );
1249
- },
1250
- $this->args['dynamic_element_selectors']
1251
- ) ) . '#';
1252
- }
1253
-
1254
- $final_size = 0;
1255
- foreach ( $stylesheet_set['pending_stylesheets'] as $pending_stylesheet ) {
1256
- $stylesheet = '';
1257
- foreach ( $pending_stylesheet['stylesheet'] as $stylesheet_part ) {
1258
- if ( is_string( $stylesheet_part ) ) {
1259
- $stylesheet .= $stylesheet_part;
1260
- } else {
1261
- list( $selectors_parsed, $declaration_block ) = $stylesheet_part;
1262
- if ( $should_tree_shake ) {
1263
- $selectors = array();
1264
- foreach ( $selectors_parsed as $selector => $class_names ) {
1265
- $should_include = (
1266
- ( $dynamic_selector_pattern && preg_match( $dynamic_selector_pattern, $selector ) )
1267
- ||
1268
- // If all class