add xpath playground support for docs

This commit is contained in:
Valdir Stumm Junior 2017-06-12 19:06:41 -03:00
parent fad6b70d92
commit bfcc2395e3
9 changed files with 219 additions and 1 deletions

51
docs/_ext/xpathdemo.py Normal file
View File

@ -0,0 +1,51 @@
from docutils import nodes
from sphinx.util.compat import Directive
class xpath_demo_node(nodes.Element):
pass
class XPathDemoDirective(Directive):
has_content = True
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
def run(self):
demo_node = xpath_demo_node()
document = self.state.document
env = document.settings.env
_, demo_node.form_template = env.relfn2path('/_static/html/xpathdemo.html')
demo_node.xpath_expression = self.arguments[0]
demo_node.html_input = '\n'.join(self.content)
return [demo_node]
def setup(app):
app.add_node(
xpath_demo_node,
html=(
visit_xpath_demo_node,
depart_xpath_demo_node,
)
)
app.add_directive('xpathdemo', XPathDemoDirective)
def visit_xpath_demo_node(self, node):
try:
with open(node.form_template) as fp:
s = fp.read().format(
xpath_expression=node.xpath_expression,
html_input=node.html_input,
id=id(node),
)
self.body.append(s)
except AttributeError as e:
print('Error: {}'.format(str(e)))
def depart_xpath_demo_node(self, node):
pass

11
docs/_static/html/xpathdemo.html vendored Normal file
View File

@ -0,0 +1,11 @@
<div class="xpath_panel">
<label for="html_input">HTML Input</label>
<textarea id="html_input-{id}" rows="10" class="form-control">{html_input}</textarea>
<label for="xpath_expression">XPath Expression</label>
<input class="form-control xpath_expression"
data-target="{id}" type="text" value='{xpath_expression}' />
<label for="html_output">Result</label>
<div id="html_output-{id}" class="html_output"></div>
</div>

13
docs/_static/jquery.xpath.min.js vendored Normal file

File diff suppressed because one or more lines are too long

56
docs/_static/xpathdemo.css vendored Normal file
View File

@ -0,0 +1,56 @@
.xpath_panel {
border: 1px solid black;
border-radius: 5px;
padding: 10px;
margin-top: 20px;
margin-bottom: 20px;
}
.xpath_panel > label {
margin-top: 10px;
margin-bottom: 2px;
}
.xpath_panel > .html_output {
border: solid 1px #8D8D8D;
background-color: #F2F2F2;
min-height: 25px;
border-radius: 5px;
font-family: monospace;
}
.result_node {
margin: 10px;
border: solid 1px #8D8D8D;
background-color: #fff;
min-height: 25px;
padding: 4px 8px;
border-radius: 5px;
}
.result_node + .result_node {
margin-top: 10px;
}
.error_output {
color: #FD7C82;
border: solid 1px #FD7C82;
text-align: center;
vertical-align: middle;
}
.xpath_panel > textarea {
min-height: 200px;
overflow-y: scroll;
}
.xpath_panel > input {
width: 100%;
}
.xpath_panel > input,
.xpath_panel > textarea {
font-family: monospace;
font-size: 14px;
border-radius: 5px;
}

52
docs/_static/xpathdemo.js vendored Normal file
View File

@ -0,0 +1,52 @@
$(function(){
function evalXPath($xpath, $html_input) {
var $node = $($.parseXML($html_input.val()));
var xpathExpr = $xpath.val();
console.log('expr', xpathExpr);
return $node.xpath(xpathExpr);
}
function nodeToString(node) {
if (node.nodeType == 2)
return node.value;
if (node.nodeType == 3)
return node.wholeText;
if (node.nodeType == 8)
return "<!--" + node.textContent + "-->";
if (node.outerHTML === undefined)
return node;
return node.outerHTML;
}
function evalXPathUpdateResult() {
var $xpath = $(this);
var target_id = $xpath.data('target');
var $html_input = $('#html_input-' + target_id);
var $html_output = $('#html_output-' + target_id);
try {
var nodes = evalXPath($xpath, $html_input);
var htmlNodes = $.map(nodes, function(node){
return $("<div>").text(nodeToString(node)).addClass("result_node");
});
$html_output.removeClass('error_output');
$html_output.html(htmlNodes)
console.info('nodes', nodes);
} catch (e) {
// don't show the "expected expression" message when empty
if (e.code === "XPST0003" && $xpath.val() === '') {
$html_output.html('');
} else {
$html_output.addClass('error_output');
// TODO: show nicer error message
$html_output.html("ERROR: " + e.message);
}
console.error(e);
}
}
$('.xpath_expression').on('keyup', evalXPathUpdateResult);
$('.xpath_expression').each(evalXPathUpdateResult);
})

View File

@ -1,7 +1,11 @@
{% extends "!layout.html" %}
{% block footer %}
{{ super() }}
<script type="text/javascript" src="{{ pathto('_static/jquery.xpath.min.js', 1) }}"></script>
<script type="text/javascript" src="{{ pathto('_static/xpathdemo.js', 1) }}"></script>
<link rel="stylesheet" href="{{ pathto('_static/xpathdemo.css', 1) }}" type="text/css" />
<script type="text/javascript">
!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t){var e=document.createElement("script");e.type="text/javascript";e.async=!0;e.src=("https:"===document.location.protocol?"https://":"http://")+"cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(e,n)};analytics.SNIPPET_VERSION="3.1.0";
analytics.load("8UDQfnf3cyFSTsM4YANnW5sXmgZVILbA");

View File

@ -28,7 +28,8 @@ sys.path.insert(0, path.dirname(path.dirname(__file__)))
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'scrapydocs',
'sphinx.ext.autodoc'
'sphinx.ext.autodoc',
'xpathdemo',
]
# Add any paths that contain templates here, relative to this directory.

View File

@ -159,6 +159,8 @@ Solving specific problems
topics/autothrottle
topics/benchmarking
topics/jobs
topics/xpath-tutorial
:doc:`faq`
Get answers to most frequently asked questions.

View File

@ -0,0 +1,28 @@
==============
XPath Tutorial
==============
Welcome to the xpath tutorial. Have a look at this expression:
.. xpathdemo:: //h2/a
<html>
<head>
<title>My page</title>
</head>
<body>
<h2>Welcome to my <a href="#">page</a></h2>
<p>This is the first paragraph</p>.
<!-- this is the end -->
</body>
</html>
And this one :-) :
.. xpathdemo:: //h2
<html>
<h2>Welcome to my <a href="#">page</a></h2>
<p>This is the first paragraph</p>.
<!-- this is the end -->
</html>