From 49065e6ae0535da596ec92ae55202133957a56cb Mon Sep 17 00:00:00 2001 From: Ankita Saxena Date: Thu, 14 Dec 2017 10:51:25 +0530 Subject: [PATCH] Added video directive (#370) * added video extension * import extension in configuration file * ignore pycache * used video directive * minor fix * alt option added * alternate text for non html builders * added support for html attributes * added robust alt content support * minor fix * changed poster copy over location --- .gitignore | 1 + conf.py | 15 ++--- form-widgets.rst | 20 +------ video.py | 150 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 24 deletions(-) create mode 100644 video.py diff --git a/.gitignore b/.gitignore index 00b7b021f..abf4457a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ +__pycache__/ .DS_Store \#*.*\# .\#* \ No newline at end of file diff --git a/conf.py b/conf.py index 708ecc517..5dbbce4cc 100644 --- a/conf.py +++ b/conf.py @@ -17,10 +17,10 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - +import os +import sys +sys.path.insert(0, os.path.abspath('.')) +import video # -- General configuration ------------------------------------------------ @@ -36,7 +36,8 @@ 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', - 'sphinx.ext.mathjax'] + 'sphinx.ext.mathjax', + 'video'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -115,8 +116,8 @@ html_static_path = ['_static'] # Add paths that contain extra files which are not directly related to the -# documentation and which are are copied to the output directory. -html_extra_path = ['vid'] +# documentation and which are copied to the output directory. +# html_extra_path = [] # -- Options for HTMLHelp output ------------------------------------------ diff --git a/form-widgets.rst b/form-widgets.rst index ac8611324..9e3da1ed7 100644 --- a/form-widgets.rst +++ b/form-widgets.rst @@ -15,7 +15,6 @@ Basic Form Widgets This section shows examples of all the form widgets types, with no additional options displayed. - .. _string-input: String Input @@ -1649,12 +1648,7 @@ Autoadvance Widget Advances immediately to the next question once a selection is made. -.. raw:: html - - - +.. video:: /vid/form-widgets/auto-advance.mp4 XLSForm Rows """"""""""""" @@ -1986,11 +1980,7 @@ Compact Single Select with Images and Autoadvance The :tc:`quickcompact` appearance attribute combines the design of the :ref:`compact-single-image-select` widget with the :ref:`autoadvance-widget` functionality. -.. raw:: html - - +.. video:: /vid/form-widgets/quickcompact.mp4 XLSForm Rows """"""""""""" @@ -2043,11 +2033,7 @@ Compact Single Select with Images and Autoadvance, width specified As with :ref:`compact `, you can specify a width when using :tc:`quickcompact`. To display two images on each row, set the :th:`appearance` attribute to :tc:`quickcompact-2`. -.. raw:: html - - +.. video:: /vid/form-widgets/quickcompact2.mp4 XLSForm Rows """""""""""""" diff --git a/video.py b/video.py new file mode 100644 index 000000000..0003f9c0a --- /dev/null +++ b/video.py @@ -0,0 +1,150 @@ +import os +import shutil +from docutils import nodes +from docutils.parsers.rst import directives +from sphinx.util.compat import Directive + +def yes_no(name, arg): + + if arg == 'yes' or arg == 'true': + return name + elif arg == 'no' or arg == 'false': + return None + else: + raise Exception("Value for {} attribute can only be a boolean" .format(name)) + +def preload_choice(arg): + + if arg == 'auto' or arg == 'metadata' or arg == 'none': + return arg + else: + raise Exception("Value for preload attribute can only be auto, metadata or none") + +class video_node(nodes.General, nodes.Element): pass + +def visit_video_html(self, node): + + if os.path.exists("./build/_videos"): + pass + else: + os.makedirs("./build/_videos/") + + vsrc = node["uri"] + spth = ".%s" % vsrc + dpth = "./build/_videos/%s" %vsrc[vsrc.rfind('/')+1:] + + shutil.copyfile(spth, dpth) + + src = "../_videos/%s" % vsrc[vsrc.rfind('/')+1:] + + attrs = { + "src":"%s" %src, + "style":"max-width:100%", + } + + if node["poster"] is not None: + psrc = node["poster"] + p_spth = ".%s" % psrc + p_dpth = "./build/_videos/%s" %psrc[psrc.rfind('/')+1:] + + shutil.copyfile(p_spth, p_dpth) + + psrc = "../_videos/%s" % psrc[psrc.rfind('/')+1:] + attrs["poster"] = "%s" % psrc + + if node["autoplay"] == "autoplay": + attrs["autoplay"] = "autoplay" + + if node["controls"] == "controls": + attrs["controls"] = "controls" + + if node["loop"] == "loop": + attrs["loop"] = "loop" + + if node["muted"] == "muted": + attrs["muted"] = "muted" + + if node["preload"] is not None: + attrs["preload"] = "%s" % node["preload"] + + if node["cl"] is not None: + attrs["class"] = "%s" % node["cl"] + + self.body.append(self.starttag(node, "video", **attrs)) + +def depart_video_html(self, node): + self.body.append("") + +def visit_video_nonhtml(self, node): + pass + +def depart_video_nonhtml(self,node): + pass + +class Video(Directive): + + has_content = True + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = True + option_spec = { + 'autoplay' : directives.unchanged, + 'controls' : directives.unchanged, + 'loop' : directives.unchanged, + 'muted' : directives.unchanged, + 'poster' : directives.unchanged, + 'preload' : directives.unchanged, + 'class' : directives.unchanged, + } + + + def run(self): + + autoplay = None + controls = "controls" + loop = None + muted = "muted" + poster = None + preload = None + cl = None + + if "autoplay" in self.options: + autoplay = yes_no("autoplay",self.options["autoplay"]) + + if "controls" in self.options: + controls = yes_no("controls",self.options["controls"]) + + if "loop" in self.options: + loop = yes_no("loop",self.options["loop"]) + + if "muted" in self.options: + muted = yes_no("muted",self.options["muted"]) + + if "poster" in self.options: + poster = directives.uri(self.options["poster"]) + + if "preload" in self.options: + preload = preload_choice(self.options["preload"]) + + if "class" in self.options: + cl = self.options["class"] + + uri = directives.uri(self.arguments[0]) + + vid = video_node(uri = uri, autoplay = autoplay, controls = controls, + loop = loop, muted = muted, poster = poster, + preload = preload, cl = cl) + + self.state.nested_parse(self.content, self.content_offset, vid) + + return [vid] + +def setup(app): + + app.add_node(video_node, html = (visit_video_html, depart_video_html), + latex = (visit_video_nonhtml, depart_video_nonhtml), + epub = (visit_video_nonhtml, depart_video_nonhtml), + text = (visit_video_nonhtml, depart_video_nonhtml), + ) + app.add_directive("video", Video) +