Version Description
Download this release
Release Info
Developer | philipjohn |
Plugin | Instant Articles for WP |
Version | 3.1.2 |
Comparing to | |
See all releases |
Code changes from version 3.1.1 to 3.1.2
- facebook-instant-articles.php +1 -1
- readme.txt +1 -1
- vendor/composer/installed.json +6 -6
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/Element.php +18 -1
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/GeoTag.php +4 -1
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/InstantArticle.php +1 -1
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/ChildrenGetter.php +5 -1
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/ElementGetter.php +3 -1
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/FragmentGetter.php +49 -0
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/GetterFactory.php +7 -1
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/MultipleElementsGetter.php +44 -0
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/NextSiblingElementGetter.php +75 -0
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php +77 -0
- vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Warnings/InvalidSelector.php +12 -4
- vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CMS/WPTransformerTest.php +21 -1
- vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CMS/wp-ia.xml +47 -0
- vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CMS/wp-rules.json +90 -2
- vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CMS/wp.html +88 -0
- vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/Example/simple-ia.html +1 -1
- vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/TransformerTest.php +93 -19
- vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/instant-article-example-multibyte.html +204 -0
- vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/instant-article-example-nonutf8.html +204 -0
facebook-instant-articles.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
* Description: Add support for Instant Articles for Facebook to your WordPress site.
|
5 |
* Author: Automattic, Dekode, Facebook
|
6 |
* Author URI: https://vip.wordpress.com/plugins/instant-articles/
|
7 |
-
* Version: 3.1.
|
8 |
* Text Domain: instant-articles
|
9 |
* License: GPLv2
|
10 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
4 |
* Description: Add support for Instant Articles for Facebook to your WordPress site.
|
5 |
* Author: Automattic, Dekode, Facebook
|
6 |
* Author URI: https://vip.wordpress.com/plugins/instant-articles/
|
7 |
+
* Version: 3.1.2
|
8 |
* Text Domain: instant-articles
|
9 |
* License: GPLv2
|
10 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: trrine, olethomas, bjornjohansen, dekode, automattic, facebook
|
|
3 |
Tags: instant articles, facebook, mobile
|
4 |
Requires at least: 4.3
|
5 |
Tested up to: 4.6
|
6 |
-
Stable tag: 3.1.
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
3 |
Tags: instant articles, facebook, mobile
|
4 |
Requires at least: 4.3
|
5 |
Tested up to: 4.6
|
6 |
+
Stable tag: 3.1.2
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
vendor/composer/installed.json
CHANGED
@@ -148,17 +148,17 @@
|
|
148 |
},
|
149 |
{
|
150 |
"name": "facebook/facebook-instant-articles-sdk-php",
|
151 |
-
"version": "v1.
|
152 |
-
"version_normalized": "1.
|
153 |
"source": {
|
154 |
"type": "git",
|
155 |
"url": "https://github.com/facebook/facebook-instant-articles-sdk-php.git",
|
156 |
-
"reference": "
|
157 |
},
|
158 |
"dist": {
|
159 |
"type": "zip",
|
160 |
-
"url": "https://api.github.com/repos/facebook/facebook-instant-articles-sdk-php/zipball/
|
161 |
-
"reference": "
|
162 |
"shasum": ""
|
163 |
},
|
164 |
"require": {
|
@@ -172,7 +172,7 @@
|
|
172 |
"phpunit/phpunit": "^4.8",
|
173 |
"squizlabs/php_codesniffer": "^2.6.0"
|
174 |
},
|
175 |
-
"time": "2016-08-13
|
176 |
"type": "library",
|
177 |
"installation-source": "dist",
|
178 |
"autoload": {
|
148 |
},
|
149 |
{
|
150 |
"name": "facebook/facebook-instant-articles-sdk-php",
|
151 |
+
"version": "v1.5.0",
|
152 |
+
"version_normalized": "1.5.0.0",
|
153 |
"source": {
|
154 |
"type": "git",
|
155 |
"url": "https://github.com/facebook/facebook-instant-articles-sdk-php.git",
|
156 |
+
"reference": "e7ba342acea3106a83210196c952fbbed0f0fe30"
|
157 |
},
|
158 |
"dist": {
|
159 |
"type": "zip",
|
160 |
+
"url": "https://api.github.com/repos/facebook/facebook-instant-articles-sdk-php/zipball/e7ba342acea3106a83210196c952fbbed0f0fe30",
|
161 |
+
"reference": "e7ba342acea3106a83210196c952fbbed0f0fe30",
|
162 |
"shasum": ""
|
163 |
},
|
164 |
"require": {
|
172 |
"phpunit/phpunit": "^4.8",
|
173 |
"squizlabs/php_codesniffer": "^2.6.0"
|
174 |
},
|
175 |
+
"time": "2016-08-26 13:55:03",
|
176 |
"type": "library",
|
177 |
"installation-source": "dist",
|
178 |
"autoload": {
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/Element.php
CHANGED
@@ -37,11 +37,28 @@ abstract class Element
|
|
37 |
$document->formatOutput = $formatted;
|
38 |
$element = $this->toDOMElement($document);
|
39 |
$document->appendChild($element);
|
40 |
-
$rendered = $doctype.$document->saveXML($element);
|
41 |
|
42 |
// We can't currently use DOMDocument::saveHTML, because it doesn't produce proper HTML5 markup, so we have to strip CDATA enclosures
|
43 |
// TODO Consider replacing this workaround with a parent class for elements that will be rendered and in this class use the `srcdoc` attribute to output the (escaped) markup
|
44 |
$rendered = preg_replace('/<!\[CDATA\[(.*?)\]\]>/is', '$1', $rendered);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
return $rendered;
|
47 |
}
|
37 |
$document->formatOutput = $formatted;
|
38 |
$element = $this->toDOMElement($document);
|
39 |
$document->appendChild($element);
|
40 |
+
$rendered = $doctype.$document->saveXML($element, LIBXML_NOEMPTYTAG);
|
41 |
|
42 |
// We can't currently use DOMDocument::saveHTML, because it doesn't produce proper HTML5 markup, so we have to strip CDATA enclosures
|
43 |
// TODO Consider replacing this workaround with a parent class for elements that will be rendered and in this class use the `srcdoc` attribute to output the (escaped) markup
|
44 |
$rendered = preg_replace('/<!\[CDATA\[(.*?)\]\]>/is', '$1', $rendered);
|
45 |
+
// Fix void HTML5 elements (these can't be closed like in XML)
|
46 |
+
$rendered = str_replace('></area>', '/>', $rendered);
|
47 |
+
$rendered = str_replace('></base>', '/>', $rendered);
|
48 |
+
$rendered = str_replace('></br>', '/>', $rendered);
|
49 |
+
$rendered = str_replace('></col>', '/>', $rendered);
|
50 |
+
$rendered = str_replace('></command>', '/>', $rendered);
|
51 |
+
$rendered = str_replace('></embed>', '/>', $rendered);
|
52 |
+
$rendered = str_replace('></hr>', '/>', $rendered);
|
53 |
+
$rendered = str_replace('></img>', '/>', $rendered);
|
54 |
+
$rendered = str_replace('></input>', '/>', $rendered);
|
55 |
+
$rendered = str_replace('></keygen>', '/>', $rendered);
|
56 |
+
$rendered = str_replace('></link>', '/>', $rendered);
|
57 |
+
$rendered = str_replace('></meta>', '/>', $rendered);
|
58 |
+
$rendered = str_replace('></param>', '/>', $rendered);
|
59 |
+
$rendered = str_replace('></source>', '/>', $rendered);
|
60 |
+
$rendered = str_replace('></track>', '/>', $rendered);
|
61 |
+
$rendered = str_replace('></wbr>', '/>', $rendered);
|
62 |
|
63 |
return $rendered;
|
64 |
}
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/GeoTag.php
CHANGED
@@ -101,7 +101,10 @@ class GeoTag extends Element
|
|
101 |
|
102 |
// Required script field
|
103 |
if ($this->script) {
|
104 |
-
|
|
|
|
|
|
|
105 |
}
|
106 |
|
107 |
return $element;
|
101 |
|
102 |
// Required script field
|
103 |
if ($this->script) {
|
104 |
+
// script may contain html entities so import it as CDATA
|
105 |
+
$element->appendChild(
|
106 |
+
$element->ownerDocument->importNode(new \DOMCdataSection($this->script), true)
|
107 |
+
);
|
108 |
}
|
109 |
|
110 |
return $element;
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/InstantArticle.php
CHANGED
@@ -34,7 +34,7 @@ use Facebook\InstantArticles\Validators\Type;
|
|
34 |
|
35 |
class InstantArticle extends Element implements Container, InstantArticleInterface
|
36 |
{
|
37 |
-
const CURRENT_VERSION = '1.
|
38 |
|
39 |
/**
|
40 |
* The meta properties that are used on <head>
|
34 |
|
35 |
class InstantArticle extends Element implements Container, InstantArticleInterface
|
36 |
{
|
37 |
+
const CURRENT_VERSION = '1.5.0';
|
38 |
|
39 |
/**
|
40 |
* The meta properties that are used on <head>
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/ChildrenGetter.php
CHANGED
@@ -8,6 +8,9 @@
|
|
8 |
*/
|
9 |
namespace Facebook\InstantArticles\Transformer\Getters;
|
10 |
|
|
|
|
|
|
|
11 |
class ChildrenGetter extends ElementGetter
|
12 |
{
|
13 |
public function get($node)
|
@@ -16,7 +19,8 @@ class ChildrenGetter extends ElementGetter
|
|
16 |
if ($element) {
|
17 |
$fragment = $element->ownerDocument->createDocumentFragment();
|
18 |
foreach ($element->childNodes as $child) {
|
19 |
-
|
|
|
20 |
}
|
21 |
if ($fragment->hasChildNodes()) {
|
22 |
return $fragment;
|
8 |
*/
|
9 |
namespace Facebook\InstantArticles\Transformer\Getters;
|
10 |
|
11 |
+
use Facebook\InstantArticles\Validators\Type;
|
12 |
+
use Facebook\InstantArticles\Transformer\Transformer;
|
13 |
+
|
14 |
class ChildrenGetter extends ElementGetter
|
15 |
{
|
16 |
public function get($node)
|
19 |
if ($element) {
|
20 |
$fragment = $element->ownerDocument->createDocumentFragment();
|
21 |
foreach ($element->childNodes as $child) {
|
22 |
+
Transformer::markAsProcessed($child);
|
23 |
+
$fragment->appendChild(Transformer::cloneNode($child));
|
24 |
}
|
25 |
if ($fragment->hasChildNodes()) {
|
26 |
return $fragment;
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/ElementGetter.php
CHANGED
@@ -9,6 +9,7 @@
|
|
9 |
namespace Facebook\InstantArticles\Transformer\Getters;
|
10 |
|
11 |
use Facebook\InstantArticles\Validators\Type;
|
|
|
12 |
use Symfony\Component\CssSelector\CssSelectorConverter;
|
13 |
|
14 |
class ElementGetter extends AbstractGetter
|
@@ -53,7 +54,8 @@ class ElementGetter extends AbstractGetter
|
|
53 |
{
|
54 |
$elements = self::findAll($node, $this->selector);
|
55 |
if (!empty($elements)) {
|
56 |
-
|
|
|
57 |
}
|
58 |
return null;
|
59 |
}
|
9 |
namespace Facebook\InstantArticles\Transformer\Getters;
|
10 |
|
11 |
use Facebook\InstantArticles\Validators\Type;
|
12 |
+
use Facebook\InstantArticles\Transformer\Transformer;
|
13 |
use Symfony\Component\CssSelector\CssSelectorConverter;
|
14 |
|
15 |
class ElementGetter extends AbstractGetter
|
54 |
{
|
55 |
$elements = self::findAll($node, $this->selector);
|
56 |
if (!empty($elements)) {
|
57 |
+
Transformer::markAsProcessed($elements->item(0));
|
58 |
+
return Transformer::cloneNode($elements->item(0));
|
59 |
}
|
60 |
return null;
|
61 |
}
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/FragmentGetter.php
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright (c) 2016-present, Facebook, Inc.
|
4 |
+
* All rights reserved.
|
5 |
+
*
|
6 |
+
* This source code is licensed under the license found in the
|
7 |
+
* LICENSE file in the root directory of this source tree.
|
8 |
+
*/
|
9 |
+
namespace Facebook\InstantArticles\Transformer\Getters;
|
10 |
+
|
11 |
+
use Facebook\InstantArticles\Validators\Type;
|
12 |
+
use Facebook\InstantArticles\Transformer\Transformer;
|
13 |
+
use Symfony\Component\CssSelector\CssSelectorConverter;
|
14 |
+
|
15 |
+
class FragmentGetter extends AbstractGetter
|
16 |
+
{
|
17 |
+
/**
|
18 |
+
* @var string
|
19 |
+
*/
|
20 |
+
protected $fragment;
|
21 |
+
|
22 |
+
public function createFrom($properties)
|
23 |
+
{
|
24 |
+
return $this->withFragment($properties['fragment']);
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @param string $fragment
|
29 |
+
*
|
30 |
+
* @return $this
|
31 |
+
*/
|
32 |
+
public function withFragment($fragment)
|
33 |
+
{
|
34 |
+
Type::enforce($fragment, Type::STRING);
|
35 |
+
$this->fragment = $fragment;
|
36 |
+
|
37 |
+
return $this;
|
38 |
+
}
|
39 |
+
|
40 |
+
public function get($node)
|
41 |
+
{
|
42 |
+
$fragment = $node->ownerDocument->createDocumentFragment();
|
43 |
+
$is_valid_markup = @$fragment->appendXML($this->fragment);
|
44 |
+
if ($is_valid_markup) {
|
45 |
+
return $fragment;
|
46 |
+
}
|
47 |
+
return null;
|
48 |
+
}
|
49 |
+
}
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/GetterFactory.php
CHANGED
@@ -14,10 +14,13 @@ class GetterFactory
|
|
14 |
const TYPE_INTEGER_GETTER = 'int';
|
15 |
const TYPE_CHILDREN_GETTER = 'children';
|
16 |
const TYPE_ELEMENT_GETTER = 'element';
|
|
|
17 |
const TYPE_NEXTSIBLING_GETTER = 'sibling';
|
|
|
18 |
const TYPE_EXISTS_GETTER = 'exists';
|
19 |
const TYPE_JSON_GETTER = 'json';
|
20 |
const TYPE_XPATH_GETTER = 'xpath';
|
|
|
21 |
|
22 |
/**
|
23 |
* Creates an Getter class.
|
@@ -47,10 +50,13 @@ class GetterFactory
|
|
47 |
self::TYPE_INTEGER_GETTER => IntegerGetter::getClassName(),
|
48 |
self::TYPE_CHILDREN_GETTER => ChildrenGetter::getClassName(),
|
49 |
self::TYPE_ELEMENT_GETTER => ElementGetter::getClassName(),
|
|
|
50 |
self::TYPE_NEXTSIBLING_GETTER => NextSiblingGetter::getClassName(),
|
|
|
51 |
self::TYPE_EXISTS_GETTER => ExistsGetter::getClassName(),
|
52 |
self::TYPE_JSON_GETTER => JSONGetter::getClassName(),
|
53 |
-
self::TYPE_XPATH_GETTER => XpathGetter::getClassName()
|
|
|
54 |
];
|
55 |
|
56 |
$class = $getter_configuration['type'];
|
14 |
const TYPE_INTEGER_GETTER = 'int';
|
15 |
const TYPE_CHILDREN_GETTER = 'children';
|
16 |
const TYPE_ELEMENT_GETTER = 'element';
|
17 |
+
const TYPE_FRAGMENT_GETTER = 'fragment';
|
18 |
const TYPE_NEXTSIBLING_GETTER = 'sibling';
|
19 |
+
const TYPE_NEXTSIBLINGELEMENT_GETTER = 'next-sibling-element-of';
|
20 |
const TYPE_EXISTS_GETTER = 'exists';
|
21 |
const TYPE_JSON_GETTER = 'json';
|
22 |
const TYPE_XPATH_GETTER = 'xpath';
|
23 |
+
const TYPE_MULTIPLEELEMENTS_GETTER = 'multiple';
|
24 |
|
25 |
/**
|
26 |
* Creates an Getter class.
|
50 |
self::TYPE_INTEGER_GETTER => IntegerGetter::getClassName(),
|
51 |
self::TYPE_CHILDREN_GETTER => ChildrenGetter::getClassName(),
|
52 |
self::TYPE_ELEMENT_GETTER => ElementGetter::getClassName(),
|
53 |
+
self::TYPE_FRAGMENT_GETTER => FragmentGetter::getClassName(),
|
54 |
self::TYPE_NEXTSIBLING_GETTER => NextSiblingGetter::getClassName(),
|
55 |
+
self::TYPE_NEXTSIBLINGELEMENT_GETTER => NextSiblingElementGetter::getClassName(),
|
56 |
self::TYPE_EXISTS_GETTER => ExistsGetter::getClassName(),
|
57 |
self::TYPE_JSON_GETTER => JSONGetter::getClassName(),
|
58 |
+
self::TYPE_XPATH_GETTER => XpathGetter::getClassName(),
|
59 |
+
self::TYPE_MULTIPLEELEMENTS_GETTER => MultipleElementsGetter::getClassName()
|
60 |
];
|
61 |
|
62 |
$class = $getter_configuration['type'];
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/MultipleElementsGetter.php
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright (c) 2016-present, Facebook, Inc.
|
4 |
+
* All rights reserved.
|
5 |
+
*
|
6 |
+
* This source code is licensed under the license found in the
|
7 |
+
* LICENSE file in the root directory of this source tree.
|
8 |
+
*/
|
9 |
+
namespace Facebook\InstantArticles\Transformer\Getters;
|
10 |
+
|
11 |
+
use Facebook\InstantArticles\Validators\Type;
|
12 |
+
use Facebook\InstantArticles\Transformer\Transformer;
|
13 |
+
use Symfony\Component\CssSelector\CssSelectorConverter;
|
14 |
+
|
15 |
+
class MultipleElementsGetter extends AbstractGetter
|
16 |
+
{
|
17 |
+
/**
|
18 |
+
* @var Getters
|
19 |
+
*/
|
20 |
+
protected $children = [];
|
21 |
+
|
22 |
+
public function createFrom($properties)
|
23 |
+
{
|
24 |
+
foreach ($properties['children'] as $getter_configuration) {
|
25 |
+
$this->children[] = GetterFactory::create($getter_configuration);
|
26 |
+
}
|
27 |
+
return $this;
|
28 |
+
}
|
29 |
+
|
30 |
+
public function get($node)
|
31 |
+
{
|
32 |
+
$fragment = $node->ownerDocument->createDocumentFragment();
|
33 |
+
foreach ($this->children as $child) {
|
34 |
+
$cloned_node = $child->get($node);
|
35 |
+
if (Type::is($cloned_node, 'DOMNode')) {
|
36 |
+
$fragment->appendChild($cloned_node);
|
37 |
+
}
|
38 |
+
}
|
39 |
+
if ($fragment->hasChildNodes()) {
|
40 |
+
return $fragment;
|
41 |
+
}
|
42 |
+
return null;
|
43 |
+
}
|
44 |
+
}
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Getters/NextSiblingElementGetter.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Copyright (c) 2016-present, Facebook, Inc.
|
4 |
+
* All rights reserved.
|
5 |
+
*
|
6 |
+
* This source code is licensed under the license found in the
|
7 |
+
* LICENSE file in the root directory of this source tree.
|
8 |
+
*/
|
9 |
+
namespace Facebook\InstantArticles\Transformer\Getters;
|
10 |
+
|
11 |
+
use Facebook\InstantArticles\Validators\Type;
|
12 |
+
use Facebook\InstantArticles\Transformer\Transformer;
|
13 |
+
use Facebook\InstantArticles\Transformer\Warnings\InvalidSelector;
|
14 |
+
|
15 |
+
class NextSiblingElementGetter extends ElementGetter
|
16 |
+
{
|
17 |
+
protected $siblingSelector;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @param string $siblingSelector
|
21 |
+
*
|
22 |
+
* @return $this
|
23 |
+
*/
|
24 |
+
public function withSiblingSelector($siblingSelector)
|
25 |
+
{
|
26 |
+
Type::enforce($siblingSelector, Type::STRING);
|
27 |
+
$this->siblingSelector = $siblingSelector;
|
28 |
+
|
29 |
+
return $this;
|
30 |
+
}
|
31 |
+
|
32 |
+
public function createFrom($properties)
|
33 |
+
{
|
34 |
+
if (isset($properties['selector'])) {
|
35 |
+
$this->withSelector($properties['selector']);
|
36 |
+
}
|
37 |
+
if (isset($properties['attribute'])) {
|
38 |
+
$this->withAttribute($properties['attribute']);
|
39 |
+
}
|
40 |
+
if (isset($properties['sibling.selector'])) {
|
41 |
+
$this->withSiblingSelector($properties['sibling.selector']);
|
42 |
+
}
|
43 |
+
|
44 |
+
return $this;
|
45 |
+
}
|
46 |
+
|
47 |
+
public function get($node)
|
48 |
+
{
|
49 |
+
Type::enforce($node, 'DOMNode');
|
50 |
+
$elements = self::findAll($node, $this->selector);
|
51 |
+
if (!empty($elements) && $elements->item(0)) {
|
52 |
+
$element = $elements->item(0);
|
53 |
+
do {
|
54 |
+
$element = $element->nextSibling;
|
55 |
+
} while ($element !== null && !Type::is($element, 'DOMElement'));
|
56 |
+
|
57 |
+
if ($element && Type::is($element, 'DOMElement')) {
|
58 |
+
if ($this->siblingSelector) {
|
59 |
+
$siblings = self::findAll($element, $this->siblingSelector);
|
60 |
+
if (!empty($siblings) && $siblings->item(0)) {
|
61 |
+
$siblingElement = $siblings->item(0);
|
62 |
+
} else {
|
63 |
+
// Returns null because sibling content doesn't match
|
64 |
+
return null;
|
65 |
+
}
|
66 |
+
} else {
|
67 |
+
$siblingElement = $element;
|
68 |
+
}
|
69 |
+
Transformer::markAsProcessed($siblingElement);
|
70 |
+
return Transformer::cloneNode($siblingElement);
|
71 |
+
}
|
72 |
+
}
|
73 |
+
return null;
|
74 |
+
}
|
75 |
+
}
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php
CHANGED
@@ -46,6 +46,50 @@ class Transformer
|
|
46 |
*/
|
47 |
private $instantArticle;
|
48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
/**
|
50 |
* Gets all types a given class is, including itself, parent classes and interfaces.
|
51 |
*
|
@@ -120,6 +164,36 @@ class Transformer
|
|
120 |
return $this->instantArticle;
|
121 |
}
|
122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
/**
|
124 |
* @param InstantArticle $context
|
125 |
* @param \DOMNode $node
|
@@ -147,6 +221,9 @@ class Transformer
|
|
147 |
$current_context = $context;
|
148 |
if ($node->hasChildNodes()) {
|
149 |
foreach ($node->childNodes as $child) {
|
|
|
|
|
|
|
150 |
$matched = false;
|
151 |
$log->debug("===========================");
|
152 |
$log->debug($child->ownerDocument->saveHtml($child));
|
46 |
*/
|
47 |
private $instantArticle;
|
48 |
|
49 |
+
/**
|
50 |
+
* Flag attribute added to elements processed by a getter, so they
|
51 |
+
* are not processed again by other rules.
|
52 |
+
*/
|
53 |
+
const INSTANT_ARTICLES_PARSED_FLAG = 'data-instant-articles-element-processed';
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Clones a node for appending to raw-html containing Elements like Interactive.
|
57 |
+
*
|
58 |
+
* @param DOMNode $node The node to clone
|
59 |
+
* @return DOMNode The cloned node.
|
60 |
+
*/
|
61 |
+
public static function cloneNode($node)
|
62 |
+
{
|
63 |
+
$clone = $node->cloneNode(true);
|
64 |
+
if (Type::is($clone, 'DOMElement') && $clone->hasAttribute(self::INSTANT_ARTICLES_PARSED_FLAG)) {
|
65 |
+
$clone->removeAttribute(self::INSTANT_ARTICLES_PARSED_FLAG);
|
66 |
+
}
|
67 |
+
return $clone;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Marks a node as processed.
|
72 |
+
*
|
73 |
+
* @param DOMElement $node The node to clone
|
74 |
+
*/
|
75 |
+
public static function markAsProcessed($node)
|
76 |
+
{
|
77 |
+
if (Type::is($node, 'DOMElement')) {
|
78 |
+
$node->setAttribute(self::INSTANT_ARTICLES_PARSED_FLAG, true);
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Returns whether a node is processed
|
84 |
+
*
|
85 |
+
* @param DOMNode $node The node to clone
|
86 |
+
*/
|
87 |
+
protected static function isProcessed($node)
|
88 |
+
{
|
89 |
+
return Type::is($node, 'DOMElement') && $node->getAttribute(self::INSTANT_ARTICLES_PARSED_FLAG);
|
90 |
+
}
|
91 |
+
|
92 |
+
|
93 |
/**
|
94 |
* Gets all types a given class is, including itself, parent classes and interfaces.
|
95 |
*
|
164 |
return $this->instantArticle;
|
165 |
}
|
166 |
|
167 |
+
/**
|
168 |
+
* @param InstantArticle $context
|
169 |
+
* @param string $content
|
170 |
+
*
|
171 |
+
* @return mixed
|
172 |
+
*/
|
173 |
+
public function transformString($context, $content, $encoding = "utf-8")
|
174 |
+
{
|
175 |
+
$libxml_previous_state = libxml_use_internal_errors(true);
|
176 |
+
$document = new \DOMDocument('1.0');
|
177 |
+
if (function_exists('mb_convert_encoding')) {
|
178 |
+
$document->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', $encoding));
|
179 |
+
} else {
|
180 |
+
$log = \Logger::getLogger('facebook-instantarticles-transformer');
|
181 |
+
$log->debug(
|
182 |
+
'Your content encoding is "' . $encoding . '" ' .
|
183 |
+
'but your PHP environment does not have mbstring. Trying to load your content with using meta tags.'
|
184 |
+
);
|
185 |
+
// wrap the content with charset meta tags
|
186 |
+
$document->loadHTML(
|
187 |
+
'<html><head>' .
|
188 |
+
'<meta http-equiv="Content-Type" content="text/html; charset=' . $encoding . '">' .
|
189 |
+
'</head><body>' . $content . '</body></html>'
|
190 |
+
);
|
191 |
+
}
|
192 |
+
libxml_clear_errors();
|
193 |
+
libxml_use_internal_errors($libxml_previous_state);
|
194 |
+
return $this->transform($context, $document);
|
195 |
+
}
|
196 |
+
|
197 |
/**
|
198 |
* @param InstantArticle $context
|
199 |
* @param \DOMNode $node
|
221 |
$current_context = $context;
|
222 |
if ($node->hasChildNodes()) {
|
223 |
foreach ($node->childNodes as $child) {
|
224 |
+
if (self::isProcessed($child)) {
|
225 |
+
continue;
|
226 |
+
}
|
227 |
$matched = false;
|
228 |
$log->debug("===========================");
|
229 |
$log->debug($child->ownerDocument->saveHtml($child));
|
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Warnings/InvalidSelector.php
CHANGED
@@ -55,11 +55,19 @@ class InvalidSelector
|
|
55 |
*/
|
56 |
public function __toString()
|
57 |
{
|
58 |
-
|
59 |
-
|
|
|
|
|
|
|
|
|
60 |
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
63 |
|
64 |
$has_properties = false;
|
65 |
$str_properties = '';
|
55 |
*/
|
56 |
public function __toString()
|
57 |
{
|
58 |
+
if (isset($this->context)) {
|
59 |
+
$reflection = new \ReflectionClass(get_class($this->context));
|
60 |
+
$class_name = $reflection->getShortName();
|
61 |
+
} else {
|
62 |
+
$class_name = 'no context provided';
|
63 |
+
}
|
64 |
|
65 |
+
if (isset($this->rule)) {
|
66 |
+
$reflection = new \ReflectionClass(get_class($this->rule));
|
67 |
+
$rule_name = $reflection->getShortName();
|
68 |
+
} else {
|
69 |
+
$rule_name = 'no rule provided';
|
70 |
+
}
|
71 |
|
72 |
$has_properties = false;
|
73 |
$str_properties = '';
|
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CMS/WPTransformerTest.php
CHANGED
@@ -73,6 +73,26 @@ class WPTransformerTest extends \PHPUnit_Framework_TestCase
|
|
73 |
|
74 |
$this->assertEquals($expected, $result);
|
75 |
// there must be 3 warnings related to <img> inside <li> that is not supported by IA
|
76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
}
|
78 |
}
|
73 |
|
74 |
$this->assertEquals($expected, $result);
|
75 |
// there must be 3 warnings related to <img> inside <li> that is not supported by IA
|
76 |
+
// And 1 warning related to the getter
|
77 |
+
$this->assertEquals(4, count($transformer->getWarnings()));
|
78 |
+
}
|
79 |
+
|
80 |
+
public function testTitleTransformedWithBold()
|
81 |
+
{
|
82 |
+
$transformer = new Transformer();
|
83 |
+
$json_file = file_get_contents(__DIR__ . '/wp-rules.json');
|
84 |
+
$transformer->loadRules($json_file);
|
85 |
+
|
86 |
+
$title_html_string = '<?xml encoding="utf-8" ?><h1>Title <b>in bold</b></h1>';
|
87 |
+
|
88 |
+
libxml_use_internal_errors(true);
|
89 |
+
$document = new \DOMDocument();
|
90 |
+
$document->loadHtml($title_html_string);
|
91 |
+
libxml_use_internal_errors(false);
|
92 |
+
|
93 |
+
$header = Header::create();
|
94 |
+
$transformer->transform($header, $document);
|
95 |
+
|
96 |
+
$this->assertEquals('<h1>Title <b>in bold</b></h1>', $header->getTitle()->render());
|
97 |
}
|
98 |
}
|
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CMS/wp-ia.xml
CHANGED
@@ -146,10 +146,57 @@
|
|
146 |
<figcaption> Image 3 </figcaption>
|
147 |
</figure>
|
148 |
</figure>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
<figure>
|
150 |
<img src="http://example.com/img.jpg"/>
|
151 |
<figcaption>blue eyes</figcaption>
|
152 |
</figure>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
</article>
|
154 |
</body>
|
155 |
</html>
|
146 |
<figcaption> Image 3 </figcaption>
|
147 |
</figure>
|
148 |
</figure>
|
149 |
+
<figure class="op-interactive">
|
150 |
+
<iframe class="no-margin">
|
151 |
+
<blockquote class="instagram-media" data-instgrm-captioned="" data-instgrm-version="6" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);">
|
152 |
+
<div style="padding:8px;">
|
153 |
+
<div style=" background:#F8F8F8; line-height:0; margin-top:40px; padding:62.5% 0; text-align:center; width:100%;">
|
154 |
+
<div style=" background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAAGFBMVEUiIiI9PT0eHh4gIB4hIBkcHBwcHBwcHBydr+JQAAAACHRSTlMABA4YHyQsM5jtaMwAAADfSURBVDjL7ZVBEgMhCAQBAf//42xcNbpAqakcM0ftUmFAAIBE81IqBJdS3lS6zs3bIpB9WED3YYXFPmHRfT8sgyrCP1x8uEUxLMzNWElFOYCV6mHWWwMzdPEKHlhLw7NWJqkHc4uIZphavDzA2JPzUDsBZziNae2S6owH8xPmX8G7zzgKEOPUoYHvGz1TBCxMkd3kwNVbU0gKHkx+iZILf77IofhrY1nYFnB/lQPb79drWOyJVa/DAvg9B/rLB4cC+Nqgdz/TvBbBnr6GBReqn/nRmDgaQEej7WhonozjF+Y2I/fZou/qAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-22px; width:44px;"></div>
|
155 |
+
</div>
|
156 |
+
<p style=" margin:8px 0 0 0; padding:0 4px;">
|
157 |
+
<a href="https://www.instagram.com/p/BAXbKP1POQe/" style=" color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;" target="_blank">ð¸ @natthaponwuttipetch</a>
|
158 |
+
</p>
|
159 |
+
<p style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;">
|
160 |
+
A photo posted by Ann Hathairat Vidhyaphum (@annvidh) on <time style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px;" datetime="2016-01-10T16:56:06+00:00">Jan 10, 2016 at 8:56am PST</time></p>
|
161 |
+
</div>
|
162 |
+
</blockquote>
|
163 |
+
<script async="" defer="defer" src="//platform.instagram.com/en_US/embeds.js"></script>
|
164 |
+
</iframe>
|
165 |
+
</figure>
|
166 |
<figure>
|
167 |
<img src="http://example.com/img.jpg"/>
|
168 |
<figcaption>blue eyes</figcaption>
|
169 |
</figure>
|
170 |
+
<figure class="op-interactive">
|
171 |
+
<iframe class="no-margin">
|
172 |
+
<h1>Sibling content</h1>
|
173 |
+
<div>sibling body</div></iframe>
|
174 |
+
</figure>
|
175 |
+
<p>Standard paragraph that <b>shouldn't</b> lie within the interactive block.</p>
|
176 |
+
<figure class="op-interactive">
|
177 |
+
<iframe class="no-margin">
|
178 |
+
<p>Extra markup</p>
|
179 |
+
<div class="fb-post" data-href="https://www.facebook.com/some-page/posts/some-post"></div>
|
180 |
+
</iframe>
|
181 |
+
</figure>
|
182 |
+
<figure class="op-slideshow">
|
183 |
+
<figure>
|
184 |
+
<img src="http://example.com/konservnye-banki-osobenno-lyubyat-yaponcy-810x471.jpg"/>
|
185 |
+
<figcaption>Caption Img 1</figcaption>
|
186 |
+
</figure>
|
187 |
+
<figure>
|
188 |
+
<img src="http://example.com/a-vot-chto-vnutri.jpg"/>
|
189 |
+
<figcaption>Alternative text </figcaption>
|
190 |
+
</figure>
|
191 |
+
<figure>
|
192 |
+
<img src="http://example.com/brelok-s-bezopasnostyu-vsegda-s-soboj.jpg"/>
|
193 |
+
<figcaption>Caption img 3</figcaption>
|
194 |
+
</figure>
|
195 |
+
</figure>
|
196 |
+
<figure>
|
197 |
+
<img src="http://example.com/image.jpg"/>
|
198 |
+
<figcaption>caption</figcaption>
|
199 |
+
</figure>
|
200 |
</article>
|
201 |
</body>
|
202 |
</html>
|
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CMS/wp-rules.json
CHANGED
@@ -120,6 +120,23 @@
|
|
120 |
}, {
|
121 |
"class": "H2Rule",
|
122 |
"selector" : "h3,h4,h5,h6"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
}, {
|
124 |
"class": "InteractiveRule",
|
125 |
"selector" : "iframe",
|
@@ -250,6 +267,24 @@
|
|
250 |
"attribute": "width"
|
251 |
}
|
252 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
253 |
}, {
|
254 |
"class": "InteractiveInsideParagraphRule",
|
255 |
"selector" : "iframe",
|
@@ -397,8 +432,10 @@
|
|
397 |
}, {
|
398 |
"class": "CaptionRule",
|
399 |
"selector" : "figcaption"
|
400 |
-
},
|
401 |
-
|
|
|
|
|
402 |
"class": "ImageRule",
|
403 |
"selector" : "figure",
|
404 |
"properties" : {
|
@@ -486,6 +523,10 @@
|
|
486 |
"class": "SlideshowRule",
|
487 |
"selector" : "div.tiled-gallery"
|
488 |
},
|
|
|
|
|
|
|
|
|
489 |
{
|
490 |
"class": "Compat\\JetpackSlideshowRule",
|
491 |
"selector" : "div.jetpack-slideshow",
|
@@ -501,6 +542,33 @@
|
|
501 |
"class": "CaptionRule",
|
502 |
"selector" : "div.tiled-gallery-caption"
|
503 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
504 |
|
505 |
|
506 |
{
|
@@ -513,6 +581,26 @@
|
|
513 |
"attribute": "src"
|
514 |
}
|
515 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
516 |
}
|
517 |
]
|
518 |
}
|
120 |
}, {
|
121 |
"class": "H2Rule",
|
122 |
"selector" : "h3,h4,h5,h6"
|
123 |
+
}, {
|
124 |
+
"class": "InteractiveRule",
|
125 |
+
"selector" : "blockquote.instagram-media",
|
126 |
+
"properties" : {
|
127 |
+
"interactive.iframe" : {
|
128 |
+
"type" : "multiple",
|
129 |
+
"children": [
|
130 |
+
{
|
131 |
+
"type": "element",
|
132 |
+
"selector": "blockquote"
|
133 |
+
}, {
|
134 |
+
"type": "next-sibling-element-of",
|
135 |
+
"selector": "blockquote"
|
136 |
+
}
|
137 |
+
]
|
138 |
+
}
|
139 |
+
}
|
140 |
}, {
|
141 |
"class": "InteractiveRule",
|
142 |
"selector" : "iframe",
|
267 |
"attribute": "width"
|
268 |
}
|
269 |
}
|
270 |
+
}, {
|
271 |
+
"class": "InteractiveRule",
|
272 |
+
"selector" : "div.fb-post",
|
273 |
+
"properties" : {
|
274 |
+
"interactive.iframe" : {
|
275 |
+
"type": "multiple",
|
276 |
+
"children": [
|
277 |
+
{
|
278 |
+
"type": "fragment",
|
279 |
+
"fragment": "<p>Extra markup</p>"
|
280 |
+
},
|
281 |
+
{
|
282 |
+
"type" : "element",
|
283 |
+
"selector" : "div.fb-post"
|
284 |
+
}
|
285 |
+
]
|
286 |
+
}
|
287 |
+
}
|
288 |
}, {
|
289 |
"class": "InteractiveInsideParagraphRule",
|
290 |
"selector" : "iframe",
|
432 |
}, {
|
433 |
"class": "CaptionRule",
|
434 |
"selector" : "figcaption"
|
435 |
+
}, {
|
436 |
+
"class": "CaptionRule",
|
437 |
+
"selector" : "p.wp-caption-text"
|
438 |
+
}, {
|
439 |
"class": "ImageRule",
|
440 |
"selector" : "figure",
|
441 |
"properties" : {
|
523 |
"class": "SlideshowRule",
|
524 |
"selector" : "div.tiled-gallery"
|
525 |
},
|
526 |
+
{
|
527 |
+
"class": "SlideshowRule",
|
528 |
+
"selector" : "div.tiled-gallery"
|
529 |
+
},
|
530 |
{
|
531 |
"class": "Compat\\JetpackSlideshowRule",
|
532 |
"selector" : "div.jetpack-slideshow",
|
542 |
"class": "CaptionRule",
|
543 |
"selector" : "div.tiled-gallery-caption"
|
544 |
},
|
545 |
+
{
|
546 |
+
"class" : "PassThroughRule",
|
547 |
+
"selector" : "div.vce-gallery-big"
|
548 |
+
},
|
549 |
+
{
|
550 |
+
"class" : "PassThroughRule",
|
551 |
+
"selector" : "div.vce-gallery-small"
|
552 |
+
},
|
553 |
+
{
|
554 |
+
"class" : "IgnoreRule",
|
555 |
+
"selector" : "div.vce-gallery-slider"
|
556 |
+
},
|
557 |
+
{
|
558 |
+
"class": "SlideshowImageRule",
|
559 |
+
"selector" : "div.big-gallery-item",
|
560 |
+
"properties" : {
|
561 |
+
"image.url" : {
|
562 |
+
"type" : "string",
|
563 |
+
"selector" : "img",
|
564 |
+
"attribute": "src"
|
565 |
+
},
|
566 |
+
"caption.title" : {
|
567 |
+
"type" : "string",
|
568 |
+
"selector" : "figcaption.wp-caption-text"
|
569 |
+
}
|
570 |
+
}
|
571 |
+
},
|
572 |
|
573 |
|
574 |
{
|
581 |
"attribute": "src"
|
582 |
}
|
583 |
}
|
584 |
+
},
|
585 |
+
|
586 |
+
{
|
587 |
+
"class": "InteractiveRule",
|
588 |
+
"selector" : "iframe.sibling",
|
589 |
+
"properties" : {
|
590 |
+
"interactive.iframe" : {
|
591 |
+
"type" : "multiple",
|
592 |
+
"children": [
|
593 |
+
{
|
594 |
+
"type": "children",
|
595 |
+
"selector": "iframe"
|
596 |
+
}, {
|
597 |
+
"type": "next-sibling-element-of",
|
598 |
+
"selector": "iframe",
|
599 |
+
"sibling.selector": "script"
|
600 |
+
}
|
601 |
+
]
|
602 |
+
}
|
603 |
+
}
|
604 |
}
|
605 |
]
|
606 |
}
|
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CMS/wp.html
CHANGED
@@ -121,6 +121,20 @@
|
|
121 |
</div>
|
122 |
<p> <!-- close row -->
|
123 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
<p>
|
125 |
<figure style="width: 1280px" class="wp-caption alignnone">
|
126 |
<img src="http://example.com/img.jpg" width="1280" height="740" class />
|
@@ -128,6 +142,80 @@
|
|
128 |
<figcaption class="wp-caption-text">blue eyes</figcaption>
|
129 |
</figure>
|
130 |
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
</body>
|
133 |
</html>
|
121 |
</div>
|
122 |
<p> <!-- close row -->
|
123 |
</div>
|
124 |
+
<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-version="6" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);">
|
125 |
+
<div style="padding:8px;">
|
126 |
+
<div style=" background:#F8F8F8; line-height:0; margin-top:40px; padding:62.5% 0; text-align:center; width:100%;">
|
127 |
+
<div style=" background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAAGFBMVEUiIiI9PT0eHh4gIB4hIBkcHBwcHBwcHBydr+JQAAAACHRSTlMABA4YHyQsM5jtaMwAAADfSURBVDjL7ZVBEgMhCAQBAf//42xcNbpAqakcM0ftUmFAAIBE81IqBJdS3lS6zs3bIpB9WED3YYXFPmHRfT8sgyrCP1x8uEUxLMzNWElFOYCV6mHWWwMzdPEKHlhLw7NWJqkHc4uIZphavDzA2JPzUDsBZziNae2S6owH8xPmX8G7zzgKEOPUoYHvGz1TBCxMkd3kwNVbU0gKHkx+iZILf77IofhrY1nYFnB/lQPb79drWOyJVa/DAvg9B/rLB4cC+Nqgdz/TvBbBnr6GBReqn/nRmDgaQEej7WhonozjF+Y2I/fZou/qAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-22px; width:44px;"></div>
|
128 |
+
</div>
|
129 |
+
<p style=" margin:8px 0 0 0; padding:0 4px;">
|
130 |
+
<a href="https://www.instagram.com/p/BAXbKP1POQe/" style=" color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;" target="_blank">📸 @natthaponwuttipetch</a>
|
131 |
+
</p>
|
132 |
+
<p style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;">
|
133 |
+
A photo posted by Ann Hathairat Vidhyaphum (@annvidh) on <time style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px;" datetime="2016-01-10T16:56:06+00:00">Jan 10, 2016 at 8:56am PST</time>
|
134 |
+
</p>
|
135 |
+
</div>
|
136 |
+
</blockquote>
|
137 |
+
<script async defer src="//platform.instagram.com/en_US/embeds.js"></script>
|
138 |
<p>
|
139 |
<figure style="width: 1280px" class="wp-caption alignnone">
|
140 |
<img src="http://example.com/img.jpg" width="1280" height="740" class />
|
142 |
<figcaption class="wp-caption-text">blue eyes</figcaption>
|
143 |
</figure>
|
144 |
</p>
|
145 |
+
<iframe class="sibling">
|
146 |
+
<h1>Sibling content</h1>
|
147 |
+
<div>sibling body</div></iframe>
|
148 |
+
<script src="//sibling.com/brother.js"></script>
|
149 |
+
<p>Standard paragraph that <b>shouldn't</b> lie within the interactive block.</p>
|
150 |
+
<div class="fb-post" data-href="https://www.facebook.com/some-page/posts/some-post"></div>
|
151 |
|
152 |
+
<div id="gallery-3" class="vce-gallery gallery galleryid-15219 gallery-columns-3 gallery-size-vce-lay-b">
|
153 |
+
<div class="vce-gallery-big">
|
154 |
+
<div class="big-gallery-item item-0">
|
155 |
+
<div class="gallery-icon">
|
156 |
+
<a href="http://example.com/konservnye-banki-osobenno-lyubyat-yaponcy.jpg"><img width="810" height="471" src="http://example.com/konservnye-banki-osobenno-lyubyat-yaponcy-810x471.jpg" class="attachment-vce-lay-a size-vce-lay-a" alt="Caption Img 1" srcset="http://example.com/konservnye-banki-osobenno-lyubyat-yaponcy-810x471.jpg 810w, http://example.com/konservnye-banki-osobenno-lyubyat-yaponcy-300x174.jpg 300w, http://example.com/konservnye-banki-osobenno-lyubyat-yaponcy-768x447.jpg 768w, http://example.com/konservnye-banki-osobenno-lyubyat-yaponcy.jpg 860w" sizes="(max-width: 810px) 100vw, 810px"></a>
|
157 |
+
</div>
|
158 |
+
<figcaption class="wp-caption-text gallery-caption">Caption Img 1</figcaption>
|
159 |
+
</div>
|
160 |
+
<div class="big-gallery-item item-1" style="display:none;">
|
161 |
+
<div class="gallery-icon">
|
162 |
+
<a href="http://example.com/a-vot-chto-vnutri.jpg">
|
163 |
+
<img width="699" height="443" src="http://example.com/a-vot-chto-vnutri.jpg" class="attachment-vce-lay-a size-vce-lay-a" alt="Alternative text" srcset="http://example.com/a-vot-chto-vnutri.jpg 699w, http://example.com/a-vot-chto-vnutri-300x190.jpg 300w" sizes="(max-width: 699px) 100vw, 699px">
|
164 |
+
</a>
|
165 |
+
</div>
|
166 |
+
<figcaption class="wp-caption-text gallery-caption">Alternative text </figcaption>
|
167 |
+
</div>
|
168 |
+
<div class="big-gallery-item item-2" style="display:none;">
|
169 |
+
<div class="gallery-icon">
|
170 |
+
<a href="http://example.com/brelok-s-bezopasnostyu-vsegda-s-soboj.jpg">
|
171 |
+
<img width="700" height="467" src="http://example.com/brelok-s-bezopasnostyu-vsegda-s-soboj.jpg" class="attachment-vce-lay-a size-vce-lay-a" alt="Caption img 3" srcset="http://example.com/brelok-s-bezopasnostyu-vsegda-s-soboj.jpg 700w, http://example.com/brelok-s-bezopasnostyu-vsegda-s-soboj-300x200.jpg 300w" sizes="(max-width: 700px) 100vw, 700px">
|
172 |
+
</a>
|
173 |
+
</div>
|
174 |
+
<figcaption class="wp-caption-text gallery-caption">Caption img 3</figcaption>
|
175 |
+
</div>
|
176 |
+
</div>
|
177 |
+
<div class="vce-gallery-slider owl-carousel owl-theme owl-loaded owl-text-select-on" data-columns="3">
|
178 |
+
<div class="owl-stage-outer">
|
179 |
+
<div class="owl-stage" style="transform: translate3d(-761px, 0px, 0px); transition: 0s; width: 3551.34px;">
|
180 |
+
<div class="owl-item active" style="width: 252.667px; margin-right: 1px;">
|
181 |
+
<figure class="gallery-item" data-item="0">
|
182 |
+
<div class="gallery-icon landscape">
|
183 |
+
<a href="http://example.com/konservnye-banki-osobenno-lyubyat-yaponcy.jpg"><img width="375" height="195" src="http://example.com/konservnye-banki-osobenno-lyubyat-yaponcy-375x195.jpg" class="attachment-vce-lay-b size-vce-lay-b" alt="Caption Img 1"></a>
|
184 |
+
</div>
|
185 |
+
</figure>
|
186 |
+
</div>
|
187 |
+
<div class="owl-item active" style="width: 252.667px; margin-right: 1px;">
|
188 |
+
<figure class="gallery-item" data-item="1">
|
189 |
+
<div class="gallery-icon landscape">
|
190 |
+
<a href="http://example.com/a-vot-chto-vnutri.jpg"><img width="375" height="195" src="http://example.com/a-vot-chto-vnutri-375x195.jpg" class="attachment-vce-lay-b size-vce-lay-b" alt="Alternative text"></a>
|
191 |
+
</div>
|
192 |
+
</figure>
|
193 |
+
</div>
|
194 |
+
<div class="owl-item active" style="width: 252.667px; margin-right: 1px;">
|
195 |
+
<figure class="gallery-item" data-item="2">
|
196 |
+
<div class="gallery-icon landscape">
|
197 |
+
<a href="http://example.com/brelok-s-bezopasnostyu-vsegda-s-soboj.jpg"><img width="375" height="195" src="http://example.com/brelok-s-bezopasnostyu-vsegda-s-soboj-375x195.jpg" class="attachment-vce-lay-b size-vce-lay-b" alt="Caption img 3"></a>
|
198 |
+
</div>
|
199 |
+
</figure>
|
200 |
+
</div>
|
201 |
+
</div>
|
202 |
+
</div>
|
203 |
+
<div class="owl-controls">
|
204 |
+
<div class="owl-nav">
|
205 |
+
<div class="owl-prev" style=""><i class="fa fa-angle-left"></i></div>
|
206 |
+
<div class="owl-next" style=""><i class="fa fa-angle-right"></i></div>
|
207 |
+
</div>
|
208 |
+
<div class="owl-dots" style="">
|
209 |
+
<div class="owl-dot active"><span></span></div>
|
210 |
+
<div class="owl-dot"><span></span></div>
|
211 |
+
<div class="owl-dot"><span></span></div>
|
212 |
+
</div>
|
213 |
+
</div>
|
214 |
+
</div>
|
215 |
+
</div>
|
216 |
+
<div id="attachment_22553" style="width: 800px" class="wp-caption alignnone">
|
217 |
+
<img class="wp-image-22553 size-large" src="http://example.com/image.jpg" alt="alt text" width="800" height="552" srcset="http://example.com/image-800.jpg 800w, http://example.com/image-400.jpg 400w, http://example.com/image-768.jpg 768w" sizes="(max-width: 800px) 100vw, 800px" />
|
218 |
+
<p class="wp-caption-text">caption</p>
|
219 |
+
</div>
|
220 |
</body>
|
221 |
</html>
|
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/Example/simple-ia.html
CHANGED
@@ -28,7 +28,7 @@
|
|
28 |
<p>Curabitur vulputate odio eu justo <i>venenatis</i>, a pretium orci placerat. Nam sed neque quis eros vestibulum mattis. Donec vitae mi egestas, laoreet massa et, fringilla libero.</p>
|
29 |
<figure class="op-interactive">
|
30 |
<iframe>
|
31 |
-
<iframe width="620" height="349" src="https://www.youtube.com/embed/s1tN0ggNreA?feature=oembed" frameborder="0" allowfullscreen=""
|
32 |
</iframe>
|
33 |
</figure>
|
34 |
<figure class="op-interactive">
|
28 |
<p>Curabitur vulputate odio eu justo <i>venenatis</i>, a pretium orci placerat. Nam sed neque quis eros vestibulum mattis. Donec vitae mi egestas, laoreet massa et, fringilla libero.</p>
|
29 |
<figure class="op-interactive">
|
30 |
<iframe>
|
31 |
+
<iframe width="620" height="349" src="https://www.youtube.com/embed/s1tN0ggNreA?feature=oembed" frameborder="0" allowfullscreen=""></iframe>
|
32 |
</iframe>
|
33 |
</figure>
|
34 |
<figure class="op-interactive">
|
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/TransformerTest.php
CHANGED
@@ -39,6 +39,51 @@ class TransformerTest extends \PHPUnit_Framework_TestCase
|
|
39 |
);
|
40 |
}
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
public function testSelfTransformerContent()
|
43 |
{
|
44 |
$json_file = file_get_contents('src/Facebook/InstantArticles/Parser/instant-articles-rules.json');
|
@@ -64,6 +109,54 @@ class TransformerTest extends \PHPUnit_Framework_TestCase
|
|
64 |
$this->assertEquals($html_file, $result);
|
65 |
}
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
public function testTransformerAddAndGetRules()
|
68 |
{
|
69 |
$transformer = new Transformer();
|
@@ -93,23 +186,4 @@ class TransformerTest extends \PHPUnit_Framework_TestCase
|
|
93 |
$transformer->resetRules();
|
94 |
$this->assertEquals([], $transformer->getRules());
|
95 |
}
|
96 |
-
|
97 |
-
public function testTitleTransformedWithBold()
|
98 |
-
{
|
99 |
-
$transformer = new Transformer();
|
100 |
-
$json_file = file_get_contents(__DIR__ . '/CMS/wp-rules.json');
|
101 |
-
$transformer->loadRules($json_file);
|
102 |
-
|
103 |
-
$title_html_string = '<?xml encoding="utf-8" ?><h1>Title <b>in bold</b></h1>';
|
104 |
-
|
105 |
-
libxml_use_internal_errors(true);
|
106 |
-
$document = new \DOMDocument();
|
107 |
-
$document->loadHtml($title_html_string);
|
108 |
-
libxml_use_internal_errors(false);
|
109 |
-
|
110 |
-
$header = Header::create();
|
111 |
-
$transformer->transform($header, $document);
|
112 |
-
|
113 |
-
$this->assertEquals('<h1>Title <b>in bold</b></h1>', $header->getTitle()->render());
|
114 |
-
}
|
115 |
}
|
39 |
);
|
40 |
}
|
41 |
|
42 |
+
public function testTransformString()
|
43 |
+
{
|
44 |
+
$json_file = file_get_contents('src/Facebook/InstantArticles/Parser/instant-articles-rules.json');
|
45 |
+
|
46 |
+
$instant_article = InstantArticle::create();
|
47 |
+
$transformer = new Transformer();
|
48 |
+
$transformer->loadRules($json_file);
|
49 |
+
|
50 |
+
$title_html_string = '<h1>Title String</h1>';
|
51 |
+
$header = Header::create();
|
52 |
+
$transformer->transformString($header, $title_html_string);
|
53 |
+
|
54 |
+
$this->assertEquals('<h1>Title String</h1>', $header->getTitle()->render());
|
55 |
+
}
|
56 |
+
|
57 |
+
public function testTransformStringWithMultibyteUTF8Content()
|
58 |
+
{
|
59 |
+
$json_file = file_get_contents('src/Facebook/InstantArticles/Parser/instant-articles-rules.json');
|
60 |
+
|
61 |
+
$instant_article = InstantArticle::create();
|
62 |
+
$transformer = new Transformer();
|
63 |
+
$transformer->loadRules($json_file);
|
64 |
+
|
65 |
+
$title_html_string = '<h1>Test:あÖÄÜöäü</h1>';
|
66 |
+
$header = Header::create();
|
67 |
+
$transformer->transformString($header, $title_html_string);
|
68 |
+
|
69 |
+
$this->assertEquals('<h1>Test:あÖÄÜöäü</h1>', $header->getTitle()->render());
|
70 |
+
}
|
71 |
+
|
72 |
+
public function testTransformStringWithMultibyteNonUTF8Content()
|
73 |
+
{
|
74 |
+
$json_file = file_get_contents('src/Facebook/InstantArticles/Parser/instant-articles-rules.json');
|
75 |
+
|
76 |
+
$instant_article = InstantArticle::create();
|
77 |
+
$transformer = new Transformer();
|
78 |
+
$transformer->loadRules($json_file);
|
79 |
+
|
80 |
+
$title_html_string = mb_convert_encoding('<h1>Test:あÖÄÜöäü</h1>', 'euc-jp', 'utf-8');
|
81 |
+
$header = Header::create();
|
82 |
+
$transformer->transformString($header, $title_html_string, 'euc-jp');
|
83 |
+
|
84 |
+
$this->assertEquals('<h1>Test:あÖÄÜöäü</h1>', $header->getTitle()->render());
|
85 |
+
}
|
86 |
+
|
87 |
public function testSelfTransformerContent()
|
88 |
{
|
89 |
$json_file = file_get_contents('src/Facebook/InstantArticles/Parser/instant-articles-rules.json');
|
109 |
$this->assertEquals($html_file, $result);
|
110 |
}
|
111 |
|
112 |
+
public function testSelfTransformerMultibyteContent()
|
113 |
+
{
|
114 |
+
$json_file = file_get_contents('src/Facebook/InstantArticles/Parser/instant-articles-rules.json');
|
115 |
+
|
116 |
+
$instant_article = InstantArticle::create();
|
117 |
+
$transformer = new Transformer();
|
118 |
+
$transformer->loadRules($json_file);
|
119 |
+
|
120 |
+
$html_file = file_get_contents(__DIR__ . '/instant-article-example-multibyte.html');
|
121 |
+
|
122 |
+
$transformer->transformString($instant_article, $html_file, 'utf-8');
|
123 |
+
$instant_article->withCanonicalURL('http://foo.com/article.html');
|
124 |
+
$instant_article->addMetaProperty('op:generator:version', '1.0.0');
|
125 |
+
$instant_article->addMetaProperty('op:generator:transformer:version', '1.0.0');
|
126 |
+
$result = $instant_article->render('', true)."\n";
|
127 |
+
|
128 |
+
// some fragments are written as html entities even after transformed so
|
129 |
+
// noralize all strings to html entities and compare them.
|
130 |
+
$this->assertEquals(
|
131 |
+
mb_convert_encoding($html_file, 'HTML-ENTITIES', 'utf-8'),
|
132 |
+
mb_convert_encoding($result, 'HTML-ENTITIES', 'utf-8')
|
133 |
+
);
|
134 |
+
}
|
135 |
+
|
136 |
+
public function testSelfTransformerNonUTF8Content()
|
137 |
+
{
|
138 |
+
$json_file = file_get_contents('src/Facebook/InstantArticles/Parser/instant-articles-rules.json');
|
139 |
+
|
140 |
+
$instant_article = InstantArticle::create();
|
141 |
+
$transformer = new Transformer();
|
142 |
+
$transformer->loadRules($json_file);
|
143 |
+
|
144 |
+
$html_file = file_get_contents(__DIR__ . '/instant-article-example-nonutf8.html');
|
145 |
+
|
146 |
+
$transformer->transformString($instant_article, $html_file, 'euc-jp');
|
147 |
+
$instant_article->withCanonicalURL('http://foo.com/article.html');
|
148 |
+
$instant_article->addMetaProperty('op:generator:version', '1.0.0');
|
149 |
+
$instant_article->addMetaProperty('op:generator:transformer:version', '1.0.0');
|
150 |
+
$result = $instant_article->render('', true)."\n";
|
151 |
+
|
152 |
+
// some fragments are written as html entities even after transformed so
|
153 |
+
// noralize all strings to html entities and compare them.
|
154 |
+
$this->assertEquals(
|
155 |
+
mb_convert_encoding($html_file, 'HTML-ENTITIES', 'euc-jp'),
|
156 |
+
mb_convert_encoding($result, 'HTML-ENTITIES', 'utf-8')
|
157 |
+
);
|
158 |
+
}
|
159 |
+
|
160 |
public function testTransformerAddAndGetRules()
|
161 |
{
|
162 |
$transformer = new Transformer();
|
186 |
$transformer->resetRules();
|
187 |
$this->assertEquals([], $transformer->getRules());
|
188 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
}
|
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/instant-article-example-multibyte.html
ADDED
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<html>
|
2 |
+
<head>
|
3 |
+
<link rel="canonical" href="http://foo.com/article.html"/>
|
4 |
+
<meta charset="utf-8"/>
|
5 |
+
<meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
|
6 |
+
<meta property="op:generator:version" content="1.0.0"/>
|
7 |
+
<meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
|
8 |
+
<meta property="op:generator:transformer:version" content="1.0.0"/>
|
9 |
+
<meta property="op:markup_version" content="v1.0"/>
|
10 |
+
</head>
|
11 |
+
<body>
|
12 |
+
<article>
|
13 |
+
<header>
|
14 |
+
<figure>
|
15 |
+
<img src="https://jpeg.org/images/jpegls-home.jpg"/>
|
16 |
+
<figcaption><h1>イメージ名</h1>テキストノード<cite>イメージキャプション</cite></figcaption>
|
17 |
+
</figure>
|
18 |
+
<h1>ビッグトップ <b>タイトル</b></h1>
|
19 |
+
<h2>スモール <b>サブタイトル</b></h2>
|
20 |
+
<time class="op-published" datetime="1984-08-14T19:30:00+00:00">August 14th, 7:30pm</time>
|
21 |
+
<time class="op-modified" datetime="2016-02-10T10:00:00+00:00">February 10th, 10:00am</time>
|
22 |
+
<address><a href="#" title="Title of author">著者名</a>
|
23 |
+
著者に関する詳しい情報
|
24 |
+
さらなる詳細
|
25 |
+
</address>
|
26 |
+
<address><a href="http://facebook.com/author" rel="facebook">FB上の著者</a>
|
27 |
+
facebook内の著者情報
|
28 |
+
</address>
|
29 |
+
<address><a title="PHP Programmer">開発者</a>
|
30 |
+
</address>
|
31 |
+
<h3 class="op-kicker">記事のキッカー</h3>
|
32 |
+
<ul class="op-sponsors">
|
33 |
+
<li>
|
34 |
+
<a href="http://facebook.com/my-sponsor" rel="facebook"></a>
|
35 |
+
</li>
|
36 |
+
</ul>
|
37 |
+
</header>
|
38 |
+
<p>パラグラフ内のテキストのテストです。</p>
|
39 |
+
<figure data-feedback="fb:likes">
|
40 |
+
<img src="http://mydomain.com/path/to/img.jpg"/>
|
41 |
+
<audio title="オーディオタイトル" autoplay="autoplay" muted="muted">
|
42 |
+
<source src="http://foo.com/mp3"/>
|
43 |
+
</audio>
|
44 |
+
</figure>
|
45 |
+
<figure data-feedback="fb:comments">
|
46 |
+
<img src="http://mydomain.com/path/to/img.jpg"/>
|
47 |
+
<script type="application/json" class="op-geotag">
|
48 |
+
{
|
49 |
+
"type": "Feature",
|
50 |
+
"geometry": {
|
51 |
+
"type": "Point",
|
52 |
+
"coordinates": [23.166667, 89.216667]
|
53 |
+
},
|
54 |
+
"properties": {
|
55 |
+
"title": "バングラデシュ ジョソール県",
|
56 |
+
"radius": 750000,
|
57 |
+
"pivot": true,
|
58 |
+
"style": "satellite",
|
59 |
+
}
|
60 |
+
}
|
61 |
+
</script>
|
62 |
+
<audio title="オーディオタイトル" autoplay="autoplay" muted="muted">
|
63 |
+
<source src="http://foo.com/mp3"/>
|
64 |
+
</audio>
|
65 |
+
</figure>
|
66 |
+
<figure data-feedback="fb:likes,fb:comments">
|
67 |
+
<img src="https://jpeg.org/images/jpegls-home.jpg"/>
|
68 |
+
<figcaption><h1>イメージ名</h1>テキストノード<cite>イメージキャプション</cite></figcaption>
|
69 |
+
</figure>
|
70 |
+
<p>第2段落内のテキストのテストです。</p>
|
71 |
+
<figure class="op-slideshow">
|
72 |
+
<figure>
|
73 |
+
<img src="https://jpeg.org/images/jpegls-home.jpg"/>
|
74 |
+
</figure>
|
75 |
+
<figure>
|
76 |
+
<img src="https://jpeg.org/images/jpegls-home2.jpg"/>
|
77 |
+
</figure>
|
78 |
+
<figure>
|
79 |
+
<img src="https://jpeg.org/images/jpegls-home3.jpg"/>
|
80 |
+
</figure>
|
81 |
+
<figcaption><h1>イメージ名</h1>テキストノード<cite>イメージキャプション</cite></figcaption>
|
82 |
+
<audio title="オーディオタイトル" autoplay="autoplay" muted="muted">
|
83 |
+
<source src="http://foo.com/mp3"/>
|
84 |
+
</audio>
|
85 |
+
</figure>
|
86 |
+
<ol>
|
87 |
+
<li>最初のリスト項目</li>
|
88 |
+
<li>パラグラフ</li>
|
89 |
+
<li>spanタグ</li>
|
90 |
+
<li>div内のテキスト?</li>
|
91 |
+
<li>li上のその他の <a href="#">段落</a></li>
|
92 |
+
<li>最後のリスト項目</li>
|
93 |
+
</ol>
|
94 |
+
<p>段落内のテキストのテストです。</p>
|
95 |
+
<figure class="op-interactive">
|
96 |
+
<iframe src="http://example.com/custom-interactive" class="column-width" height="60">
|
97 |
+
<h1>カスタムコード</h1>
|
98 |
+
<script>alert("テスト");</script></iframe>
|
99 |
+
<figcaption>このグラフィックは素晴らしい。</figcaption>
|
100 |
+
</figure>
|
101 |
+
<figure class="op-ad">
|
102 |
+
<iframe src="http://foo.com"></iframe>
|
103 |
+
</figure>
|
104 |
+
<blockquote>blockquoteは記事の中で<b>magic</b>を作ります。</blockquote>
|
105 |
+
<figure class="op-map">
|
106 |
+
<script type="application/json" class="op-geotag">
|
107 |
+
{
|
108 |
+
"type": "Feature",
|
109 |
+
"geometry":
|
110 |
+
{
|
111 |
+
"type": "Point",
|
112 |
+
"coordinates": [23.166667, 89.216667]
|
113 |
+
},
|
114 |
+
"properties":
|
115 |
+
{
|
116 |
+
"title": "バングラデシュ ジョソール県",
|
117 |
+
"radius": 750000,
|
118 |
+
"pivot": true,
|
119 |
+
"style": "satellite",
|
120 |
+
}
|
121 |
+
}
|
122 |
+
</script>
|
123 |
+
<figcaption class="op-vertical-above"><h1 class="op-vertical-above op-center">キャプション用タイトル</h1><h2 class="op-vertical-below op-right">キャプション用サブタイトル</h2>
|
124 |
+
|
125 |
+
|
126 |
+
<cite class="op-vertical-center op-left">キャプション内のクレジット</cite></figcaption>
|
127 |
+
<audio title="audio title" autoplay="autoplay" muted="muted">
|
128 |
+
<source src="http://foo.com/mp3"/>
|
129 |
+
</audio>
|
130 |
+
</figure>
|
131 |
+
<aside>
|
132 |
+
私たちはどこで成長させるか、何を成長させるか、どうやって成長させるか、について、もっと効率的になれるはずです。
|
133 |
+
<cite>フルーツストカンパニー</cite></aside>
|
134 |
+
<p>第2段落内のテキストのテストです。</p>
|
135 |
+
<figure class="op-tracker">
|
136 |
+
<iframe>
|
137 |
+
<h1>カスタムコード</h1>
|
138 |
+
<script>alert("テスト");</script></iframe>
|
139 |
+
</figure>
|
140 |
+
<figure class="op-tracker">
|
141 |
+
<iframe>
|
142 |
+
<h1>トラッカー用スクリプト</h1>
|
143 |
+
<div><script>alert("テスト");</script></div>
|
144 |
+
</iframe>
|
145 |
+
</figure>
|
146 |
+
<figure class="op-interactive">
|
147 |
+
<iframe class="no-margin">
|
148 |
+
<h1>ソーシャル埋め込み用カスタムコード</h1>
|
149 |
+
<script>alert("テスト");</script></iframe>
|
150 |
+
</figure>
|
151 |
+
<figure data-mode="fullscreen" data-feedback="fb:likes,fb:comments">
|
152 |
+
<video data-fb-disable-autoplay="data-fb-disable-autoplay" controls="controls">
|
153 |
+
<source src="http://mydomain.com/path/to/video.mp4" type="video/mp4"/>
|
154 |
+
</video>
|
155 |
+
<figcaption class="op-vertical-below"><h1>ビデオタイトル</h1>
|
156 |
+
|
157 |
+
<cite>属性ソース</cite></figcaption>
|
158 |
+
<script type="application/json" class="op-geotag">
|
159 |
+
{
|
160 |
+
"type": "Feature",
|
161 |
+
"geometry": {
|
162 |
+
"type": "Point",
|
163 |
+
"coordinates": [ [23.166667, 89.216667], [23.166667, 89.216667] ]
|
164 |
+
},
|
165 |
+
"properties": {
|
166 |
+
"title": "バングラデシュ ジョソール県",
|
167 |
+
"radius": 750000,
|
168 |
+
"pivot": true,
|
169 |
+
"style": "satellite",
|
170 |
+
}
|
171 |
+
}
|
172 |
+
</script>
|
173 |
+
</figure>
|
174 |
+
<ul class="op-related-articles" title="The related ones in the middle">
|
175 |
+
<li>
|
176 |
+
<a href="http://example.com/article.html"></a>
|
177 |
+
</li>
|
178 |
+
<li data-sponsored="true">
|
179 |
+
<a href="http://example.com/sponsored-article.html"></a>
|
180 |
+
</li>
|
181 |
+
<li>
|
182 |
+
<a href="http://example.com/another-article.html"></a>
|
183 |
+
</li>
|
184 |
+
</ul>
|
185 |
+
<footer>
|
186 |
+
<aside>
|
187 |
+
<p><a href="http://facebook.com/author" rel="facebook">著者</a>へのクレジット情報</p>
|
188 |
+
<p>クレジットとしてのパラグラフ</p>
|
189 |
+
</aside>
|
190 |
+
<ul class="op-related-articles" title="The related ones in the footer">
|
191 |
+
<li>
|
192 |
+
<a href="http://example.com/article.html"></a>
|
193 |
+
</li>
|
194 |
+
<li data-sponsored="true">
|
195 |
+
<a href="http://example.com/sponsored-article.html"></a>
|
196 |
+
</li>
|
197 |
+
<li>
|
198 |
+
<a href="http://example.com/another-article.html"></a>
|
199 |
+
</li>
|
200 |
+
</ul>
|
201 |
+
</footer>
|
202 |
+
</article>
|
203 |
+
</body>
|
204 |
+
</html>
|
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/instant-article-example-nonutf8.html
ADDED
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<html>
|
2 |
+
<head>
|
3 |
+
<link rel="canonical" href="http://foo.com/article.html"/>
|
4 |
+
<meta charset="euc-jp"/>
|
5 |
+
<meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
|
6 |
+
<meta property="op:generator:version" content="1.0.0"/>
|
7 |
+
<meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
|
8 |
+
<meta property="op:generator:transformer:version" content="1.0.0"/>
|
9 |
+
<meta property="op:markup_version" content="v1.0"/>
|
10 |
+
</head>
|
11 |
+
<body>
|
12 |
+
<article>
|
13 |
+
<header>
|
14 |
+
<figure>
|
15 |
+
<img src="https://jpeg.org/images/jpegls-home.jpg"/>
|
16 |
+
<figcaption><h1>�����̾</h1>�ƥ����ȥΡ���<cite>���������ץ����</cite></figcaption>
|
17 |
+
</figure>
|
18 |
+
<h1>�ӥå��ȥå� <b>�����ȥ�</b></h1>
|
19 |
+
<h2>���⡼�� <b>���֥����ȥ�</b></h2>
|
20 |
+
<time class="op-published" datetime="1984-08-14T19:30:00+00:00">August 14th, 7:30pm</time>
|
21 |
+
<time class="op-modified" datetime="2016-02-10T10:00:00+00:00">February 10th, 10:00am</time>
|
22 |
+
<address><a href="#" title="Title of author">����̾</a>
|
23 |
+
���Ԥ˴ؤ���ܤ�������
|
24 |
+
����ʤ�ܺ�
|
25 |
+
</address>
|
26 |
+
<address><a href="http://facebook.com/author" rel="facebook">FB�������</a>
|
27 |
+
facebook������Ծ���
|
28 |
+
</address>
|
29 |
+
<address><a title="PHP Programmer">��ȯ��</a>
|
30 |
+
</address>
|
31 |
+
<h3 class="op-kicker">�����Υ��å���</h3>
|
32 |
+
<ul class="op-sponsors">
|
33 |
+
<li>
|
34 |
+
<a href="http://facebook.com/my-sponsor" rel="facebook"></a>
|
35 |
+
</li>
|
36 |
+
</ul>
|
37 |
+
</header>
|
38 |
+
<p>�ѥ饰�����Υƥ����ȤΥƥ��ȤǤ���</p>
|
39 |
+
<figure data-feedback="fb:likes">
|
40 |
+
<img src="http://mydomain.com/path/to/img.jpg"/>
|
41 |
+
<audio title="オーディオタイトル" autoplay="autoplay" muted="muted">
|
42 |
+
<source src="http://foo.com/mp3"/>
|
43 |
+
</audio>
|
44 |
+
</figure>
|
45 |
+
<figure data-feedback="fb:comments">
|
46 |
+
<img src="http://mydomain.com/path/to/img.jpg"/>
|
47 |
+
<script type="application/json" class="op-geotag">
|
48 |
+
{
|
49 |
+
"type": "Feature",
|
50 |
+
"geometry": {
|
51 |
+
"type": "Point",
|
52 |
+
"coordinates": [23.166667, 89.216667]
|
53 |
+
},
|
54 |
+
"properties": {
|
55 |
+
"title": "�Х�ǥ��塡���祽���븩",
|
56 |
+
"radius": 750000,
|
57 |
+
"pivot": true,
|
58 |
+
"style": "satellite",
|
59 |
+
}
|
60 |
+
}
|
61 |
+
</script>
|
62 |
+
<audio title="オーディオタイトル" autoplay="autoplay" muted="muted">
|
63 |
+
<source src="http://foo.com/mp3"/>
|
64 |
+
</audio>
|
65 |
+
</figure>
|
66 |
+
<figure data-feedback="fb:likes,fb:comments">
|
67 |
+
<img src="https://jpeg.org/images/jpegls-home.jpg"/>
|
68 |
+
<figcaption><h1>�����̾</h1>�ƥ����ȥΡ���<cite>���������ץ����</cite></figcaption>
|
69 |
+
</figure>
|
70 |
+
<p>��2������Υƥ����ȤΥƥ��ȤǤ���</p>
|
71 |
+
<figure class="op-slideshow">
|
72 |
+
<figure>
|
73 |
+
<img src="https://jpeg.org/images/jpegls-home.jpg"/>
|
74 |
+
</figure>
|
75 |
+
<figure>
|
76 |
+
<img src="https://jpeg.org/images/jpegls-home2.jpg"/>
|
77 |
+
</figure>
|
78 |
+
<figure>
|
79 |
+
<img src="https://jpeg.org/images/jpegls-home3.jpg"/>
|
80 |
+
</figure>
|
81 |
+
<figcaption><h1>�����̾</h1>�ƥ����ȥΡ���<cite>���������ץ����</cite></figcaption>
|
82 |
+
<audio title="オーディオタイトル" autoplay="autoplay" muted="muted">
|
83 |
+
<source src="http://foo.com/mp3"/>
|
84 |
+
</audio>
|
85 |
+
</figure>
|
86 |
+
<ol>
|
87 |
+
<li>�ǽ�Υꥹ�ȹ���</li>
|
88 |
+
<li>�ѥ饰���</li>
|
89 |
+
<li>span����</li>
|
90 |
+
<li>div��Υƥ����ȡ�</li>
|
91 |
+
<li>li��Τ���¾�� <a href="#">����</a></li>
|
92 |
+
<li>�Ǹ�Υꥹ�ȹ���</li>
|
93 |
+
</ol>
|
94 |
+
<p>������Υƥ����ȤΥƥ��ȤǤ���</p>
|
95 |
+
<figure class="op-interactive">
|
96 |
+
<iframe src="http://example.com/custom-interactive" class="column-width" height="60">
|
97 |
+
<h1>�������ॳ����</h1>
|
98 |
+
<script>alert("�ƥ���");</script></iframe>
|
99 |
+
<figcaption>���Υ���ե��å��������餷����</figcaption>
|
100 |
+
</figure>
|
101 |
+
<figure class="op-ad">
|
102 |
+
<iframe src="http://foo.com"></iframe>
|
103 |
+
</figure>
|
104 |
+
<blockquote>blockquote�ϵ��������<b>magic</b>����ޤ���</blockquote>
|
105 |
+
<figure class="op-map">
|
106 |
+
<script type="application/json" class="op-geotag">
|
107 |
+
{
|
108 |
+
"type": "Feature",
|
109 |
+
"geometry":
|
110 |
+
{
|
111 |
+
"type": "Point",
|
112 |
+
"coordinates": [23.166667, 89.216667]
|
113 |
+
},
|
114 |
+
"properties":
|
115 |
+
{
|
116 |
+
"title": "�Х�ǥ��塡���祽���븩",
|
117 |
+
"radius": 750000,
|
118 |
+
"pivot": true,
|
119 |
+
"style": "satellite",
|
120 |
+
}
|
121 |
+
}
|
122 |
+
</script>
|
123 |
+
<figcaption class="op-vertical-above"><h1 class="op-vertical-above op-center">����ץ�����ѥ����ȥ�</h1><h2 class="op-vertical-below op-right">����ץ�����ѥ��֥����ȥ�</h2>
|
124 |
+
|
125 |
+
|
126 |
+
<cite class="op-vertical-center op-left">����ץ������Υ��쥸�å�</cite></figcaption>
|
127 |
+
<audio title="audio title" autoplay="autoplay" muted="muted">
|
128 |
+
<source src="http://foo.com/mp3"/>
|
129 |
+
</audio>
|
130 |
+
</figure>
|
131 |
+
<aside>
|
132 |
+
�䤿���Ϥɤ�����Ĺ�����뤫��������Ĺ�����뤫���ɤ���ä���Ĺ�����뤫���ˤĤ��ơ���äȸ�ΨŪ�ˤʤ��Ϥ��Ǥ���
|
133 |
+
<cite>�ե롼�ĥ��ȥ���ѥˡ�</cite></aside>
|
134 |
+
<p>��2������Υƥ����ȤΥƥ��ȤǤ���</p>
|
135 |
+
<figure class="op-tracker">
|
136 |
+
<iframe>
|
137 |
+
<h1>�������ॳ����</h1>
|
138 |
+
<script>alert("�ƥ���");</script></iframe>
|
139 |
+
</figure>
|
140 |
+
<figure class="op-tracker">
|
141 |
+
<iframe>
|
142 |
+
<h1>�ȥ�å����ѥ�����ץ�</h1>
|
143 |
+
<div><script>alert("�ƥ���");</script></div>
|
144 |
+
</iframe>
|
145 |
+
</figure>
|
146 |
+
<figure class="op-interactive">
|
147 |
+
<iframe class="no-margin">
|
148 |
+
<h1>����������������ѥ������ॳ����</h1>
|
149 |
+
<script>alert("�ƥ���");</script></iframe>
|
150 |
+
</figure>
|
151 |
+
<figure data-mode="fullscreen" data-feedback="fb:likes,fb:comments">
|
152 |
+
<video data-fb-disable-autoplay="data-fb-disable-autoplay" controls="controls">
|
153 |
+
<source src="http://mydomain.com/path/to/video.mp4" type="video/mp4"/>
|
154 |
+
</video>
|
155 |
+
<figcaption class="op-vertical-below"><h1>�ӥǥ������ȥ�</h1>
|
156 |
+
|
157 |
+
<cite>°��������</cite></figcaption>
|
158 |
+
<script type="application/json" class="op-geotag">
|
159 |
+
{
|
160 |
+
"type": "Feature",
|
161 |
+
"geometry": {
|
162 |
+
"type": "Point",
|
163 |
+
"coordinates": [ [23.166667, 89.216667], [23.166667, 89.216667] ]
|
164 |
+
},
|
165 |
+
"properties": {
|
166 |
+
"title": "�Х�ǥ��塡���祽���븩",
|
167 |
+
"radius": 750000,
|
168 |
+
"pivot": true,
|
169 |
+
"style": "satellite",
|
170 |
+
}
|
171 |
+
}
|
172 |
+
</script>
|
173 |
+
</figure>
|
174 |
+
<ul class="op-related-articles" title="The related ones in the middle">
|
175 |
+
<li>
|
176 |
+
<a href="http://example.com/article.html"></a>
|
177 |
+
</li>
|
178 |
+
<li data-sponsored="true">
|
179 |
+
<a href="http://example.com/sponsored-article.html"></a>
|
180 |
+
</li>
|
181 |
+
<li>
|
182 |
+
<a href="http://example.com/another-article.html"></a>
|
183 |
+
</li>
|
184 |
+
</ul>
|
185 |
+
<footer>
|
186 |
+
<aside>
|
187 |
+
<p><a href="http://facebook.com/author" rel="facebook">����</a>�ؤΥ��쥸�åȾ���</p>
|
188 |
+
<p>���쥸�åȤȤ��ƤΥѥ饰���</p>
|
189 |
+
</aside>
|
190 |
+
<ul class="op-related-articles" title="The related ones in the footer">
|
191 |
+
<li>
|
192 |
+
<a href="http://example.com/article.html"></a>
|
193 |
+
</li>
|
194 |
+
<li data-sponsored="true">
|
195 |
+
<a href="http://example.com/sponsored-article.html"></a>
|
196 |
+
</li>
|
197 |
+
<li>
|
198 |
+
<a href="http://example.com/another-article.html"></a>
|
199 |
+
</li>
|
200 |
+
</ul>
|
201 |
+
</footer>
|
202 |
+
</article>
|
203 |
+
</body>
|
204 |
+
</html>
|