# -*- coding: utf-8 -*-
"""
Defines a sphinx extension to add button to share a page
:githublink:`%|py|6`
"""
import sphinx
from docutils import nodes
from docutils.parsers.rst import Directive, directives
[docs]class sharenet_node(nodes.Structural, nodes.Element):
"""
Defines *sharenet* node.
:githublink:`%|py|15`
"""
pass
[docs]class ShareNetDirective(Directive):
"""
Adds buttons to share a page. It can be done by
adding::
.. sharenet::
:facebook: 1
:linkedin: 2
:twitter: 3
:head: False
Which gives:
.. sharenet::
:facebook: 1
:linkedin: 2
:twitter: 3
:head: False
The integer indicates the order in which they need to be displayed.
It is optional. The option ``:head: False`` specifies the javascript
part is added to the html body and not the header.
The header can be overwritten by other custom commands.
:githublink:`%|py|42`
"""
available_networks = {'facebook', 'linkedin', 'twitter'}
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = True
option_spec = {'facebook': directives.unchanged,
'linkedin': directives.unchanged,
'twitter': directives.unchanged,
'size': directives.unchanged,
'head': directives.unchanged,
}
has_content = True
sharenet_class = sharenet_node
[docs] def run(self):
"""
Runs the directve.
:return: a list of nodes
:githublink:`%|py|61`
"""
def options_to_int(s):
"local function"
if s is None:
return -1
elif len(s) == 0:
return 1e6
else:
return int(s)
# list of networks
bool_set = (True, 1, "True", "1", "true")
p = [(options_to_int(self.options.get(net, None)), net)
for net in ShareNetDirective.available_networks]
p.sort()
p = [a[1] for a in p if a[0] >= 0]
# build node
node = self.__class__.sharenet_class(networks=p,
size=self.options.get('size', 20),
inhead=self.options.get('head', True) in bool_set)
node['classes'] += ["sharenet"]
ns = [node]
return ns
[docs]def sharenet_role(role, rawtext, text, lineno, inliner,
options=None, content=None):
"""
Defines custom roles *sharenet*. The following instructions defines
buttons of size 20 (:sharenet:`facebook-linkedin-twitter-20-body`)::
:sharenet:`facebook-linkedin-twitter-20-body`
The last term indicates the javascript part will be included in the
HTML body instead of the head as this part might be tweaked by other
custom commands.
:param role: The role name used in the document.
:param rawtext: The entire markup snippet, with role.
:param text: The text marked with the role.
:param lineno: The line number where rawtext appears in the input.
:param inliner: The inliner instance that called us.
:param options: Directive options for customization.
:param content: The directive content for customization.
:githublink:`%|py|106`
"""
if options is None:
options = {}
if content is None:
content = []
spl = [a.strip().lower() for a in text.split('-')]
networks = []
size = 20
inhead = True
for v in spl:
if v in ShareNetDirective.available_networks:
networks.append(v)
elif v == "body":
inhead = False
elif v == "head":
inhead = True
else:
try:
i = int(v)
size = i
except ValueError: # pragma: no cover
msg = inliner.reporter.error(
"unable to interpret {0} from {1}".format(v, rawtext), line=lineno)
prb = inliner.problematic(rawtext, rawtext, msg)
return [prb], [msg]
if len(networks) == 0:
msg = inliner.reporter.error(
"no specified network from {0}".format(rawtext), line=lineno)
prb = inliner.problematic(rawtext, rawtext, msg)
return [prb], [msg]
# ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum
# set_classes(options)
node = sharenet_node(networks=networks, size=size, inhead=inhead)
node['classes'] += ["sharenet"]
return [node], []
[docs]def visit_sharenet_node(self, node):
"""
what to do when visiting a node sharenet
the function should have different behaviour,
depending on the format, or the setup should
specify a different function for each.
:githublink:`%|py|151`
"""
pass
[docs]def depart_sharenet_node_html(self, node):
"""
what to do when leaving a node sharenet
the function should have different behaviour,
depending on the format, or the setup should
specify a different function for each.
It does only html for the time being.
:githublink:`%|py|163`
"""
if node.hasattr("networks"):
networks = node["networks"]
size = node["size"]
inhead = node["inhead"]
if len(networks) > 0:
script = """
<script>
function share_url(share) {
var url = share + encodeURIComponent(window.location.href);
window.location.href = url;
}
function share_icon(divid, text) {
var canvas = document.getElementById(divid);
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = centerX;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = '#444444';
context.fill();
context.font = '' + (centerX*4/3) + 'pt Calibri';
context.textAlign = 'center';
context.fillStyle = '#FFFFFF';
context.fillText(text, centerX, centerY+centerY*16/30);
}
</script>
""".replace(" ", "")
mapping = dict(facebook="f", linkedin="in", twitter="t")
urls = dict(facebook="https://www.facebook.com/sharer/sharer.php?u=",
twitter="https://twitter.com/home?status=",
linkedin="https://www.linkedin.com/shareArticle?mini=true&title=&summary=&source=&url=")
link = """<a href="#" onclick="share_url('{0}');return false;"><canvas height="{2}" id="canvas-{1}" width="{2}"/>""" + \
"""</a><script>share_icon('canvas-{1}', '{1}');</script>"""
rows = []
for key in networks:
text = mapping[key]
ld = link.format(urls[key], text, size)
rows.append(ld)
if len(rows) > 0:
if inhead:
self.head.append(script)
else:
self.body.append(script)
self.body.extend(rows)
[docs]def depart_sharenet_node(self, node):
"""
what to do when leaving a node sharenet
the function should have different behaviour,
depending on the format, or the setup should
specify a different function for each.
It does only html for the time being.
:githublink:`%|py|225`
"""
pass
[docs]def visit_sharenet_node_rst(self, node):
"""
what to do when visiting a node sharenet
the function should have different behaviour,
depending on the format, or the setup should
specify a different function for each.
:githublink:`%|py|235`
"""
inside = "-".join(node['networks'])
inside = "{0}-{1}-{2}".format(inside,
node["size"], "head" if node['inhead'] else "body")
self.add_text(":sharenet:`{0}`".format(inside))
[docs]def depart_sharenet_node_rst(self, node):
"""
what to do when leaving a node sharenet
the function should have different behaviour,
depending on the format, or the setup should
specify a different function for each.
:githublink:`%|py|248`
"""
pass
[docs]def setup(app):
"""
setup for ``sharenet`` (sphinx)
:githublink:`%|py|255`
"""
if hasattr(app, "add_mapping"):
app.add_mapping('sharenet', sharenet_node)
app.add_node(sharenet_node,
html=(visit_sharenet_node, depart_sharenet_node_html),
epub=(visit_sharenet_node, depart_sharenet_node_html),
elatex=(visit_sharenet_node, depart_sharenet_node),
latex=(visit_sharenet_node, depart_sharenet_node),
rst=(visit_sharenet_node_rst, depart_sharenet_node_rst),
md=(visit_sharenet_node_rst, depart_sharenet_node_rst),
text=(visit_sharenet_node, depart_sharenet_node))
app.add_directive('sharenet', ShareNetDirective)
app.add_role('sharenet', sharenet_role)
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}