summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml11
-rw-r--r--AUTHORS12
-rw-r--r--CHANGES257
-rw-r--r--MANIFEST.in4
-rw-r--r--Makefile3
-rw-r--r--doc/Makefile8
-rw-r--r--doc/_static/bookcover.pngbin29597 -> 27523 bytes
-rw-r--r--doc/_static/conf.py.txt360
-rw-r--r--doc/_static/pocoo.pngbin2003 -> 1498 bytes
-rw-r--r--doc/_static/sphinx.pngbin36665 -> 34213 bytes
-rw-r--r--doc/_templates/index.html21
-rw-r--r--doc/_themes/sphinx13/static/bodybg.pngbin513 -> 429 bytes
-rw-r--r--doc/_themes/sphinx13/static/footerbg.pngbin220 -> 180 bytes
-rw-r--r--doc/_themes/sphinx13/static/headerbg.pngbin230 -> 189 bytes
-rw-r--r--doc/_themes/sphinx13/static/listitem.pngbin207 -> 149 bytes
-rw-r--r--doc/_themes/sphinx13/static/relbg.pngbin223 -> 183 bytes
-rw-r--r--doc/_themes/sphinx13/static/sphinx13.css6
-rw-r--r--doc/_themes/sphinx13/static/sphinxheader.pngbin12567 -> 11719 bytes
-rw-r--r--doc/builders.rst15
-rw-r--r--doc/conf.py3
-rw-r--r--doc/config.rst278
-rw-r--r--doc/contents.rst17
-rw-r--r--doc/domains.rst108
-rw-r--r--doc/ext/builtins.rst24
-rw-r--r--doc/ext/doctest.rst23
-rw-r--r--doc/ext/example_google.py65
-rw-r--r--doc/ext/example_numpy.py79
-rw-r--r--doc/ext/graphviz.rst4
-rw-r--r--doc/ext/inheritance.rst5
-rw-r--r--doc/ext/intersphinx.rst11
-rw-r--r--doc/ext/napoleon.rst85
-rw-r--r--doc/ext/thirdparty.rst35
-rw-r--r--doc/ext/todo.rst15
-rw-r--r--doc/ext/viewcode.rst28
-rw-r--r--doc/extdev/appapi.rst2
-rw-r--r--doc/extdev/nodes.rst1
-rw-r--r--doc/extensions.rst61
-rw-r--r--doc/faq.rst40
-rw-r--r--doc/install.rst6
-rw-r--r--doc/installpython.jpgbin28408 -> 25206 bytes
-rw-r--r--doc/intro.rst2
-rw-r--r--doc/invocation.rst43
-rw-r--r--doc/latex.rst445
-rw-r--r--doc/man/sphinx-apidoc.rst1
-rw-r--r--doc/markup/code.rst2
-rw-r--r--doc/markup/inline.rst11
-rw-r--r--doc/markup/misc.rst11
-rw-r--r--doc/markup/toctree.rst10
-rw-r--r--doc/more.pngbin1473 -> 1351 bytes
-rw-r--r--doc/pythonorg.pngbin153185 -> 149780 bytes
-rw-r--r--doc/rest.rst8
-rw-r--r--doc/themes/agogo.pngbin29278 -> 25792 bytes
-rw-r--r--doc/themes/alabaster.pngbin33972 -> 32356 bytes
-rw-r--r--doc/themes/bizstyle.pngbin36234 -> 27139 bytes
-rw-r--r--doc/themes/classic.pngbin43969 -> 39927 bytes
-rw-r--r--doc/themes/fullsize/agogo.pngbin61906 -> 56954 bytes
-rw-r--r--doc/themes/fullsize/alabaster.pngbin55934 -> 40248 bytes
-rw-r--r--doc/themes/fullsize/bizstyle.pngbin103961 -> 75192 bytes
-rw-r--r--doc/themes/fullsize/classic.pngbin78947 -> 72597 bytes
-rw-r--r--doc/themes/fullsize/haiku.pngbin88689 -> 84200 bytes
-rw-r--r--doc/themes/fullsize/nature.pngbin36087 -> 32266 bytes
-rw-r--r--doc/themes/fullsize/pyramid.pngbin107322 -> 102717 bytes
-rw-r--r--doc/themes/fullsize/scrolls.pngbin97121 -> 88111 bytes
-rw-r--r--doc/themes/fullsize/sphinx_rtd_theme.pngbin57187 -> 39411 bytes
-rw-r--r--doc/themes/fullsize/sphinxdoc.pngbin91063 -> 84439 bytes
-rw-r--r--doc/themes/fullsize/traditional.pngbin99337 -> 91744 bytes
-rw-r--r--doc/themes/haiku.pngbin44727 -> 43184 bytes
-rw-r--r--doc/themes/nature.pngbin32041 -> 28536 bytes
-rw-r--r--doc/themes/pyramid.pngbin40085 -> 38805 bytes
-rw-r--r--doc/themes/scrolls.pngbin31717 -> 27800 bytes
-rw-r--r--doc/themes/sphinx_rtd_theme.pngbin31686 -> 29138 bytes
-rw-r--r--doc/themes/sphinxdoc.pngbin33091 -> 30225 bytes
-rw-r--r--doc/themes/traditional.pngbin35367 -> 32258 bytes
-rw-r--r--doc/theming.rst2
-rw-r--r--doc/translation.pngbin14572 -> 13791 bytes
-rw-r--r--setup.cfg2
-rw-r--r--setup.py44
-rw-r--r--sphinx/__init__.py12
-rw-r--r--sphinx/addnodes.py60
-rw-r--r--sphinx/apidoc.py64
-rw-r--r--sphinx/application.py81
-rw-r--r--sphinx/builders/__init__.py27
-rw-r--r--sphinx/builders/applehelp.py57
-rw-r--r--sphinx/builders/changes.py47
-rw-r--r--sphinx/builders/devhelp.py32
-rw-r--r--sphinx/builders/dummy.py4
-rw-r--r--sphinx/builders/epub.py69
-rw-r--r--sphinx/builders/epub3.py87
-rw-r--r--sphinx/builders/gettext.py26
-rw-r--r--sphinx/builders/html.py180
-rw-r--r--sphinx/builders/htmlhelp.py36
-rw-r--r--sphinx/builders/latex.py140
-rw-r--r--sphinx/builders/linkcheck.py139
-rw-r--r--sphinx/builders/manpage.py11
-rw-r--r--sphinx/builders/qthelp.py29
-rw-r--r--sphinx/builders/texinfo.py24
-rw-r--r--sphinx/builders/text.py12
-rw-r--r--sphinx/builders/websupport.py4
-rw-r--r--sphinx/builders/xml.py12
-rw-r--r--sphinx/cmdline.py114
-rw-r--r--sphinx/config.py242
-rw-r--r--sphinx/directives/__init__.py26
-rw-r--r--sphinx/directives/code.py61
-rw-r--r--sphinx/directives/other.py46
-rw-r--r--sphinx/directives/patches.py26
-rw-r--r--sphinx/domains/__init__.py17
-rw-r--r--sphinx/domains/c.py4
-rw-r--r--sphinx/domains/cpp.py489
-rw-r--r--sphinx/domains/javascript.py4
-rw-r--r--sphinx/domains/python.py35
-rw-r--r--sphinx/domains/rst.py4
-rw-r--r--sphinx/domains/std.py287
-rw-r--r--sphinx/environment/__init__.py (renamed from sphinx/environment.py)968
-rw-r--r--sphinx/environment/managers/__init__.py37
-rw-r--r--sphinx/environment/managers/indexentries.py172
-rw-r--r--sphinx/environment/managers/toctree.py561
-rw-r--r--sphinx/errors.py5
-rw-r--r--sphinx/ext/autodoc.py39
-rw-r--r--sphinx/ext/autosummary/__init__.py33
-rw-r--r--sphinx/ext/coverage.py20
-rw-r--r--sphinx/ext/doctest.py7
-rw-r--r--sphinx/ext/graphviz.py38
-rw-r--r--sphinx/ext/imgmath.py5
-rw-r--r--sphinx/ext/inheritance_diagram.py8
-rw-r--r--sphinx/ext/intersphinx.py119
-rw-r--r--sphinx/ext/jsmath.py6
-rw-r--r--sphinx/ext/mathbase.py186
-rw-r--r--sphinx/ext/mathjax.py5
-rw-r--r--sphinx/ext/napoleon/__init__.py95
-rw-r--r--sphinx/ext/napoleon/docstring.py127
-rw-r--r--sphinx/ext/todo.py7
-rw-r--r--sphinx/ext/viewcode.py5
-rw-r--r--sphinx/io.py30
-rw-r--r--sphinx/jinja2glue.py4
-rw-r--r--sphinx/locale/sphinx.pot336
-rw-r--r--sphinx/make_mode.py48
-rw-r--r--sphinx/pycode/__init__.py2
-rw-r--r--sphinx/pycode/pgen2/driver.py46
-rw-r--r--sphinx/pycode/pgen2/pgen.py5
-rw-r--r--sphinx/quickstart.py1158
-rw-r--r--sphinx/roles.py19
-rw-r--r--sphinx/search/__init__.py68
-rw-r--r--sphinx/search/en.py2
-rw-r--r--sphinx/search/test (renamed from tests/roots/test-html_extra_path/extra/.htaccess)0
-rw-r--r--sphinx/setup_command.py47
-rw-r--r--sphinx/templates/latex/content.tex_t52
-rw-r--r--sphinx/templates/quickstart/Makefile.new_t20
-rw-r--r--sphinx/templates/quickstart/Makefile_t242
-rw-r--r--sphinx/templates/quickstart/conf.py_t193
-rw-r--r--sphinx/templates/quickstart/make.bat.new_t34
-rw-r--r--sphinx/templates/quickstart/make.bat_t282
-rw-r--r--sphinx/templates/quickstart/master_doc.rst_t21
-rw-r--r--sphinx/texinputs/Makefile_t (renamed from sphinx/texinputs/Makefile)14
-rw-r--r--sphinx/texinputs/fncychap.sty683
-rw-r--r--sphinx/texinputs/footnotehyper-sphinx.sty156
-rwxr-xr-xsphinx/texinputs/iftex.sty97
-rw-r--r--sphinx/texinputs/newfloat.sty737
-rw-r--r--sphinx/texinputs/sphinx.sty881
-rw-r--r--sphinx/texinputs/sphinxhowto.cls37
-rw-r--r--sphinx/texinputs/sphinxmanual.cls44
-rw-r--r--sphinx/texinputs/tabulary.sty452
-rw-r--r--sphinx/themes/agogo/static/agogo.css_t14
-rw-r--r--sphinx/themes/agogo/static/bgfooter.pngbin434 -> 276 bytes
-rw-r--r--sphinx/themes/agogo/static/bgtop.pngbin430 -> 266 bytes
-rw-r--r--sphinx/themes/basic/defindex.html6
-rw-r--r--sphinx/themes/basic/domainindex.html2
-rw-r--r--sphinx/themes/basic/genindex-single.html16
-rw-r--r--sphinx/themes/basic/genindex.html16
-rw-r--r--sphinx/themes/basic/layout.html7
-rw-r--r--sphinx/themes/basic/static/basic.css_t57
-rw-r--r--sphinx/themes/basic/static/comment-bright.pngbin3500 -> 756 bytes
-rw-r--r--sphinx/themes/basic/static/comment-close.pngbin3578 -> 829 bytes
-rw-r--r--sphinx/themes/basic/static/comment.pngbin3445 -> 641 bytes
-rw-r--r--sphinx/themes/basic/static/down-pressed.pngbin347 -> 222 bytes
-rw-r--r--sphinx/themes/basic/static/down.pngbin347 -> 202 bytes
-rw-r--r--sphinx/themes/basic/static/file.pngbin358 -> 286 bytes
-rw-r--r--sphinx/themes/basic/static/jquery-3.1.0.js (renamed from sphinx/themes/basic/static/jquery-1.11.1.js)8518
-rw-r--r--sphinx/themes/basic/static/jquery.js8
-rw-r--r--sphinx/themes/basic/static/minus.pngbin173 -> 90 bytes
-rw-r--r--sphinx/themes/basic/static/plus.pngbin173 -> 90 bytes
-rw-r--r--sphinx/themes/basic/static/searchtools.js_t13
-rw-r--r--sphinx/themes/basic/static/up-pressed.pngbin345 -> 214 bytes
-rw-r--r--sphinx/themes/basic/static/up.pngbin345 -> 203 bytes
-rw-r--r--sphinx/themes/bizstyle/static/background_b01.pngbin87 -> 78 bytes
-rw-r--r--sphinx/themes/classic/layout.html4
-rw-r--r--sphinx/themes/classic/static/classic.css_t4
-rw-r--r--sphinx/themes/epub/layout.html11
-rw-r--r--sphinx/themes/epub/static/epub.css_t591
-rw-r--r--sphinx/themes/haiku/static/alert_info_32.pngbin1168 -> 1128 bytes
-rw-r--r--sphinx/themes/haiku/static/alert_warning_32.pngbin1060 -> 944 bytes
-rw-r--r--sphinx/themes/haiku/static/bg-page.pngbin147 -> 82 bytes
-rw-r--r--sphinx/themes/haiku/static/bullet_orange.pngbin365 -> 165 bytes
-rw-r--r--sphinx/themes/nonav/layout.html23
-rw-r--r--sphinx/themes/nonav/static/nonav.css (renamed from sphinx/themes/epub/static/epub.css)50
-rw-r--r--sphinx/themes/nonav/theme.conf8
-rw-r--r--sphinx/themes/pyramid/static/dialog-note.pngbin1461 -> 1394 bytes
-rw-r--r--sphinx/themes/pyramid/static/dialog-seealso.pngbin1473 -> 1351 bytes
-rw-r--r--sphinx/themes/pyramid/static/dialog-todo.pngbin1311 -> 1186 bytes
-rw-r--r--sphinx/themes/pyramid/static/dialog-topic.pngbin1910 -> 1798 bytes
-rw-r--r--sphinx/themes/pyramid/static/dialog-warning.pngbin1365 -> 1280 bytes
-rw-r--r--sphinx/themes/pyramid/static/headerbg.pngbin203 -> 190 bytes
-rw-r--r--sphinx/themes/pyramid/static/middlebg.pngbin2763 -> 101 bytes
-rw-r--r--sphinx/themes/scrolls/static/darkmetal.pngbin25389 -> 25238 bytes
-rw-r--r--sphinx/themes/scrolls/static/headerbg.pngbin298 -> 172 bytes
-rw-r--r--sphinx/themes/scrolls/static/logo.pngbin8654 -> 8305 bytes
-rw-r--r--sphinx/themes/scrolls/static/metal.pngbin7939 -> 7547 bytes
-rw-r--r--sphinx/themes/scrolls/static/navigation.pngbin216 -> 124 bytes
-rw-r--r--sphinx/themes/scrolls/static/scrolls.css_t16
-rw-r--r--sphinx/themes/scrolls/static/watermark.pngbin53916 -> 44483 bytes
-rw-r--r--sphinx/themes/scrolls/static/watermark_blur.pngbin8970 -> 8049 bytes
-rw-r--r--sphinx/themes/sphinxdoc/static/contents.pngbin202 -> 107 bytes
-rw-r--r--sphinx/themes/sphinxdoc/static/navigation.pngbin218 -> 120 bytes
-rw-r--r--sphinx/themes/traditional/static/traditional.css_t14
-rw-r--r--sphinx/theming.py5
-rw-r--r--sphinx/transforms/__init__.py223
-rw-r--r--sphinx/transforms/compact_bullet_list.py82
-rw-r--r--sphinx/transforms/i18n.py (renamed from sphinx/transforms.py)226
-rw-r--r--sphinx/util/__init__.py55
-rw-r--r--sphinx/util/compat.py2
-rw-r--r--sphinx/util/docfields.py28
-rw-r--r--sphinx/util/docutils.py99
-rw-r--r--sphinx/util/fileutil.py82
-rw-r--r--sphinx/util/i18n.py12
-rw-r--r--sphinx/util/inspect.py14
-rw-r--r--sphinx/util/matching.py21
-rw-r--r--sphinx/util/nodes.py49
-rw-r--r--sphinx/util/osutil.py90
-rw-r--r--sphinx/util/png.py15
-rw-r--r--sphinx/util/pycompat.py7
-rw-r--r--sphinx/util/requests.py55
-rw-r--r--sphinx/util/template.py61
-rw-r--r--sphinx/websupport/__init__.py12
-rw-r--r--sphinx/websupport/search/__init__.py8
-rw-r--r--sphinx/websupport/search/nullsearch.py2
-rw-r--r--sphinx/websupport/search/whooshsearch.py2
-rw-r--r--sphinx/writers/html.py40
-rw-r--r--sphinx/writers/latex.py539
-rw-r--r--sphinx/writers/manpage.py6
-rw-r--r--sphinx/writers/text.py13
-rw-r--r--test-reqs.txt3
-rwxr-xr-xtests/coverage.py16
-rw-r--r--tests/root/Makefile2
-rw-r--r--tests/root/autodoc_missing_imports.py9
-rw-r--r--tests/root/img.foo.pngbin67765 -> 66247 bytes
-rw-r--r--tests/root/img.pngbin67765 -> 66247 bytes
-rw-r--r--tests/root/objects.txt8
-rw-r--r--tests/root/pep_0420/a/b/c/__init__.py1
-rw-r--r--tests/root/pep_0420/a/b/c/d.py1
-rw-r--r--tests/root/pep_0420/a/b/x/y.py1
-rw-r--r--tests/root/rimg.pngbin218 -> 120 bytes
-rw-r--r--tests/root/subdir/img.pngbin67765 -> 66247 bytes
-rw-r--r--tests/root/subdir/simg.pngbin67765 -> 66247 bytes
-rw-r--r--tests/root/testtheme/static/staticimg.pngbin218 -> 120 bytes
-rw-r--r--tests/roots/test-add_enumerable_node/rimg.pngbin218 -> 120 bytes
-rw-r--r--tests/roots/test-config/conf.py3
-rw-r--r--tests/roots/test-directive-code/lineno_match.rst6
-rw-r--r--tests/roots/test-ext-autodoc/autodoc_dummy_module.py6
-rw-r--r--tests/roots/test-ext-autodoc/conf.py12
-rw-r--r--tests/roots/test-ext-autodoc/contents.rst3
-rw-r--r--tests/roots/test-ext-graphviz/index.rst6
-rw-r--r--tests/roots/test-ext-inheritance_diagram/index.rst3
-rw-r--r--tests/roots/test-ext-math/index.rst4
-rw-r--r--tests/roots/test-ext-todo/bar.rst4
-rw-r--r--tests/roots/test-ext-todo/conf.py4
-rw-r--r--tests/roots/test-ext-todo/foo.rst4
-rw-r--r--tests/roots/test-ext-todo/index.rst9
-rw-r--r--tests/roots/test-footnotes/index.rst28
-rw-r--r--tests/roots/test-footnotes/rimg.pngbin218 -> 120 bytes
-rw-r--r--tests/roots/test-html_assets/conf.py (renamed from tests/roots/test-html_extra_path/conf.py)3
-rw-r--r--tests/roots/test-html_assets/extra/.htaccess (renamed from tests/roots/test-html_extra_path/extra/.htpasswd)0
-rw-r--r--tests/roots/test-html_assets/extra/.htpasswd (renamed from tests/roots/test-html_extra_path/extra/API.html_t)0
-rw-r--r--tests/roots/test-html_assets/extra/API.html_t1
-rw-r--r--tests/roots/test-html_assets/extra/css/style.css (renamed from tests/roots/test-html_extra_path/extra/css/style.css)0
-rw-r--r--tests/roots/test-html_assets/extra/rimg.pngbin0 -> 120 bytes
-rw-r--r--tests/roots/test-html_assets/extra/subdir/.htaccess (renamed from tests/roots/test-html_extra_path/subdir/_build/index.html)0
-rw-r--r--tests/roots/test-html_assets/extra/subdir/.htpasswd0
-rw-r--r--tests/roots/test-html_assets/index.rst (renamed from tests/roots/test-html_extra_path/index.rst)0
-rw-r--r--tests/roots/test-html_assets/static/.htaccess0
-rw-r--r--tests/roots/test-html_assets/static/.htpasswd0
-rw-r--r--tests/roots/test-html_assets/static/API.html_t1
-rw-r--r--tests/roots/test-html_assets/static/css/style.css0
-rw-r--r--tests/roots/test-html_assets/static/rimg.pngbin0 -> 120 bytes
-rw-r--r--tests/roots/test-html_assets/static/subdir/.htaccess0
-rw-r--r--tests/roots/test-html_assets/static/subdir/.htpasswd0
-rw-r--r--tests/roots/test-html_assets/subdir/_build/index.html0
-rw-r--r--tests/roots/test-html_assets/subdir/background.pngbin0 -> 120 bytes
-rw-r--r--tests/roots/test-html_extra_path/extra/rimg.pngbin218 -> 0 bytes
-rw-r--r--tests/roots/test-html_extra_path/subdir/background.pngbin218 -> 0 bytes
-rw-r--r--tests/roots/test-image-glob/img.ja.pngbin67765 -> 66247 bytes
-rw-r--r--tests/roots/test-image-glob/img.pngbin67765 -> 66247 bytes
-rw-r--r--tests/roots/test-image-glob/img.zh.pngbin67765 -> 66247 bytes
-rw-r--r--tests/roots/test-image-glob/rimg.pngbin218 -> 120 bytes
-rw-r--r--tests/roots/test-image-glob/rimg.xx.pngbin218 -> 120 bytes
-rw-r--r--tests/roots/test-image-glob/subdir/rimg.pngbin218 -> 120 bytes
-rw-r--r--tests/roots/test-image-glob/subdir/rimg.xx.pngbin218 -> 120 bytes
-rw-r--r--tests/roots/test-image-glob/testimäge.pngbin67765 -> 66247 bytes
-rw-r--r--tests/roots/test-image-in-section/pic.pngbin218 -> 120 bytes
-rw-r--r--tests/roots/test-intl/contents.po26
-rw-r--r--tests/roots/test-intl/contents.txt5
-rw-r--r--tests/roots/test-intl/i18n.pngbin67765 -> 66247 bytes
-rw-r--r--tests/roots/test-intl/img.pngbin67765 -> 66247 bytes
-rw-r--r--tests/roots/test-intl/only.po29
-rw-r--r--tests/roots/test-intl/only.txt14
-rw-r--r--tests/roots/test-keep_warnings/conf.py4
-rw-r--r--tests/roots/test-keep_warnings/index.rst2
-rw-r--r--tests/roots/test-linkcheck/conf.py4
-rw-r--r--tests/roots/test-linkcheck/links.txt11
-rw-r--r--tests/roots/test-maxlistdepth/conf.py14
-rw-r--r--tests/roots/test-maxlistdepth/index.rst57
-rw-r--r--tests/roots/test-numfig/bar.rst8
-rw-r--r--tests/roots/test-numfig/baz.rst2
-rw-r--r--tests/roots/test-numfig/foo.rst10
-rw-r--r--tests/roots/test-numfig/index.rst7
-rw-r--r--tests/roots/test-numfig/rimg.pngbin218 -> 120 bytes
-rw-r--r--tests/roots/test-refonly_bullet_list/conf.py8
-rw-r--r--tests/roots/test-refonly_bullet_list/index.rst14
-rw-r--r--tests/roots/test-search/conf.py3
-rw-r--r--tests/roots/test-search/index.rst30
-rw-r--r--tests/roots/test-search/tocitem.rst10
-rw-r--r--tests/roots/test-toctree-glob/index.rst16
-rw-r--r--tests/roots/test-toctree-maxdepth/qux.rst9
-rw-r--r--tests/roots/test-toctree/bar.rst2
-rw-r--r--tests/roots/test-toctree/baz.rst2
-rw-r--r--tests/roots/test-toctree/conf.py7
-rw-r--r--tests/roots/test-toctree/foo.rst15
-rw-r--r--tests/roots/test-toctree/index.rst54
-rw-r--r--tests/roots/test-toctree/quux.rst2
-rw-r--r--tests/roots/test-toctree/qux.rst1
-rw-r--r--tests/roots/test-toctree/tocdepth.rst15
-rwxr-xr-xtests/run.py4
-rw-r--r--tests/test_api_translator.py2
-rw-r--r--tests/test_apidoc.py88
-rw-r--r--tests/test_application.py9
-rw-r--r--tests/test_autodoc.py61
-rw-r--r--tests/test_build.py29
-rw-r--r--tests/test_build_html.py186
-rw-r--r--tests/test_build_latex.py392
-rw-r--r--tests/test_build_linkcheck.py38
-rw-r--r--tests/test_build_texinfo.py5
-rw-r--r--tests/test_build_text.py2
-rw-r--r--tests/test_config.py16
-rw-r--r--tests/test_directive_code.py16
-rw-r--r--tests/test_directive_only.py3
-rw-r--r--tests/test_domain_cpp.py85
-rw-r--r--tests/test_domain_std.py4
-rw-r--r--tests/test_environment_indexentries.py136
-rw-r--r--tests/test_environment_toctree.py332
-rw-r--r--tests/test_ext_autodoc.py25
-rw-r--r--tests/test_ext_graphviz.py9
-rw-r--r--tests/test_ext_inheritance_diagram.py25
-rw-r--r--tests/test_ext_intersphinx.py97
-rw-r--r--tests/test_ext_math.py18
-rw-r--r--tests/test_ext_napoleon.py2
-rw-r--r--tests/test_ext_napoleon_docstring.py51
-rw-r--r--tests/test_ext_todo.py85
-rw-r--r--tests/test_intl.py60
-rw-r--r--tests/test_markup.py54
-rw-r--r--tests/test_quickstart.py13
-rw-r--r--tests/test_search.py73
-rw-r--r--tests/test_searchadapters.py2
-rw-r--r--tests/test_setup_command.py22
-rw-r--r--tests/test_theming.py8
-rw-r--r--tests/test_util_fileutil.py114
-rw-r--r--tests/test_util_i18n.py12
-rw-r--r--tests/test_util_matching.py91
-rw-r--r--tests/test_writer_latex.py36
-rw-r--r--tests/typing_test_data.py14
-rw-r--r--tests/util.py40
-rw-r--r--tox.ini25
-rwxr-xr-xutils/check_sources.py5
-rwxr-xr-xutils/reindent.py9
-rw-r--r--utils/release-checklist1
372 files changed, 15440 insertions, 11333 deletions
diff --git a/.travis.yml b/.travis.yml
index 501f427dd..5f035b73b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,16 +4,15 @@ cache:
directories:
- $HOME/.cache/pip
python:
- - "2.6"
- "2.7"
- - "3.3"
- "3.4"
- "3.5"
- - "3.5-dev"
+ - "nightly"
- "pypy"
env:
global:
- TEST='-v --with-timer --timer-top-n 25'
+ - PYTHONFAULTHANDLER=x
matrix:
- DOCUTILS=0.11
- DOCUTILS=0.12
@@ -25,12 +24,14 @@ addons:
- texlive-latex-extra
- texlive-fonts-recommended
- texlive-fonts-extra
+ - texlive-xetex
+ - lmodern
install:
- - pip install -U pip
+ - pip install -U pip setuptools
- pip install docutils==$DOCUTILS
- pip install -r test-reqs.txt
before_script:
- if [[ $TRAVIS_PYTHON_VERSION != '2.6' ]]; then flake8; fi
script:
- - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then make test-async; fi
+ - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then make style-check test-async; fi
- if [[ $TRAVIS_PYTHON_VERSION != '3.5' ]]; then make test; fi
diff --git a/AUTHORS b/AUTHORS
index e1e4e8a59..24897985e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -11,6 +11,7 @@ Other co-maintainers:
* Rob Ruana <@RobRuana>
* Robert Lehmann <@lehmannro>
* Roland Meister <@rolmei>
+* Takeshi Komiya <@tk0miya>
Other contributors, listed alphabetically, are:
@@ -19,6 +20,7 @@ Other contributors, listed alphabetically, are:
* Jakob Lykke Andersen -- Rewritten C++ domain
* Henrique Bastos -- SVG support for graphviz extension
* Daniel Bültmann -- todo extension
+* Jean-François Burnol -- LaTeX improvements
* Etienne Desautels -- apidoc module
* Michael Droettboom -- inheritance_diagram extension
* Charles Duffy -- original graphviz extension
@@ -29,8 +31,7 @@ Other contributors, listed alphabetically, are:
* Horst Gutmann -- internationalization support
* Martin Hans -- autodoc improvements
* Doug Hellmann -- graphviz improvements
-* Timotheus Kampik - JS enhancements, stop words language fix
-* Takeshi Komiya -- numref feature
+* Timotheus Kampik - JS theme & search enhancements
* Dave Kuhlman -- original LaTeX writer
* Blaise Laflamme -- pyramid theme
* Thomas Lamb -- linkcheck builder
@@ -41,16 +42,19 @@ Other contributors, listed alphabetically, are:
* Martin Mahner -- nature theme
* Will Maier -- directory HTML builder
* Jacob Mason -- websupport library (GSOC project)
+* Glenn Matthews -- python domain signature improvements
* Roland Meister -- epub builder
* Ezio Melotti -- collapsible sidebar JavaScript
+* Bruce Mitchener -- Minor epub improvement
* Daniel Neuhäuser -- JavaScript domain, Python 3 support (GSOC)
* Christopher Perkins -- autosummary integration
* Benjamin Peterson -- unittests
-* T. Powers -- HTML output improvements
+* \T. Powers -- HTML output improvements
* Jeppe Pihl -- literalinclude improvements
* Rob Ruana -- napoleon extension
* Stefan Seefeld -- toctree improvements
-* Shibukawa Yoshiki -- pluggable search API and Japanese search
+* Gregory Szorc -- performance improvements
+* Shibukawa Yoshiki -- pluggable search API and Japanese search, epub3 builder improvements
* Taku Shimizu -- epub3 builder
* Antonio Valentino -- qthelp builder
* Filip Vavera -- napoleon todo directive
diff --git a/CHANGES b/CHANGES
index 1120e0d7b..0a0606a5a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,260 @@
+Release 1.5 beta2 (in development)
+==================================
+
+Incompatible changes
+--------------------
+
+Features added
+--------------
+
+Bugs fixed
+----------
+
+Release 1.5 beta1 (released Nov 6, 2016)
+========================================
+
+Features added
+--------------
+
+* #2513: A better default settings for XeLaTeX
+* #3096: ``'maxlistdepth'`` key to work around LaTeX list limitations
+* #3060: autodoc supports documentation for attributes of Enum class. Now autodoc render
+ just the value of Enum attributes instead of Enum attribute representation.
+* Add ``--extensions`` to ``sphinx-quickstart`` to support enable arbitrary
+ extensions from command line (ref: #2904)
+* #3104, #3122: ``'sphinxsetup'`` for key=value styling of Sphinx LaTeX
+* #3071: Autodoc: Allow mocked module decorators to pass-through functions
+ unchanged
+* #2495: linkcheck: Allow skipping anchor checking using
+ :confval:`linkcheck_anchors_ignore`
+* #3083: let Unicode no-break space act like LaTeX ``~`` (fixed #3019)
+* #3116: allow word wrap in PDF output for inline literals (ref #3110)
+* #930: sphinx-apidoc allow wildcards for excluding paths. Thanks to Nick Coghlan.
+* #3121: add ``inlineliteralwraps`` option to control if inline literal
+ word-wraps in latex
+
+Bugs fixed
+----------
+
+* #2432: Fix unwanted * between varargs and keyword only args. Thanks to Alex Grönholm.
+* #3062: Failed to build PDF using 1.5a2 (undefined ``\hypersetup`` for
+ Japanese documents since PR#3030)
+* Better rendering of multiline signatures in html.
+* #777: LaTeX output "too deeply nested" (ref #3096)
+* Let LaTeX image inclusion obey ``scale`` before textwidth fit (ref #2865, #3059)
+* #3019: LaTeX fails on description of C function with arguments (ref #3083)
+* fix latex inline literals where ``< > -`` gobbled a space
+
+Release 1.5 alpha2 (released Oct 17, 2016)
+==========================================
+
+Incompatible changes
+--------------------
+
+* #2983: Rename ``epub3_description`` and ``epub3_contributor`` to
+ ``epub_description`` and ``epub_contributor``.
+* Remove themes/basic/defindex.html; no longer used
+* Sphinx does not ship anymore (but still uses) LaTeX style file ``fncychap``
+* #2435: Slim down quickstarted conf.py
+* The ``sphinx.sty`` latex package does not load itself "hyperref", as this
+ is done later in the preamble of the latex output via ``'hyperref'`` key.
+* Sphinx does not ship anymore a custom modified LaTeX style file ``tabulary``.
+ The non-modified package is used.
+* #3057: By default, footnote marks in latex PDF output are not preceded by a
+ space anymore, ``\sphinxBeforeFootnote`` allows user customization if needed.
+
+Features added
+--------------
+
+* #3008: ``linkcheck`` builder ignores self-signed certificate URL
+* #3020: new ``'geometry'`` key to ``latex_elements`` whose default uses
+ LaTeX style file ``geometry.sty`` to set page layout
+* #2843: Add :start-at: and :end-at: options to literalinclude directive
+* #2527: Add ``:reversed:`` option to toctree directive
+* Add ``-t`` and ``-d`` option to ``sphinx-quickstart`` to support templating
+ generated sphinx project.
+* #3028: Add ``{path}`` and ``{basename}`` to the format of
+ ``figure_language_filename``
+* new ``'hyperref'`` key in the ``latex_elements`` dictionary (ref #3030)
+* #3022: Allow code-blocks in footnotes for LaTeX PDF output
+
+Bugs fixed
+----------
+
+* #2810: Problems with pdflatex in an Italian document
+* Use ``latex_elements.papersize`` to specify papersize of LaTeX in Makefile
+* #2988: linkcheck: retry with GET request if denied HEAD request
+* #2990: linkcheck raises "Can't convert 'bytes' object to str implicitly" error
+ if linkcheck_anchors enabled
+* #3004: Invalid link types "top" and "up" are used
+* #3009: Bad rendering of parsed-literals in LaTeX since Sphinx 1.4.4
+* #3000: ``option`` directive generates invalid HTML anchors
+* #2984: Invalid HTML has been generated if `html_split_index` enabled
+* #2986: themes/basic/defindex.html should be changed for html5 friendly
+* #2987: Invalid HTML has been generated if multiple IDs are assigned to a list
+* #2891: HTML search does not provide all the results
+* #1986: Title in PDF Output
+* #147: Problem with latex chapter style
+* #3018: LaTeX problem with page layout dimensions and chapter titles
+* Fix an issue with ``\pysigline`` in LaTeX style file (ref #3023)
+* #3038: ``sphinx.ext.math*`` raises TypeError if labels are duplicated
+* #3031: incompatibility with LaTeX package ``tocloft``
+* #3003: literal blocks in footnotes are not supported by Latex
+* #3047: spacing before footnote in pdf output is not coherent and allows breaks
+* #3045: HTML search index creator should ignore "raw" content if now html
+* #3039: English stemmer returns wrong word if the word is capitalized
+* Fix make-mode Makefile template (ref #3056, #2936)
+
+Testing
+--------
+
+* To simplify, sphinx uses external mock package even if unittest.mock exists.
+
+Release 1.5 alpha1 (released Sep 21, 2016)
+==========================================
+
+Incompatible changes
+--------------------
+
+* latex, package fancybox is not longer a dependency of sphinx.sty
+* Use ``'locales'`` as a default value of `locale_dirs`
+* latex, package ifthen is not any longer a dependency of sphinx.sty
+* latex, style file does not modify fancyvrb's Verbatim (also available as
+ OriginalVerbatim) but uses sphinxVerbatim for name of custom wrapper.
+* latex, package newfloat is no longer a dependency of sphinx.sty (ref #2660;
+ it was shipped with Sphinx since 1.3.4).
+* latex, literal blocks in tables do not use OriginalVerbatim but
+ sphinxVerbatimintable which handles captions and wraps lines(ref #2704).
+* latex, replace ``pt`` by TeX equivalent ``bp`` if found in ``width`` or
+ ``height`` attribute of an image.
+* latex, if ``width`` or ``height`` attribute of an image is given with no unit,
+ use ``px`` rather than ignore it.
+* latex: Separate stylesheets of pygments to independent .sty file
+* #2454: The filename of sourcelink is now changed. The value of
+ `html_sourcelink_suffix` will be appended to the original filename (like
+ ``index.rst.txt``).
+* ``sphinx.util.copy_static_entry()`` is now deprecated.
+ Use ``sphinx.util.fileutil.copy_asset()`` instead.
+* ``sphinx.util.osutil.filecopy()`` skips copying if the file has not been changed
+ (ref: #2510, #2753)
+* Internet Explorer 6-8, Opera 12.1x or Safari 5.1+ support is dropped
+ because jQuery version is updated from 1.11.0 to 3.1.0 (ref: #2634, #2773)
+* QtHelpBuilder doens't generate search page (ref: #2352)
+* QtHelpBuilder uses ``nonav`` theme instead of default one
+ to improve readability.
+* latex: To provide good default settings to Japanese docs, Sphinx uses ``jsbooks``
+ as a docclass by default if the ``language`` is ``ja``.
+* latex: To provide good default settings to Japanese docs, Sphinx uses
+ ``jreport`` and ``jsbooks`` as a docclass by default if the ``language`` is
+ ``ja``.
+* ``sphinx-quickstart`` now allows a project version is empty
+* Fix :download: role on epub/qthelp builder. They ignore the role because they don't support it.
+* ``sphinx.ext.viewcode`` doesn't work on epub building by default. ``viewcode_enable_epub`` option
+* ``sphinx.ext.viewcode`` disabled on singlehtml builder.
+* Use make-mode of ``sphinx-quickstart`` by default. To disable this, use
+ ``-M`` option
+* Fix ``genindex.html``, Sphinx's document template, link address to itself to satisfy xhtml standard.
+* Use epub3 builder by default. And the old epub builder is renamed to epub2.
+* Fix ``epub`` and ``epub3`` builders that contained links to ``genindex`` even if ``epub_use_index = False``.
+* `html_translator_class` is now deprecated.
+ Use `Sphinx.set_translator()` API instead.
+* Drop python 2.6 and 3.3 support
+* Drop epub3 builder's ``epub3_page_progression_direction`` option (use ``epub3_writing_mode``).
+* #2877: Rename ``latex_elements['footer']`` to
+ ``latex_elements['atendofbody']``
+
+Features added
+--------------
+
+* #2951: Add ``--implicit-namespaces`` PEP-0420 support to apidoc.
+* Add ``:caption:`` option for sphinx.ext.inheritance_diagram.
+* #2471: Add config variable for default doctest flags.
+* Convert linkcheck builder to requests for better encoding handling
+* #2463, #2516: Add keywords of "meta" directive to search index
+* ``:maxdepth:`` option of toctree affects ``secnumdepth`` (ref: #2547)
+* #2575: Now ``sphinx.ext.graphviz`` allows ``:align:`` option
+* Show warnings if unknown key is specified to `latex_elements`
+* Show warnings if no domains match with `primary_domain` (ref: #2001)
+* C++, show warnings when the kind of role is misleading for the kind
+ of target it refers to (e.g., using the `class` role for a function).
+* latex, writer abstracts more of text styling into customizable macros, e.g.
+ the ``visit_emphasis`` will output ``\sphinxstyleemphasis`` rather than
+ ``\emph`` (which may be in use elsewhere or in an added LaTeX package). See
+ list at end of ``sphinx.sty`` (ref: #2686)
+* latex, public names for environments and parameters used by note, warning,
+ and other admonition types, allowing full customizability from the
+ ``'preamble'`` key or an input file (ref: feature request #2674, #2685)
+* latex, better computes column widths of some tables (as a result, there will
+ be slight changes as tables now correctly fill the line width; ref: #2708)
+* latex, sphinxVerbatim environment is more easily customizable (ref: #2704).
+ In addition to already existing VerbatimColor and VerbatimBorderColor:
+
+ - two lengths ``\sphinxverbatimsep`` and ``\sphinxverbatimborder``,
+ - booleans ``\ifsphinxverbatimwithframe`` and ``\ifsphinxverbatimwrapslines``.
+
+* latex, captions for literal blocks inside tables are handled, and long code
+ lines wrapped to fit table cell (ref: #2704)
+* #2597: Show warning messages as darkred
+* latex, allow image dimensions using px unit (default is 96px=1in)
+* Show warnings if invalid dimension units found
+* #2650: Add ``--pdb`` option to setup.py command
+* latex, make the use of ``\small`` for code listings customizable (ref #2721)
+* #2663: Add ``--warning-is-error`` option to setup.py command
+* Show warnings if deprecated latex options are used
+* Add sphinx.config.ENUM to check the config values is in candidates
+* math: Add hyperlink marker to each equations in HTML output
+* Add new theme ``nonav`` that doesn't include any navigation links.
+ This is for any help generator like qthelp.
+* #2680: `sphinx.ext.todo` now emits warnings if `todo_emit_warnings` enabled.
+ Also, it emits an additional event named `todo-defined` to handle the TODO
+ entries in 3rd party extensions.
+* Python domain signature parser now uses the xref mixin for 'exceptions',
+ allowing exception classes to be autolinked.
+* #2513: Add `latex_engine` to switch the LaTeX engine by conf.py
+* #2682: C++, basic support for attributes (C++11 style and GNU style).
+ The new configuration variables 'cpp_id_attributes' and 'cpp_paren_attributes'
+ can be used to introduce custom attributes.
+* #1958: C++, add configuration variable 'cpp_index_common_prefix' for removing
+ prefixes from the index text of C++ objects.
+* C++, added concept directive. Thanks to mickk-on-cpp.
+* C++, added support for template introduction syntax. Thanks to mickk-on-cpp.
+* #2725: latex builder: allow to use user-defined template file (experimental)
+* apidoc now avoids invalidating cached files by not writing to files whose
+ content doesn't change. This can lead to significant performance wins if
+ apidoc is run frequently.
+* #2851: ``sphinx.ext.math`` emits missing-reference event if equation not found
+* #1210: ``eqref`` role now supports cross reference
+* #2892: Added ``-a`` (``--append-syspath``) option to ``sphinx-apidoc``
+* #1604: epub3 builder: Obey font-related CSS when viewing in iBooks.
+* #646: ``option`` directive support '.' character as a part of options
+* Add document about kindlegen and fix document structure for it.
+* #2474: Add ``intersphinx_timeout`` option to ``sphinx.ext.intersphinx``
+* #2926: EPUB3 builder supports vertical mode (``epub3_writing_mode`` option)
+* #2695: ``build_sphinx`` subcommand for setuptools handles exceptions as same
+ as ``sphinx-build`` does
+* #326: `numref` role can also refer sections
+* #2916: `numref` role can also refer caption as an its linktext
+
+Bugs fixed
+----------
+
+* #2707: (latex) the column width is badly computed for tabular
+* #2799: Sphinx installs roles and directives automatically on importing sphinx
+ module. Now Sphinx installs them on running application.
+* `sphinx.ext.autodoc` crashes if target code imports * from mock modules
+ by `autodoc_mock_imports`.
+* #1953: ``Sphinx.add_node`` does not add handlers the translator installed by
+ `html_translator_class`
+* #1797: text builder inserts blank line on top
+* #2894: quickstart main() doesn't use argv argument
+* #2874: gettext builder could not extract all text under the ``only``
+ directives
+* #2485: autosummary crashes with multiple source_suffix values
+* #1734: Could not translate the caption of toctree directive
+* Could not translate the content of meta directive (ref: #1734)
+* #2550: external links are opened in help viewer
+* #2687: Running Sphinx multiple times produces 'already registered' warnings
+
Release 1.4.9 (in development)
==============================
diff --git a/MANIFEST.in b/MANIFEST.in
index bb0be4958..e2560383c 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -13,6 +13,7 @@ include sphinx-build.py
include sphinx-quickstart.py
include sphinx-apidoc.py
+recursive-include sphinx/templates *
recursive-include sphinx/texinputs *
recursive-include sphinx/themes *
recursive-include sphinx/locale *
@@ -20,8 +21,7 @@ recursive-include sphinx/search/non-minified-js *.js
recursive-include sphinx/ext/autosummary/templates *
recursive-include tests *
recursive-include utils *
-include sphinx/pycode/Grammar-py2.txt
-include sphinx/pycode/Grammar-py3.txt
+include sphinx/pycode/Grammar-py*
recursive-include doc *
prune doc/_build
diff --git a/Makefile b/Makefile
index fa2a846f5..01e3a7837 100644
--- a/Makefile
+++ b/Makefile
@@ -6,11 +6,12 @@ PYTHON ?= python
DONT_CHECK = -i build -i dist -i sphinx/style/jquery.js \
-i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py \
-i .ropeproject -i doc/_build -i tests/path.py \
- -i tests/coverage.py -i env -i utils/convert.py \
+ -i tests/coverage.py -i utils/convert.py \
-i tests/typing_test_data.py \
-i tests/test_autodoc_py35.py \
-i tests/roots/test-warnings/undecodable.rst \
-i tests/build \
+ -i tests/roots/test-warnings/undecodable.rst \
-i sphinx/search/da.py \
-i sphinx/search/de.py \
-i sphinx/search/en.py \
diff --git a/doc/Makefile b/doc/Makefile
index dcd67186d..d0e4e297b 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,4 +1,3 @@
-.PHONY: man
# Makefile for Sphinx documentation
#
@@ -9,14 +8,13 @@ SPHINXPROJ = sphinx
SOURCEDIR = .
BUILDDIR = _build
-# Has to be explicit, otherwise we don't get "make" without targets right.
+# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-man:
- @$(SPHINXBUILD) -M man "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
-%:
+%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/doc/_static/bookcover.png b/doc/_static/bookcover.png
index 5b521b67b..0a8167fcc 100644
--- a/doc/_static/bookcover.png
+++ b/doc/_static/bookcover.png
Binary files differ
diff --git a/doc/_static/conf.py.txt b/doc/_static/conf.py.txt
new file mode 100644
index 000000000..ab54f15b8
--- /dev/null
+++ b/doc/_static/conf.py.txt
@@ -0,0 +1,360 @@
+# -*- coding: utf-8 -*-
+#
+# test documentation build configuration file, created by
+# sphinx-quickstart on Sun Jun 26 00:00:43 2016.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# 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('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#
+# source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'test'
+copyright = u'2016, test'
+author = u'test'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = u'test'
+# The full version, including alpha/beta/rc tags.
+release = u'test'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#
+# today = ''
+#
+# Else, today_fmt is used as the format for a strftime call.
+#
+# today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#
+# default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#
+# add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#
+# add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#
+# show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+# modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+# keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+# html_theme_path = []
+
+# The name for this set of Sphinx documents.
+# "<project> v<release> documentation" by default.
+#
+# html_title = u'test vtest'
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#
+# html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#
+# html_logo = None
+
+# The name of an image file (relative to this directory) to use as a favicon of
+# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#
+# html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#
+# html_extra_path = []
+
+# If not None, a 'Last updated on:' timestamp is inserted at every page
+# bottom, using the given strftime format.
+# The empty string is equivalent to '%b %d, %Y'.
+#
+# html_last_updated_fmt = None
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#
+# html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#
+# html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#
+# html_additional_pages = {}
+
+# If false, no module index is generated.
+#
+# html_domain_indices = True
+
+# If false, no index is generated.
+#
+# html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#
+# html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#
+# html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#
+# html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#
+# html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#
+# html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+# html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
+# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
+#
+# html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# 'ja' uses this config value.
+# 'zh' user can custom change `jieba` dictionary path.
+#
+# html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#
+# html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'testdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'test.tex', u'test Documentation',
+ u'test', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#
+# latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#
+# latex_use_parts = False
+
+# If true, show page references after internal links.
+#
+# latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#
+# latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#
+# latex_appendices = []
+
+# If false, will not define \strong, \code, \titleref, \crossref ... but only
+# \sphinxstrong, ..., \sphinxtitleref, ... to help avoid clash with user added
+# packages.
+#
+# latex_keep_old_macro_names = True
+
+# If false, no module index is generated.
+#
+# latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'test', u'test Documentation',
+ [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#
+# man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'test', u'test Documentation',
+ author, 'test', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#
+# texinfo_appendices = []
+
+# If false, no module index is generated.
+#
+# texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#
+# texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#
+# texinfo_no_detailmenu = False
+
+# -- A random example -----------------------------------------------------
+
+import sys, os
+sys.path.insert(0, os.path.abspath('.'))
+exclude_patterns = ['zzz']
+
+numfig = True
+#language = 'ja'
+
+extensions.append('sphinx.ext.todo')
+extensions.append('sphinx.ext.autodoc')
+#extensions.append('sphinx.ext.autosummary')
+extensions.append('sphinx.ext.intersphinx')
+extensions.append('sphinx.ext.mathjax')
+extensions.append('sphinx.ext.viewcode')
+extensions.append('sphinx.ext.graphviz')
+
+
+autosummary_generate = True
+html_theme = 'default'
+#source_suffix = ['.rst', '.txt']
diff --git a/doc/_static/pocoo.png b/doc/_static/pocoo.png
index 67663b976..1648bb8d7 100644
--- a/doc/_static/pocoo.png
+++ b/doc/_static/pocoo.png
Binary files differ
diff --git a/doc/_static/sphinx.png b/doc/_static/sphinx.png
index 4bd9c7536..0a103cd3e 100644
--- a/doc/_static/sphinx.png
+++ b/doc/_static/sphinx.png
Binary files differ
diff --git a/doc/_templates/index.html b/doc/_templates/index.html
index e0a8ce68a..755a79122 100644
--- a/doc/_templates/index.html
+++ b/doc/_templates/index.html
@@ -13,9 +13,8 @@
Sphinx is a tool that makes it easy to create intelligent and beautiful
documentation, written by Georg Brandl and licensed under the BSD license.{%endtrans%}</p>
<p>{%trans%}It was originally created for <a href="https://docs.python.org/">the
- new Python documentation</a>, and it has excellent facilities for the
- documentation of Python projects, but C/C++ is already supported as well,
- and it is planned to add special support for other languages as well. Of
+ Python documentation</a>, and it has excellent facilities for the
+ documentation of software projects in a range of languages. Of
course, this site is also created from reStructuredText sources using
Sphinx! The following features should be highlighted:{%endtrans%}
</p>
@@ -31,7 +30,7 @@
module indices{%endtrans%}</li>
<li>{%trans%}<b>Code handling:</b> automatic highlighting using the <a
href="http://pygments.org">Pygments</a> highlighter{%endtrans%}</li>
- <li>{%trans path=pathto('extensions')%}<b>Extensions:</b> automatic testing of code snippets, inclusion of
+ <li>{%trans path=pathto('ext/builtins')%}<b>Extensions:</b> automatic testing of code snippets, inclusion of
docstrings from Python modules (API docs), and
<a href="{{ path }}#builtin-sphinx-extensions">more</a>{%endtrans%}</li>
<li>{%trans path=pathto('develop')%}<b>Contributed extensions:</b> more than
@@ -47,17 +46,17 @@
<h2 style="margin-bottom: 0">{%trans%}Documentation{%endtrans%}</h2>
- <table class="contentstable" align="center" style="margin-left: 30px"><tr>
- <td width="50%">
+ <table class="contentstable"><tr>
+ <td>
<p class="biglink"><a class="biglink" href="{{ pathto("tutorial") }}">{%trans%}First steps with Sphinx{%endtrans%}</a><br/>
<span class="linkdescr">{%trans%}overview of basic tasks{%endtrans%}</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">{%trans%}Contents{%endtrans%}</a><br/>
<span class="linkdescr">{%trans%}for a complete overview{%endtrans%}</span></p>
- </td><td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("search") }}">{%trans%}Search page{%endtrans%}</a><br/>
- <span class="linkdescr">{%trans%}search the documentation{%endtrans%}</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">{%trans%}General Index{%endtrans%}</a><br/>
- <span class="linkdescr">{%trans%}all functions, classes, terms{%endtrans%}</span></p>
+ </td><td>
+ {%- if hasdoc('search') %}<p class="biglink"><a class="biglink" href="{{ pathto("search") }}">{%trans%}Search page{%endtrans%}</a><br/>
+ <span class="linkdescr">{%trans%}search the documentation{%endtrans%}</span></p>{%- endif %}
+ {%- if hasdoc('genindex') %}<p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">{%trans%}General Index{%endtrans%}</a><br/>
+ <span class="linkdescr">{%trans%}all functions, classes, terms{%endtrans%}</span></p>{%- endif %}
</td></tr>
</table>
diff --git a/doc/_themes/sphinx13/static/bodybg.png b/doc/_themes/sphinx13/static/bodybg.png
index ebe92f669..6f667b99e 100644
--- a/doc/_themes/sphinx13/static/bodybg.png
+++ b/doc/_themes/sphinx13/static/bodybg.png
Binary files differ
diff --git a/doc/_themes/sphinx13/static/footerbg.png b/doc/_themes/sphinx13/static/footerbg.png
index df783e2c7..d1bcb009b 100644
--- a/doc/_themes/sphinx13/static/footerbg.png
+++ b/doc/_themes/sphinx13/static/footerbg.png
Binary files differ
diff --git a/doc/_themes/sphinx13/static/headerbg.png b/doc/_themes/sphinx13/static/headerbg.png
index 22830f99e..522504964 100644
--- a/doc/_themes/sphinx13/static/headerbg.png
+++ b/doc/_themes/sphinx13/static/headerbg.png
Binary files differ
diff --git a/doc/_themes/sphinx13/static/listitem.png b/doc/_themes/sphinx13/static/listitem.png
index e45715f91..f7f814d00 100644
--- a/doc/_themes/sphinx13/static/listitem.png
+++ b/doc/_themes/sphinx13/static/listitem.png
Binary files differ
diff --git a/doc/_themes/sphinx13/static/relbg.png b/doc/_themes/sphinx13/static/relbg.png
index 2006af7d2..68a9b77eb 100644
--- a/doc/_themes/sphinx13/static/relbg.png
+++ b/doc/_themes/sphinx13/static/relbg.png
Binary files differ
diff --git a/doc/_themes/sphinx13/static/sphinx13.css b/doc/_themes/sphinx13/static/sphinx13.css
index 1739ac36b..26df65b45 100644
--- a/doc/_themes/sphinx13/static/sphinx13.css
+++ b/doc/_themes/sphinx13/static/sphinx13.css
@@ -398,3 +398,9 @@ div.viewcode-block:target {
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
+
+.contentstable {
+ margin-left: 30px;
+ margin: 0 auto;
+ table-layout: fixed;
+}
diff --git a/doc/_themes/sphinx13/static/sphinxheader.png b/doc/_themes/sphinx13/static/sphinxheader.png
index 12988c3d1..845da4ab9 100644
--- a/doc/_themes/sphinx13/static/sphinxheader.png
+++ b/doc/_themes/sphinx13/static/sphinxheader.png
Binary files differ
diff --git a/doc/builders.rst b/doc/builders.rst
index be73b3029..f3bacb139 100644
--- a/doc/builders.rst
+++ b/doc/builders.rst
@@ -140,6 +140,11 @@ The builder's "name" must be given to the **-b** command-line option of
.. autoattribute:: supported_image_types
+ .. deprecated:: 1.5
+
+ Since Sphinx-1.5, the epub3 builder is used for the default builder of epub.
+ Now EpubBuilder is renamed to epub2.
+
.. module:: sphinx.builders.epub3
.. class:: Epub3Builder
@@ -149,9 +154,6 @@ The builder's "name" must be given to the **-b** command-line option of
`<http://idpf.org/epub>`_ or `<https://en.wikipedia.org/wiki/EPUB>`_.
The builder creates *EPUB 3* files.
- This builder is still *experimental* because it can't generate valid EPUB 3
- files.
-
.. autoattribute:: name
.. autoattribute:: format
@@ -160,6 +162,10 @@ The builder's "name" must be given to the **-b** command-line option of
.. versionadded:: 1.4
+ .. versionchanged:: 1.5
+
+ Since Sphinx-1.5, the epub3 builder is used for the default builder of epub.
+
.. module:: sphinx.builders.latex
.. class:: LaTeXBuilder
@@ -271,8 +277,7 @@ for details.
A module that implements `dump()`, `load()`, `dumps()` and `loads()`
functions that conform to the functions with the same names from the
pickle module. Known modules implementing this interface are
- `simplejson` (or `json` in Python 2.6), `phpserialize`, `plistlib`,
- and others.
+ `simplejson`, `phpserialize`, `plistlib`, and others.
.. attribute:: out_suffix
diff --git a/doc/conf.py b/doc/conf.py
index 269b67275..349c0e745 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -48,13 +48,14 @@ epub_max_image_width = 0
epub_show_urls = 'inline'
epub_use_index = False
epub_guide = (('toc', 'contents.xhtml', u'Table of Contents'),)
-epub3_description = 'Sphinx documentation generator system manual'
+epub_description = 'Sphinx documentation generator system manual'
latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation',
'Georg Brandl', 'manual', 1)]
latex_logo = '_static/sphinx.png'
latex_elements = {
'fontpkg': '\\usepackage{palatino}',
+ 'passoptionstopackages': '\\PassOptionsToPackage{svgnames}{xcolor}',
}
latex_show_urls = 'footnote'
diff --git a/doc/config.rst b/doc/config.rst
index 2d427042f..34900535f 100644
--- a/doc/config.rst
+++ b/doc/config.rst
@@ -40,7 +40,7 @@ Important points to note:
delete them from the namespace with ``del`` if appropriate. Modules are
removed automatically, so you don't need to ``del`` your imports after use.
-.. _conf-tags:
+ .. _conf-tags:
* There is a special object named ``tags`` available in the config file.
It can be used to query and change the tags (see :ref:`tags`). Use
@@ -288,19 +288,27 @@ General configuration
.. note::
- LaTeX builder always assign numbers whether this option is enabled or not.
+ The LaTeX builder always assigns numbers whether this option is enabled or
+ not.
.. versionadded:: 1.3
.. confval:: numfig_format
- A dictionary mapping ``'figure'``, ``'table'`` and ``'code-block'`` to
- strings that are used for format of figure numbers. Default is to use
- ``'Fig. %s'`` for ``'figure'``, ``'Table %s'`` for ``'table'`` and
- ``'Listing %s'`` for ``'code-block'``.
+ A dictionary mapping ``'figure'``, ``'table'``, ``'code-block'`` and
+ ``'section'`` to strings that are used for format of figure numbers.
+ As a special character, `%s` and `{number}` will be replaced to figure
+ number. `{name}` will be replaced to figure caption.
+
+ Default is to use ``'Fig. %s'`` for ``'figure'``, ``'Table %s'`` for
+ ``'table'``, ``'Listing %s'`` for ``'code-block'`` and ``'Section'`` for
+ ``'section'``.
.. versionadded:: 1.3
+ .. versionchanged:: 1.5
+ Support format of section. Allow to refer the caption of figures.
+
.. confval:: numfig_secnum_depth
The scope of figure numbers, that is, the numfig feature numbers figures
@@ -521,7 +529,10 @@ documentation on :ref:`intl` for details.
:file:`./locale/{language}/LC_MESSAGES/sphinx.mo`. The text domain of
individual documents depends on :confval:`gettext_compact`.
- The default is ``[]``.
+ The default is ``['locales']``.
+
+ .. versionchanged:: 1.5
+ Use ``locales`` directory as a default value
.. confval:: gettext_compact
@@ -589,9 +600,25 @@ documentation on :ref:`intl` for details.
The filename format for language-specific figures. The default value is
``{root}.{language}{ext}``. It will be expanded to
``dirname/filename.en.png`` from ``.. image:: dirname/filename.png``.
+ The available format tokens are:
+
+ * ``{root}`` - the filename, including any path component, without the file
+ extension, e.g. ``dirname/filename``
+ * ``{path}`` - the directory path component of the filename, with a trailing
+ slash if non-empty, e.g. ``dirname/``
+ * ``{basename}`` - the filename without the directory path or file extension
+ components, e.g. ``filename``
+ * ``{ext}`` - the file extension, e.g. ``.png``
+ * ``{language}`` - the translation language, e.g. ``en``
+
+ For example, setting this to ``{path}{language}/{basename}{ext}`` will
+ expand to ``dirname/en/filename.png`` instead.
.. versionadded:: 1.4
+ .. versionchanged:: 1.5
+ Added ``{path}`` and ``{basename}`` tokens.
+
.. _html-options:
Options for HTML output
@@ -867,6 +894,13 @@ that use Sphinx's HTMLWriter class.
.. versionadded:: 0.6
+.. confval:: html_sourcelink_suffix
+
+ Suffix to be appended to source links (see :confval:`html_show_sourcelink`),
+ unless they have this suffix already. Default is ``'.txt'``.
+
+ .. versionadded:: 1.5
+
.. confval:: html_use_opensearch
If nonempty, an `OpenSearch <http://www.opensearch.org/Home>`_ description file will be
@@ -900,6 +934,11 @@ that use Sphinx's HTMLWriter class.
.. seealso:: :meth:`~sphinx.application.Sphinx.set_translator`
+ .. deprecated:: 1.5
+
+ Implement your translator as extension and use `Sphinx.set_translator`
+ instead.
+
.. confval:: html_show_copyright
If true, "(C) Copyright ..." is shown in the HTML footer. Default is
@@ -1267,18 +1306,21 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
The title of the document. It defaults to the :confval:`html_title` option
but can be set independently for epub creation.
-.. confval:: epub3_description
+.. confval:: epub_description
The description of the document. The default value is ``''``.
.. versionadded:: 1.4
+ .. versionchanged:: 1.5
+ Renamed from ``epub3_description``
+
.. confval:: epub_author
The author of the document. This is put in the Dublin Core metadata. The
default value is ``'unknown'``.
-.. confval:: epub3_contributor
+.. confval:: epub_contributor
The name of a person, organization, etc. that played a secondary role in
the creation of the content of an EPUB Publication. The default value is
@@ -1286,6 +1328,9 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
.. versionadded:: 1.4
+ .. versionchanged:: 1.5
+ Renamed from ``epub3_contributor``
+
.. confval:: epub_language
The language of the document. This is put in the Dublin Core metadata. The
@@ -1445,6 +1490,30 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
.. versionadded:: 1.2
+.. confval:: epub_writing_mode
+
+ It specifies writing direction. It can accept ``'horizontal'`` (default) and
+ ``'vertical'``
+
+ .. list-table::
+ :header-rows: 1
+ :stub-columns: 1
+
+ - * ``epub_writing_mode``
+ * ``'horizontal'``
+ * ``'vertical'``
+ - * writing-mode [#]_
+ * ``horizontal-tb``
+ * ``vertical-rl``
+ - * page progression
+ * left to right
+ * right to left
+ - * iBook's Scroll Theme support
+ * scroll-axis is vertical.
+ * scroll-axis is horizontal.
+
+ .. [#] https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode
+
.. confval:: epub3_page_progression_direction
The global direction in which the content flows.
@@ -1456,12 +1525,25 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
.. versionadded:: 1.4
+ .. deprecated:: 1.5
+ Use ``epub_writing_mode`` instead.
+
.. _latex-options:
Options for LaTeX output
------------------------
-These options influence LaTeX output.
+These options influence LaTeX output. See further :doc:`latex`.
+
+.. confval:: latex_engine
+
+ The LaTeX engine to build the docs. The setting can have the following
+ values:
+
+ * ``'pdflatex'`` -- PDFLaTeX (default)
+ * ``'xelatex'`` -- XeLaTeX
+ * ``'lualatex'`` -- LuaLaTeX
+ * ``'platex'`` -- pLaTeX (default if :confval:`language` is ``'ja'``)
.. confval:: latex_documents
@@ -1481,11 +1563,13 @@ These options influence LaTeX output.
* *author*: Author for the LaTeX document. The same LaTeX markup caveat as
for *title* applies. Use ``\and`` to separate multiple authors, as in:
``'John \and Sarah'``.
- * *documentclass*: Normally, one of ``'manual'`` or ``'howto'`` (provided by
- Sphinx). Other document classes can be given, but they must include the
- "sphinx" package in order to define Sphinx's custom LaTeX commands. "howto"
- documents will not get appendices. Also, howtos will have a simpler title
- page.
+ * *documentclass*: Normally, one of ``'manual'`` or ``'howto'`` (provided
+ by Sphinx and based on ``'report'``, resp. ``'article'``; Japanese
+ documents use ``'jsbook'``, resp. ``'jreport'``.) "howto" (non-Japanese)
+ documents will not get appendices. Also they have a simpler title page.
+ Other document classes can be given. Independently of the document class,
+ the "sphinx" package is always loaded in order to define Sphinx's custom
+ LaTeX commands.
* *toctree_only*: Must be ``True`` or ``False``. If true, the *startdoc*
document itself is not included in the output, only the documents
@@ -1602,8 +1686,40 @@ These options influence LaTeX output.
``'pointsize'``
Point size option of the document class (``'10pt'``, ``'11pt'`` or
``'12pt'``), default ``'10pt'``.
+ ``'pxunit'``
+ the value of the ``px`` when used in image attributes ``width`` and
+ ``height``. The default value is ``'49336sp'`` which achieves
+ ``96px=1in`` (``1in = 72.27*65536 = 4736286.72sp``, and all dimensions
+ in TeX are internally integer multiples of ``sp``). To obtain for
+ example ``100px=1in``, one can use ``'0.01in'`` but it is more precise
+ to use ``'47363sp'``. To obtain ``72px=1in``, use ``'1bp'``.
+
+ .. versionadded:: 1.5
+ ``'sphinxsetup'``
+ A comma separated list of ``key=value`` package options for the Sphinx
+ LaTeX style, default empty. See :doc:`latex`.
+
+ .. versionadded:: 1.5
+ ``'passoptionstopackages'``
+ A string which will be positioned early in the preamble, designed to
+ contain ``\\PassOptionsToPackage{options}{foo}`` commands. Default empty.
+
+ .. versionadded:: 1.4
+ ``'geometry'``
+ "geometry" package inclusion, the default definition is:
+
+ ``'\\usepackage[margin=1in,marginparwidth=0.5in]{geometry}'``.
+
+ .. versionadded:: 1.5
``'babel'``
- "babel" package inclusion, default ``'\\usepackage{babel}'``.
+ "babel" package inclusion, default ``'\\usepackage{babel}'`` (the
+ suitable document language string is passed as class option, and
+ ``english`` is used if no language.) For Japanese documents, the
+ default is the empty string.
+
+ .. versionchanged:: 1.5
+ For :confval:`latex_engine` set to ``'xelatex'``, the default
+ is ``'\\usepackage{polyglossia}\n\\setmainlanguage{<language>}'``.
``'fontpkg'``
Font package inclusion, default ``'\\usepackage{times}'`` (which uses
Times and Helvetica). You can set this to ``''`` to use the Computer
@@ -1612,19 +1728,22 @@ These options influence LaTeX output.
.. versionchanged:: 1.2
Defaults to ``''`` when the :confval:`language` uses the Cyrillic
script.
+ .. versionchanged:: 1.5
+ Defaults to ``''`` when :confval:`latex_engine` is ``'xelatex'``.
``'fncychap'``
Inclusion of the "fncychap" package (which makes fancy chapter titles),
- default ``'\\usepackage[Bjarne]{fncychap}'`` for English documentation,
+ default ``'\\usepackage[Bjarne]{fncychap}'`` for English documentation
+ (this option is slightly customized by Sphinx),
``'\\usepackage[Sonny]{fncychap}'`` for internationalized docs (because
the "Bjarne" style uses numbers spelled out in English). Other
- "fncychap" styles you can try include "Lenny", "Glenn", "Conny" and
- "Rejne". You can also set this to ``''`` to disable fncychap.
- ``'passoptionstopackages'``
- "PassOptionsToPackage" call, default empty.
-
- .. versionadded:: 1.4
+ "fncychap" styles you can try are "Lenny", "Glenn", "Conny", "Rejne" and
+ "Bjornstrup". You can also set this to ``''`` to disable fncychap.
``'preamble'``
- Additional preamble content, default empty.
+ Additional preamble content, default empty. See :doc:`latex`.
+ ``'atendofbody'``
+ Additional document content (right before the indices), default empty.
+
+ .. versionadded:: 1.5
``'figure_align'``
Latex figure float alignment, default 'htbp' (here, top, bottom, page).
Whenever an image doesn't fit into the current page, it will be
@@ -1636,12 +1755,32 @@ These options influence LaTeX output.
``'footer'``
Additional footer content (before the indices), default empty.
+ .. deprecated:: 1.5
+ Use ``'atendofbody'`` key instead.
+
* Keys that don't need be overridden unless in special cases are:
+ ``'maxlistdepth'``
+ LaTeX allows by default at most 6 levels for nesting list and
+ quote-like environments, with at most 4 enumerated lists, and 4 bullet
+ lists. Setting this key for example to ``'10'`` (as a string) will
+ allow up to 10 nested levels (of all sorts). Leaving it to the empty
+ string means to obey the LaTeX default.
+
+ .. warning::
+
+ - Using this key may prove incompatible with some LaTeX packages
+ or special document classes which do their own list customization.
+
+ - The key setting is silently *ignored* if ``\usepackage{enumitem}``
+ is executed inside the document preamble. Use then rather the
+ dedicated commands of this LaTeX package.
+
+ .. versionadded:: 1.5
``'inputenc'``
"inputenc" package inclusion, defaults to
``'\\usepackage[utf8]{inputenc}'`` when using pdflatex.
- Otherwise unset.
+ Otherwise empty.
.. versionchanged:: 1.4.3
Previously ``'\\usepackage[utf8]{inputenc}'`` was used for all
@@ -1652,16 +1791,41 @@ These options influence LaTeX output.
.. versionadded:: 1.2
``'fontenc'``
"fontenc" package inclusion, default ``'\\usepackage[T1]{fontenc}'``.
+
+ .. versionchanged:: 1.5
+ Defaults to ``'\\usepackage{fontspec}'`` when
+ :confval:`latex_engine` is ``'xelatex'``.
+ ``'hyperref'``
+ "hyperref" package inclusion; also loads package "hypcap" and issues
+ ``\urlstyle{same}``. This is done after :file:`sphinx.sty` file is
+ loaded and before executing the contents of ``'preamble'`` key.
+
+ .. attention::
+
+ Loading of packages "hyperref" and "hypcap" is mandatory.
+
+ .. versionadded:: 1.5
+ Previously this was done from inside :file:`sphinx.sty`.
``'maketitle'``
- "maketitle" call, default ``'\\maketitle'``. Override if you want to
+ "maketitle" call, default ``'\\maketitle'`` (but it has been
+ redefined by the Sphinx ``manual`` and ``howto`` classes.) Override
+ if you want to
generate a differently-styled title page.
``'releasename'``
value that prefixes ``'release'`` element on title page, default
``'Release'``.
``'tableofcontents'``
- "tableofcontents" call, default ``'\\tableofcontents'``. Override if
+ "tableofcontents" call, default ``'\\sphinxtableofcontents'`` (it is a
+ wrapper of unmodified ``\tableofcontents``, which may itself be
+ customized by user loaded packages.)
+ Override if
you want to generate a different table of contents or put content
between the title page and the TOC.
+
+ .. versionchanged:: 1.5
+ Previously the meaning of ``\tableofcontents`` itself was modified
+ by Sphinx. This created an incompatibility with dedicated packages
+ modifying it also such as "tocloft" or "etoc".
``'transition'``
Commands used to display transitions, default
``'\n\n\\bigskip\\hrule{}\\bigskip\n\n'``. Override if you want to
@@ -1671,7 +1835,9 @@ These options influence LaTeX output.
``'printindex'``
"printindex" call, the last thing in the file, default
``'\\printindex'``. Override if you want to generate the index
- differently or append some content after the index.
+ differently or append some content after the index. For example
+ ``'\\footnotesize\\raggedright\\printindex'`` is advisable when the
+ index is full of long entries.
* Keys that are set by other options and therefore should not be overridden
are:
@@ -1694,6 +1860,11 @@ These options influence LaTeX output.
.. versionadded:: 1.0
+ .. versionchanged:: 1.5
+
+ In Japanese docs (:confval:`language` is ``'ja'``), by default
+ ``'jreport'`` is used for ``'howto'`` and ``'jsbook'`` for ``'manual'``.
+
.. confval:: latex_additional_files
A list of file names, relative to the configuration directory, to copy to the
@@ -1931,9 +2102,8 @@ Options for the linkcheck builder
.. confval:: linkcheck_timeout
- A timeout value, in seconds, for the linkcheck builder. **Only works in
- Python 2.6 and higher.** The default is to use Python's global socket
- timeout.
+ A timeout value, in seconds, for the linkcheck builder. The default is to
+ use Python's global socket timeout.
.. versionadded:: 1.1
@@ -1952,6 +2122,17 @@ Options for the linkcheck builder
.. versionadded:: 1.2
+.. confval:: linkcheck_anchors_ignore
+
+ A list of regular expressions that match URIs that should skip checking
+ the validity of anchors in links. This allows skipping entire sites, where
+ anchors are used to control dynamic pages, or just specific anchors within
+ a page, where javascript is used to add anchors dynamically, or use the
+ fragment as part of to trigger an internal REST request. Default is
+ ``["/#!"]``.
+
+ .. versionadded:: 1.5
+
Options for the XML builder
---------------------------
@@ -1969,3 +2150,38 @@ Options for the XML builder
constructs ``*``, ``?``, ``[...]`` and ``[!...]`` with the feature that
these all don't match slashes. A double star ``**`` can be used to match
any sequence of characters *including* slashes.
+
+
+.. _cpp-config:
+
+Options for the C++ domain
+--------------------------
+
+.. confval:: cpp_index_common_prefix
+
+ A list of prefixes that will be ignored when sorting C++ objects in the global index.
+ For example ``['awesome_lib::']``.
+
+ .. versionadded:: 1.5
+
+.. confval:: cpp_id_attributes
+
+ A list of strings that the parser additionally should accept as attributes.
+ This can for example be used when attributes have been ``#define`` d for portability.
+
+ .. versionadded:: 1.5
+
+.. confval:: cpp_paren_attributes
+
+ A list of strings that the parser additionally should accept as attributes with one argument.
+ That is, if ``my_align_as`` is in the list, then ``my_align_as(X)`` is parsed as an attribute
+ for all strings ``X`` that have balanced brances (``()``, ``[]``, and ``{}``).
+ This can for example be used when attributes have been ``#define`` d for portability.
+
+ .. versionadded:: 1.5
+
+Example of configuration file
+=============================
+
+.. literalinclude:: _static/conf.py.txt
+ :language: python
diff --git a/doc/contents.rst b/doc/contents.rst
index a51910b81..0f5527bae 100644
--- a/doc/contents.rst
+++ b/doc/contents.rst
@@ -1,3 +1,4 @@
+
.. _contents:
Sphinx documentation contents
@@ -17,6 +18,7 @@ Sphinx documentation contents
intl
theming
templating
+ latex
extensions
extdev/index
websupport
@@ -32,7 +34,14 @@ Sphinx documentation contents
Indices and tables
==================
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-* :ref:`glossary`
+.. only:: builder_html
+
+ * :ref:`genindex`
+ * :ref:`modindex`
+ * :ref:`search`
+ * :ref:`glossary`
+
+.. only:: not builder_html
+
+ * :ref:`modindex`
+ * :ref:`glossary`
diff --git a/doc/domains.rst b/doc/domains.rst
index dcecf4df5..7ff0d2f5f 100644
--- a/doc/domains.rst
+++ b/doc/domains.rst
@@ -359,6 +359,25 @@ single word, like this::
:param int priority: The priority of the message, can be a number 1-5
+.. versionadded:: 1.5
+
+Container types such as lists and dictionaries can be linked automatically
+using the following syntax::
+
+ :type priorities: list(int)
+ :type priorities: list[int]
+ :type mapping: dict(str, int)
+ :type mapping: dict[str, int]
+ :type point: tuple(float, float)
+ :type point: tuple[float, float]
+
+Multiple types in a type field will be linked automatically if separated by
+the word "or"::
+
+ :type an_arg: int or None
+ :vartype a_var: str or int
+ :rtype: float or str
+
.. _python-roles:
Cross-referencing Python objects
@@ -685,6 +704,89 @@ a visibility statement (``public``, ``private`` or ``protected``).
.. cpp:enumerator:: MyEnum::myOtherEnumerator = 42
+.. rst:directive:: .. cpp:concept:: template-parameter-list name
+ .. cpp:concept:: template-parameter-list name()
+
+ .. warning:: The support for concepts is experimental. It is based on the
+ Concepts Technical Specification, and the features may change as the TS evolves.
+
+ Describe a variable concept or a function concept. Both must have exactly 1
+ template parameter list. The name may be a nested name. Examples::
+
+ .. cpp:concept:: template<typename It> std::Iterator
+
+ Proxy to an element of a notional sequence that can be compared,
+ indirected, or incremented.
+
+ .. cpp:concept:: template<typename Cont> std::Container()
+
+ Holder of elements, to which it can provide access via
+ :cpp:concept:`Iterator` s.
+
+ They will render as follows:
+
+ .. cpp:concept:: template<typename It> std::Iterator
+
+ Proxy to an element of a notional sequence that can be compared,
+ indirected, or incremented.
+
+ .. cpp:concept:: template<typename Cont> std::Container()
+
+ Holder of elements, to which it can provide access via
+ :cpp:concept:`Iterator` s.
+
+Constrained Templates
+~~~~~~~~~~~~~~~~~~~~~
+
+.. warning:: The support for constrained templates is experimental. It is based on the
+ Concepts Technical Specification, and the features may change as the TS evolves.
+
+.. note:: Sphinx does not currently support ``requires`` clauses.
+
+Placeholders
+............
+
+Declarations may use the name of a concept to introduce constrained template
+parameters, or the keyword ``auto`` to introduce unconstrained template parameters::
+
+ .. cpp:function:: void f(auto &&arg)
+
+ A function template with a single unconstrained template parameter.
+
+ .. cpp:function:: void f(std::Iterator it)
+
+ A function template with a single template parameter, constrained by the
+ Iterator concept.
+
+Template Introductions
+......................
+
+Simple constrained function or class templates can be declared with a
+`template introduction` instead of a template parameter list::
+
+ .. cpp:function:: std::Iterator{It} void advance(It &it)
+
+ A function template with a template parameter constrained to be an Iterator.
+
+ .. cpp:class:: std::LessThanComparable{T} MySortedContainer
+
+ A class template with a template parameter constrained to be LessThanComparable.
+
+They are rendered as follows.
+
+.. cpp:function:: std::Iterator{It} void advance(It &it)
+
+ A function template with a template parameter constrained to be an Iterator.
+
+.. cpp:class:: std::LessThanComparable{T} MySortedContainer
+
+ A class template with a template parameter constrained to be LessThanComparable.
+
+Note however that no checking is performed with respect to parameter
+compatibility. E.g., ``Iterator{A, B, C}`` will be accepted as an introduction
+even though it would not be valid C++.
+
+
Namespacing
~~~~~~~~~~~~~~~~~
@@ -790,6 +892,7 @@ These roles link to the given declaration types:
cpp:member
cpp:var
cpp:type
+ cpp:concept
cpp:enum
cpp:enumerator
@@ -888,6 +991,11 @@ References to partial specialisations must always include the template parameter
Currently the lookup only succeed if the template parameter identifiers are equal strings.
+Configuration Variables
+~~~~~~~~~~~~~~~~~~~~~~~
+
+See :ref:`cpp-config`.
+
The Standard Domain
-------------------
diff --git a/doc/ext/builtins.rst b/doc/ext/builtins.rst
new file mode 100644
index 000000000..6d5e59a89
--- /dev/null
+++ b/doc/ext/builtins.rst
@@ -0,0 +1,24 @@
+Builtin Sphinx extensions
+-------------------------
+
+These extensions are built in and can be activated by respective entries in the
+:confval:`extensions` configuration value:
+
+.. toctree::
+
+ autodoc
+ autosectionlabel
+ autosummary
+ coverage
+ doctest
+ extlinks
+ githubpages
+ graphviz
+ ifconfig
+ inheritance
+ intersphinx
+ linkcode
+ math
+ napoleon
+ todo
+ viewcode
diff --git a/doc/ext/doctest.rst b/doc/ext/doctest.rst
index 2d06b69e6..818b86007 100644
--- a/doc/ext/doctest.rst
+++ b/doc/ext/doctest.rst
@@ -59,12 +59,9 @@ a comma-separated list of group names.
.. rst:directive:: .. doctest:: [group]
A doctest-style code block. You can use standard :mod:`doctest` flags for
- controlling how actual output is compared with what you give as output. By
- default, these options are enabled: ``ELLIPSIS`` (allowing you to put
- ellipses in the expected output that match anything in the actual output),
- ``IGNORE_EXCEPTION_DETAIL`` (not comparing tracebacks),
- ``DONT_ACCEPT_TRUE_FOR_1`` (by default, doctest accepts "True" in the output
- where "1" is given -- this is a relic of pre-Python 2.2 times).
+ controlling how actual output is compared with what you give as output. The
+ default set of flags is specified by the :confval:`doctest_default_flags`
+ configuration variable.
This directive supports two options:
@@ -182,6 +179,20 @@ Configuration
The doctest extension uses the following configuration values:
+.. confval:: doctest_default_flags
+
+ By default, these options are enabled:
+
+ - ``ELLIPSIS``, allowing you to put ellipses in the expected output that
+ match anything in the actual output;
+ - ``IGNORE_EXCEPTION_DETAIL``, causing everything following the leftmost
+ colon and any module information in the exception name to be ignored;
+ - ``DONT_ACCEPT_TRUE_FOR_1``, rejecting "True" in the output where "1" is
+ given -- the default behavior of accepting this substitution is a relic of
+ pre-Python 2.2 times.
+
+ .. versionadded:: 1.5
+
.. confval:: doctest_path
A list of directories that will be added to :data:`sys.path` when the doctest
diff --git a/doc/ext/example_google.py b/doc/ext/example_google.py
index 81a312cfd..34a720e36 100644
--- a/doc/ext/example_google.py
+++ b/doc/ext/example_google.py
@@ -43,6 +43,39 @@ on the first line, separated by a colon.
"""
+def function_with_types_in_docstring(param1, param2):
+ """Example function with types documented in the docstring.
+
+ `PEP 484`_ type annotations are supported. If attribute, parameter, and
+ return types are annotated according to `PEP 484`_, they do not need to be
+ included in the docstring:
+
+ Args:
+ param1 (int): The first parameter.
+ param2 (str): The second parameter.
+
+ Returns:
+ bool: The return value. True for success, False otherwise.
+
+ .. _PEP 484:
+ https://www.python.org/dev/peps/pep-0484/
+
+ """
+
+
+def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
+ """Example function with PEP 484 type annotations.
+
+ Args:
+ param1: The first parameter.
+ param2: The second parameter.
+
+ Returns:
+ The return value. True for success, False otherwise.
+
+ """
+
+
def module_level_function(param1, param2=None, *args, **kwargs):
"""This is an example of a module level function.
@@ -50,9 +83,6 @@ def module_level_function(param1, param2=None, *args, **kwargs):
of each parameter is required. The type and description of each parameter
is optional, but should be included if not obvious.
- Parameter types -- if given -- should be specified according to
- `PEP 484`_, though `PEP 484`_ conformance isn't required or enforced.
-
If \*args or \*\*kwargs are accepted,
they should be listed as ``*args`` and ``**kwargs``.
@@ -67,7 +97,7 @@ def module_level_function(param1, param2=None, *args, **kwargs):
Args:
param1 (int): The first parameter.
- param2 (Optional[str]): The second parameter. Defaults to None.
+ param2 (:obj:`str`, optional): The second parameter. Defaults to None.
Second line of description should be indented.
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
@@ -94,10 +124,6 @@ def module_level_function(param1, param2=None, *args, **kwargs):
that are relevant to the interface.
ValueError: If `param2` is equal to `param1`.
-
- .. _PEP 484:
- https://www.python.org/dev/peps/pep-0484/
-
"""
if param1 == param2:
raise ValueError('param1 may not be equal to param2')
@@ -139,7 +165,7 @@ class ExampleError(Exception):
Args:
msg (str): Human readable string describing the exception.
- code (Optional[int]): Error code.
+ code (:obj:`int`, optional): Error code.
Attributes:
msg (str): Human readable string describing the exception.
@@ -163,16 +189,9 @@ class ExampleClass(object):
Properties created with the ``@property`` decorator should be documented
in the property's getter method.
- Attribute and property types -- if given -- should be specified according
- to `PEP 484`_, though `PEP 484`_ conformance isn't required or enforced.
-
Attributes:
attr1 (str): Description of `attr1`.
- attr2 (Optional[int]): Description of `attr2`.
-
-
- .. _PEP 484:
- https://www.python.org/dev/peps/pep-0484/
+ attr2 (:obj:`int`, optional): Description of `attr2`.
"""
@@ -190,20 +209,20 @@ class ExampleClass(object):
Args:
param1 (str): Description of `param1`.
- param2 (Optional[int]): Description of `param2`. Multiple
+ param2 (:obj:`int`, optional): Description of `param2`. Multiple
lines are supported.
- param3 (List[str]): Description of `param3`.
+ param3 (list(str)): Description of `param3`.
"""
self.attr1 = param1
self.attr2 = param2
self.attr3 = param3 #: Doc comment *inline* with attribute
- #: List[str]: Doc comment *before* attribute, with type specified
+ #: list(str): Doc comment *before* attribute, with type specified
self.attr4 = ['attr4']
self.attr5 = None
- """Optional[str]: Docstring *after* attribute, with type specified."""
+ """str: Docstring *after* attribute, with type specified."""
@property
def readonly_property(self):
@@ -212,8 +231,8 @@ class ExampleClass(object):
@property
def readwrite_property(self):
- """List[str]: Properties with both a getter and setter should only
- be documented in their getter method.
+ """list(str): Properties with both a getter and setter
+ should only be documented in their getter method.
If the setter method contains notable behavior, it should be
mentioned here.
diff --git a/doc/ext/example_numpy.py b/doc/ext/example_numpy.py
index bb91cac82..7a2db94cc 100644
--- a/doc/ext/example_numpy.py
+++ b/doc/ext/example_numpy.py
@@ -37,6 +37,7 @@ module_level_variable1 : int
one convention to document module level variables and be consistent
with it.
+
.. _NumPy Documentation HOWTO:
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
@@ -52,6 +53,52 @@ on the first line, separated by a colon.
"""
+def function_with_types_in_docstring(param1, param2):
+ """Example function with types documented in the docstring.
+
+ `PEP 484`_ type annotations are supported. If attribute, parameter, and
+ return types are annotated according to `PEP 484`_, they do not need to be
+ included in the docstring:
+
+ Parameters
+ ----------
+ param1 : int
+ The first parameter.
+ param2 : str
+ The second parameter.
+
+ Returns
+ -------
+ bool
+ True if successful, False otherwise.
+
+ .. _PEP 484:
+ https://www.python.org/dev/peps/pep-0484/
+
+ """
+
+
+def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
+ """Example function with PEP 484 type annotations.
+
+ The return type must be duplicated in the docstring to comply
+ with the NumPy docstring style.
+
+ Parameters
+ ----------
+ param1
+ The first parameter.
+ param2
+ The second parameter.
+
+ Returns
+ -------
+ bool
+ True if successful, False otherwise.
+
+ """
+
+
def module_level_function(param1, param2=None, *args, **kwargs):
"""This is an example of a module level function.
@@ -59,9 +106,6 @@ def module_level_function(param1, param2=None, *args, **kwargs):
The name of each parameter is required. The type and description of each
parameter is optional, but should be included if not obvious.
- Parameter types -- if given -- should be specified according to
- `PEP 484`_, though `PEP 484`_ conformance isn't required or enforced.
-
If \*args or \*\*kwargs are accepted,
they should be listed as ``*args`` and ``**kwargs``.
@@ -81,7 +125,7 @@ def module_level_function(param1, param2=None, *args, **kwargs):
----------
param1 : int
The first parameter.
- param2 : Optional[str]
+ param2 : :obj:`str`, optional
The second parameter.
*args
Variable length argument list.
@@ -113,10 +157,6 @@ def module_level_function(param1, param2=None, *args, **kwargs):
ValueError
If `param2` is equal to `param1`.
-
- .. _PEP 484:
- https://www.python.org/dev/peps/pep-0484/
-
"""
if param1 == param2:
raise ValueError('param1 may not be equal to param2')
@@ -166,7 +206,7 @@ class ExampleError(Exception):
----------
msg : str
Human readable string describing the exception.
- code : Optional[int]
+ code : :obj:`int`, optional
Numeric error code.
Attributes
@@ -194,20 +234,13 @@ class ExampleClass(object):
Properties created with the ``@property`` decorator should be documented
in the property's getter method.
- Attribute and property types -- if given -- should be specified according
- to `PEP 484`_, though `PEP 484`_ conformance isn't required or enforced.
-
Attributes
----------
attr1 : str
Description of `attr1`.
- attr2 : Optional[int]
+ attr2 : :obj:`int`, optional
Description of `attr2`.
-
- .. _PEP 484:
- https://www.python.org/dev/peps/pep-0484/
-
"""
def __init__(self, param1, param2, param3):
@@ -227,10 +260,10 @@ class ExampleClass(object):
----------
param1 : str
Description of `param1`.
- param2 : List[str]
+ param2 : list(str)
Description of `param2`. Multiple
lines are supported.
- param3 : Optional[int]
+ param3 : :obj:`int`, optional
Description of `param3`.
"""
@@ -238,11 +271,11 @@ class ExampleClass(object):
self.attr2 = param2
self.attr3 = param3 #: Doc comment *inline* with attribute
- #: List[str]: Doc comment *before* attribute, with type specified
+ #: list(str): Doc comment *before* attribute, with type specified
self.attr4 = ["attr4"]
self.attr5 = None
- """Optional[str]: Docstring *after* attribute, with type specified."""
+ """str: Docstring *after* attribute, with type specified."""
@property
def readonly_property(self):
@@ -251,8 +284,8 @@ class ExampleClass(object):
@property
def readwrite_property(self):
- """List[str]: Properties with both a getter and setter should only
- be documented in their getter method.
+ """list(str): Properties with both a getter and setter
+ should only be documented in their getter method.
If the setter method contains notable behavior, it should be
mentioned here.
diff --git a/doc/ext/graphviz.rst b/doc/ext/graphviz.rst
index ca34fa281..0994c932a 100644
--- a/doc/ext/graphviz.rst
+++ b/doc/ext/graphviz.rst
@@ -96,6 +96,10 @@ It adds these directives:
All three directives support a ``graphviz_dot`` option that can be switch the
``dot`` command within the directive.
+.. versionadded:: 1.5
+ All three directives support a ``align`` option to align the graph horizontal.
+ The values "left", "center", "right" are allowed.
+
There are also these new config values:
.. confval:: graphviz_dot
diff --git a/doc/ext/inheritance.rst b/doc/ext/inheritance.rst
index 5e0a76fcc..bd287aa49 100644
--- a/doc/ext/inheritance.rst
+++ b/doc/ext/inheritance.rst
@@ -33,10 +33,15 @@ It adds this directive:
It also supports a ``private-bases`` flag option; if given, private base
classes (those whose name starts with ``_``) will be included.
+ You can use ``caption`` option to give a caption to the diagram.
+
.. versionchanged:: 1.1
Added ``private-bases`` option; previously, all bases were always
included.
+ .. versionchanged:: 1.5
+ Added ``caption`` option
+
New config values are:
diff --git a/doc/ext/intersphinx.rst b/doc/ext/intersphinx.rst
index 785164a0c..fb0114fc4 100644
--- a/doc/ext/intersphinx.rst
+++ b/doc/ext/intersphinx.rst
@@ -121,3 +121,14 @@ linking:
The maximum number of days to cache remote inventories. The default is
``5``, meaning five days. Set this to a negative value to cache inventories
for unlimited time.
+
+.. confval:: intersphinx_timeout
+
+ The number of seconds for timeout. The default is ``None``, meaning do not
+ timeout.
+
+ .. note::
+
+ timeout is not a time limit on the entire response download; rather, an
+ exception is raised if the server has not issued a response for timeout
+ seconds.
diff --git a/doc/ext/napoleon.rst b/doc/ext/napoleon.rst
index 304d8ac22..ea3e4042f 100644
--- a/doc/ext/napoleon.rst
+++ b/doc/ext/napoleon.rst
@@ -186,11 +186,60 @@ not be mixed. Choose one style for your project and be consistent with it.
* :ref:`example_google`
* :ref:`example_numpy`
- For Python type annotations, see `PEP 484`_.
+
+Type Annotations
+----------------
+
+`PEP 484`_ introduced a standard way to express types in Python code.
+This is an alternative to expressing types directly in docstrings.
+One benefit of expressing types according to `PEP 484`_ is that
+type checkers and IDEs can take advantage of them for static code
+analysis.
+
+Google style with Python 3 type annotations::
+
+ def func(arg1: int, arg2: str) -> bool:
+ """Summary line.
+
+ Extended description of function.
+
+ Args:
+ arg1: Description of arg1
+ arg2: Description of arg2
+
+ Returns:
+ Description of return value
+
+ """
+ return True
+
+Google style with types in docstrings::
+
+ def func(arg1, arg2):
+ """Summary line.
+
+ Extended description of function.
+
+ Args:
+ arg1 (int): Description of arg1
+ arg2 (str): Description of arg2
+
+ Returns:
+ bool: Description of return value
+
+ """
+ return True
+
+.. Note::
+ `Python 2/3 compatible annotations`_ aren't currently
+ supported by Sphinx and won't show up in the docs.
.. _PEP 484:
https://www.python.org/dev/peps/pep-0484/
+.. _Python 2/3 compatible annotations:
+ https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code
+
Configuration
=============
@@ -208,6 +257,7 @@ enabled in `conf.py`::
# Napoleon settings
napoleon_google_docstring = True
napoleon_numpy_docstring = True
+ napoleon_include_init_with_doc = False
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = True
napoleon_use_admonition_for_examples = False
@@ -234,6 +284,23 @@ enabled in `conf.py`::
True to parse `NumPy style`_ docstrings. False to disable support
for NumPy style docstrings. *Defaults to True.*
+.. confval:: napoleon_include_init_with_doc
+
+ True to list ``__init___`` docstrings separately from the class
+ docstring. False to fall back to Sphinx's default behavior, which
+ considers the ``__init___`` docstring as part of the class
+ documentation. *Defaults to False.*
+
+ **If True**::
+
+ def __init__(self):
+ \"\"\"
+ This will be included in the docs because it has a docstring
+ \"\"\"
+
+ def __init__(self):
+ # This will NOT be included in the docs
+
.. confval:: napoleon_include_private_with_doc
True to include private members (like ``_membername``) with docstrings
@@ -371,6 +438,22 @@ enabled in `conf.py`::
* **arg2** (*int, optional*) --
Description of `arg2`, defaults to 0
+.. confval:: napoleon_use_keyword
+
+ True to use a ``:keyword:`` role for each function keyword argument.
+ False to use a single ``:keyword arguments:`` role for all the
+ keywords.
+ *Defaults to True.*
+
+ This behaves similarly to :attr:`napoleon_use_param`. Note unlike docutils,
+ ``:keyword:`` and ``:param:`` will not be treated the same way - there will
+ be a separate "Keyword Arguments" section, rendered in the same fashion as
+ "Parameters" section (type links created if possible)
+
+ .. seealso::
+
+ :attr:`napoleon_use_param`
+
.. confval:: napoleon_use_rtype
True to use the ``:rtype:`` role for the return type. False to output
diff --git a/doc/ext/thirdparty.rst b/doc/ext/thirdparty.rst
new file mode 100644
index 000000000..6304e4af3
--- /dev/null
+++ b/doc/ext/thirdparty.rst
@@ -0,0 +1,35 @@
+Third-party extensions
+----------------------
+
+You can find several extensions contributed by users in the `Sphinx Contrib`_
+repository. It is open for anyone who wants to maintain an extension
+publicly; just send a short message asking for write permissions.
+
+There are also several extensions hosted elsewhere. The `Sphinx extension
+survey <http://sphinxext-survey.readthedocs.org/en/latest/>`__ contains a
+comprehensive list.
+
+If you write an extension that you think others will find useful or you think
+should be included as a part of Sphinx, please write to the project mailing
+list (`join here <https://groups.google.com/forum/#!forum/sphinx-dev>`_).
+
+.. _Sphinx Contrib: https://bitbucket.org/birkenfeld/sphinx-contrib
+
+
+Where to put your own extensions?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Extensions local to a project should be put within the project's directory
+structure. Set Python's module search path, ``sys.path``, accordingly so that
+Sphinx can find them.
+E.g., if your extension ``foo.py`` lies in the ``exts`` subdirectory of the
+project root, put into :file:`conf.py`::
+
+ import sys, os
+
+ sys.path.append(os.path.abspath('exts'))
+
+ extensions = ['foo']
+
+You can also install extensions anywhere else on ``sys.path``, e.g. in the
+``site-packages`` directory.
diff --git a/doc/ext/todo.rst b/doc/ext/todo.rst
index a809bc665..09abfa9b8 100644
--- a/doc/ext/todo.rst
+++ b/doc/ext/todo.rst
@@ -34,6 +34,13 @@ There is also an additional config value:
If this is ``True``, :rst:dir:`todo` and :rst:dir:`todolist` produce output,
else they produce nothing. The default is ``False``.
+.. confval:: todo_emit_warnings
+
+ If this is ``True``, :rst:dir:`todo` emits a warning for each TODO entries.
+ The default is ``False``.
+
+ .. versionadded:: 1.5
+
.. confval:: todo_link_only
If this is ``True``, :rst:dir:`todolist` produce output without file path and line,
@@ -41,3 +48,11 @@ There is also an additional config value:
.. versionadded:: 1.4
+autodoc provides the following an additional event:
+
+.. event:: todo-defined (app, node)
+
+ .. versionadded:: 1.5
+
+ Emitted when a todo is defined. *node* is the defined ``sphinx.ext.todo.todo_node``
+ node.
diff --git a/doc/ext/viewcode.rst b/doc/ext/viewcode.rst
index 5bf8eb033..5823090f6 100644
--- a/doc/ext/viewcode.rst
+++ b/doc/ext/viewcode.rst
@@ -15,6 +15,11 @@ a highlighted version of the source code, and a link will be added to all object
descriptions that leads to the source code of the described object. A link back
from the source to the description will also be inserted.
+This extension works only on HTML related builders like ``html``,
+``applehelp``, ``devhelp``, ``htmlhelp``, ``qthelp`` and so on except
+``singlehtml``. By default ``epub`` builder doesn't
+support this extension (see :confval:`viewcode_enable_epub`).
+
There is an additional config value:
.. confval:: viewcode_import
@@ -34,3 +39,26 @@ There is an additional config value:
main routine is protected by a ``if __name__ == '__main__'`` condition.
.. versionadded:: 1.3
+
+.. confval:: viewcode_enable_epub
+
+ If this is ``True``, viewcode extension is also enabled even if you use
+ epub builders. This extension generates pages outside toctree, but this
+ is not preferred as epub format.
+
+ Until 1.4.x, this extension is always enabled. If you want to generate
+ epub as same as 1.4.x, you should set ``True``, but epub format checker's
+ score becomes worse.
+
+ The default is ``False``.
+
+ .. versionadded:: 1.5
+
+ .. warning::
+
+ Not all epub readers support pages generated by viewcode extension.
+ These readers ignore links to pages are not under toctree.
+
+ Some reader's rendering result are corrupted and
+ `epubcheck <https://github.com/IDPF/epubcheck>`_'s score
+ becomes worse even if the reader supports.
diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst
index b5cb33a33..b3ffb7af0 100644
--- a/doc/extdev/appapi.rst
+++ b/doc/extdev/appapi.rst
@@ -358,7 +358,7 @@ package.
.. versionadded:: 1.1
-.. method:: Sphinx.add_source_parser(name, suffix, parser)
+.. method:: Sphinx.add_source_parser(suffix, parser)
Register a parser class for specified *suffix*.
diff --git a/doc/extdev/nodes.rst b/doc/extdev/nodes.rst
index e67fa3da6..359410e25 100644
--- a/doc/extdev/nodes.rst
+++ b/doc/extdev/nodes.rst
@@ -10,6 +10,7 @@ Nodes for domain-specific object descriptions
.. autoclass:: desc
.. autoclass:: desc_signature
+.. autoclass:: desc_signature_line
.. autoclass:: desc_addname
.. autoclass:: desc_type
.. autoclass:: desc_returns
diff --git a/doc/extensions.rst b/doc/extensions.rst
index f58361eb1..afd211c34 100644
--- a/doc/extensions.rst
+++ b/doc/extensions.rst
@@ -10,64 +10,7 @@ any aspect of document processing.
This chapter describes the extensions bundled with Sphinx. For the API
documentation on writing your own extension, see :ref:`dev-extensions`.
-Builtin Sphinx extensions
--------------------------
-
-These extensions are built in and can be activated by respective entries in the
-:confval:`extensions` configuration value:
-
.. toctree::
- ext/autodoc
- ext/autosectionlabel
- ext/autosummary
- ext/coverage
- ext/doctest
- ext/extlinks
- ext/githubpages
- ext/graphviz
- ext/ifconfig
- ext/inheritance
- ext/intersphinx
- ext/linkcode
- ext/math
- ext/napoleon
- ext/todo
- ext/viewcode
-
-
-Third-party extensions
-----------------------
-
-You can find several extensions contributed by users in the `Sphinx Contrib`_
-repository. It is open for anyone who wants to maintain an extension
-publicly; just send a short message asking for write permissions.
-
-There are also several extensions hosted elsewhere. The `Sphinx extension
-survey <http://sphinxext-survey.readthedocs.org/en/latest/>`__ contains a
-comprehensive list.
-
-If you write an extension that you think others will find useful or you think
-should be included as a part of Sphinx, please write to the project mailing
-list (`join here <https://groups.google.com/forum/#!forum/sphinx-dev>`_).
-
-.. _Sphinx Contrib: https://bitbucket.org/birkenfeld/sphinx-contrib
-
-
-Where to put your own extensions?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Extensions local to a project should be put within the project's directory
-structure. Set Python's module search path, ``sys.path``, accordingly so that
-Sphinx can find them.
-E.g., if your extension ``foo.py`` lies in the ``exts`` subdirectory of the
-project root, put into :file:`conf.py`::
-
- import sys, os
-
- sys.path.append(os.path.abspath('exts'))
-
- extensions = ['foo']
-
-You can also install extensions anywhere else on ``sys.path``, e.g. in the
-``site-packages`` directory.
+ ext/builtins
+ ext/thirdparty
diff --git a/doc/faq.rst b/doc/faq.rst
index ac78b05ca..eaa663d92 100644
--- a/doc/faq.rst
+++ b/doc/faq.rst
@@ -167,11 +167,45 @@ The following list gives some hints for the creation of epub files:
:confval:`html_static_path` directory and reference it with its full path in
the :confval:`epub_cover` config option.
+* kindlegen_ command can convert from epub3 resulting file to ``.mobi`` file
+ for Kindle. You can get ``yourdoc.mobi`` under ``_build/epub`` after the
+ following command:
+
+ .. code-block:: bash
+
+ $ make epub
+ $ kindlegen _build/epub/yourdoc.epub
+
+ kindlegen commands doesn't accept documents that have section
+ titles surrounding ``toctree`` directive:
+
+ .. code-block:: rst
+
+ Section Title
+ =============
+
+ .. toctree::
+
+ subdocument
+
+ Section After Toc Tree
+ ======================
+
+ kindlegen assumes all documents order in line, but resulting document
+ has complecated order for kindlegen::
+
+ ``parent.xhtml`` -> ``child.xhtml`` -> ``parent.xhtml``
+
+ If you got the following error, fix document structure::
+
+ Error(prcgen):E24011: TOC section scope is not included in the parent chapter:(title)
+ Error(prcgen):E24001: The table of content could not be built.
+
.. _Epubcheck: https://code.google.com/archive/p/epubcheck
.. _Calibre: http://calibre-ebook.com/
.. _FBreader: https://fbreader.org/
.. _Bookworm: http://www.oreilly.com/bookworm/index.html
-
+.. _kindlegen: https://www.amazon.com/gp/feature.html?docId=1000765211
.. _texinfo-faq:
@@ -248,10 +282,6 @@ The following notes may be helpful if you want to create Texinfo files:
info:Texinfo#makeinfo_options
- which produces::
-
- info:Texinfo#makeinfo_options
-
- Inline markup
The standard formatting for ``*strong*`` and ``_emphasis_`` can
diff --git a/doc/install.rst b/doc/install.rst
index a2aeaf9cb..b3519e1ba 100644
--- a/doc/install.rst
+++ b/doc/install.rst
@@ -4,7 +4,7 @@ Installing Sphinx
=================
Since Sphinx is written in the Python language, you need to install Python
-(the required version is at least 2.6) and Sphinx.
+(the required version is at least 2.7) and Sphinx.
Sphinx packages are available on the `Python Package Index
<https://pypi.python.org/pypi/Sphinx>`_.
@@ -80,8 +80,8 @@ sidebar and under "Quick Links", click "Windows Installer" to download.
.. note::
Currently, Python offers two major versions, 2.x and 3.x. Sphinx 1.3 can run
- under Python 2.6, 2.7, 3.3, 3.4, with the recommended version being
- 2.7. This chapter assumes you have installed Python 2.7.
+ under Python 2.7, 3.4, 3.5, with the recommended version being 2.7. This
+ chapter assumes you have installed Python 2.7.
Follow the Windows installer for Python.
diff --git a/doc/installpython.jpg b/doc/installpython.jpg
index b0e458e40..fff4630ae 100644
--- a/doc/installpython.jpg
+++ b/doc/installpython.jpg
Binary files differ
diff --git a/doc/intro.rst b/doc/intro.rst
index ae3ec0b33..b79f7f4a4 100644
--- a/doc/intro.rst
+++ b/doc/intro.rst
@@ -54,7 +54,7 @@ See the :ref:`pertinent section in the FAQ list <usingwith>`.
Prerequisites
-------------
-Sphinx needs at least **Python 2.6** or **Python 3.3** to run, as well as the
+Sphinx needs at least **Python 2.7** or **Python 3.4** to run, as well as the
docutils_ and Jinja2_ libraries. Sphinx should work with docutils version 0.10
or some (not broken) SVN trunk snapshot. If you like to have source code
highlighting support, you must also install the Pygments_ library.
diff --git a/doc/invocation.rst b/doc/invocation.rst
index ce51fe080..436c652f9 100644
--- a/doc/invocation.rst
+++ b/doc/invocation.rst
@@ -118,6 +118,10 @@ Extension options
Enable `sphinx.ext.viewcode` extension.
+.. option:: --extensions=EXTENSIONS
+
+ Enable arbitary extensions.
+
Makefile and Batchfile creation options
---------------------------------------
@@ -138,6 +142,32 @@ Makefile and Batchfile creation options
.. versionadded:: 1.3
Add various options for sphinx-quickstart invocation.
+Project templating
+------------------
+
+.. option:: -t, --templatedir=TEMPLATEDIR
+
+ Template directory for template files. You can modify the templates of
+ sphinx project files generated by quickstart. Following Jinja2 template
+ files are allowed:
+
+ * master_doc.rst_t
+ * conf.py_t
+ * Makefile_t
+ * Makefile.new_t
+ * make.bat_t
+ * make.bat.new_t
+
+ In detail, please refer the system template files Sphinx provides.
+ (sphinx/templates/quickstart)
+
+.. option:: -d NAME=VALUE
+
+ Define a template variable
+
+.. versionadded:: 1.5
+ Project templating options for sphinx-quickstart
+
Invocation of sphinx-build
==========================
@@ -453,11 +483,24 @@ The :program:`sphinx-apidoc` script has several options:
to default values, but you can influence the most important ones using the
following options.
+.. option:: --implicit-namespaces
+
+ By default sphinx-apidoc processes sys.path searching for modules only.
+ Python 3.3 introduced :pep:`420` implicit namespaces that allow module path
+ structures such as ``foo/bar/module.py`` or ``foo/bar/baz/__init__.py``
+ (notice that ``bar`` and ``foo`` are namespaces, not modules).
+
+ Specifying this option interprets paths recursively according to PEP-0420.
+
.. option:: -M
This option makes sphinx-apidoc put module documentation before submodule
documentation.
+.. option:: -a
+
+ Append module_path to sys.path.
+
.. option:: -H project
Sets the project name to put in generated files (see :confval:`project`).
diff --git a/doc/latex.rst b/doc/latex.rst
new file mode 100644
index 000000000..d378f2090
--- /dev/null
+++ b/doc/latex.rst
@@ -0,0 +1,445 @@
+.. highlightlang:: python
+
+.. _latex:
+
+LaTeX customization
+===================
+
+.. module:: latex
+ :synopsis: LaTeX specifics.
+
+The *latex* target does not benefit from pre-prepared themes like the
+*html* target does (see :doc:`theming`).
+
+.. raw:: latex
+
+ \begingroup
+ \sphinxsetup{verbatimwithframe=false,%
+ VerbatimColor={named}{OldLace}, TitleColor={named}{DarkGoldenrod},%
+ hintBorderColor={named}{LightCoral}, attentionBgColor={named}{LightPink},%
+ attentionborder=3pt, attentionBorderColor={named}{Crimson},%
+ noteBorderColor={named}{Olive}, noteborder=2pt,%
+ cautionBorderColor={named}{Cyan}, cautionBgColor={named}{LightCyan},%
+ cautionborder=3pt}
+ \relax
+
+
+Basic customization
+-------------------
+
+It is available from ``conf.py`` via usage of the
+:ref:`latex-options` as described in :doc:`config` (backslashes must be doubled
+in Python string literals to reach latex.) For example::
+
+ # inside conf.py
+ latex_engine = 'xelatex'
+ latex_elements = {
+ 'fontenc': '\\usepackage{fontspec}',
+ 'fontpkg': '''\
+ \\setmainfont{DejaVu Serif}
+ \\setsansfont{DejaVu Sans}
+ \\setmonofont{DejaVu Sans Mono}''',
+ 'geometry': '\\usepackage[vmargin=2.5cm, hmargin=3cm]{geometry}',
+ 'preamble': '''\
+ \\usepackage[titles]{tocloft}
+ \\cftsetpnumwidth {1.25cm}\\cftsetrmarg{1.5cm}
+ \\setlength{\\cftchapnumwidth}{0.75cm}
+ \\setlength{\\cftsecindent}{\\cftchapnumwidth}
+ \\setlength{\\cftsecnumwidth}{1.25cm}''',
+ 'fncychap': '\\usepackage[Bjornstrup]{fncychap}',
+ 'printindex': '\\footnotesize\\raggedright\\printindex',
+ }
+ latex_show_urls = 'footnote'
+
+.. the above was tested on Sphinx's own 1.5a2 documentation with good effect !
+
+.. highlight:: latex
+
+More advanced customization will be obtained via insertion into the LaTeX
+preamble of relevant ``\renewcommand``, ``\renewenvironment``, ``\setlength``,
+or ``\definecolor`` commands. The ``'preamble'`` key of
+:confval:`latex_elements` will serve for inserting these commands. If they are
+numerous, it may prove more convenient to assemble them into a specialized
+file :file:`mystyle.tex` and then use::
+
+ 'preamble': r'\makeatletter\input{mystyle.tex}\makeatother',
+
+or, better, to set up a style file
+:file:`mystyle.sty` which can then be loaded via::
+
+ 'preamble': r'\usepackage{mystyle}',
+
+The :ref:`build configuration file <build-config>` file for the project needs
+to have its variable :confval:`latex_additional_files` appropriately
+configured, for example::
+
+ latex_additional_files = ["mystyle.sty"]
+
+The Sphinx LaTeX style package options
+--------------------------------------
+
+The ``'sphinxsetup'`` key to :confval:`latex_elements` provides a
+more convenient interface to various style parameters. It is a comma separated
+string of ``key=value`` instructions::
+
+ key1=value1,key2=value2, ...
+
+- if a key is repeated, it is its last occurence which counts,
+- spaces around the commas and equal signs are ignored.
+
+If non-empty, it will be passed as argument to the ``\sphinxsetup`` command::
+
+ \usepackage{sphinx}
+ \sphinxsetup{key1=value1,key2=value2,...}
+
+.. versionadded:: 1.5
+
+.. note::
+
+ - Most options described next could also have been positioned as
+ :file:`sphinx.sty` package options. But for those where the key value
+ contains some LaTeX code the use of ``\sphinxsetup`` is mandatory. Hence
+ the whole ``'sphinxsetup'`` string is passed as argument to
+ ``\sphinxsetup``.
+
+ - As an alternative to the ``'sphinxsetup'`` key, it is possibly
+ to insert explicitely the ``\\sphinxsetup{key=value,..}`` inside the
+ ``'preamble'`` key. It is even possible to use the ``\sphinxsetup`` in
+ the body of the document, via the :rst:dir:`raw` directive, to modify
+ dynamically the option values: this is actually what we did for the
+ duration of this chapter for the PDF output, which is styled using::
+
+ verbatimwithframe=false,
+ VerbatimColor={named}{OldLace}, TitleColor={named}{DarkGoldenrod},
+ hintBorderColor={named}{LightCoral}, attentionBgColor={named}{LightPink},
+ attentionborder=3pt, attentionBorderColor={named}{Crimson},
+ noteBorderColor={named}{Olive}, noteborder=2pt,
+ cautionBorderColor={named}{Cyan}, cautionBgColor={named}{LightCyan},
+ cautionborder=3pt
+
+ and with the ``svgnames`` option having been passed to "xcolor" package::
+
+ latex_elements = {
+ 'passoptionstopackages': r'\PassOptionsToPackage{svgnames}{xcolor}',
+ }
+
+
+Here are the currently available options together with their default values.
+
+.. caution::
+
+ These options correspond to what has been so far the default LaTeX
+ rendering by Sphinx; if in future Sphinx offers various *themes* for LaTeX,
+ the interface may change.
+
+``verbatimwithframe``
+ default ``true``. Boolean to specify if :rst:dir:`code-block`\ s and literal
+ includes are framed. Setting it to ``false`` does not deactivate use of
+ package "framed", because it is still in use for the optional background
+ colour (see below).
+
+ .. attention::
+
+ LaTeX requires ``true`` or ``false`` to be specified in *lowercase*.
+
+``verbatimwrapslines``
+ default ``true``. Tells whether long lines in :rst:dir:`code-block`\ s
+ should be wrapped.
+
+ .. (comment) It is theoretically possible to customize this even
+ more and decide at which characters a line-break can occur and whether
+ before or after, but this is accessible currently only by re-defining some
+ macros with complicated LaTeX syntax from :file:`sphinx.sty`.
+
+``inlineliteralwraps``
+ default ``true``. Allows linebreaks inside inline literals: but extra
+ potential break-points (additionally to those allowed by LaTeX at spaces
+ or for hyphenation) are currently inserted only after the characters
+ ``. , ; ? ! /``. Due to TeX internals, white space in the line will be
+ stretched
+ (or shrinked) in order to accomodate the linebreak.
+
+ .. versionadded:: 1.5
+ set this option to ``false`` to recover former behaviour.
+
+``verbatimvisiblespace``
+ default ``\textcolor{red}{\textvisiblespace}``. When a long code line is
+ split, space characters located at end of the line before the break are
+ displayed using this code.
+
+``verbatimcontinued``
+ The default is::
+
+ \makebox[2\fontcharwd\font`\x][r]{\textcolor{red}{\tiny$\hookrightarrow$}}
+
+ It is printed at start of continuation lines. This rather formidable
+ expression reserves twice the width of a typical character in the current
+ (monospaced) font and puts there a small red hook pointing to the right.
+
+ .. versionchanged:: 1.5
+ The breaking of long code lines was introduced at 1.4.2. The space
+ reserved to the continuation symbol was changed at 1.5 to obey the
+ current font characteristics (this was needed as Sphinx 1.5 LaTeX
+ allows code-blocks in footnotes which use a smaller font size).
+
+ .. hint::
+
+ This specification gives the same spacing as before 1.5::
+
+ \normalfont\normalsize\makebox[3ex][r]{\textcolor{red}{\tiny$\hookrightarrow$}
+
+``TitleColor``
+ default ``{rgb}{0.126,0.263,0.361}``. The colour for titles (as configured
+ via use of package "titlesec".) It must obey the syntax of the
+ ``\definecolor`` command. Check the documentation of packages ``color`` or
+ ``xcolor``.
+
+``InnerLinkColor``
+ default ``{rgb}{0.208,0.374,0.486}``. A colour passed to ``hyperref`` as
+ value of ``linkcolor`` and ``citecolor``.
+
+``OuterLinkColor``
+ default ``{rgb}{0.216,0.439,0.388}``. A colour passed to ``hyperref`` as
+ value of ``filecolor``, ``menucolor``, and ``urlcolor``.
+
+``VerbatimColor``
+ default ``{rgb}{1,1,1}``. The background colour for
+ :rst:dir:`code-block`\ s. The default is white.
+
+``VerbatimBorderColor``
+ default ``{rgb}{0,0,0}``. The frame color, defaults to black.
+
+``verbatimsep``
+ default ``\fboxsep``. The separation between code lines and the frame.
+
+``verbatimborder``
+ default ``\fboxrule``. The width of the frame around
+ :rst:dir:`code-block`\ s.
+
+``shadowsep``
+ default ``5pt``. The separation between contents and frame for
+ :dudir:`contents` and :dudir:`topic` boxes.
+
+``shadowsize``
+ default ``4pt``. The width of the lateral "shadow" to the right.
+
+``shadowrule``
+ default ``\fboxrule``. The width of the frame around :dudir:`topic` boxes.
+
+``noteBorderColor``
+ default ``{rgb}{0,0,0}``. The colour for the two horizontal rules used by
+ Sphinx in LaTeX for styling a
+ :dudir:`note` admonition. Defaults to black.
+
+ .. note::
+
+ The actual name of the colour as declared to "color" or "xcolor" is
+ ``sphinxnoteBorderColor``. The same "sphinx" prefix applies to all
+ colours for notices and admonitions.
+
+``hintBorderColor``
+ default ``{rgb}{0,0,0}``. id.
+
+``importantBorderColor``
+ default ``{rgb}{0,0,0}``. id.
+
+``tipBorderColor``
+ default ``{rgb}{0,0,0}``. id.
+
+``noteborder``
+ default ``0.5pt``. The width of the two horizontal rules.
+
+``hintborder``
+ default ``0.5pt``. id.
+
+``importantborder``
+ default ``0.5pt``. id.
+
+``tipborder``
+ default ``0.5pt``. id.
+
+``warningBorderColor``
+ default ``{rgb}{0,0,0}``. The colour of the frame for :dudir:`warning` type
+ admonitions. Defaults to black.
+
+``cautionBorderColor``
+ default ``{rgb}{0,0,0}``. id.
+
+``attentionBorderColor``
+ default ``{rgb}{0,0,0}``. id.
+
+``dangerBorderColor``
+ default ``{rgb}{0,0,0}``. id.
+
+``errorBorderColor``
+ default ``{rgb}{0,0,0}``. id.
+
+``warningBgColor``
+ default ``{rgb}{1,1,1}``. The background colour for :dudir:`warning` type
+ admonition, defaults to white.
+
+``cautionBgColor``
+ default ``{rgb}{1,1,1}``. id.
+
+``attentionBgColor``
+ default ``{rgb}{1,1,1}``. id.
+
+``dangerBgColor``
+ default ``{rgb}{1,1,1}``. id.
+
+``errorBgColor``
+ default ``{rgb}{1,1,1}``. id.
+
+``warningborder``
+ default ``1pt``. The width of the frame.
+
+``cautionborder``
+ default ``1pt``. id.
+
+``attentionborder``
+ default ``1pt``. id.
+
+``dangerborder``
+ default ``1pt``. id.
+
+``errorborder``
+ default ``1pt``. id.
+
+``AtStartFootnote``
+ default ``\mbox{ }``. LaTeX macros inserted at the start of the footnote
+ text at bottom of page, after the footnote number.
+
+``BeforeFootnote``
+ default ``\leavevmode\unskip``. LaTeX macros inserted before the footnote
+ mark. The default removes possible space before it.
+
+ It can be set to empty (``BeforeFootnote={},``) to recover the earlier
+ behaviour of Sphinx, or alternatively contain a ``\nobreak\space`` or a
+ ``\thinspace`` after the ``\unskip`` to insert some chosen
+ (non-breakable) space.
+
+ .. versionadded:: 1.5
+ formerly, footnotes from explicit mark-up were
+ preceded by a space (hence a linebreak there was possible), but
+ automatically generated footnotes had no such space.
+
+``HeaderFamily``
+ default ``\sffamily\bfseries``. Sets the font used by headings.
+
+As seen above, key values may even be used for LaTeX commands. But don't
+forget to double the backslashes if not using "raw" Python strings.
+
+The LaTeX environments defined by Sphinx
+----------------------------------------
+
+Let us now list some macros from the package file
+:file:`sphinx.sty` and class file :file:`sphinxhowto.cls` or
+:file:`sphinxmanual.cls`, which can be entirely redefined, if desired.
+
+- text styling commands (they have one argument): ``\sphinx<foo>`` with
+ ``<foo>`` being one of ``strong``, ``bfcode``, ``email``, ``tablecontinued``,
+ ``titleref``, ``menuselection``, ``accelerator``, ``crossref``, ``termref``,
+ ``optional``. By default and for backwards compatibility the ``\sphinx<foo>``
+ expands to ``\<foo>`` hence the user can choose to customize rather the latter
+ (the non-prefixed macros will be left undefined if option
+ :confval:`latex_keep_old_macro_names` is set to ``False`` in :file:`conf.py`.)
+
+ .. versionchanged:: 1.4.5
+ use of ``\sphinx`` prefixed macro names to limit possibilities of conflict
+ with user added packages: if
+ :confval:`latex_keep_old_macro_names` is set to ``False`` in
+ :file:`conf.py` only the prefixed names are defined.
+- more text styling commands: ``\sphinxstyle<bar>`` with ``<bar>`` one of
+ ``indexentry``, ``indexextra``, ``indexpageref``, ``topictitle``,
+ ``sidebartitle``, ``othertitle``, ``sidebarsubtitle``, ``thead``,
+ ``emphasis``, ``literalemphasis``, ``strong``, ``literalstrong``,
+ ``abbreviation``, ``literalintitle``.
+
+ .. versionadded:: 1.5
+ the new macros are wrappers of the formerly hard-coded ``\texttt``,
+ ``\emph``, ... The default definitions can be found in
+ :file:`sphinx.sty`.
+- paragraph level environments: for each admonition type ``<foo>``, the
+ used environment is named ``sphinx<foo>``. They may be ``\renewenvironment``
+ 'd individually, and must then be defined with one argument (it is the heading
+ of the notice, for example ``Warning:`` for :dudir:`warning` directive, if
+ English is the document language). Their default definitions use either the
+ *sphinxheavybox* (for the first listed directives) or the *sphinxlightbox*
+ environments, configured to use the parameters (colours, border thickness)
+ specific to each type, which can be set via ``'sphinxsetup'`` string.
+
+ .. versionchanged:: 1.5
+ use of public environment names, separate customizability of the parameters.
+- the :dudir:`contents` directive (with ``:local:`` option) and the
+ :dudir:`topic` directive are implemented by environment ``sphinxShadowBox``.
+ See above for the three dimensions associated with it.
+
+ .. versionchanged:: 1.5
+ use of public names for the three lengths. The environment itself was
+ redefined to allow page breaks at release 1.4.2.
+- the literal blocks (:rst:dir:`code-block` directives, etc ...), are
+ implemented using ``sphinxVerbatim`` environment which is a wrapper of
+ ``Verbatim`` environment from package ``fancyvrb.sty``. It adds the handling
+ of the top caption and the wrapping of long lines, and a frame which allows
+ pagebreaks. Inside tables the used
+ environment is ``sphinxVerbatimintable`` (it does not draw a frame, but
+ allows a caption).
+
+ .. versionchanged:: 1.5
+ ``Verbatim`` keeps exact same meaning as in ``fancyvrb.sty`` (meaning
+ which is the one of ``OriginalVerbatim`` too), and custom one is called
+ ``sphinxVerbatim``. Also, earlier version of Sphinx used
+ ``OriginalVerbatim`` inside tables (captions were lost, long code lines
+ were not wrapped), it now uses there ``sphinxVerbatimintable``.
+ .. versionadded:: 1.5
+ the two customizable lengths, the ``sphinxVerbatimintable``, the boolean
+ toggles described above.
+- by default the Sphinx style file ``sphinx.sty`` includes the command
+ ``\fvset{fontsize=\small}`` as part of its configuration of
+ ``fancyvrb.sty``. The user may override this for example via
+ ``\fvset{fontsize=auto}`` which will use for listings the ambient
+ font size. Refer to ``fancyvrb.sty``'s documentation for further keys.
+
+ .. versionadded:: 1.5
+ formerly, the use of ``\small`` for code listings was not customizable.
+- the section, subsection, ... headings are set using *titlesec*'s
+ ``\titleformat`` command. Check :file:`sphinx.sty` for the definitions.
+- for the ``'sphinxmanual'`` class (corresponding to the fifth element of
+ :confval:`latex_documents` being set to ``'manual'``), the chapter headings
+ can be customized using *fncychap*'s commands ``\ChNameVar``, ``\ChNumVar``,
+ ``\ChTitleVar``. Check :file:`sphinx.sty` for the default definitions. They
+ are applied only if *fncychap* is loaded with option ``Bjarne``. It is also
+ possible to use an empty ``'fncychap'`` key, and use the *titlesec*
+ ``\titleformat`` command to style the chapter titles.
+
+ .. versionchanged:: 1.5
+ formerly, use of *fncychap* with other styles than ``Bjarne`` was
+ dysfunctional.
+- the table of contents is typeset via ``\sphinxtableofcontents`` which is a
+ wrapper (whose definition can be found in :file:`sphinxhowto.cls` or in
+ :file:`sphinxmanual.cls`) of standard ``\tableofcontents``.
+
+ .. versionchanged:: 1.5
+ formerly, the meaning of ``\tableofcontents`` was modified by Sphinx.
+- the bibliography and Python Module index are typeset respectively within
+ environments ``sphinxthebibliography`` and ``sphinxtheindex``, which are
+ simple wrappers of the non-modified ``thebibliography`` and ``theindex``
+ environments.
+
+ .. versionchanged:: 1.5
+ formerly, the original environments were modified by Sphinx.
+
+- the list is not exhaustive: refer to :file:`sphinx.sty` for more.
+
+.. hint::
+
+ As an experimental feature, Sphinx can use user-defined template file for
+ LaTeX source if you have a file named ``_templates/latex.tex_t`` on your
+ project. Now all template variables are unstable and undocumented. They
+ will be changed in future version.
+
+ .. versionadded:: 1.5
+
+.. raw:: latex
+
+ \endgroup
diff --git a/doc/man/sphinx-apidoc.rst b/doc/man/sphinx-apidoc.rst
index a01d2a82f..be0c3d3a3 100644
--- a/doc/man/sphinx-apidoc.rst
+++ b/doc/man/sphinx-apidoc.rst
@@ -49,6 +49,7 @@ Options
These options are used with ``-F``:
+-a Append module_path to sys.path.
-H <project> Project name to put into the configuration.
-A <author> Author name(s) to put into the configuration.
-V <version> Project version.
diff --git a/doc/markup/code.rst b/doc/markup/code.rst
index 6e8028fe4..c7cb0f911 100644
--- a/doc/markup/code.rst
+++ b/doc/markup/code.rst
@@ -241,7 +241,7 @@ Dedent
.. versionadded:: 1.3
-A ``dedent`` option can be given to strip a precedence characters from the code
+A ``dedent`` option can be given to strip indentation characters from the code
block. For example::
.. literalinclude:: example.rb
diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst
index ae47f820d..bd02dfa08 100644
--- a/doc/markup/inline.rst
+++ b/doc/markup/inline.rst
@@ -212,15 +212,18 @@ Cross-referencing figures by figure number
.. versionadded:: 1.3
+.. versionchanged:: 1.5
+ `numref` role can also refer sections.
+
.. rst:role:: numref
- Link to the specified figures, tables and code-blocks; the standard reST
- labels are used. When you use this role, it will insert a reference to the
- figure with link text by its figure number like "Fig. 1.1".
+ Link to the specified figures, tables, code-blocks and sections; the standard
+ reST labels are used. When you use this role, it will insert a reference to
+ the figure with link text by its figure number like "Fig. 1.1".
If an explicit link text is given (like usual: ``:numref:`Image of Sphinx (Fig.
%s) <my-figure>```), the link caption will be the title of the reference.
- As a special character, `%s` will be replaced to figure number.
+ The format of link text is same as :confval:`numfig_format`.
If :confval:`numfig` is ``False``, figures are not numbered.
so this role inserts not a reference but labels or link text.
diff --git a/doc/markup/misc.rst b/doc/markup/misc.rst
index 1f9f446f1..bdfc3346c 100644
--- a/doc/markup/misc.rst
+++ b/doc/markup/misc.rst
@@ -238,10 +238,19 @@ following directive exists:
By default, Sphinx uses a table layout with ``L`` for every column.
+ .. hint::
+
+ For columns which are known to be much narrower than the others it is
+ recommended to use the lowercase specifiers. For more information, check
+ the ``tabulary`` manual.
+
.. versionadded:: 0.3
.. warning::
+ Tables with more than 30 rows are rendered using ``longtable``, not
+ ``tabulary``, in order to allow pagebreaks.
+
Tables that contain list-like elements such as object descriptions,
blockquotes or any kind of lists cannot be set out of the box with
``tabulary``. They are therefore set with the standard LaTeX ``tabular``
@@ -253,8 +262,6 @@ following directive exists:
literal block are always set with ``tabular``. Also, the verbatim
environment used for literal blocks only works in ``p{width}`` columns, which
means that by default, Sphinx generates such column specs for such tables.
- Use the :rst:dir:`tabularcolumns` directive to get finer control over such
- tables.
.. rubric:: Footnotes
diff --git a/doc/markup/toctree.rst b/doc/markup/toctree.rst
index b4c7105fd..a0161ee3c 100644
--- a/doc/markup/toctree.rst
+++ b/doc/markup/toctree.rst
@@ -123,6 +123,16 @@ tables of contents. The ``toctree`` directive is the central element.
toctree directive. This is useful if you want to generate a "sitemap" from
the toctree.
+ You can use the ``reversed`` flag option to reverse the order of the entries
+ in the list. This can be useful when using the ``glob`` flag option to
+ reverse the ordering of the files. Example::
+
+ .. toctree::
+ :glob:
+ :reversed:
+
+ recipe/*
+
You can also give a "hidden" option to the directive, like this::
.. toctree::
diff --git a/doc/more.png b/doc/more.png
index a27a0fcba..97553a8b7 100644
--- a/doc/more.png
+++ b/doc/more.png
Binary files differ
diff --git a/doc/pythonorg.png b/doc/pythonorg.png
index 32f0787d1..cf9ccbbdb 100644
--- a/doc/pythonorg.png
+++ b/doc/pythonorg.png
Binary files differ
diff --git a/doc/rest.rst b/doc/rest.rst
index 293b2ea02..7b2b92ddc 100644
--- a/doc/rest.rst
+++ b/doc/rest.rst
@@ -363,8 +363,9 @@ directory on building (e.g. the ``_static`` directory for HTML output.)
Interpretation of image size options (``width`` and ``height``) is as follows:
if the size has no unit or the unit is pixels, the given size will only be
-respected for output channels that support pixels (i.e. not in LaTeX output).
-Other units (like ``pt`` for points) will be used for HTML and LaTeX output.
+respected for output channels that support pixels. Other units (like ``pt``
+for points) will be used for HTML and LaTeX output (the latter replaces ``pt``
+by ``bp`` as this is the TeX unit such that ``72bp=1in``).
Sphinx extends the standard docutils behavior by allowing an asterisk for the
extension::
@@ -386,6 +387,9 @@ Note that image file names should not contain spaces.
.. versionchanged:: 0.6
Image paths can now be absolute.
+.. versionchanged:: 1.5
+ latex target supports pixels (default is ``96px=1in``).
+
Footnotes
---------
diff --git a/doc/themes/agogo.png b/doc/themes/agogo.png
index 453a1f7dc..5a09cb96c 100644
--- a/doc/themes/agogo.png
+++ b/doc/themes/agogo.png
Binary files differ
diff --git a/doc/themes/alabaster.png b/doc/themes/alabaster.png
index 6e02c35ca..4a49c1ad0 100644
--- a/doc/themes/alabaster.png
+++ b/doc/themes/alabaster.png
Binary files differ
diff --git a/doc/themes/bizstyle.png b/doc/themes/bizstyle.png
index 4deae9a79..e19fb6b34 100644
--- a/doc/themes/bizstyle.png
+++ b/doc/themes/bizstyle.png
Binary files differ
diff --git a/doc/themes/classic.png b/doc/themes/classic.png
index 6989ebe9b..3b3c9cbd8 100644
--- a/doc/themes/classic.png
+++ b/doc/themes/classic.png
Binary files differ
diff --git a/doc/themes/fullsize/agogo.png b/doc/themes/fullsize/agogo.png
index bfdba3a17..106a16cea 100644
--- a/doc/themes/fullsize/agogo.png
+++ b/doc/themes/fullsize/agogo.png
Binary files differ
diff --git a/doc/themes/fullsize/alabaster.png b/doc/themes/fullsize/alabaster.png
index 3e026c999..5eca20912 100644
--- a/doc/themes/fullsize/alabaster.png
+++ b/doc/themes/fullsize/alabaster.png
Binary files differ
diff --git a/doc/themes/fullsize/bizstyle.png b/doc/themes/fullsize/bizstyle.png
index d917e2ff2..586064765 100644
--- a/doc/themes/fullsize/bizstyle.png
+++ b/doc/themes/fullsize/bizstyle.png
Binary files differ
diff --git a/doc/themes/fullsize/classic.png b/doc/themes/fullsize/classic.png
index 9c00f6899..269dab22f 100644
--- a/doc/themes/fullsize/classic.png
+++ b/doc/themes/fullsize/classic.png
Binary files differ
diff --git a/doc/themes/fullsize/haiku.png b/doc/themes/fullsize/haiku.png
index 8d807f4e1..707d2bfec 100644
--- a/doc/themes/fullsize/haiku.png
+++ b/doc/themes/fullsize/haiku.png
Binary files differ
diff --git a/doc/themes/fullsize/nature.png b/doc/themes/fullsize/nature.png
index 02d8743b3..00730c0a5 100644
--- a/doc/themes/fullsize/nature.png
+++ b/doc/themes/fullsize/nature.png
Binary files differ
diff --git a/doc/themes/fullsize/pyramid.png b/doc/themes/fullsize/pyramid.png
index 961cb896c..3b9d04d13 100644
--- a/doc/themes/fullsize/pyramid.png
+++ b/doc/themes/fullsize/pyramid.png
Binary files differ
diff --git a/doc/themes/fullsize/scrolls.png b/doc/themes/fullsize/scrolls.png
index 4e5c45f21..8a1c1faf5 100644
--- a/doc/themes/fullsize/scrolls.png
+++ b/doc/themes/fullsize/scrolls.png
Binary files differ
diff --git a/doc/themes/fullsize/sphinx_rtd_theme.png b/doc/themes/fullsize/sphinx_rtd_theme.png
index 4a3d74c88..95cff4ccd 100644
--- a/doc/themes/fullsize/sphinx_rtd_theme.png
+++ b/doc/themes/fullsize/sphinx_rtd_theme.png
Binary files differ
diff --git a/doc/themes/fullsize/sphinxdoc.png b/doc/themes/fullsize/sphinxdoc.png
index b74633452..eb498e3e8 100644
--- a/doc/themes/fullsize/sphinxdoc.png
+++ b/doc/themes/fullsize/sphinxdoc.png
Binary files differ
diff --git a/doc/themes/fullsize/traditional.png b/doc/themes/fullsize/traditional.png
index da69efe12..07ad00875 100644
--- a/doc/themes/fullsize/traditional.png
+++ b/doc/themes/fullsize/traditional.png
Binary files differ
diff --git a/doc/themes/haiku.png b/doc/themes/haiku.png
index 78a2570c4..4530debb9 100644
--- a/doc/themes/haiku.png
+++ b/doc/themes/haiku.png
Binary files differ
diff --git a/doc/themes/nature.png b/doc/themes/nature.png
index cbe773d5c..ad39b32b7 100644
--- a/doc/themes/nature.png
+++ b/doc/themes/nature.png
Binary files differ
diff --git a/doc/themes/pyramid.png b/doc/themes/pyramid.png
index eb13cd5f2..72749dd6b 100644
--- a/doc/themes/pyramid.png
+++ b/doc/themes/pyramid.png
Binary files differ
diff --git a/doc/themes/scrolls.png b/doc/themes/scrolls.png
index 30ccc8d49..1a117379f 100644
--- a/doc/themes/scrolls.png
+++ b/doc/themes/scrolls.png
Binary files differ
diff --git a/doc/themes/sphinx_rtd_theme.png b/doc/themes/sphinx_rtd_theme.png
index e13f52b04..7c3b7ae05 100644
--- a/doc/themes/sphinx_rtd_theme.png
+++ b/doc/themes/sphinx_rtd_theme.png
Binary files differ
diff --git a/doc/themes/sphinxdoc.png b/doc/themes/sphinxdoc.png
index 31512d8d8..587363e61 100644
--- a/doc/themes/sphinxdoc.png
+++ b/doc/themes/sphinxdoc.png
Binary files differ
diff --git a/doc/themes/traditional.png b/doc/themes/traditional.png
index 5ff44f869..9820fd0ea 100644
--- a/doc/themes/traditional.png
+++ b/doc/themes/traditional.png
Binary files differ
diff --git a/doc/theming.rst b/doc/theming.rst
index bb7dd8305..1d895ec19 100644
--- a/doc/theming.rst
+++ b/doc/theming.rst
@@ -263,7 +263,7 @@ These themes are:
.. versionchanged:: 1.3
The 'default' theme has been renamed to 'classic'. 'default' is still
- available, however it will emit notice a recommendation that using new
+ available, however it will emit a notice that it is an alias for the new
'alabaster' theme.
Creating themes
diff --git a/doc/translation.png b/doc/translation.png
index 347e287f6..11f3d02cd 100644
--- a/doc/translation.png
+++ b/doc/translation.png
Binary files differ
diff --git a/setup.cfg b/setup.cfg
index be78d68d3..a65719461 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -26,4 +26,4 @@ universal = 1
[flake8]
max-line-length=95
ignore=E113,E116,E221,E226,E241,E251,E901
-exclude=tests/*,build/*,sphinx/search/*,sphinx/pycode/pgen2/*
+exclude=tests/*,build/*,sphinx/search/*,sphinx/pycode/pgen2/*,doc/ext/example*.py
diff --git a/setup.py b/setup.py
index 8611fc008..3fa024634 100644
--- a/setup.py
+++ b/setup.py
@@ -4,6 +4,7 @@ from setuptools import setup, find_packages
import os
import sys
from distutils import log
+from distutils.cmd import Command
import sphinx
@@ -36,8 +37,8 @@ Among its features are the following:
* Setuptools integration
'''
-if sys.version_info < (2, 6) or (3, 0) <= sys.version_info < (3, 3):
- print('ERROR: Sphinx requires at least Python 2.6 or 3.3 to run.')
+if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 4):
+ print('ERROR: Sphinx requires at least Python 2.7 or 3.4 to run.')
sys.exit(1)
requires = [
@@ -49,6 +50,7 @@ requires = [
'babel>=1.3,!=2.0',
'alabaster>=0.7,<0.8',
'imagesize',
+ 'requests',
]
extras_require = {
# Environment Marker works for wheel 0.24 or later
@@ -61,8 +63,9 @@ extras_require = {
],
'test': [
'nose',
- 'mock', # it would be better for 'test:python_version in "2.6,2.7"'
+ 'mock', # it would be better for 'test:python_version in 2.7'
'simplejson', # better: 'test:platform_python_implementation=="PyPy"'
+ 'html5lib',
],
}
@@ -136,11 +139,8 @@ else:
domain + '.js'))
for js_file, (locale, po_file) in zip(js_files, po_files):
- infile = open(po_file, 'r')
- try:
+ with open(po_file, 'r') as infile:
catalog = read_po(infile, locale)
- finally:
- infile.close()
if catalog.fuzzy and not self.use_fuzzy:
continue
@@ -157,8 +157,7 @@ else:
msgid = msgid[0]
jscatalog[msgid] = message.string
- outfile = open(js_file, 'wb')
- try:
+ with open(js_file, 'wb') as outfile:
outfile.write('Documentation.addTranslations(')
dump(dict(
messages=jscatalog,
@@ -166,12 +165,35 @@ else:
locale=str(catalog.locale)
), outfile, sort_keys=True)
outfile.write(');')
- finally:
- outfile.close()
cmdclass['compile_catalog'] = compile_catalog_plusjs
+class CompileGrammarCommand(Command):
+ description = 'Compile python grammar file for pycode'
+ user_options = []
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ from sphinx.pycode.pgen2.driver import compile_grammar
+
+ compile_grammar('sphinx/pycode/Grammar-py2.txt')
+ print('sphinx/pycode/Grammar-py2.txt ... done')
+
+ compile_grammar('sphinx/pycode/Grammar-py3.txt')
+ print('sphinx/pycode/Grammar-py3.txt ... done')
+
+ def sub_commands(self):
+ pass
+
+cmdclass['compile_grammar'] = CompileGrammarCommand
+
+
setup(
name='Sphinx',
version=sphinx.__version__,
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 60b42d70e..415a85421 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -15,13 +15,13 @@
import sys
from os import path
-__version__ = '1.4.9+'
-__released__ = '1.4.9' # used when Sphinx builds its own docs
+__version__ = '1.5b2'
+__released__ = '1.5b2' # used when Sphinx builds its own docs
# version info for better programmatic use
# possible values for 3rd element: 'alpha', 'beta', 'rc', 'final'
# 'final' has 0 as the last element
-version_info = (1, 4, 9, 'beta', 1)
+version_info = (1, 5, 0, 'beta', 2)
package_dir = path.abspath(path.dirname(__file__))
@@ -53,9 +53,9 @@ def main(argv=sys.argv):
def build_main(argv=sys.argv):
"""Sphinx build "main" command-line entry."""
- if (sys.version_info[:3] < (2, 6, 0) or
- (3, 0, 0) <= sys.version_info[:3] < (3, 3, 0)):
- sys.stderr.write('Error: Sphinx requires at least Python 2.6 or 3.3 to run.\n')
+ if (sys.version_info[:3] < (2, 7, 0) or
+ (3, 0, 0) <= sys.version_info[:3] < (3, 4, 0)):
+ sys.stderr.write('Error: Sphinx requires at least Python 2.7 or 3.4 to run.\n')
return 1
try:
from sphinx import cmdline
diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py
index ac07b3793..4035faa2d 100644
--- a/sphinx/addnodes.py
+++ b/sphinx/addnodes.py
@@ -14,9 +14,53 @@ import warnings
from docutils import nodes
-class toctree(nodes.General, nodes.Element):
+class translatable(object):
+ """Node which supports translation.
+
+ The translation goes forward with following steps:
+
+ 1. Preserve original translatable messages
+ 2. Apply translated messages from message catalog
+ 3. Extract preserved messages (for gettext builder)
+
+ The translatable nodes MUST preserve original messages.
+ And these messages should not be overridden at applying step.
+ Because they are used at final step; extraction.
+ """
+
+ def preserve_original_messages(self):
+ """Preserve original translatable messages."""
+ raise NotImplementedError
+
+ def apply_translated_message(self, original_message, translated_message):
+ """Apply translated message."""
+ raise NotImplementedError
+
+ def extract_original_messages(self):
+ """Extract translation messages.
+
+ :returns: list of extracted messages or messages generator
+ """
+ raise NotImplementedError
+
+
+class toctree(nodes.General, nodes.Element, translatable):
"""Node for inserting a "TOC tree"."""
+ def preserve_original_messages(self):
+ if 'caption' in self:
+ self['rawcaption'] = self['caption']
+
+ def apply_translated_message(self, original_message, translated_message):
+ if self.get('rawcaption') == original_message:
+ self['caption'] = translated_message
+
+ def extract_original_messages(self):
+ if 'rawcaption' in self:
+ return [self['rawcaption']]
+ else:
+ return []
+
# domain-specific object descriptions (class, function etc.)
@@ -32,10 +76,22 @@ class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement):
"""Node for object signatures.
The "term" part of the custom Sphinx definition list.
+
+ As default the signature is a single line signature,
+ but set ``is_multiline = True`` to describe a multi-line signature.
+ In that case all child nodes must be ``desc_signature_line`` nodes.
+ """
+
+
+class desc_signature_line(nodes.Part, nodes.Inline, nodes.TextElement):
+ """Node for a line in a multi-line object signatures.
+
+ It should only be used in a ``desc_signature`` with ``is_multiline`` set.
+ Set ``add_permalink = True`` for the line that should get the permalink.
"""
-# nodes to use within a desc_signature
+# nodes to use within a desc_signature or desc_signature_line
class desc_addname(nodes.Part, nodes.Inline, nodes.TextElement):
"""Node for additional name parts (module name, class name)."""
diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py
index 90d0e3c8d..d4793ff4d 100644
--- a/sphinx/apidoc.py
+++ b/sphinx/apidoc.py
@@ -21,8 +21,9 @@ import sys
import optparse
from os import path
from six import binary_type
+from fnmatch import fnmatch
-from sphinx.util.osutil import walk
+from sphinx.util.osutil import FileAvoidWrite, walk
from sphinx import __display_version__
# automodule options
@@ -62,11 +63,8 @@ def write_file(name, text, opts):
print('File %s already exists, skipping.' % fname)
else:
print('Creating file %s.' % fname)
- f = open(fname, 'w')
- try:
+ with FileAvoidWrite(fname) as f:
f.write(text)
- finally:
- f.close()
def format_heading(level, text):
@@ -94,11 +92,12 @@ def create_module_file(package, module, opts):
write_file(makename(package, module), text, opts)
-def create_package_file(root, master_package, subroot, py_files, opts, subs):
+def create_package_file(root, master_package, subroot, py_files, opts, subs, is_namespace):
"""Build the text of the file and write the file."""
- text = format_heading(1, '%s package' % makename(master_package, subroot))
+ text = format_heading(1, ('%s package' if not is_namespace else "%s namespace")
+ % makename(master_package, subroot))
- if opts.modulefirst:
+ if opts.modulefirst and not is_namespace:
text += format_directive(subroot, master_package)
text += '\n'
@@ -141,7 +140,7 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs):
text += '\n'
text += '\n'
- if not opts.modulefirst:
+ if not opts.modulefirst and not is_namespace:
text += format_heading(2, 'Module contents')
text += format_directive(subroot, master_package)
@@ -168,9 +167,14 @@ def create_modules_toc_file(modules, opts, name='modules'):
def shall_skip(module, opts):
"""Check if we want to skip this module."""
+ # skip if the file doesn't exist and not using implicit namespaces
+ if not opts.implicit_namespaces and not path.exists(module):
+ return True
+
# skip it if there is nothing (or just \n or \r\n) in the file
- if path.getsize(module) <= 2:
+ if path.exists(module) and path.getsize(module) <= 2:
return True
+
# skip if it has a "private" name and this is selected
filename = path.basename(module)
if filename != '__init__.py' and filename.startswith('_') and \
@@ -194,19 +198,22 @@ def recurse_tree(rootpath, excludes, opts):
toplevels = []
followlinks = getattr(opts, 'followlinks', False)
includeprivate = getattr(opts, 'includeprivate', False)
+ implicit_namespaces = getattr(opts, 'implicit_namespaces', False)
for root, subs, files in walk(rootpath, followlinks=followlinks):
# document only Python module files (that aren't excluded)
py_files = sorted(f for f in files
if path.splitext(f)[1] in PY_SUFFIXES and
not is_excluded(path.join(root, f), excludes))
is_pkg = INITPY in py_files
+ is_namespace = INITPY not in py_files and implicit_namespaces
if is_pkg:
py_files.remove(INITPY)
py_files.insert(0, INITPY)
elif root != rootpath:
- # only accept non-package at toplevel
- del subs[:]
- continue
+ # only accept non-package at toplevel unless using implicit namespaces
+ if not implicit_namespaces:
+ del subs[:]
+ continue
# remove hidden ('.') and private ('_') directories, as well as
# excluded dirs
if includeprivate:
@@ -216,15 +223,17 @@ def recurse_tree(rootpath, excludes, opts):
subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and
not is_excluded(path.join(root, sub), excludes))
- if is_pkg:
+ if is_pkg or is_namespace:
# we are in a package with something to document
- if subs or len(py_files) > 1 or not \
- shall_skip(path.join(root, INITPY), opts):
+ if subs or len(py_files) > 1 or not shall_skip(path.join(root, INITPY), opts):
subpackage = root[len(rootpath):].lstrip(path.sep).\
replace(path.sep, '.')
- create_package_file(root, root_package, subpackage,
- py_files, opts, subs)
- toplevels.append(makename(root_package, subpackage))
+ # if this is not a namespace or
+ # a namespace and there is something there to document
+ if not is_namespace or len(py_files) > 0:
+ create_package_file(root, root_package, subpackage,
+ py_files, opts, subs, is_namespace)
+ toplevels.append(makename(root_package, subpackage))
else:
# if we are at the root level, we don't require it to be a package
assert root == rootpath and root_package is None
@@ -249,7 +258,7 @@ def is_excluded(root, excludes):
e.g. an exlude "foo" also accidentally excluding "foobar".
"""
for exclude in excludes:
- if root == exclude:
+ if fnmatch(root, exclude):
return True
return False
@@ -258,13 +267,13 @@ def main(argv=sys.argv):
"""Parse and check the command line arguments."""
parser = optparse.OptionParser(
usage="""\
-usage: %prog [options] -o <output_path> <module_path> [exclude_path, ...]
+usage: %prog [options] -o <output_path> <module_path> [exclude_pattern, ...]
Look recursively in <module_path> for Python modules and packages and create
one reST file with automodule directives per package in the <output_path>.
-The <exclude_path>s can be files and/or directories that will be excluded
-from generation.
+The <exclude_pattern>s can be file and/or directory patterns that will be
+excluded from generation.
Note: By default this script will not overwrite already created files.""")
@@ -298,10 +307,17 @@ Note: By default this script will not overwrite already created files.""")
dest='modulefirst',
help='Put module documentation before submodule '
'documentation')
+ parser.add_option('--implicit-namespaces', action='store_true',
+ dest='implicit_namespaces',
+ help='Interpret module paths according to PEP-0420 '
+ 'implicit namespaces specification')
parser.add_option('-s', '--suffix', action='store', dest='suffix',
help='file suffix (default: rst)', default='rst')
parser.add_option('-F', '--full', action='store_true', dest='full',
help='Generate a full project with sphinx-quickstart')
+ parser.add_option('-a', '--append-syspath', action='store_true',
+ dest='append_syspath',
+ help='Append module_path to sys.path, used when --full is given')
parser.add_option('-H', '--doc-project', action='store', dest='header',
help='Project name (default: root module name)')
parser.add_option('-A', '--doc-author', action='store', dest='author',
@@ -369,6 +385,8 @@ Note: By default this script will not overwrite already created files.""")
mastertocmaxdepth = opts.maxdepth,
mastertoctree = text,
language = 'en',
+ module_path = rootpath,
+ append_syspath = opts.append_syspath,
)
if isinstance(opts.header, binary_type):
d['project'] = d['project'].decode('utf-8')
diff --git a/sphinx/application.py b/sphinx/application.py
index 9d99227c5..93f12f3b6 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -32,9 +32,8 @@ from sphinx.roles import XRefRole
from sphinx.config import Config
from sphinx.errors import SphinxError, SphinxWarning, ExtensionError, \
VersionRequirementError, ConfigError
-from sphinx.domains import ObjType, BUILTIN_DOMAINS
+from sphinx.domains import ObjType
from sphinx.domains.std import GenericObject, Target, StandardDomain
-from sphinx.builders import BUILTIN_BUILDERS
from sphinx.environment import BuildEnvironment
from sphinx.io import SphinxStandaloneReader
from sphinx.util import pycompat # noqa: F401
@@ -42,13 +41,10 @@ from sphinx.util import import_object
from sphinx.util.tags import Tags
from sphinx.util.osutil import ENOENT
from sphinx.util.logging import is_suppressed_warning
-from sphinx.util.console import bold, lightgray, darkgray, darkgreen, \
+from sphinx.util.console import bold, lightgray, darkgray, darkred, darkgreen, \
term_width_line
from sphinx.util.i18n import find_catalog_source_files
-if hasattr(sys, 'intern'):
- intern = sys.intern
-
# List of all known core events. Maps name to arguments description.
events = {
'builder-inited': '',
@@ -65,6 +61,36 @@ events = {
'html-page-context': 'pagename, context, doctree or None',
'build-finished': 'exception',
}
+builtin_extensions = (
+ 'sphinx.builders.applehelp',
+ 'sphinx.builders.changes',
+ 'sphinx.builders.epub',
+ 'sphinx.builders.epub3',
+ 'sphinx.builders.devhelp',
+ 'sphinx.builders.dummy',
+ 'sphinx.builders.gettext',
+ 'sphinx.builders.html',
+ 'sphinx.builders.htmlhelp',
+ 'sphinx.builders.latex',
+ 'sphinx.builders.linkcheck',
+ 'sphinx.builders.manpage',
+ 'sphinx.builders.qthelp',
+ 'sphinx.builders.texinfo',
+ 'sphinx.builders.text',
+ 'sphinx.builders.websupport',
+ 'sphinx.builders.xml',
+ 'sphinx.domains.c',
+ 'sphinx.domains.cpp',
+ 'sphinx.domains.javascript',
+ 'sphinx.domains.python',
+ 'sphinx.domains.rst',
+ 'sphinx.domains.std',
+ 'sphinx.directives',
+ 'sphinx.directives.code',
+ 'sphinx.directives.other',
+ 'sphinx.directives.patches',
+ 'sphinx.roles',
+)
CONFIG_FILENAME = 'conf.py'
ENV_PICKLE_FILENAME = 'environment.pickle'
@@ -87,9 +113,9 @@ class Sphinx(object):
self._additional_source_parsers = {}
self._listeners = {}
self._setting_up_extension = ['?']
- self.domains = BUILTIN_DOMAINS.copy()
+ self.domains = {}
self.buildername = buildername
- self.builderclasses = BUILTIN_BUILDERS.copy()
+ self.builderclasses = {}
self.builder = None
self.env = None
self.enumerable_nodes = {}
@@ -147,11 +173,21 @@ class Sphinx(object):
'This project needs at least Sphinx v%s and therefore cannot '
'be built with this version.' % self.config.needs_sphinx)
+ # force preload html_translator_class
+ if self.config.html_translator_class:
+ translator_class = self.import_object(self.config.html_translator_class,
+ 'html_translator_class setting')
+ self.set_translator('html', translator_class)
+
# set confdir to srcdir if -C given (!= no confdir); a few pieces
# of code expect a confdir to be set
if self.confdir is None:
self.confdir = self.srcdir
+ # load all built-in extension modules
+ for extension in builtin_extensions:
+ self.setup_extension(extension)
+
# extension loading support for alabaster theme
# self.config.html_theme is not set from conf.py at here
# for now, sphinx always load a 'alabaster' extension.
@@ -192,6 +228,10 @@ class Sphinx(object):
'version %s and therefore cannot be built with the '
'loaded version (%s).' % (extname, needs_ver, has_ver))
+ # check primary_domain if requested
+ if self.config.primary_domain and self.config.primary_domain not in self.domains:
+ self.warn('primary_domain %r not found, ignored.' % self.config.primary_domain)
+
# set up translation infrastructure
self._init_i18n()
# check all configuration values for permissible types
@@ -250,6 +290,7 @@ class Sphinx(object):
self.env = BuildEnvironment.frompickle(
self.srcdir, self.config, path.join(self.doctreedir, ENV_PICKLE_FILENAME))
self.env.set_warnfunc(self.warn)
+ self.env.init_managers()
self.env.domains = {}
for domain in self.domains.keys():
# this can raise if the data version doesn't fit
@@ -270,11 +311,6 @@ class Sphinx(object):
raise SphinxError('Builder name %s not registered' % buildername)
builderclass = self.builderclasses[buildername]
- if isinstance(builderclass, tuple):
- # builtin builder
- mod, cls = builderclass
- builderclass = getattr(
- __import__('sphinx.builders.' + mod, None, None, [cls]), cls)
self.builder = builderclass(self)
self.emit('builder-inited')
@@ -329,7 +365,8 @@ class Sphinx(object):
wfile.flush()
self.messagelog.append(message)
- def warn(self, message, location=None, prefix='WARNING: ', type=None, subtype=None):
+ def warn(self, message, location=None, prefix='WARNING: ',
+ type=None, subtype=None, colorfunc=darkred):
"""Emit a warning.
If *location* is given, it should either be a tuple of (docname, lineno)
@@ -359,7 +396,7 @@ class Sphinx(object):
if self.warningiserror:
raise SphinxWarning(warntext)
self._warncount += 1
- self._log(warntext, self._warning, True)
+ self._log(colorfunc(warntext), self._warning, True)
def info(self, message='', nonl=False):
"""Emit an informational message.
@@ -517,7 +554,6 @@ class Sphinx(object):
# event interface
def _validate_event(self, event):
- event = intern(event)
if event not in self._events:
raise ExtensionError('Unknown event name: %s' % event)
@@ -565,13 +601,9 @@ class Sphinx(object):
raise ExtensionError('Builder class %s has no "name" attribute'
% builder)
if builder.name in self.builderclasses:
- if isinstance(self.builderclasses[builder.name], tuple):
- raise ExtensionError('Builder %r is a builtin builder' %
- builder.name)
- else:
- raise ExtensionError(
- 'Builder %r already exists (in module %s)' % (
- builder.name, self.builderclasses[builder.name].__module__))
+ raise ExtensionError(
+ 'Builder %r already exists (in module %s)' % (
+ builder.name, self.builderclasses[builder.name].__module__))
self.builderclasses[builder.name] = builder
def add_config_value(self, name, default, rebuild, types=()):
@@ -772,8 +804,7 @@ class Sphinx(object):
def add_latex_package(self, packagename, options=None):
self.debug('[app] adding latex package: %r', packagename)
- from sphinx.builders.latex import LaTeXBuilder
- LaTeXBuilder.usepackages.append((packagename, options))
+ self.builder.usepackages.append((packagename, options))
def add_lexer(self, alias, lexer):
self.debug('[app] adding lexer: %r', (alias, lexer))
diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py
index d0b6c2ca0..fe0c9c665 100644
--- a/sphinx/builders/__init__.py
+++ b/sphinx/builders/__init__.py
@@ -451,30 +451,3 @@ class Builder(object):
except AttributeError:
optname = '%s_%s' % (default, option)
return getattr(self.config, optname)
-
-
-BUILTIN_BUILDERS = {
- 'dummy': ('dummy', 'DummyBuilder'),
- 'html': ('html', 'StandaloneHTMLBuilder'),
- 'dirhtml': ('html', 'DirectoryHTMLBuilder'),
- 'singlehtml': ('html', 'SingleFileHTMLBuilder'),
- 'pickle': ('html', 'PickleHTMLBuilder'),
- 'json': ('html', 'JSONHTMLBuilder'),
- 'web': ('html', 'PickleHTMLBuilder'),
- 'htmlhelp': ('htmlhelp', 'HTMLHelpBuilder'),
- 'devhelp': ('devhelp', 'DevhelpBuilder'),
- 'qthelp': ('qthelp', 'QtHelpBuilder'),
- 'applehelp': ('applehelp', 'AppleHelpBuilder'),
- 'epub': ('epub', 'EpubBuilder'),
- 'epub3': ('epub3', 'Epub3Builder'),
- 'latex': ('latex', 'LaTeXBuilder'),
- 'text': ('text', 'TextBuilder'),
- 'man': ('manpage', 'ManualPageBuilder'),
- 'texinfo': ('texinfo', 'TexinfoBuilder'),
- 'changes': ('changes', 'ChangesBuilder'),
- 'linkcheck': ('linkcheck', 'CheckExternalLinksBuilder'),
- 'websupport': ('websupport', 'WebSupportBuilder'),
- 'gettext': ('gettext', 'MessageCatalogBuilder'),
- 'xml': ('xml', 'XMLBuilder'),
- 'pseudoxml': ('xml', 'PseudoXMLBuilder'),
-}
diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py
index a6c89b628..7db086953 100644
--- a/sphinx/builders/applehelp.py
+++ b/sphinx/builders/applehelp.py
@@ -13,14 +13,16 @@ from __future__ import print_function
import codecs
import pipes
-from os import path
+from os import path, environ
+import shlex
from sphinx.builders.html import StandaloneHTMLBuilder
-from sphinx.util import copy_static_entry
-from sphinx.util.osutil import copyfile, ensuredir
+from sphinx.config import string_classes
+from sphinx.util.osutil import copyfile, ensuredir, make_filename
from sphinx.util.console import bold
+from sphinx.util.fileutil import copy_asset
from sphinx.util.pycompat import htmlescape
-from sphinx.util.matching import compile_matchers
+from sphinx.util.matching import Matcher
from sphinx.errors import SphinxError
import plistlib
@@ -105,17 +107,15 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
self.finish_tasks.add_task(self.build_helpbook)
def copy_localized_files(self):
- source_dir = path.join(self.confdir,
- self.config.applehelp_locale + '.lproj')
+ source_dir = path.join(self.confdir, self.config.applehelp_locale + '.lproj')
target_dir = self.outdir
if path.isdir(source_dir):
self.info(bold('copying localized files... '), nonl=True)
- ctx = self.globalcontext.copy()
- matchers = compile_matchers(self.config.exclude_patterns)
- copy_static_entry(source_dir, target_dir, self, ctx,
- exclude_matchers=matchers)
+ excluded = Matcher(self.config.exclude_patterns + ['**/.*'])
+ copy_asset(source_dir, target_dir, excluded,
+ context=self.globalcontext, renderer=self.templates)
self.info('done')
@@ -179,14 +179,11 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
# Build the access page
self.info(bold('building access page...'), nonl=True)
- f = codecs.open(path.join(language_dir, '_access.html'), 'w')
- try:
+ with codecs.open(path.join(language_dir, '_access.html'), 'w') as f:
f.write(access_page_template % {
'toc': htmlescape(toc, quote=True),
'title': htmlescape(self.config.applehelp_title)
})
- finally:
- f.close()
self.info('done')
# Generate the help index
@@ -264,3 +261,35 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
self.info('done')
except OSError:
raise AppleHelpCodeSigningFailed('Command not found: %s' % args[0])
+
+
+def setup(app):
+ app.setup_extension('sphinx.builders.html')
+ app.add_builder(AppleHelpBuilder)
+
+ app.add_config_value('applehelp_bundle_name',
+ lambda self: make_filename(self.project), 'applehelp')
+ app.add_config_value('applehelp_bundle_id', None, 'applehelp', string_classes)
+ app.add_config_value('applehelp_dev_region', 'en-us', 'applehelp')
+ app.add_config_value('applehelp_bundle_version', '1', 'applehelp')
+ app.add_config_value('applehelp_icon', None, 'applehelp', string_classes)
+ app.add_config_value('applehelp_kb_product',
+ lambda self: '%s-%s' % (make_filename(self.project), self.release),
+ 'applehelp')
+ app.add_config_value('applehelp_kb_url', None, 'applehelp', string_classes)
+ app.add_config_value('applehelp_remote_url', None, 'applehelp', string_classes)
+ app.add_config_value('applehelp_index_anchors', False, 'applehelp', string_classes)
+ app.add_config_value('applehelp_min_term_length', None, 'applehelp', string_classes)
+ app.add_config_value('applehelp_stopwords',
+ lambda self: self.language or 'en', 'applehelp')
+ app.add_config_value('applehelp_locale', lambda self: self.language or 'en', 'applehelp')
+ app.add_config_value('applehelp_title', lambda self: self.project + ' Help', 'applehelp')
+ app.add_config_value('applehelp_codesign_identity',
+ lambda self: environ.get('CODE_SIGN_IDENTITY', None),
+ 'applehelp'),
+ app.add_config_value('applehelp_codesign_flags',
+ lambda self: shlex.split(environ.get('OTHER_CODE_SIGN_FLAGS', '')),
+ 'applehelp'),
+ app.add_config_value('applehelp_indexer_path', '/usr/bin/hiutil', 'applehelp')
+ app.add_config_value('applehelp_codesign_path', '/usr/bin/codesign', 'applehelp')
+ app.add_config_value('applehelp_disable_external_tools', False, None)
diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py
index c077b7dd2..1bccb67d9 100644
--- a/sphinx/builders/changes.py
+++ b/sphinx/builders/changes.py
@@ -15,12 +15,12 @@ from os import path
from six import iteritems
from sphinx import package_dir
-from sphinx.util import copy_static_entry
from sphinx.locale import _
from sphinx.theming import Theme
from sphinx.builders import Builder
from sphinx.util.osutil import ensuredir, os_path
from sphinx.util.console import bold
+from sphinx.util.fileutil import copy_asset_file
from sphinx.util.pycompat import htmlescape
@@ -101,16 +101,10 @@ class ChangesBuilder(Builder):
'show_copyright': self.config.html_show_copyright,
'show_sphinx': self.config.html_show_sphinx,
}
- f = codecs.open(path.join(self.outdir, 'index.html'), 'w', 'utf8')
- try:
+ with codecs.open(path.join(self.outdir, 'index.html'), 'w', 'utf8') as f:
f.write(self.templates.render('changes/frameset.html', ctx))
- finally:
- f.close()
- f = codecs.open(path.join(self.outdir, 'changes.html'), 'w', 'utf8')
- try:
+ with codecs.open(path.join(self.outdir, 'changes.html'), 'w', 'utf8') as f:
f.write(self.templates.render('changes/versionchanges.html', ctx))
- finally:
- f.close()
hltext = ['.. versionadded:: %s' % version,
'.. versionchanged:: %s' % version,
@@ -126,35 +120,28 @@ class ChangesBuilder(Builder):
self.info(bold('copying source files...'))
for docname in self.env.all_docs:
- f = codecs.open(self.env.doc2path(docname), 'r',
- self.env.config.source_encoding)
- try:
- lines = f.readlines()
- except UnicodeDecodeError:
- self.warn('could not read %r for changelog creation' % docname)
- continue
- finally:
- f.close()
+ with codecs.open(self.env.doc2path(docname), 'r',
+ self.env.config.source_encoding) as f:
+ try:
+ lines = f.readlines()
+ except UnicodeDecodeError:
+ self.warn('could not read %r for changelog creation' % docname)
+ continue
targetfn = path.join(self.outdir, 'rst', os_path(docname)) + '.html'
ensuredir(path.dirname(targetfn))
- f = codecs.open(targetfn, 'w', 'utf-8')
- try:
+ with codecs.open(targetfn, 'w', 'utf-8') as f:
text = ''.join(hl(i+1, line) for (i, line) in enumerate(lines))
ctx = {
'filename': self.env.doc2path(docname, None),
'text': text
}
f.write(self.templates.render('changes/rstsource.html', ctx))
- finally:
- f.close()
themectx = dict(('theme_' + key, val) for (key, val) in
iteritems(self.theme.get_options({})))
- copy_static_entry(path.join(package_dir, 'themes', 'default',
- 'static', 'default.css_t'),
- self.outdir, self, themectx)
- copy_static_entry(path.join(package_dir, 'themes', 'basic',
- 'static', 'basic.css'),
- self.outdir, self)
+ copy_asset_file(path.join(package_dir, 'themes', 'default', 'static', 'default.css_t'),
+ self.outdir, context=themectx, renderer=self.templates)
+ copy_asset_file(path.join(package_dir, 'themes', 'basic', 'static', 'basic.css'),
+ self.outdir)
def hl(self, text, version):
text = htmlescape(text)
@@ -165,3 +152,7 @@ class ChangesBuilder(Builder):
def finish(self):
pass
+
+
+def setup(app):
+ app.add_builder(ChangesBuilder)
diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py
index 523941110..fd6f3400e 100644
--- a/sphinx/builders/devhelp.py
+++ b/sphinx/builders/devhelp.py
@@ -13,32 +13,19 @@
from __future__ import absolute_import
import re
+import gzip
from os import path
from docutils import nodes
from sphinx import addnodes
+from sphinx.util.osutil import make_filename
from sphinx.builders.html import StandaloneHTMLBuilder
try:
import xml.etree.ElementTree as etree
except ImportError:
- try:
- import lxml.etree as etree
- except ImportError:
- try:
- import elementtree.ElementTree as etree
- except ImportError:
- import cElementTree as etree
-
-try:
- import gzip
-
- def comp_open(filename, mode='rb'):
- return gzip.open(filename + '.gz', mode)
-except ImportError:
- def comp_open(filename, mode='rb'):
- return open(filename, mode)
+ import lxml.etree as etree
class DevhelpBuilder(StandaloneHTMLBuilder):
@@ -128,8 +115,13 @@ class DevhelpBuilder(StandaloneHTMLBuilder):
write_index(title, refs, subitems)
# Dump the XML file
- f = comp_open(path.join(outdir, outname + '.devhelp'), 'w')
- try:
+ xmlfile = path.join(outdir, outname + '.devhelp.gz')
+ with gzip.open(xmlfile, 'w') as f:
tree.write(f, 'utf-8')
- finally:
- f.close()
+
+
+def setup(app):
+ app.setup_extension('sphinx.builders.html')
+ app.add_builder(DevhelpBuilder)
+
+ app.add_config_value('devhelp_basename', lambda self: make_filename(self.project), None)
diff --git a/sphinx/builders/dummy.py b/sphinx/builders/dummy.py
index 75b834c2b..b119d9687 100644
--- a/sphinx/builders/dummy.py
+++ b/sphinx/builders/dummy.py
@@ -34,3 +34,7 @@ class DummyBuilder(Builder):
def finish(self):
pass
+
+
+def setup(app):
+ app.add_builder(DummyBuilder)
diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py
index ade887e56..b4b657468 100644
--- a/sphinx/builders/epub.py
+++ b/sphinx/builders/epub.py
@@ -29,7 +29,7 @@ from docutils import nodes
from sphinx import addnodes
from sphinx.builders.html import StandaloneHTMLBuilder
-from sphinx.util.osutil import ensuredir, copyfile, EEXIST
+from sphinx.util.osutil import ensuredir, copyfile, make_filename, EEXIST
from sphinx.util.smartypants import sphinx_smarty_pants as ssp
from sphinx.util.console import brown
@@ -179,7 +179,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
META-INF/container.xml. Afterwards, all necessary files are zipped to an
epub file.
"""
- name = 'epub'
+ name = 'epub2'
# don't copy the reST source
copysource = False
@@ -188,8 +188,12 @@ class EpubBuilder(StandaloneHTMLBuilder):
# don't add links
add_permalinks = False
+ # don't use # as current path. ePub check reject it.
+ allow_sharp_as_current_path = False
# don't add sidebar etc.
embedded = True
+ # disable download role
+ download_support = False
# dont' create links to original images from images
html_scaled_image_link = False
# don't generate search index or include search page
@@ -223,6 +227,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
self.link_suffix = '.xhtml'
self.playorder = 0
self.tocid = 0
+ self.use_index = self.get_builder_config('use_index', 'epub')
def get_theme_config(self):
return self.config.epub_theme, self.config.epub_theme_options
@@ -485,6 +490,9 @@ class EpubBuilder(StandaloneHTMLBuilder):
else:
super(EpubBuilder, self).copy_image_files()
+ def copy_download_files(self):
+ pass
+
def handle_page(self, pagename, addctx, templatename='page.html',
outfilename=None, event_arg=None):
"""Create a rendered page.
@@ -493,6 +501,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
attributes.
"""
if pagename.startswith('genindex'):
+ if not self.use_index:
+ return
self.fix_genindex(addctx['genindexentries'])
addctx['doctype'] = self.doctype
StandaloneHTMLBuilder.handle_page(self, pagename, addctx, templatename,
@@ -511,11 +521,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
def build_mimetype(self, outdir, outname):
"""Write the metainfo file mimetype."""
self.info('writing %s file...' % outname)
- f = codecs.open(path.join(outdir, outname), 'w', 'utf-8')
- try:
+ with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f:
f.write(self.mimetype_template)
- finally:
- f.close()
def build_container(self, outdir, outname):
"""Write the metainfo file META-INF/cointainer.xml."""
@@ -526,11 +533,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
except OSError as err:
if err.errno != EEXIST:
raise
- f = codecs.open(path.join(outdir, outname), 'w', 'utf-8')
- try:
+ with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f:
f.write(self.container_template)
- finally:
- f.close()
def content_metadata(self, files, spine, guide):
"""Create a dictionary with all metadata for the content.opf
@@ -565,8 +569,11 @@ class EpubBuilder(StandaloneHTMLBuilder):
self.files = []
self.ignored_files = ['.buildinfo', 'mimetype', 'content.opf',
'toc.ncx', 'META-INF/container.xml',
+ 'Thumbs.db', 'ehthumbs.db', '.DS_Store',
self.config.epub_basename + '.epub'] + \
self.config.epub_exclude_files
+ if not self.use_index:
+ self.ignored_files.append('genindex' + self.out_suffix)
for root, dirs, files in os.walk(outdir):
for fn in files:
filename = path.join(root, fn)[olen:]
@@ -604,7 +611,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
'idref': self.esc(self.make_id(info[0] + self.out_suffix))
})
spinefiles.add(info[0] + self.out_suffix)
- if self.get_builder_config('use_index', 'epub'):
+ if self.use_index:
spine.append(self.spine_template % {
'idref': self.esc(self.make_id('genindex' + self.out_suffix))
})
@@ -677,12 +684,9 @@ class EpubBuilder(StandaloneHTMLBuilder):
guide = '\n'.join(guide)
# write the project file
- f = codecs.open(path.join(outdir, outname), 'w', 'utf-8')
- try:
+ with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f:
f.write(content_tmpl %
self.content_metadata(projectfiles, spine, guide))
- finally:
- f.close()
def new_navpoint(self, node, level, incr=True):
"""Create a new entry in the toc from the node at given level."""
@@ -774,11 +778,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
navpoints = self.build_navpoints(refnodes)
level = max(item['level'] for item in self.refnodes)
level = min(level, self.config.epub_tocdepth)
- f = codecs.open(path.join(outdir, outname), 'w', 'utf-8')
- try:
+ with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f:
f.write(self.toc_template % self.toc_metadata(level, navpoints))
- finally:
- f.close()
def build_epub(self, outdir, outname):
"""Write the epub file.
@@ -797,3 +798,33 @@ class EpubBuilder(StandaloneHTMLBuilder):
fp = path.join(outdir, file)
epub.write(fp, file, zipfile.ZIP_DEFLATED)
epub.close()
+
+
+def setup(app):
+ app.setup_extension('sphinx.builders.html')
+ app.add_builder(EpubBuilder)
+
+ # config values
+ app.add_config_value('epub_basename', lambda self: make_filename(self.project), None)
+ app.add_config_value('epub_theme', 'epub', 'html')
+ app.add_config_value('epub_theme_options', {}, 'html')
+ app.add_config_value('epub_title', lambda self: self.html_title, 'html')
+ app.add_config_value('epub_author', 'unknown', 'html')
+ app.add_config_value('epub_language', lambda self: self.language or 'en', 'html')
+ app.add_config_value('epub_publisher', 'unknown', 'html')
+ app.add_config_value('epub_copyright', lambda self: self.copyright, 'html')
+ app.add_config_value('epub_identifier', 'unknown', 'html')
+ app.add_config_value('epub_scheme', 'unknown', 'html')
+ app.add_config_value('epub_uid', 'unknown', 'env')
+ app.add_config_value('epub_cover', (), 'env')
+ app.add_config_value('epub_guide', (), 'env')
+ app.add_config_value('epub_pre_files', [], 'env')
+ app.add_config_value('epub_post_files', [], 'env')
+ app.add_config_value('epub_exclude_files', [], 'env')
+ app.add_config_value('epub_tocdepth', 3, 'env')
+ app.add_config_value('epub_tocdup', True, 'env')
+ app.add_config_value('epub_tocscope', 'default', 'env')
+ app.add_config_value('epub_fix_images', False, 'env')
+ app.add_config_value('epub_max_image_width', 0, 'env')
+ app.add_config_value('epub_show_urls', 'inline', 'html')
+ app.add_config_value('epub_use_index', lambda self: self.html_use_index, 'html')
diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py
index d792bd6e9..ae799986e 100644
--- a/sphinx/builders/epub3.py
+++ b/sphinx/builders/epub3.py
@@ -14,6 +14,7 @@ import codecs
from os import path
from datetime import datetime
+from sphinx.config import string_classes
from sphinx.builders.epub import EpubBuilder
@@ -52,7 +53,8 @@ NAVLIST_INDENT = ' '
PACKAGE_DOC_TEMPLATE = u'''\
<?xml version="1.0" encoding="UTF-8"?>
<package xmlns="http://www.idpf.org/2007/opf" version="3.0" xml:lang="%(lang)s"
- unique-identifier="%(uid)s">
+ unique-identifier="%(uid)s"
+ prefix="ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/">
<metadata xmlns:opf="http://www.idpf.org/2007/opf"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:language>%(lang)s</dc:language>
@@ -65,6 +67,10 @@ PACKAGE_DOC_TEMPLATE = u'''\
<dc:identifier id="%(uid)s">%(id)s</dc:identifier>
<dc:date>%(date)s</dc:date>
<meta property="dcterms:modified">%(date)s</meta>
+ <meta property="ibooks:version">%(version)s</meta>
+ <meta property="ibooks:specified-fonts">true</meta>
+ <meta property="ibooks:binding">true</meta>
+ <meta property="ibooks:scroll-axis">%(ibook_scroll_axis)s</meta>
</metadata>
<manifest>
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
@@ -94,7 +100,7 @@ class Epub3Builder(EpubBuilder):
and META-INF/container.xml. Afterwards, all necessary files are zipped to
an epub file.
"""
- name = 'epub3'
+ name = 'epub'
navigation_doc_template = NAVIGATION_DOC_TEMPLATE
navlist_template = NAVLIST_TEMPLATE
@@ -122,13 +128,43 @@ class Epub3Builder(EpubBuilder):
"""
metadata = super(Epub3Builder, self).content_metadata(
files, spine, guide)
- metadata['description'] = self.esc(self.config.epub3_description)
- metadata['contributor'] = self.esc(self.config.epub3_contributor)
- metadata['page_progression_direction'] = self.esc(
- self.config.epub3_page_progression_direction) or 'default'
+ metadata['description'] = self.esc(self.config.epub_description)
+ metadata['contributor'] = self.esc(self.config.epub_contributor)
+ metadata['page_progression_direction'] = self._page_progression_direction()
+ metadata['ibook_scroll_axis'] = self._ibook_scroll_axis()
metadata['date'] = self.esc(datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"))
+ metadata['version'] = self.esc(self.config.version)
return metadata
+ def _page_progression_direction(self):
+ if self.config.epub_writing_mode == 'horizontal':
+ page_progression_direction = 'ltr'
+ elif self.config.epub_writing_mode == 'vertical':
+ page_progression_direction = 'rtl'
+ else:
+ page_progression_direction = 'default'
+ return page_progression_direction
+
+ def _ibook_scroll_axis(self):
+ if self.config.epub_writing_mode == 'horizontal':
+ scroll_axis = 'vertical'
+ elif self.config.epub_writing_mode == 'vertical':
+ scroll_axis = 'horizontal'
+ else:
+ scroll_axis = 'default'
+ return scroll_axis
+
+ def _css_writing_mode(self):
+ if self.config.epub_writing_mode == 'vertical':
+ editing_mode = 'vertical-rl'
+ else:
+ editing_mode = 'horizontal-tb'
+ return editing_mode
+
+ def prepare_writing(self, docnames):
+ super(Epub3Builder, self).prepare_writing(docnames)
+ self.globalcontext['theme_writing_mode'] = self._css_writing_mode()
+
def new_navlist(self, node, level, has_child):
"""Create a new entry in the toc from the node at given level."""
# XXX Modifies the node
@@ -211,12 +247,37 @@ class Epub3Builder(EpubBuilder):
# 'includehidden'
refnodes = self.refnodes
navlist = self.build_navlist(refnodes)
- f = codecs.open(path.join(outdir, outname), 'w', 'utf-8')
- try:
+ with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f:
f.write(self.navigation_doc_template %
self.navigation_doc_metadata(navlist))
- finally:
- f.close()
- # Add nav.xhtml to epub file
- if outname not in self.files:
- self.files.append(outname)
+
+ # Add nav.xhtml to epub file
+ if outname not in self.files:
+ self.files.append(outname)
+
+
+def validate_config_values(app):
+ if app.config.epub3_description is not None:
+ app.warn('epub3_description is deprecated. Use epub_description instead.')
+ app.config.epub_description = app.config.epub3_description
+
+ if app.config.epub3_contributor is not None:
+ app.warn('epub3_contributor is deprecated. Use epub_contributor instead.')
+ app.config.epub_contributor = app.config.epub3_contributor
+
+ if app.config.epub3_page_progression_direction is not None:
+ app.warn('epub3_page_progression_direction option is deprecated'
+ ' from 1.5. Use epub_writing_mode instead.')
+
+
+def setup(app):
+ app.setup_extension('sphinx.builders.epub')
+ app.add_builder(Epub3Builder)
+ app.connect('builder-inited', validate_config_values)
+
+ app.add_config_value('epub_description', '', 'epub3', string_classes)
+ app.add_config_value('epub_contributor', 'unknown', 'epub3', string_classes)
+ app.add_config_value('epub_writing_mode', 'horizontal', 'epub3', string_classes)
+ app.add_config_value('epub3_description', None, 'epub3', string_classes)
+ app.add_config_value('epub3_contributor', None, 'epub3', string_classes)
+ app.add_config_value('epub3_page_progression_direction', None, 'epub3', string_classes)
diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py
index 9edbdf1d3..e118cde99 100644
--- a/sphinx/builders/gettext.py
+++ b/sphinx/builders/gettext.py
@@ -22,6 +22,7 @@ from six import iteritems
from sphinx.builders import Builder
from sphinx.util import split_index_msg
+from sphinx.util.tags import Tags
from sphinx.util.nodes import extract_messages, traverse_translatable_index
from sphinx.util.osutil import safe_relpath, ensuredir, canon_path
from sphinx.util.i18n import find_catalog
@@ -79,6 +80,16 @@ class MsgOrigin(object):
self.uid = uuid4().hex
+class I18nTags(Tags):
+ """Dummy tags module for I18nBuilder.
+
+ To translate all text inside of only nodes, this class
+ always returns True value even if no tags are defined.
+ """
+ def eval_condition(self, condition):
+ return True
+
+
class I18nBuilder(Builder):
"""
General i18n builder.
@@ -93,6 +104,7 @@ class I18nBuilder(Builder):
def init(self):
Builder.init(self)
+ self.tags = I18nTags()
self.catalogs = defaultdict(Catalog)
def get_target_uri(self, docname, typ=None):
@@ -212,8 +224,7 @@ class MessageCatalogBuilder(I18nBuilder):
ensuredir(path.join(self.outdir, path.dirname(textdomain)))
pofn = path.join(self.outdir, textdomain + '.pot')
- pofile = open(pofn, 'w', encoding='utf-8')
- try:
+ with open(pofn, 'w', encoding='utf-8') as pofile:
pofile.write(POHEADER % data)
for message in catalog.messages:
@@ -236,5 +247,12 @@ class MessageCatalogBuilder(I18nBuilder):
replace('\n', '\\n"\n"')
pofile.write('msgid "%s"\nmsgstr ""\n\n' % message)
- finally:
- pofile.close()
+
+def setup(app):
+ app.add_builder(MessageCatalogBuilder)
+
+ app.add_config_value('gettext_compact', True, 'gettext')
+ app.add_config_value('gettext_location', True, 'gettext')
+ app.add_config_value('gettext_uuid', False, 'gettext')
+ app.add_config_value('gettext_auto_build', True, 'env')
+ app.add_config_value('gettext_additional_targets', [], 'env')
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index f5d8cf549..e13d752d7 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -27,13 +27,15 @@ from docutils.frontend import OptionParser
from docutils.readers.doctree import Reader as DoctreeReader
from sphinx import package_dir, __display_version__
-from sphinx.util import jsonimpl, copy_static_entry, copy_extra_entry
+from sphinx.util import jsonimpl
from sphinx.util.i18n import format_date
from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \
movefile, copyfile
from sphinx.util.nodes import inline_all_toctrees
-from sphinx.util.matching import patmatch, compile_matchers
-from sphinx.locale import _
+from sphinx.util.fileutil import copy_asset
+from sphinx.util.matching import patmatch, Matcher, DOTFILES
+from sphinx.config import string_classes
+from sphinx.locale import _, l_
from sphinx.search import js_index
from sphinx.theming import Theme
from sphinx.builders import Builder
@@ -80,8 +82,10 @@ class StandaloneHTMLBuilder(Builder):
'image/gif', 'image/jpeg']
searchindex_filename = 'searchindex.js'
add_permalinks = True
+ allow_sharp_as_current_path = True
embedded = False # for things like HTML help or Qt help: suppresses sidebar
search = True # for things like HTML help and Apple help: suppress search
+ download_support = True # enable download role
# This is a class attribute because it is mutated by Sphinx.add_javascript.
script_files = ['_static/jquery.js', '_static/underscore.js',
@@ -120,6 +124,7 @@ class StandaloneHTMLBuilder(Builder):
if self.config.language is not None:
if self._get_translations_js():
self.script_files.append('_static/translations.js')
+ self.use_index = self.get_builder_config('use_index', 'html')
def _get_translations_js(self):
candidates = [path.join(package_dir, 'locale', self.config.language,
@@ -158,16 +163,11 @@ class StandaloneHTMLBuilder(Builder):
self.config.trim_doctest_flags)
def init_translator_class(self):
- if self.translator_class is not None:
- pass
- elif self.config.html_translator_class:
- self.translator_class = self.app.import_object(
- self.config.html_translator_class,
- 'html_translator_class setting')
- elif self.config.html_use_smartypants:
- self.translator_class = SmartyPantsHTMLTranslator
- else:
- self.translator_class = HTMLTranslator
+ if self.translator_class is None:
+ if self.config.html_use_smartypants:
+ self.translator_class = SmartyPantsHTMLTranslator
+ else:
+ self.translator_class = HTMLTranslator
def get_outdated_docs(self):
cfgdict = dict((name, self.config[name])
@@ -177,8 +177,7 @@ class StandaloneHTMLBuilder(Builder):
self.tags_hash = get_stable_hash(sorted(self.tags))
old_config_hash = old_tags_hash = ''
try:
- fp = open(path.join(self.outdir, '.buildinfo'))
- try:
+ with open(path.join(self.outdir, '.buildinfo')) as fp:
version = fp.readline()
if version.rstrip() != '# Sphinx build info version 1':
raise ValueError
@@ -189,8 +188,6 @@ class StandaloneHTMLBuilder(Builder):
tag, old_tags_hash = fp.readline().strip().split(': ')
if tag != 'tags':
raise ValueError
- finally:
- fp.close()
except ValueError:
self.warn('unsupported build info format in %r, building all' %
path.join(self.outdir, '.buildinfo'))
@@ -314,7 +311,7 @@ class StandaloneHTMLBuilder(Builder):
self.relations = self.env.collect_relations()
rellinks = []
- if self.get_builder_config('use_index', 'html'):
+ if self.use_index:
rellinks.append(('genindex', _('General Index'), 'I', _('index')))
for indexname, indexcls, content, collapse in self.domain_indices:
# if it has a short name
@@ -344,6 +341,7 @@ class StandaloneHTMLBuilder(Builder):
show_sphinx = self.config.html_show_sphinx,
has_source = self.config.html_copy_source,
show_source = self.config.html_show_sourcelink,
+ sourcelink_suffix = self.config.html_sourcelink_suffix,
file_suffix = self.out_suffix,
script_files = self.script_files,
language = self.config.language,
@@ -407,15 +405,21 @@ class StandaloneHTMLBuilder(Builder):
# title rendered as HTML
title = self.env.longtitles.get(docname)
title = title and self.render_partial(title)['title'] or ''
+
+ # Suffix for the document
+ source_suffix = path.splitext(self.env.doc2path(docname))[1]
+
# the name for the copied source
- sourcename = self.config.html_copy_source and docname + '.txt' or ''
+ if self.config.html_copy_source:
+ sourcename = docname + source_suffix
+ if source_suffix != self.config.html_sourcelink_suffix:
+ sourcename += self.config.html_sourcelink_suffix
+ else:
+ sourcename = ''
# metadata for the document
meta = self.env.metadata.get(docname)
- # Suffix for the document
- source_suffix = '.' + self.env.doc2path(docname).split('.')[-1]
-
# local TOC and global TOC tree
self_toc = self.env.get_toc_for(docname, self)
toc = self.render_partial(self_toc)['fragment']
@@ -476,7 +480,7 @@ class StandaloneHTMLBuilder(Builder):
self.info(bold('generating indices...'), nonl=1)
# the global general index
- if self.get_builder_config('use_index', 'html'):
+ if self.use_index:
self.write_genindex()
# the global domain-specific indices
@@ -586,9 +590,8 @@ class StandaloneHTMLBuilder(Builder):
self.info(bold('copying static files... '), nonl=True)
ensuredir(path.join(self.outdir, '_static'))
# first, create pygments style file
- f = open(path.join(self.outdir, '_static', 'pygments.css'), 'w')
- f.write(self.highlighter.get_stylesheet())
- f.close()
+ with open(path.join(self.outdir, '_static', 'pygments.css'), 'w') as f:
+ f.write(self.highlighter.get_stylesheet())
# then, copy translations JavaScript file
if self.config.language is not None:
jsfile = self._get_translations_js()
@@ -610,21 +613,19 @@ class StandaloneHTMLBuilder(Builder):
# then, copy over theme-supplied static files
if self.theme:
- themeentries = [path.join(themepath, 'static')
- for themepath in self.theme.get_dirchain()[::-1]]
- for entry in themeentries:
- copy_static_entry(entry, path.join(self.outdir, '_static'),
- self, ctx)
+ for theme_path in self.theme.get_dirchain()[::-1]:
+ entry = path.join(theme_path, 'static')
+ copy_asset(entry, path.join(self.outdir, '_static'), excluded=DOTFILES,
+ context=ctx, renderer=self.templates)
# then, copy over all user-supplied static files
- staticentries = [path.join(self.confdir, spath)
- for spath in self.config.html_static_path]
- matchers = compile_matchers(self.config.exclude_patterns)
- for entry in staticentries:
+ excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
+ for static_path in self.config.html_static_path:
+ entry = path.join(self.confdir, static_path)
if not path.exists(entry):
self.warn('html_static_path entry %r does not exist' % entry)
continue
- copy_static_entry(entry, path.join(self.outdir, '_static'), self,
- ctx, exclude_matchers=matchers)
+ copy_asset(entry, path.join(self.outdir, '_static'), excluded,
+ context=ctx, renderer=self.templates)
# copy logo and favicon files if not already in static path
if self.config.html_logo:
logobase = path.basename(self.config.html_logo)
@@ -647,27 +648,25 @@ class StandaloneHTMLBuilder(Builder):
def copy_extra_files(self):
# copy html_extra_path files
self.info(bold('copying extra files... '), nonl=True)
- extraentries = [path.join(self.confdir, epath)
- for epath in self.config.html_extra_path]
- matchers = compile_matchers(self.config.exclude_patterns)
- for entry in extraentries:
+ excluded = Matcher(self.config.exclude_patterns)
+
+ for extra_path in self.config.html_extra_path:
+ entry = path.join(self.confdir, extra_path)
if not path.exists(entry):
self.warn('html_extra_path entry %r does not exist' % entry)
continue
- copy_extra_entry(entry, self.outdir, matchers)
+
+ copy_asset(entry, self.outdir, excluded)
self.info('done')
def write_buildinfo(self):
# write build info file
- fp = open(path.join(self.outdir, '.buildinfo'), 'w')
- try:
+ with open(path.join(self.outdir, '.buildinfo'), 'w') as fp:
fp.write('# Sphinx build info version 1\n'
'# This file hashes the configuration used when building'
' these files. When it is not found, a full rebuild will'
' be done.\nconfig: %s\ntags: %s\n' %
(self.config_hash, self.tags_hash))
- finally:
- fp.close()
def cleanup(self):
# clean up theme stuff
@@ -707,10 +706,8 @@ class StandaloneHTMLBuilder(Builder):
f = codecs.open(searchindexfn, 'r', encoding='utf-8')
else:
f = open(searchindexfn, 'rb')
- try:
+ with f:
self.indexer.load(f, self.indexer_format)
- finally:
- f.close()
except (IOError, OSError, ValueError):
if keep:
self.warn('search index couldn\'t be loaded, but not all '
@@ -722,7 +719,12 @@ class StandaloneHTMLBuilder(Builder):
def index_page(self, pagename, doctree, title):
# only index pages with title
if self.indexer is not None and title:
- self.indexer.feed(pagename, title, doctree)
+ filename = self.env.doc2path(pagename, base=None)
+ try:
+ self.indexer.feed(pagename, filename, title, doctree)
+ except TypeError:
+ # fallback for old search-adapters
+ self.indexer.feed(pagename, title, doctree)
def _get_local_toctree(self, docname, collapse=True, **kwds):
if 'includehidden' not in kwds:
@@ -785,6 +787,8 @@ class StandaloneHTMLBuilder(Builder):
elif not resource:
otheruri = self.get_target_uri(otheruri)
uri = relative_uri(baseuri, otheruri) or '#'
+ if uri == '#' and not self.allow_sharp_as_current_path:
+ uri = baseuri
return uri
ctx['pathto'] = pathto
@@ -824,11 +828,8 @@ class StandaloneHTMLBuilder(Builder):
# outfilename's path is in general different from self.outdir
ensuredir(path.dirname(outfilename))
try:
- f = codecs.open(outfilename, 'w', encoding, 'xmlcharrefreplace')
- try:
+ with codecs.open(outfilename, 'w', encoding, 'xmlcharrefreplace') as f:
f.write(output)
- finally:
- f.close()
except (IOError, OSError) as err:
self.warn("error writing file %s: %s" % (outfilename, err))
if self.copysource and ctx.get('sourcename'):
@@ -845,8 +846,7 @@ class StandaloneHTMLBuilder(Builder):
def dump_inventory(self):
self.info(bold('dumping object inventory... '), nonl=True)
- f = open(path.join(self.outdir, INVENTORY_FILENAME), 'wb')
- try:
+ with open(path.join(self.outdir, INVENTORY_FILENAME), 'wb') as f:
f.write((u'# Sphinx inventory version 2\n'
u'# Project: %s\n'
u'# Version: %s\n'
@@ -868,8 +868,6 @@ class StandaloneHTMLBuilder(Builder):
(u'%s %s:%s %s %s %s\n' % (name, domainname, type,
prio, uri, dispname)).encode('utf-8')))
f.write(compressor.flush())
- finally:
- f.close()
self.info('done')
def dump_search_index(self):
@@ -884,10 +882,8 @@ class StandaloneHTMLBuilder(Builder):
f = codecs.open(searchindexfn + '.tmp', 'w', encoding='utf-8')
else:
f = open(searchindexfn + '.tmp', 'wb')
- try:
+ with f:
self.indexer.dump(f, self.indexer_format)
- finally:
- f.close()
movefile(searchindexfn + '.tmp', searchindexfn)
self.info('done')
@@ -1106,7 +1102,9 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
self.theme = None # no theme necessary
self.templates = None # no template bridge necessary
self.init_translator_class()
+ self.init_templates()
self.init_highlighter()
+ self.use_index = self.get_builder_config('use_index', 'html')
def get_target_uri(self, docname, typ=None):
if docname == 'index':
@@ -1120,10 +1118,8 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
f = codecs.open(filename, 'w', encoding='utf-8')
else:
f = open(filename, 'wb')
- try:
+ with f:
self.implementation.dump(context, f, *self.additional_dump_args)
- finally:
- f.close()
def handle_page(self, pagename, ctx, templatename='page.html',
outfilename=None, event_arg=None):
@@ -1201,3 +1197,59 @@ class JSONHTMLBuilder(SerializingHTMLBuilder):
def init(self):
SerializingHTMLBuilder.init(self)
+
+
+def validate_config_values(app):
+ if app.config.html_translator_class:
+ app.warn('html_translator_class is deprecated. '
+ 'Use Sphinx.set_translator() API instead.')
+
+
+def setup(app):
+ # builders
+ app.add_builder(StandaloneHTMLBuilder)
+ app.add_builder(DirectoryHTMLBuilder)
+ app.add_builder(SingleFileHTMLBuilder)
+ app.add_builder(PickleHTMLBuilder)
+ app.add_builder(JSONHTMLBuilder)
+
+ app.connect('builder-inited', validate_config_values)
+
+ # config values
+ app.add_config_value('html_theme', 'alabaster', 'html')
+ app.add_config_value('html_theme_path', [], 'html')
+ app.add_config_value('html_theme_options', {}, 'html')
+ app.add_config_value('html_title',
+ lambda self: l_('%s %s documentation') % (self.project, self.release),
+ 'html', string_classes)
+ app.add_config_value('html_short_title', lambda self: self.html_title, 'html')
+ app.add_config_value('html_style', None, 'html', string_classes)
+ app.add_config_value('html_logo', None, 'html', string_classes)
+ app.add_config_value('html_favicon', None, 'html', string_classes)
+ app.add_config_value('html_static_path', [], 'html')
+ app.add_config_value('html_extra_path', [], 'html')
+ app.add_config_value('html_last_updated_fmt', None, 'html', string_classes)
+ app.add_config_value('html_use_smartypants', True, 'html')
+ app.add_config_value('html_sidebars', {}, 'html')
+ app.add_config_value('html_additional_pages', {}, 'html')
+ app.add_config_value('html_use_modindex', True, 'html') # deprecated
+ app.add_config_value('html_domain_indices', True, 'html', [list])
+ app.add_config_value('html_add_permalinks', u'\u00B6', 'html')
+ app.add_config_value('html_use_index', True, 'html')
+ app.add_config_value('html_split_index', False, 'html')
+ app.add_config_value('html_copy_source', True, 'html')
+ app.add_config_value('html_show_sourcelink', True, 'html')
+ app.add_config_value('html_sourcelink_suffix', '.txt', 'html')
+ app.add_config_value('html_use_opensearch', '', 'html')
+ app.add_config_value('html_file_suffix', None, 'html', string_classes)
+ app.add_config_value('html_link_suffix', None, 'html', string_classes)
+ app.add_config_value('html_show_copyright', True, 'html')
+ app.add_config_value('html_show_sphinx', True, 'html')
+ app.add_config_value('html_context', {}, 'html')
+ app.add_config_value('html_output_encoding', 'utf-8', 'html')
+ app.add_config_value('html_compact_lists', True, 'html')
+ app.add_config_value('html_secnumber_suffix', '. ', 'html')
+ app.add_config_value('html_search_language', None, 'html', string_classes)
+ app.add_config_value('html_search_options', {}, 'html')
+ app.add_config_value('html_search_scorer', '', None)
+ app.add_config_value('html_scaled_image_link', True, 'html')
diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py
index f1626321e..ecc752b60 100644
--- a/sphinx/builders/htmlhelp.py
+++ b/sphinx/builders/htmlhelp.py
@@ -18,6 +18,7 @@ from os import path
from docutils import nodes
from sphinx import addnodes
+from sphinx.util.osutil import make_filename
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.util.pycompat import htmlescape
@@ -197,18 +198,22 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
def handle_finish(self):
self.build_hhx(self.outdir, self.config.htmlhelp_basename)
+ def write_doc(self, docname, doctree):
+ for node in doctree.traverse(nodes.reference):
+ # add ``target=_blank`` attributes to external links
+ if node.get('internal') is None and 'refuri' in node:
+ node['target'] = '_blank'
+
+ StandaloneHTMLBuilder.write_doc(self, docname, doctree)
+
def build_hhx(self, outdir, outname):
self.info('dumping stopword list...')
- f = self.open_file(outdir, outname+'.stp')
- try:
+ with self.open_file(outdir, outname+'.stp') as f:
for word in sorted(stopwords):
print(word, file=f)
- finally:
- f.close()
self.info('writing project file...')
- f = self.open_file(outdir, outname+'.hhp')
- try:
+ with self.open_file(outdir, outname+'.hhp') as f:
f.write(project_template % {
'outname': outname,
'title': self.config.html_title,
@@ -227,12 +232,9 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
fn.endswith('.html'):
print(path.join(root, fn)[olen:].replace(os.sep, '\\'),
file=f)
- finally:
- f.close()
self.info('writing TOC file...')
- f = self.open_file(outdir, outname+'.hhc')
- try:
+ with self.open_file(outdir, outname+'.hhc') as f:
f.write(contents_header)
# special books
f.write('<LI> ' + object_sitemap % (self.config.html_short_title,
@@ -270,13 +272,10 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
for node in tocdoc.traverse(istoctree):
write_toc(node)
f.write(contents_footer)
- finally:
- f.close()
self.info('writing index file...')
index = self.env.create_index(self)
- f = self.open_file(outdir, outname+'.hhk')
- try:
+ with self.open_file(outdir, outname+'.hhk') as f:
f.write('<UL>\n')
def write_index(title, refs, subitems):
@@ -306,5 +305,10 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
for title, (refs, subitems, key_) in group:
write_index(title, refs, subitems)
f.write('</UL>\n')
- finally:
- f.close()
+
+
+def setup(app):
+ app.setup_extension('sphinx.builders.html')
+ app.add_builder(HTMLHelpBuilder)
+
+ app.add_config_value('htmlhelp_basename', lambda self: make_filename(self.project), None)
diff --git a/sphinx/builders/latex.py b/sphinx/builders/latex.py
index ac26e33c9..0ef0d70d4 100644
--- a/sphinx/builders/latex.py
+++ b/sphinx/builders/latex.py
@@ -11,7 +11,6 @@
import os
from os import path
-import warnings
from six import iteritems
from docutils import nodes
@@ -19,14 +18,16 @@ from docutils.io import FileOutput
from docutils.utils import new_document
from docutils.frontend import OptionParser
-from sphinx import package_dir, addnodes
+from sphinx import package_dir, addnodes, highlighting
from sphinx.util import texescape
+from sphinx.config import string_classes, ENUM
from sphinx.errors import SphinxError
from sphinx.locale import _
from sphinx.builders import Builder
from sphinx.environment import NoUri
from sphinx.util.nodes import inline_all_toctrees
-from sphinx.util.osutil import SEP, copyfile
+from sphinx.util.fileutil import copy_asset_file
+from sphinx.util.osutil import SEP, make_filename
from sphinx.util.console import bold, darkgreen
from sphinx.writers.latex import LaTeXWriter
@@ -38,27 +39,12 @@ class LaTeXBuilder(Builder):
name = 'latex'
format = 'latex'
supported_image_types = ['application/pdf', 'image/png', 'image/jpeg']
- usepackages = []
def init(self):
self.docnames = []
self.document_data = []
+ self.usepackages = []
texescape.init()
- self.check_options()
-
- def check_options(self):
- if self.config.latex_toplevel_sectioning not in (None, 'part', 'chapter', 'section'):
- self.warn('invalid latex_toplevel_sectioning, ignored: %s' %
- self.config.latex_top_sectionlevel)
- self.config.latex_top_sectionlevel = None
-
- if self.config.latex_use_parts:
- warnings.warn('latex_use_parts will be removed at Sphinx-1.5. '
- 'Use latex_toplevel_sectioning instead.',
- DeprecationWarning)
-
- if self.config.latex_toplevel_sectioning:
- self.warn('latex_use_parts conflicts with latex_toplevel_sectioning, ignored.')
def get_outdated_docs(self):
return 'all documents' # for now
@@ -92,6 +78,16 @@ class LaTeXBuilder(Builder):
docname = docname[:-5]
self.titles.append((docname, entry[2]))
+ def write_stylesheet(self):
+ highlighter = highlighting.PygmentsBridge(
+ 'latex', self.config.pygments_style, self.config.trim_doctest_flags)
+ stylesheet = path.join(self.outdir, 'sphinxhighlight.sty')
+ with open(stylesheet, 'w') as f:
+ f.write('\\NeedsTeXFormat{LaTeX2e}[1995/12/01]\n')
+ f.write('\\ProvidesPackage{sphinxhighlight}'
+ '[2016/05/29 stylesheet for highlighting with pygments]\n\n')
+ f.write(highlighter.get_stylesheet())
+
def write(self, *ignored):
docwriter = LaTeXWriter(self)
docsettings = OptionParser(
@@ -100,6 +96,7 @@ class LaTeXBuilder(Builder):
read_config_files=True).get_default_values()
self.init_document_data()
+ self.write_stylesheet()
for entry in self.document_data:
docname, targetname, title, author, docclass = entry[:5]
@@ -192,33 +189,118 @@ class LaTeXBuilder(Builder):
self.info(bold('copying images...'), nonl=1)
for src, dest in iteritems(self.images):
self.info(' '+src, nonl=1)
- copyfile(path.join(self.srcdir, src),
- path.join(self.outdir, dest))
+ copy_asset_file(path.join(self.srcdir, src),
+ path.join(self.outdir, dest))
self.info()
# copy TeX support files from texinputs
+ context = {'latex_engine': self.config.latex_engine}
self.info(bold('copying TeX support files...'))
staticdirname = path.join(package_dir, 'texinputs')
for filename in os.listdir(staticdirname):
if not filename.startswith('.'):
- copyfile(path.join(staticdirname, filename),
- path.join(self.outdir, filename))
+ copy_asset_file(path.join(staticdirname, filename),
+ self.outdir, context=context)
# copy additional files
if self.config.latex_additional_files:
self.info(bold('copying additional files...'), nonl=1)
for filename in self.config.latex_additional_files:
self.info(' '+filename, nonl=1)
- copyfile(path.join(self.confdir, filename),
- path.join(self.outdir, path.basename(filename)))
+ copy_asset_file(path.join(self.confdir, filename), self.outdir)
self.info()
# the logo is handled differently
if self.config.latex_logo:
- logobase = path.basename(self.config.latex_logo)
- logotarget = path.join(self.outdir, logobase)
if not path.isfile(path.join(self.confdir, self.config.latex_logo)):
raise SphinxError('logo file %r does not exist' % self.config.latex_logo)
- elif not path.isfile(logotarget):
- copyfile(path.join(self.confdir, self.config.latex_logo), logotarget)
+ else:
+ copy_asset_file(path.join(self.confdir, self.config.latex_logo), self.outdir)
self.info('done')
+
+
+def validate_config_values(app):
+ if app.config.latex_toplevel_sectioning not in (None, 'part', 'chapter', 'section'):
+ app.warn('invalid latex_toplevel_sectioning, ignored: %s' %
+ app.config.latex_toplevel_sectioning)
+ app.config.latex_toplevel_sectioning = None
+
+ if app.config.latex_use_parts:
+ if app.config.latex_toplevel_sectioning:
+ app.warn('latex_use_parts conflicts with latex_toplevel_sectioning, ignored.')
+ else:
+ app.warn('latex_use_parts is deprecated. Use latex_toplevel_sectioning instead.')
+ app.config.latex_toplevel_sectioning = 'parts'
+
+ if app.config.latex_use_modindex is not True: # changed by user
+ app.warn('latex_use_modeindex is deprecated. Use latex_domain_indices instead.')
+
+ if app.config.latex_preamble:
+ if app.config.latex_elements.get('preamble'):
+ app.warn("latex_preamble conflicts with latex_elements['preamble'], ignored.")
+ else:
+ app.warn("latex_preamble is deprecated. Use latex_elements['preamble'] instead.")
+ app.config.latex_elements['preamble'] = app.config.latex_preamble
+
+ if app.config.latex_paper_size != 'letter':
+ if app.config.latex_elements.get('papersize'):
+ app.warn("latex_paper_size conflicts with latex_elements['papersize'], ignored.")
+ else:
+ app.warn("latex_paper_size is deprecated. "
+ "Use latex_elements['papersize'] instead.")
+ if app.config.latex_paper_size:
+ app.config.latex_elements['papersize'] = app.config.latex_paper_size + 'paper'
+
+ if app.config.latex_font_size != '10pt':
+ if app.config.latex_elements.get('pointsize'):
+ app.warn("latex_font_size conflicts with latex_elements['pointsize'], ignored.")
+ else:
+ app.warn("latex_font_size is deprecated. Use latex_elements['pointsize'] instead.")
+ app.config.latex_elements['pointsize'] = app.config.latex_font_size
+
+ if 'footer' in app.config.latex_elements:
+ if 'postamble' in app.config.latex_elements:
+ app.warn("latex_elements['footer'] conflicts with "
+ "latex_elements['postamble'], ignored.")
+ else:
+ app.warn("latex_elements['footer'] is deprecated. "
+ "Use latex_elements['preamble'] instead.")
+ app.config.latex_elements['postamble'] = app.config.latex_elements['footer']
+
+
+def setup(app):
+ app.add_builder(LaTeXBuilder)
+ app.connect('builder-inited', validate_config_values)
+
+ app.add_config_value('latex_engine',
+ lambda self: 'pdflatex' if self.language != 'ja' else 'platex',
+ None,
+ ENUM('pdflatex', 'xelatex', 'lualatex', 'platex'))
+ app.add_config_value('latex_documents',
+ lambda self: [(self.master_doc, make_filename(self.project) + '.tex',
+ self.project, '', 'manual')],
+ None)
+ app.add_config_value('latex_logo', None, None, string_classes)
+ app.add_config_value('latex_appendices', [], None)
+ app.add_config_value('latex_keep_old_macro_names', True, None)
+ # now deprecated - use latex_toplevel_sectioning
+ app.add_config_value('latex_use_parts', False, None)
+ app.add_config_value('latex_toplevel_sectioning', None, None, [str])
+ app.add_config_value('latex_use_modindex', True, None) # deprecated
+ app.add_config_value('latex_domain_indices', True, None, [list])
+ app.add_config_value('latex_show_urls', 'no', None)
+ app.add_config_value('latex_show_pagerefs', False, None)
+ # paper_size and font_size are still separate values
+ # so that you can give them easily on the command line
+ app.add_config_value('latex_paper_size', 'letter', None)
+ app.add_config_value('latex_font_size', '10pt', None)
+ app.add_config_value('latex_elements', {}, None)
+ app.add_config_value('latex_additional_files', [], None)
+
+ japanese_default = {'manual': 'jsbook',
+ 'howto': 'jreport'}
+ app.add_config_value('latex_docclass',
+ lambda self: japanese_default if self.language == 'ja' else {},
+ None)
+ # now deprecated - use latex_elements
+ app.add_config_value('latex_preamble', '', None)
diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py
index bb7967e83..f49f4f9a3 100644
--- a/sphinx/builders/linkcheck.py
+++ b/sphinx/builders/linkcheck.py
@@ -15,10 +15,9 @@ import codecs
import threading
from os import path
+from requests.exceptions import HTTPError
from six.moves import queue
-from six.moves.urllib.request import build_opener, Request, HTTPRedirectHandler
from six.moves.urllib.parse import unquote
-from six.moves.urllib.error import HTTPError
from six.moves.html_parser import HTMLParser
from docutils import nodes
@@ -36,34 +35,7 @@ from sphinx.builders import Builder
from sphinx.util import encode_uri
from sphinx.util.console import purple, red, darkgreen, darkgray, \
darkred, turquoise
-from sphinx.util.pycompat import TextIOWrapper
-
-
-class RedirectHandler(HTTPRedirectHandler):
- """A RedirectHandler that records the redirect code we got."""
-
- def redirect_request(self, req, fp, code, msg, headers, newurl):
- new_req = HTTPRedirectHandler.redirect_request(self, req, fp, code,
- msg, headers, newurl)
- req.redirect_code = code
- return new_req
-
-
-# create an opener that will simulate a browser user-agent
-opener = build_opener(RedirectHandler)
-opener.addheaders = [('User-agent', 'Mozilla/5.0 (X11; Linux x86_64; rv:25.0) '
- 'Gecko/20100101 Firefox/25.0')]
-
-
-class HeadRequest(Request):
- """Subclass of urllib2.Request that sends a HEAD request."""
- def __init__(self, *args, **kwargs):
- Request.__init__(self, *args, **kwargs)
- # we do not parse the response in HEAD, so accepting anything is okay
- self.headers['Accept-encoding'] = '*'
-
- def get_method(self):
- return 'HEAD'
+from sphinx.util.requests import requests, useragent_header, is_ssl_error
class AnchorCheckParser(HTMLParser):
@@ -79,20 +51,21 @@ class AnchorCheckParser(HTMLParser):
for key, value in attrs:
if key in ('id', 'name') and value == self.search_anchor:
self.found = True
+ break
-def check_anchor(f, anchor):
- """Reads HTML data from a filelike object 'f' searching for *anchor*.
+def check_anchor(response, anchor):
+ """Reads HTML data from a response object `response` searching for `anchor`.
Returns True if anchor was found, False otherwise.
"""
parser = AnchorCheckParser(anchor)
try:
- # Read file in chunks of 8192 bytes. If we find a matching anchor, we
- # break the loop early in hopes not to have to download the whole thing.
- chunk = f.read(8192)
- while chunk and not parser.found:
+ # Read file in chunks. If we find a matching anchor, we break
+ # the loop early in hopes not to have to download the whole thing.
+ for chunk in response.iter_content(chunk_size=4096, decode_unicode=True):
parser.feed(chunk)
- chunk = f.read(8192)
+ if parser.found:
+ break
parser.close()
except HTMLParseError:
# HTMLParser is usually pretty good with sloppy HTML, but it tends to
@@ -101,17 +74,6 @@ def check_anchor(f, anchor):
return parser.found
-def get_content_charset(f):
- content_type = f.headers.get('content-type')
- if content_type:
- params = (p.strip() for p in content_type.split(';')[1:])
- for param in params:
- if param.startswith('charset='):
- return param[8:]
-
- return None
-
-
class CheckExternalLinksBuilder(Builder):
"""
Checks for broken external links.
@@ -120,9 +82,12 @@ class CheckExternalLinksBuilder(Builder):
def init(self):
self.to_ignore = [re.compile(x) for x in self.app.config.linkcheck_ignore]
+ self.anchors_ignore = [re.compile(x)
+ for x in self.app.config.linkcheck_anchors_ignore]
self.good = set()
self.broken = {}
self.redirected = {}
+ self.headers = dict(useragent_header)
# set a timeout for non-responding servers
socket.setdefaulttimeout(5.0)
# create output file
@@ -143,10 +108,16 @@ class CheckExternalLinksBuilder(Builder):
if self.app.config.linkcheck_timeout:
kwargs['timeout'] = self.app.config.linkcheck_timeout
+ kwargs['allow_redirects'] = True
+
def check_uri():
# split off anchor
if '#' in uri:
req_url, anchor = uri.split('#', 1)
+ for rex in self.anchors_ignore:
+ if rex.match(anchor):
+ anchor = None
+ break
else:
req_url = uri
anchor = None
@@ -158,54 +129,46 @@ class CheckExternalLinksBuilder(Builder):
req_url = encode_uri(req_url)
try:
- if anchor and self.app.config.linkcheck_anchors and \
- not anchor.startswith('!'):
+ if anchor and self.app.config.linkcheck_anchors:
# Read the whole document and see if #anchor exists
- # (Anchors starting with ! are ignored since they are
- # commonly used for dynamic pages)
- req = Request(req_url)
- f = opener.open(req, **kwargs)
- encoding = 'utf-8'
- if hasattr(f.headers, 'get_content_charset'):
- encoding = f.headers.get_content_charset() or encoding
- else:
- encoding = get_content_charset(f) or encoding
- found = check_anchor(TextIOWrapper(f, encoding),
- unquote(anchor))
- f.close()
+ response = requests.get(req_url, stream=True, headers=self.headers,
+ **kwargs)
+ found = check_anchor(response, unquote(anchor))
if not found:
raise Exception("Anchor '%s' not found" % anchor)
else:
try:
- # try a HEAD request, which should be easier on
+ # try a HEAD request first, which should be easier on
# the server and the network
- req = HeadRequest(req_url)
- f = opener.open(req, **kwargs)
- f.close()
+ response = requests.head(req_url, headers=self.headers, **kwargs)
+ response.raise_for_status()
except HTTPError as err:
- if err.code not in (403, 405):
- raise
- # retry with GET if that fails, some servers
- # don't like HEAD requests and reply with 403 or 405
- req = Request(req_url)
- f = opener.open(req, **kwargs)
- f.close()
+ # retry with GET request if that fails, some servers
+ # don't like HEAD requests.
+ response = requests.get(req_url, stream=True, headers=self.headers,
+ **kwargs)
+ response.raise_for_status()
except HTTPError as err:
- if err.code == 401:
+ if err.response.status_code == 401:
# We'll take "Unauthorized" as working.
return 'working', ' - unauthorized', 0
else:
return 'broken', str(err), 0
except Exception as err:
- return 'broken', str(err), 0
- if f.url.rstrip('/') == req_url.rstrip('/'):
+ if is_ssl_error(err):
+ return 'ignored', str(err), 0
+ else:
+ return 'broken', str(err), 0
+ if response.url.rstrip('/') == req_url.rstrip('/'):
return 'working', '', 0
else:
- new_url = f.url
+ new_url = response.url
if anchor:
new_url += '#' + anchor
- code = getattr(req, 'redirect_code', 0)
+ # history contains any redirects, get last
+ if response.history:
+ code = response.history[-1].status_code
return 'redirected', new_url, code
def check():
@@ -255,7 +218,10 @@ class CheckExternalLinksBuilder(Builder):
if lineno:
self.info('(line %4d) ' % lineno, nonl=1)
if status == 'ignored':
- self.info(darkgray('-ignored- ') + uri)
+ if info:
+ self.info(darkgray('-ignored- ') + uri + ': ' + info)
+ else:
+ self.info(darkgray('-ignored- ') + uri)
elif status == 'local':
self.info(darkgray('-local- ') + uri)
self.write_entry('local', docname, lineno, uri)
@@ -264,7 +230,7 @@ class CheckExternalLinksBuilder(Builder):
elif status == 'broken':
self.write_entry('broken', docname, lineno, uri + ': ' + info)
if self.app.quiet or self.app.warningiserror:
- self.warn('broken link: %s' % uri,
+ self.warn('broken link: %s (%s)' % (uri, info),
'%s:%s' % (self.env.doc2path(docname), lineno))
else:
self.info(red('broken ') + uri + red(' - ' + info))
@@ -321,3 +287,16 @@ class CheckExternalLinksBuilder(Builder):
def finish(self):
for worker in self.workers:
self.wqueue.put((None, None, None), False)
+
+
+def setup(app):
+ app.add_builder(CheckExternalLinksBuilder)
+
+ app.add_config_value('linkcheck_ignore', [], None)
+ app.add_config_value('linkcheck_retries', 1, None)
+ app.add_config_value('linkcheck_timeout', None, None, [int])
+ app.add_config_value('linkcheck_workers', 5, None)
+ app.add_config_value('linkcheck_anchors', True, None)
+ # Anchors starting with ! are ignored since they are
+ # commonly used for dynamic pages
+ app.add_config_value('linkcheck_anchors_ignore', ["^!"], None)
diff --git a/sphinx/builders/manpage.py b/sphinx/builders/manpage.py
index a2e75f9f7..248ed40b2 100644
--- a/sphinx/builders/manpage.py
+++ b/sphinx/builders/manpage.py
@@ -19,6 +19,7 @@ from sphinx import addnodes
from sphinx.builders import Builder
from sphinx.environment import NoUri
from sphinx.util.nodes import inline_all_toctrees
+from sphinx.util.osutil import make_filename
from sphinx.util.console import bold, darkgreen
from sphinx.writers.manpage import ManualPageWriter
@@ -88,3 +89,13 @@ class ManualPageBuilder(Builder):
def finish(self):
pass
+
+
+def setup(app):
+ app.add_builder(ManualPageBuilder)
+
+ app.add_config_value('man_pages',
+ lambda self: [(self.master_doc, make_filename(self.project).lower(),
+ '%s %s' % (self.project, self.release), [], 1)],
+ None)
+ app.add_config_value('man_show_urls', False, None)
diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py
index e02985b94..c53b56657 100644
--- a/sphinx/builders/qthelp.py
+++ b/sphinx/builders/qthelp.py
@@ -21,6 +21,7 @@ from docutils import nodes
from sphinx import addnodes
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.util import force_decode
+from sphinx.util.osutil import make_filename
from sphinx.util.pycompat import htmlescape
@@ -104,8 +105,14 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
# don't add links
add_permalinks = False
+
# don't add sidebar etc.
embedded = True
+ # disable download role
+ download_support = False
+
+ # don't generate the search index or include the search page
+ search = False
def init(self):
StandaloneHTMLBuilder.init(self)
@@ -114,6 +121,9 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
self.link_suffix = '.html'
# self.config.html_style = 'traditional.css'
+ def get_theme_config(self):
+ return self.config.qthelp_theme, self.config.qthelp_theme_options
+
def handle_finish(self):
self.build_qhp(self.outdir, self.config.qthelp_basename)
@@ -180,8 +190,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
nspace = nspace.lower()
# write the project file
- f = codecs.open(path.join(outdir, outname+'.qhp'), 'w', 'utf-8')
- try:
+ with codecs.open(path.join(outdir, outname+'.qhp'), 'w', 'utf-8') as f:
f.write(project_template % {
'outname': htmlescape(outname),
'title': htmlescape(self.config.html_title),
@@ -192,23 +201,18 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
'sections': sections,
'keywords': keywords,
'files': projectfiles})
- finally:
- f.close()
homepage = 'qthelp://' + posixpath.join(
nspace, 'doc', self.get_target_uri(self.config.master_doc))
startpage = 'qthelp://' + posixpath.join(nspace, 'doc', 'index.html')
self.info('writing collection project file...')
- f = codecs.open(path.join(outdir, outname+'.qhcp'), 'w', 'utf-8')
- try:
+ with codecs.open(path.join(outdir, outname+'.qhcp'), 'w', 'utf-8') as f:
f.write(collection_template % {
'outname': htmlescape(outname),
'title': htmlescape(self.config.html_short_title),
'homepage': htmlescape(homepage),
'startpage': htmlescape(startpage)})
- finally:
- f.close()
def isdocnode(self, node):
if not isinstance(node, nodes.list_item):
@@ -297,3 +301,12 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
keywords.extend(self.build_keywords(subitem[0], subitem[1], []))
return keywords
+
+
+def setup(app):
+ app.setup_extension('sphinx.builders.html')
+ app.add_builder(QtHelpBuilder)
+
+ app.add_config_value('qthelp_basename', lambda self: make_filename(self.project), None)
+ app.add_config_value('qthelp_theme', 'nonav', 'html')
+ app.add_config_value('qthelp_theme_options', {}, 'html')
diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py
index dec278c86..f070840b6 100644
--- a/sphinx/builders/texinfo.py
+++ b/sphinx/builders/texinfo.py
@@ -22,7 +22,7 @@ from sphinx.locale import _
from sphinx.builders import Builder
from sphinx.environment import NoUri
from sphinx.util.nodes import inline_all_toctrees
-from sphinx.util.osutil import SEP, copyfile
+from sphinx.util.osutil import SEP, copyfile, make_filename
from sphinx.util.console import bold, darkgreen
from sphinx.writers.texinfo import TexinfoWriter
@@ -220,11 +220,25 @@ class TexinfoBuilder(Builder):
fn = path.join(self.outdir, 'Makefile')
self.info(fn, nonl=1)
try:
- mkfile = open(fn, 'w')
- try:
+ with open(fn, 'w') as mkfile:
mkfile.write(TEXINFO_MAKEFILE)
- finally:
- mkfile.close()
except (IOError, OSError) as err:
self.warn("error writing file %s: %s" % (fn, err))
self.info(' done')
+
+
+def setup(app):
+ app.add_builder(TexinfoBuilder)
+
+ app.add_config_value('texinfo_documents',
+ lambda self: [(self.master_doc, make_filename(self.project).lower(),
+ self.project, '', make_filename(self.project),
+ 'The %s reference manual.' %
+ make_filename(self.project),
+ 'Python')],
+ None)
+ app.add_config_value('texinfo_appendices', [], None)
+ app.add_config_value('texinfo_elements', {}, None)
+ app.add_config_value('texinfo_domain_indices', True, None, [list])
+ app.add_config_value('texinfo_show_urls', 'footnote', None)
+ app.add_config_value('texinfo_no_detailmenu', False, None)
diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py
index 85da4a1a2..2daf8b043 100644
--- a/sphinx/builders/text.py
+++ b/sphinx/builders/text.py
@@ -60,13 +60,17 @@ class TextBuilder(Builder):
outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix)
ensuredir(path.dirname(outfilename))
try:
- f = codecs.open(outfilename, 'w', 'utf-8')
- try:
+ with codecs.open(outfilename, 'w', 'utf-8') as f:
f.write(self.writer.output)
- finally:
- f.close()
except (IOError, OSError) as err:
self.warn("error writing file %s: %s" % (outfilename, err))
def finish(self):
pass
+
+
+def setup(app):
+ app.add_builder(TextBuilder)
+
+ app.add_config_value('text_sectionchars', '*=-~"+`', 'env')
+ app.add_config_value('text_newlines', 'unix', 'env')
diff --git a/sphinx/builders/websupport.py b/sphinx/builders/websupport.py
index 843b0899e..d8ff5ad8d 100644
--- a/sphinx/builders/websupport.py
+++ b/sphinx/builders/websupport.py
@@ -165,3 +165,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
def dump_search_index(self):
self.indexer.finish_indexing()
+
+
+def setup(app):
+ app.add_builder(WebSupportBuilder)
diff --git a/sphinx/builders/xml.py b/sphinx/builders/xml.py
index 91cb273f5..e0e33312c 100644
--- a/sphinx/builders/xml.py
+++ b/sphinx/builders/xml.py
@@ -77,11 +77,8 @@ class XMLBuilder(Builder):
outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix)
ensuredir(path.dirname(outfilename))
try:
- f = codecs.open(outfilename, 'w', 'utf-8')
- try:
+ with codecs.open(outfilename, 'w', 'utf-8') as f:
f.write(self.writer.output)
- finally:
- f.close()
except (IOError, OSError) as err:
self.warn("error writing file %s: %s" % (outfilename, err))
@@ -98,3 +95,10 @@ class PseudoXMLBuilder(XMLBuilder):
out_suffix = '.pseudoxml'
_writer_class = PseudoXMLWriter
+
+
+def setup(app):
+ app.add_builder(XMLBuilder)
+ app.add_builder(PseudoXMLBuilder)
+
+ app.add_config_value('xml_pretty', True, 'env')
diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py
index c4832f1c2..0d85767e4 100644
--- a/sphinx/cmdline.py
+++ b/sphinx/cmdline.py
@@ -23,6 +23,7 @@ from sphinx.errors import SphinxError
from sphinx.application import Sphinx
from sphinx.util import Tee, format_exception_cut_frames, save_traceback
from sphinx.util.console import red, nocolor, color_terminal
+from sphinx.util.docutils import docutils_namespace
from sphinx.util.osutil import abspath, fs_encoding
from sphinx.util.pycompat import terminal_safe
@@ -55,6 +56,56 @@ class MyFormatter(optparse.IndentedHelpFormatter):
return "\n".join(result)
+def handle_exception(app, opts, exception, stderr=sys.stderr):
+ if opts.pdb:
+ import pdb
+ print(red('Exception occurred while building, starting debugger:'),
+ file=stderr)
+ traceback.print_exc()
+ pdb.post_mortem(sys.exc_info()[2])
+ else:
+ print(file=stderr)
+ if opts.verbosity or opts.traceback:
+ traceback.print_exc(None, stderr)
+ print(file=stderr)
+ if isinstance(exception, KeyboardInterrupt):
+ print('interrupted!', file=stderr)
+ elif isinstance(exception, SystemMessage):
+ print(red('reST markup error:'), file=stderr)
+ print(terminal_safe(exception.args[0]), file=stderr)
+ elif isinstance(exception, SphinxError):
+ print(red('%s:' % exception.category), file=stderr)
+ print(terminal_safe(text_type(exception)), file=stderr)
+ elif isinstance(exception, UnicodeError):
+ print(red('Encoding error:'), file=stderr)
+ print(terminal_safe(text_type(exception)), file=stderr)
+ tbpath = save_traceback(app)
+ print(red('The full traceback has been saved in %s, if you want '
+ 'to report the issue to the developers.' % tbpath),
+ file=stderr)
+ elif isinstance(exception, RuntimeError) and 'recursion depth' in str(exception):
+ print(red('Recursion error:'), file=stderr)
+ print(terminal_safe(text_type(exception)), file=stderr)
+ print(file=stderr)
+ print('This can happen with very large or deeply nested source '
+ 'files. You can carefully increase the default Python '
+ 'recursion limit of 1000 in conf.py with e.g.:', file=stderr)
+ print(' import sys; sys.setrecursionlimit(1500)', file=stderr)
+ else:
+ print(red('Exception occurred:'), file=stderr)
+ print(format_exception_cut_frames().rstrip(), file=stderr)
+ tbpath = save_traceback(app)
+ print(red('The full traceback has been saved in %s, if you '
+ 'want to report the issue to the developers.' % tbpath),
+ file=stderr)
+ print('Please also report this if it was a user error, so '
+ 'that a better error message can be provided next time.',
+ file=stderr)
+ print('A bug report can be filed in the tracker at '
+ '<https://github.com/sphinx-doc/sphinx/issues>. Thanks!',
+ file=stderr)
+
+
def main(argv):
if not color_terminal():
nocolor()
@@ -238,57 +289,12 @@ def main(argv):
app = None
try:
- app = Sphinx(srcdir, confdir, outdir, doctreedir, opts.builder,
- confoverrides, status, warning, opts.freshenv,
- opts.warningiserror, opts.tags, opts.verbosity, opts.jobs)
- app.build(opts.force_all, filenames)
- return app.statuscode
- except (Exception, KeyboardInterrupt) as err:
- if opts.pdb:
- import pdb
- print(red('Exception occurred while building, starting debugger:'),
- file=error)
- traceback.print_exc()
- pdb.post_mortem(sys.exc_info()[2])
- else:
- print(file=error)
- if opts.verbosity or opts.traceback:
- traceback.print_exc(None, error)
- print(file=error)
- if isinstance(err, KeyboardInterrupt):
- print('interrupted!', file=error)
- elif isinstance(err, SystemMessage):
- print(red('reST markup error:'), file=error)
- print(terminal_safe(err.args[0]), file=error)
- elif isinstance(err, SphinxError):
- print(red('%s:' % err.category), file=error)
- print(terminal_safe(text_type(err)), file=error)
- elif isinstance(err, UnicodeError):
- print(red('Encoding error:'), file=error)
- print(terminal_safe(text_type(err)), file=error)
- tbpath = save_traceback(app)
- print(red('The full traceback has been saved in %s, if you want '
- 'to report the issue to the developers.' % tbpath),
- file=error)
- elif isinstance(err, RuntimeError) and 'recursion depth' in str(err):
- print(red('Recursion error:'), file=error)
- print(terminal_safe(text_type(err)), file=error)
- print(file=error)
- print('This can happen with very large or deeply nested source '
- 'files. You can carefully increase the default Python '
- 'recursion limit of 1000 in conf.py with e.g.:', file=error)
- print(' import sys; sys.setrecursionlimit(1500)', file=error)
- else:
- print(red('Exception occurred:'), file=error)
- print(format_exception_cut_frames().rstrip(), file=error)
- tbpath = save_traceback(app)
- print(red('The full traceback has been saved in %s, if you '
- 'want to report the issue to the developers.' % tbpath),
- file=error)
- print('Please also report this if it was a user error, so '
- 'that a better error message can be provided next time.',
- file=error)
- print('A bug report can be filed in the tracker at '
- '<https://github.com/sphinx-doc/sphinx/issues>. Thanks!',
- file=error)
- return 1
+ with docutils_namespace():
+ app = Sphinx(srcdir, confdir, outdir, doctreedir, opts.builder,
+ confoverrides, status, warning, opts.freshenv,
+ opts.warningiserror, opts.tags, opts.verbosity, opts.jobs)
+ app.build(opts.force_all, filenames)
+ return app.statuscode
+ except (Exception, KeyboardInterrupt) as exc:
+ handle_exception(app, opts, exc, error)
+ return 1
diff --git a/sphinx/config.py b/sphinx/config.py
index 462e48a57..5741d66bf 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -10,14 +10,13 @@
"""
import re
-from os import path, environ, getenv
-import shlex
+from os import path, getenv
from six import PY2, PY3, iteritems, string_types, binary_type, text_type, integer_types
from sphinx.errors import ConfigError
from sphinx.locale import l_
-from sphinx.util.osutil import make_filename, cd
+from sphinx.util.osutil import cd
from sphinx.util.pycompat import execfile_, NoneType
from sphinx.util.i18n import format_date
@@ -29,8 +28,25 @@ if PY3:
CONFIG_SYNTAX_ERROR += "\nDid you change the syntax from 2.x to 3.x?"
CONFIG_EXIT_ERROR = "The configuration file (or one of the modules it imports) " \
"called sys.exit()"
+CONFIG_ENUM_WARNING = "The config value `{name}` has to be a one of {candidates}, " \
+ "but `{current}` is given."
+CONFIG_PERMITTED_TYPE_WARNING = "The config value `{name}' has type `{current.__name__}', " \
+ "expected to {permitted}."
CONFIG_TYPE_WARNING = "The config value `{name}' has type `{current.__name__}', " \
- "defaults to `{default.__name__}.'"
+ "defaults to `{default.__name__}'."
+
+
+class ENUM(object):
+ """represents the config value should be a one of candidates.
+
+ Example:
+ app.add_config_value('latex_show_urls', 'no', ENUM('no', 'footnote', 'inline'))
+ """
+ def __init__(self, *candidates):
+ self.candidates = candidates
+
+ def match(self, value):
+ return value in self.candidates
string_classes = [text_type]
@@ -59,7 +75,7 @@ class Config(object):
today_fmt = (None, 'env', string_classes),
language = (None, 'env', string_classes),
- locale_dirs = ([], 'env'),
+ locale_dirs = (['locales'], 'env'),
figure_language_filename = (u'{root}.{language}{ext}', 'env', [str]),
master_doc = ('contents', 'env'),
@@ -86,190 +102,18 @@ class Config(object):
primary_domain = ('py', 'env', [NoneType]),
needs_sphinx = (None, None, string_classes),
needs_extensions = ({}, None),
- nitpicky = (False, 'env'),
- nitpick_ignore = ([], 'html'),
+ nitpicky = (False, None),
+ nitpick_ignore = ([], None),
numfig = (False, 'env'),
numfig_secnum_depth = (1, 'env'),
- numfig_format = ({'figure': l_('Fig. %s'),
+ numfig_format = ({'section': l_('Section %s'),
+ 'figure': l_('Fig. %s'),
'table': l_('Table %s'),
'code-block': l_('Listing %s')},
'env'),
- # HTML options
- html_theme = ('alabaster', 'html'),
- html_theme_path = ([], 'html'),
- html_theme_options = ({}, 'html'),
- html_title = (lambda self: l_('%s %s documentation') %
- (self.project, self.release),
- 'html', string_classes),
- html_short_title = (lambda self: self.html_title, 'html'),
- html_style = (None, 'html', string_classes),
- html_logo = (None, 'html', string_classes),
- html_favicon = (None, 'html', string_classes),
- html_static_path = ([], 'html'),
- html_extra_path = ([], 'html'),
- # the real default is locale-dependent
- html_last_updated_fmt = (None, 'html', string_classes),
- html_use_smartypants = (True, 'html'),
+ # pre-initialized confval for HTML builder
html_translator_class = (None, 'html', string_classes),
- html_sidebars = ({}, 'html'),
- html_additional_pages = ({}, 'html'),
- html_use_modindex = (True, 'html'), # deprecated
- html_domain_indices = (True, 'html', [list]),
- html_add_permalinks = (u'\u00B6', 'html'),
- html_use_index = (True, 'html'),
- html_split_index = (False, 'html'),
- html_copy_source = (True, 'html'),
- html_show_sourcelink = (True, 'html'),
- html_use_opensearch = ('', 'html'),
- html_file_suffix = (None, 'html', string_classes),
- html_link_suffix = (None, 'html', string_classes),
- html_show_copyright = (True, 'html'),
- html_show_sphinx = (True, 'html'),
- html_context = ({}, 'html'),
- html_output_encoding = ('utf-8', 'html'),
- html_compact_lists = (True, 'html'),
- html_secnumber_suffix = ('. ', 'html'),
- html_search_language = (None, 'html', string_classes),
- html_search_options = ({}, 'html'),
- html_search_scorer = ('', None),
- html_scaled_image_link = (True, 'html'),
-
- # HTML help only options
- htmlhelp_basename = (lambda self: make_filename(self.project), None),
-
- # Qt help only options
- qthelp_basename = (lambda self: make_filename(self.project), None),
-
- # Devhelp only options
- devhelp_basename = (lambda self: make_filename(self.project), None),
-
- # Apple help options
- applehelp_bundle_name = (lambda self: make_filename(self.project),
- 'applehelp'),
- applehelp_bundle_id = (None, 'applehelp', string_classes),
- applehelp_dev_region = ('en-us', 'applehelp'),
- applehelp_bundle_version = ('1', 'applehelp'),
- applehelp_icon = (None, 'applehelp', string_classes),
- applehelp_kb_product = (lambda self: '%s-%s' %
- (make_filename(self.project), self.release),
- 'applehelp'),
- applehelp_kb_url = (None, 'applehelp', string_classes),
- applehelp_remote_url = (None, 'applehelp', string_classes),
- applehelp_index_anchors = (False, 'applehelp', string_classes),
- applehelp_min_term_length = (None, 'applehelp', string_classes),
- applehelp_stopwords = (lambda self: self.language or 'en', 'applehelp'),
- applehelp_locale = (lambda self: self.language or 'en', 'applehelp'),
- applehelp_title = (lambda self: self.project + ' Help', 'applehelp'),
- applehelp_codesign_identity = (lambda self:
- environ.get('CODE_SIGN_IDENTITY', None),
- 'applehelp'),
- applehelp_codesign_flags = (lambda self:
- shlex.split(
- environ.get('OTHER_CODE_SIGN_FLAGS',
- '')),
- 'applehelp'),
- applehelp_indexer_path = ('/usr/bin/hiutil', 'applehelp'),
- applehelp_codesign_path = ('/usr/bin/codesign', 'applehelp'),
- applehelp_disable_external_tools = (False, None),
-
- # Epub options
- epub_basename = (lambda self: make_filename(self.project), None),
- epub_theme = ('epub', 'html'),
- epub_theme_options = ({}, 'html'),
- epub_title = (lambda self: self.html_title, 'html'),
- epub3_description = ('', 'epub3', string_classes),
- epub_author = ('unknown', 'html'),
- epub3_contributor = ('unknown', 'epub3', string_classes),
- epub_language = (lambda self: self.language or 'en', 'html'),
- epub_publisher = ('unknown', 'html'),
- epub_copyright = (lambda self: self.copyright, 'html'),
- epub_identifier = ('unknown', 'html'),
- epub_scheme = ('unknown', 'html'),
- epub_uid = ('unknown', 'env'),
- epub_cover = ((), 'env'),
- epub_guide = ((), 'env'),
- epub_pre_files = ([], 'env'),
- epub_post_files = ([], 'env'),
- epub_exclude_files = ([], 'env'),
- epub_tocdepth = (3, 'env'),
- epub_tocdup = (True, 'env'),
- epub_tocscope = ('default', 'env'),
- epub_fix_images = (False, 'env'),
- epub_max_image_width = (0, 'env'),
- epub_show_urls = ('inline', 'html'),
- epub_use_index = (lambda self: self.html_use_index, 'html'),
- epub3_page_progression_direction = ('ltr', 'epub3', string_classes),
-
- # LaTeX options
- latex_documents = (lambda self: [(self.master_doc,
- make_filename(self.project) + '.tex',
- self.project,
- '', 'manual')],
- None),
- latex_logo = (None, None, string_classes),
- latex_appendices = ([], None),
- latex_keep_old_macro_names = (True, None),
- # now deprecated - use latex_toplevel_sectioning
- latex_use_parts = (False, None),
- latex_toplevel_sectioning = (None, None, [str]),
- latex_use_modindex = (True, None), # deprecated
- latex_domain_indices = (True, None, [list]),
- latex_show_urls = ('no', None),
- latex_show_pagerefs = (False, None),
- # paper_size and font_size are still separate values
- # so that you can give them easily on the command line
- latex_paper_size = ('letter', None),
- latex_font_size = ('10pt', None),
- latex_elements = ({}, None),
- latex_additional_files = ([], None),
- latex_docclass = ({}, None),
- # now deprecated - use latex_elements
- latex_preamble = ('', None),
-
- # text options
- text_sectionchars = ('*=-~"+`', 'env'),
- text_newlines = ('unix', 'env'),
-
- # manpage options
- man_pages = (lambda self: [(self.master_doc,
- make_filename(self.project).lower(),
- '%s %s' % (self.project, self.release),
- [], 1)],
- None),
- man_show_urls = (False, None),
-
- # Texinfo options
- texinfo_documents = (lambda self: [(self.master_doc,
- make_filename(self.project).lower(),
- self.project, '',
- make_filename(self.project),
- 'The %s reference manual.' %
- make_filename(self.project),
- 'Python')],
- None),
- texinfo_appendices = ([], None),
- texinfo_elements = ({}, None),
- texinfo_domain_indices = (True, None, [list]),
- texinfo_show_urls = ('footnote', None),
- texinfo_no_detailmenu = (False, None),
-
- # linkcheck options
- linkcheck_ignore = ([], None),
- linkcheck_retries = (1, None),
- linkcheck_timeout = (None, None, [int]),
- linkcheck_workers = (5, None),
- linkcheck_anchors = (True, None),
-
- # gettext options
- gettext_compact = (True, 'gettext'),
- gettext_location = (True, 'gettext'),
- gettext_uuid = (False, 'gettext'),
- gettext_auto_build = (True, 'env'),
- gettext_additional_targets = ([], 'env'),
-
- # XML options
- xml_pretty = (True, 'env'),
)
def __init__(self, dirname, filename, overrides, tags):
@@ -328,19 +172,29 @@ class Config(object):
if default is None and not permitted:
continue # neither inferrable nor expliclitly permitted types
current = self[name]
- if type(current) is type(default):
- continue
- if type(current) in permitted:
- continue
+ if isinstance(permitted, ENUM):
+ if not permitted.match(current):
+ warn(CONFIG_ENUM_WARNING.format(
+ name=name, current=current, candidates=permitted.candidates))
+ else:
+ if type(current) is type(default):
+ continue
+ if type(current) in permitted:
+ continue
- common_bases = (set(type(current).__bases__ + (type(current),)) &
- set(type(default).__bases__))
- common_bases.discard(object)
- if common_bases:
- continue # at least we share a non-trivial base class
+ common_bases = (set(type(current).__bases__ + (type(current),)) &
+ set(type(default).__bases__))
+ common_bases.discard(object)
+ if common_bases:
+ continue # at least we share a non-trivial base class
- warn(CONFIG_TYPE_WARNING.format(
- name=name, current=type(current), default=type(default)))
+ if permitted:
+ warn(CONFIG_PERMITTED_TYPE_WARNING.format(
+ name=name, current=type(current),
+ permitted=str([cls.__name__ for cls in permitted])))
+ else:
+ warn(CONFIG_TYPE_WARNING.format(
+ name=name, current=type(current), default=type(default)))
def check_unicode(self, warn):
# check all string values for non-ASCII characters in bytestrings,
@@ -378,7 +232,7 @@ class Config(object):
def pre_init_values(self, warn):
"""Initialize some limited config variables before loading extensions"""
- variables = ['needs_sphinx', 'suppress_warnings']
+ variables = ['needs_sphinx', 'suppress_warnings', 'html_translator_class']
for name in variables:
try:
if name in self.overrides:
diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py
index 52965c0e2..76b54f9d6 100644
--- a/sphinx/directives/__init__.py
+++ b/sphinx/directives/__init__.py
@@ -17,10 +17,17 @@ from docutils.parsers.rst import Directive, directives, roles
from sphinx import addnodes
from sphinx.util.docfields import DocFieldTransformer
-# import and register directives
-from sphinx.directives.code import * # noqa
-from sphinx.directives.other import * # noqa
-from sphinx.directives.patches import * # noqa
+# import all directives sphinx provides
+from sphinx.directives.code import ( # noqa
+ Highlight, CodeBlock, LiteralInclude
+)
+from sphinx.directives.other import ( # noqa
+ TocTree, Author, Index, VersionChange, SeeAlso,
+ TabularColumns, Centered, Acks, HList, Only, Include, Class
+)
+from sphinx.directives.patches import ( # noqa
+ Figure, Meta
+)
# RE to strip backslash escapes
@@ -217,8 +224,9 @@ class DefaultDomain(Directive):
return []
-directives.register_directive('default-role', DefaultRole)
-directives.register_directive('default-domain', DefaultDomain)
-directives.register_directive('describe', ObjectDescription)
-# new, more consistent, name
-directives.register_directive('object', ObjectDescription)
+def setup(app):
+ directives.register_directive('default-role', DefaultRole)
+ directives.register_directive('default-domain', DefaultDomain)
+ directives.register_directive('describe', ObjectDescription)
+ # new, more consistent, name
+ directives.register_directive('object', ObjectDescription)
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index 35439ae39..5bef8c386 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -170,6 +170,8 @@ class LiteralInclude(Directive):
'lines': directives.unchanged_required,
'start-after': directives.unchanged_required,
'end-before': directives.unchanged_required,
+ 'start-at': directives.unchanged_required,
+ 'end-at': directives.unchanged_required,
'prepend': directives.unchanged_required,
'append': directives.unchanged_required,
'emphasize-lines': directives.unchanged_required,
@@ -180,13 +182,12 @@ class LiteralInclude(Directive):
}
def read_with_encoding(self, filename, document, codec_info, encoding):
- f = None
try:
- f = codecs.StreamReaderWriter(open(filename, 'rb'), codec_info[2],
- codec_info[3], 'strict')
- lines = f.readlines()
- lines = dedent_lines(lines, self.options.get('dedent'))
- return lines
+ with codecs.StreamReaderWriter(open(filename, 'rb'), codec_info[2],
+ codec_info[3], 'strict') as f:
+ lines = f.readlines()
+ lines = dedent_lines(lines, self.options.get('dedent'))
+ return lines
except (IOError, OSError):
return [document.reporter.warning(
'Include file %r not found or reading it failed' % filename,
@@ -196,9 +197,6 @@ class LiteralInclude(Directive):
'Encoding %r used for reading included file %r seems to '
'be wrong, try giving an :encoding: option' %
(encoding, filename))]
- finally:
- if f is not None:
- f.close()
def run(self):
document = self.state.document
@@ -224,6 +222,16 @@ class LiteralInclude(Directive):
'Cannot use "lineno-match" and "append" or "prepend"',
line=self.lineno)]
+ if 'start-after' in self.options and 'start-at' in self.options:
+ return [document.reporter.warning(
+ 'Cannot use both "start-after" and "start-at" options',
+ line=self.lineno)]
+
+ if 'end-before' in self.options and 'end-at' in self.options:
+ return [document.reporter.warning(
+ 'Cannot use both "end-before" and "end-at" options',
+ line=self.lineno)]
+
encoding = self.options.get('encoding', env.config.source_encoding)
codec_info = codecs.lookup(encoding)
@@ -296,17 +304,29 @@ class LiteralInclude(Directive):
else:
hl_lines = None
- startafter = self.options.get('start-after')
- endbefore = self.options.get('end-before')
- if startafter is not None or endbefore is not None:
- use = not startafter
+ start_str = self.options.get('start-after')
+ start_inclusive = False
+ if self.options.get('start-at') is not None:
+ start_str = self.options.get('start-at')
+ start_inclusive = True
+ end_str = self.options.get('end-before')
+ end_inclusive = False
+ if self.options.get('end-at') is not None:
+ end_str = self.options.get('end-at')
+ end_inclusive = True
+ if start_str is not None or end_str is not None:
+ use = not start_str
res = []
for line_number, line in enumerate(lines):
- if not use and startafter and startafter in line:
+ if not use and start_str and start_str in line:
if 'lineno-match' in self.options:
linenostart += line_number + 1
use = True
- elif use and endbefore and endbefore in line:
+ if start_inclusive:
+ res.append(line)
+ elif use and end_str and end_str in line:
+ if end_inclusive:
+ res.append(line)
break
elif use:
res.append(line)
@@ -357,8 +377,9 @@ class LiteralInclude(Directive):
return [retnode]
-directives.register_directive('highlight', Highlight)
-directives.register_directive('highlightlang', Highlight) # old
-directives.register_directive('code-block', CodeBlock)
-directives.register_directive('sourcecode', CodeBlock)
-directives.register_directive('literalinclude', LiteralInclude)
+def setup(app):
+ directives.register_directive('highlight', Highlight)
+ directives.register_directive('highlightlang', Highlight) # old
+ directives.register_directive('code-block', CodeBlock)
+ directives.register_directive('sourcecode', CodeBlock)
+ directives.register_directive('literalinclude', LiteralInclude)
diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py
index 52d3e9453..e071b327e 100644
--- a/sphinx/directives/other.py
+++ b/sphinx/directives/other.py
@@ -46,6 +46,7 @@ class TocTree(Directive):
'includehidden': directives.flag,
'numbered': int_or_nothing,
'titlesonly': directives.flag,
+ 'reversed': directives.flag,
}
def run(self):
@@ -106,6 +107,8 @@ class TocTree(Directive):
subnode = addnodes.toctree()
subnode['parent'] = env.docname
# entries contains all entries (self references, external links etc.)
+ if 'reversed' in self.options:
+ entries.reverse()
subnode['entries'] = entries
# includefiles only entries that are documents
subnode['includefiles'] = includefiles
@@ -406,24 +409,25 @@ class Include(BaseInclude):
return BaseInclude.run(self)
-directives.register_directive('toctree', TocTree)
-directives.register_directive('sectionauthor', Author)
-directives.register_directive('moduleauthor', Author)
-directives.register_directive('codeauthor', Author)
-directives.register_directive('index', Index)
-directives.register_directive('deprecated', VersionChange)
-directives.register_directive('versionadded', VersionChange)
-directives.register_directive('versionchanged', VersionChange)
-directives.register_directive('seealso', SeeAlso)
-directives.register_directive('tabularcolumns', TabularColumns)
-directives.register_directive('centered', Centered)
-directives.register_directive('acks', Acks)
-directives.register_directive('hlist', HList)
-directives.register_directive('only', Only)
-directives.register_directive('include', Include)
-
-# register the standard rst class directive under a different name
-# only for backwards compatibility now
-directives.register_directive('cssclass', Class)
-# new standard name when default-domain with "class" is in effect
-directives.register_directive('rst-class', Class)
+def setup(app):
+ directives.register_directive('toctree', TocTree)
+ directives.register_directive('sectionauthor', Author)
+ directives.register_directive('moduleauthor', Author)
+ directives.register_directive('codeauthor', Author)
+ directives.register_directive('index', Index)
+ directives.register_directive('deprecated', VersionChange)
+ directives.register_directive('versionadded', VersionChange)
+ directives.register_directive('versionchanged', VersionChange)
+ directives.register_directive('seealso', SeeAlso)
+ directives.register_directive('tabularcolumns', TabularColumns)
+ directives.register_directive('centered', Centered)
+ directives.register_directive('acks', Acks)
+ directives.register_directive('hlist', HList)
+ directives.register_directive('only', Only)
+ directives.register_directive('include', Include)
+
+ # register the standard rst class directive under a different name
+ # only for backwards compatibility now
+ directives.register_directive('cssclass', Class)
+ # new standard name when default-domain with "class" is in effect
+ directives.register_directive('rst-class', Class)
diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py
index 4f6f3729f..041bee360 100644
--- a/sphinx/directives/patches.py
+++ b/sphinx/directives/patches.py
@@ -9,7 +9,9 @@
from docutils import nodes
from docutils.parsers.rst import directives
-from docutils.parsers.rst.directives import images
+from docutils.parsers.rst.directives import images, html
+
+from sphinx import addnodes
class Figure(images.Figure):
@@ -35,4 +37,24 @@ class Figure(images.Figure):
return [figure_node]
-directives.register_directive('figure', Figure)
+class Meta(html.Meta):
+ def run(self):
+ env = self.state.document.settings.env
+ result = html.Meta.run(self)
+ for node in result:
+ if (isinstance(node, nodes.pending) and
+ isinstance(node.details['nodes'][0], html.MetaBody.meta)):
+ meta = node.details['nodes'][0]
+ meta.source = env.doc2path(env.docname)
+ meta.line = self.lineno
+ meta.rawcontent = meta['content']
+
+ # docutils' meta nodes aren't picklable because the class is nested
+ meta.__class__ = addnodes.meta
+
+ return result
+
+
+def setup(app):
+ directives.register_directive('figure', Figure)
+ directives.register_directive('meta', Meta)
diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py
index bee03fce7..da7e5d9ae 100644
--- a/sphinx/domains/__init__.py
+++ b/sphinx/domains/__init__.py
@@ -275,20 +275,3 @@ class Domain(object):
if primary:
return type.lname
return _('%s %s') % (self.label, type.lname)
-
-
-from sphinx.domains.c import CDomain # noqa
-from sphinx.domains.cpp import CPPDomain # noqa
-from sphinx.domains.std import StandardDomain # noqa
-from sphinx.domains.python import PythonDomain # noqa
-from sphinx.domains.javascript import JavaScriptDomain # noqa
-from sphinx.domains.rst import ReSTDomain # noqa
-
-BUILTIN_DOMAINS = {
- 'std': StandardDomain,
- 'py': PythonDomain,
- 'c': CDomain,
- 'cpp': CPPDomain,
- 'js': JavaScriptDomain,
- 'rst': ReSTDomain,
-}
diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py
index 8ba159d32..43e869dbc 100644
--- a/sphinx/domains/c.py
+++ b/sphinx/domains/c.py
@@ -302,3 +302,7 @@ class CDomain(Domain):
def get_objects(self):
for refname, (docname, type) in list(self.data['objects'].items()):
yield (refname, refname, type, docname, 'c.' + refname, 1)
+
+
+def setup(app):
+ app.add_domain(CDomain)
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index 323905256..6c12d6aca 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -46,6 +46,7 @@ from sphinx.util.docfields import Field, GroupedField
Each desc_signature node will have the attribute 'sphinx_cpp_tagname' set to
- 'templateParams', if the line is on the form 'template<...>',
+ - 'templateIntroduction, if the line is on the form 'conceptName{...}'
- 'declarator', if the line contains the name of the declared object.
No other desc_signature nodes should exist (so far).
@@ -54,7 +55,8 @@ from sphinx.util.docfields import Field, GroupedField
----------------------------------------------------------------------------
See http://www.nongnu.org/hcb/ for the grammar,
- or https://github.com/cplusplus/draft/blob/master/source/grammar.tex
+ and https://github.com/cplusplus/draft/blob/master/source/grammar.tex,
+ and https://github.com/cplusplus/concepts-ts
for the newest grammar.
common grammar things:
@@ -201,6 +203,17 @@ from sphinx.util.docfields import Field, GroupedField
We additionally add the possibility for specifying the visibility as the
first thing.
+ concept_object:
+ goal:
+ just a declaration of the name (for now)
+ either a variable concept or function concept
+
+ grammar: only a single template parameter list, and the nested name
+ may not have any template argument lists
+
+ "template" "<" template-parameter-list ">"
+ nested-name-specifier "()"[opt]
+
type_object:
goal:
either a single type (e.g., "MyClass:Something_T" or a typedef-like
@@ -540,6 +553,80 @@ def _verify_description_mode(mode):
raise Exception("Description mode '%s' is invalid." % mode)
+class ASTCPPAttribute(ASTBase):
+ def __init__(self, arg):
+ self.arg = arg
+
+ def __unicode__(self):
+ return "[[" + self.arg + "]]"
+
+ def describe_signature(self, signode):
+ txt = text_type(self)
+ signode.append(nodes.Text(txt, txt))
+
+
+class ASTGnuAttribute(ASTBase):
+ def __init__(self, name, args):
+ self.name = name
+ self.args = args
+
+ def __unicode__(self):
+ res = [self.name]
+ if self.args:
+ res.append('(')
+ res.append(text_type(self.args))
+ res.append(')')
+ return ''.join(res)
+
+
+class ASTGnuAttributeList(ASTBase):
+ def __init__(self, attrs):
+ self.attrs = attrs
+
+ def __unicode__(self):
+ res = ['__attribute__((']
+ first = True
+ for attr in self.attrs:
+ if not first:
+ res.append(', ')
+ first = False
+ res.append(text_type(attr))
+ res.append('))')
+ return ''.join(res)
+
+ def describe_signature(self, signode):
+ txt = text_type(self)
+ signode.append(nodes.Text(txt, txt))
+
+
+class ASTIdAttribute(ASTBase):
+ """For simple attributes defined by the user."""
+
+ def __init__(self, id):
+ self.id = id
+
+ def __unicode__(self):
+ return self.id
+
+ def describe_signature(self, signode):
+ signode.append(nodes.Text(self.id, self.id))
+
+
+class ASTParenAttribute(ASTBase):
+ """For paren attributes defined by the user."""
+
+ def __init__(self, id, arg):
+ self.id = id
+ self.arg = arg
+
+ def __unicode__(self):
+ return self.id + '(' + self.arg + ')'
+
+ def describe_signature(self, signode):
+ txt = text_type(self)
+ signode.append(nodes.Text(txt, txt))
+
+
class ASTIdentifier(ASTBase):
def __init__(self, identifier):
assert identifier is not None
@@ -567,7 +654,8 @@ class ASTIdentifier(ASTBase):
_verify_description_mode(mode)
if mode == 'markType':
targetText = prefix + self.identifier
- pnode = addnodes.pending_xref('', refdomain='cpp', reftype='type',
+ pnode = addnodes.pending_xref('', refdomain='cpp',
+ reftype='typeOrConcept',
reftarget=targetText, modname=None,
classname=None)
key = symbol.get_lookup_key()
@@ -751,6 +839,7 @@ class ASTTemplateParams(ASTBase):
return ''.join(res)
def describe_signature(self, signode, mode, env, symbol):
+ signode.sphinx_cpp_tagname = 'templateParams'
signode += nodes.Text("template<")
first = True
for param in self.params:
@@ -761,6 +850,92 @@ class ASTTemplateParams(ASTBase):
signode += nodes.Text(">")
+class ASTTemplateIntroductionParameter(ASTBase):
+ def __init__(self, identifier, parameterPack):
+ self.identifier = identifier
+ self.parameterPack = parameterPack
+
+ def get_identifier(self):
+ return self.identifier
+
+ def get_id_v2(self, objectType=None, symbol=None):
+ # this is not part of the normal name mangling in C++
+ if symbol:
+ # the anchor will be our parent
+ return symbol.parent.declaration.get_id_v2(prefixed=None)
+ else:
+ if self.parameterPack:
+ return 'Dp'
+ else:
+ return '0' # we need to put something
+
+ def get_id_v2_as_arg(self):
+ # used for the implicit requires clause
+ res = self.identifier.get_id_v2()
+ if self.parameterPack:
+ return u'sp' + res
+ else:
+ return res
+
+ def __unicode__(self):
+ res = []
+ if self.parameterPack:
+ res.append('...')
+ res.append(text_type(self.identifier))
+ return ''.join(res)
+
+ def describe_signature(self, signode, mode, env, symbol):
+ if self.parameterPack:
+ signode += nodes.Text('...')
+ self.identifier.describe_signature(signode, mode, env, '', symbol)
+
+
+class ASTTemplateIntroduction(ASTBase):
+ def __init__(self, concept, params):
+ assert len(params) > 0
+ self.concept = concept
+ self.params = params
+
+ # id_v1 does not exist
+
+ def get_id_v2(self):
+ # first do the same as a normal template parameter list
+ res = []
+ res.append("I")
+ for param in self.params:
+ res.append(param.get_id_v2())
+ res.append("E")
+ # let's use X expr E, which is otherwise for constant template args
+ res.append("X")
+ res.append(self.concept.get_id_v2())
+ res.append("I")
+ for param in self.params:
+ res.append(param.get_id_v2_as_arg())
+ res.append("E")
+ res.append("E")
+ return ''.join(res)
+
+ def __unicode__(self):
+ res = []
+ res.append(text_type(self.concept))
+ res.append('{')
+ res.append(', '.join(text_type(param) for param in self.params))
+ res.append('} ')
+ return ''.join(res)
+
+ def describe_signature(self, signode, mode, env, symbol):
+ signode.sphinx_cpp_tagname = 'templateIntroduction'
+ self.concept.describe_signature(signode, 'markType', env, symbol)
+ signode += nodes.Text('{')
+ first = True
+ for param in self.params:
+ if not first:
+ signode += nodes.Text(', ')
+ first = False
+ param.describe_signature(signode, mode, env, symbol)
+ signode += nodes.Text('}')
+
+
class ASTTemplateDeclarationPrefix(ASTBase):
def __init__(self, templates):
assert templates is not None
@@ -785,8 +960,7 @@ class ASTTemplateDeclarationPrefix(ASTBase):
def describe_signature(self, signode, mode, env, symbol):
_verify_description_mode(mode)
for t in self.templates:
- templateNode = addnodes.desc_signature()
- templateNode.sphinx_cpp_tagname = 'templateParams'
+ templateNode = addnodes.desc_signature_line()
t.describe_signature(templateNode, 'lastIsName', env, symbol)
signode += templateNode
@@ -1256,7 +1430,7 @@ class ASTParametersQualifiers(ASTBase):
class ASTDeclSpecsSimple(ASTBase):
def __init__(self, storage, threadLocal, inline, virtual, explicit,
- constexpr, volatile, const, friend):
+ constexpr, volatile, const, friend, attrs):
self.storage = storage
self.threadLocal = threadLocal
self.inline = inline
@@ -1266,6 +1440,7 @@ class ASTDeclSpecsSimple(ASTBase):
self.volatile = volatile
self.const = const
self.friend = friend
+ self.attrs = attrs
def mergeWith(self, other):
if not other:
@@ -1278,10 +1453,12 @@ class ASTDeclSpecsSimple(ASTBase):
self.constexpr or other.constexpr,
self.volatile or other.volatile,
self.const or other.const,
- self.friend or other.friend)
+ self.friend or other.friend,
+ self.attrs + other.attrs)
def __unicode__(self):
res = []
+ res.extend(text_type(attr) for attr in self.attrs)
if self.storage:
res.append(self.storage)
if self.threadLocal:
@@ -1307,6 +1484,10 @@ class ASTDeclSpecsSimple(ASTBase):
if len(modifiers) > 0:
modifiers.append(nodes.Text(' '))
modifiers.append(addnodes.desc_annotation(text, text))
+ for attr in self.attrs:
+ if len(modifiers) > 0:
+ modifiers.append(nodes.Text(' '))
+ modifiers.append(attr.describe_signature(modifiers))
if self.storage:
_add(modifiers, self.storage)
if self.threadLocal:
@@ -2025,6 +2206,39 @@ class ASTTypeUsing(ASTBase):
self.type.describe_signature(signode, 'markType', env, symbol=symbol)
+class ASTConcept(ASTBase):
+ def __init__(self, nestedName, isFunction, initializer):
+ self.nestedName = nestedName
+ self.isFunction = isFunction # otherwise it's a variable concept
+ self.initializer = initializer
+
+ @property
+ def name(self):
+ return self.nestedName
+
+ def get_id_v1(self, objectType=None, symbol=None):
+ raise NoOldIdError()
+
+ def get_id_v2(self, objectType, symbol):
+ return symbol.get_full_nested_name().get_id_v2()
+
+ def __unicode__(self):
+ res = text_type(self.nestedName)
+ if self.isFunction:
+ res += "()"
+ if self.initializer:
+ res += text_type(self.initializer)
+ return res
+
+ def describe_signature(self, signode, mode, env, symbol):
+ signode += nodes.Text(text_type("bool "))
+ self.nestedName.describe_signature(signode, mode, env, symbol)
+ if self.isFunction:
+ signode += nodes.Text("()")
+ if self.initializer:
+ self.initializer.describe_signature(signode, mode)
+
+
class ASTBaseClass(ASTBase):
def __init__(self, name, visibility, virtual, pack):
self.name = name
@@ -2215,17 +2429,19 @@ class ASTDeclaration(ASTBase):
def describe_signature(self, signode, mode, env):
_verify_description_mode(mode)
- # the caller of the domain added a desc_signature node
- # let's pop it so we can add templates before that
- parentNode = signode.parent
- mainDeclNode = signode
+ # The caller of the domain added a desc_signature node.
+ # Always enable multiline:
+ signode['is_multiline'] = True
+ # Put each line in a desc_signature_line node.
+ mainDeclNode = addnodes.desc_signature_line()
mainDeclNode.sphinx_cpp_tagname = 'declarator'
- parentNode.pop()
+ mainDeclNode['add_permalink'] = True
assert self.symbol
if self.templatePrefix:
- self.templatePrefix.describe_signature(parentNode, mode, env,
+ self.templatePrefix.describe_signature(signode, mode, env,
symbol=self.symbol)
+ signode += mainDeclNode
if self.visibility and self.visibility != "public":
mainDeclNode += addnodes.desc_annotation(self.visibility + " ",
self.visibility + " ")
@@ -2233,6 +2449,8 @@ class ASTDeclaration(ASTBase):
prefix = self.declaration.get_type_declaration_prefix()
prefix += ' '
mainDeclNode += addnodes.desc_annotation(prefix, prefix)
+ elif self.objectType == 'concept':
+ mainDeclNode += addnodes.desc_annotation('concept ', 'concept ')
elif self.objectType == 'member':
pass
elif self.objectType == 'function':
@@ -2251,7 +2469,6 @@ class ASTDeclaration(ASTBase):
assert False
self.declaration.describe_signature(mainDeclNode, mode, env,
symbol=self.symbol)
- parentNode += mainDeclNode
class ASTNamespace(ASTBase):
@@ -2709,7 +2926,7 @@ class DefinitionParser(object):
_prefix_keys = ('class', 'struct', 'enum', 'union', 'typename')
- def __init__(self, definition, warnEnv):
+ def __init__(self, definition, warnEnv, config):
self.definition = definition.strip()
self.pos = 0
self.end = len(self.definition)
@@ -2717,6 +2934,7 @@ class DefinitionParser(object):
self._previous_state = (0, None)
self.warnEnv = warnEnv
+ self.config = config
def _make_multi_error(self, errors, header):
if len(errors) == 1:
@@ -2785,6 +3003,12 @@ class DefinitionParser(object):
return True
return False
+ def skip_string_and_ws(self, string):
+ if self.skip_string(string):
+ self.skip_ws()
+ return True
+ return False
+
@property
def eof(self):
return self.pos >= self.end
@@ -2811,6 +3035,85 @@ class DefinitionParser(object):
if not self.eof:
self.fail('Expected end of definition.')
+ def _parse_balanced_token_seq(self, end):
+ # TODO: add handling of string literals and similar
+ brackets = {'(': ')', '[': ']', '{': '}'}
+ startPos = self.pos
+ symbols = []
+ while not self.eof:
+ if len(symbols) == 0 and self.current_char in end:
+ break
+ if self.current_char in brackets.keys():
+ symbols.append(brackets[self.current_char])
+ elif len(symbols) > 0 and self.current_char == symbols[-1]:
+ symbols.pop()
+ elif self.current_char in ")]}":
+ self.fail("Unexpected '%s' in balanced-token-seq." % self.current_char)
+ self.pos += 1
+ if self.eof:
+ self.fail("Could not find end of balanced-token-seq starting at %d."
+ % startPos)
+ return self.definition[startPos:self.pos]
+
+ def _parse_attribute(self):
+ self.skip_ws()
+ # try C++11 style
+ startPos = self.pos
+ if self.skip_string_and_ws('['):
+ if not self.skip_string('['):
+ self.pos = startPos
+ else:
+ # TODO: actually implement the correct grammar
+ arg = self._parse_balanced_token_seq(end=[']'])
+ if not self.skip_string_and_ws(']'):
+ self.fail("Expected ']' in end of attribute.")
+ if not self.skip_string_and_ws(']'):
+ self.fail("Expected ']' in end of attribute after [[...]")
+ return ASTCPPAttribute(arg)
+
+ # try GNU style
+ if self.skip_word_and_ws('__attribute__'):
+ if not self.skip_string_and_ws('('):
+ self.fail("Expected '(' after '__attribute__'.")
+ if not self.skip_string_and_ws('('):
+ self.fail("Expected '(' after '__attribute__('.")
+ attrs = []
+ while 1:
+ if self.match(_identifier_re):
+ name = self.matched_text
+ self.skip_ws()
+ if self.skip_string_and_ws('('):
+ self.fail('Parameterized GNU style attribute not yet supported.')
+ attrs.append(ASTGnuAttribute(name, None))
+ # TODO: parse arguments for the attribute
+ if self.skip_string_and_ws(','):
+ continue
+ elif self.skip_string_and_ws(')'):
+ break
+ else:
+ self.fail("Expected identifier, ')', or ',' in __attribute__.")
+ if not self.skip_string_and_ws(')'):
+ self.fail("Expected ')' after '__attribute__((...)'")
+ return ASTGnuAttributeList(attrs)
+
+ # try the simple id attributes defined by the user
+ for id in self.config.cpp_id_attributes:
+ if self.skip_word_and_ws(id):
+ return ASTIdAttribute(id)
+
+ # try the paren attributes defined by the user
+ for id in self.config.cpp_paren_attributes:
+ if not self.skip_string_and_ws(id):
+ continue
+ if not self.skip_string('('):
+ self.fail("Expected '(' after user-defined paren-attribute.")
+ arg = self._parse_balanced_token_seq(end=[')'])
+ if not self.skip_string(')'):
+ self.fail("Expected ')' to end user-defined paren-attribute.")
+ return ASTParenAttribute(id, arg)
+
+ return None
+
def _parse_expression(self, end):
# Stupidly "parse" an expression.
# 'end' should be a list of characters which ends the expression.
@@ -3092,6 +3395,7 @@ class DefinitionParser(object):
volatile = None
const = None
friend = None
+ attrs = []
while 1: # accept any permutation of a subset of some decl-specs
self.skip_ws()
if not storage:
@@ -3145,9 +3449,14 @@ class DefinitionParser(object):
const = self.skip_word('const')
if const:
continue
+ attr = self._parse_attribute()
+ if attr:
+ attrs.append(attr)
+ continue
break
return ASTDeclSpecsSimple(storage, threadLocal, inline, virtual,
- explicit, constexpr, volatile, const, friend)
+ explicit, constexpr, volatile, const,
+ friend, attrs)
def _parse_decl_specs(self, outer, typed=True):
if outer:
@@ -3430,6 +3739,23 @@ class DefinitionParser(object):
type = self._parse_type(False, None)
return ASTTypeUsing(name, type)
+ def _parse_concept(self):
+ nestedName = self._parse_nested_name()
+ isFunction = False
+
+ self.skip_ws()
+ if self.skip_string('('):
+ isFunction = True
+ self.skip_ws()
+ if not self.skip_string(')'):
+ self.fail("Expected ')' in function concept declaration.")
+
+ initializer = self._parse_initializer('member')
+ if initializer and isFunction:
+ self.fail("Function concept with initializer.")
+
+ return ASTConcept(nestedName, isFunction, initializer)
+
def _parse_class(self):
name = self._parse_nested_name()
self.skip_ws()
@@ -3548,14 +3874,62 @@ class DefinitionParser(object):
prevErrors.append((e, ""))
raise self._make_multi_error(prevErrors, header)
- def _parse_template_declaration_prefix(self):
- templates = []
+ def _parse_template_introduction(self):
+ pos = self.pos
+ try:
+ concept = self._parse_nested_name()
+ except:
+ self.pos = pos
+ return None
+ self.skip_ws()
+ if not self.skip_string('{'):
+ self.pos = pos
+ return None
+
+ # for sure it must be a template introduction now
+ params = []
while 1:
self.skip_ws()
- if not self.skip_word("template"):
+ parameterPack = self.skip_string('...')
+ self.skip_ws()
+ if not self.match(_identifier_re):
+ self.fail("Expected identifier in template introduction list.")
+ identifier = self.matched_text
+ # make sure there isn't a keyword
+ if identifier in _keywords:
+ self.fail("Expected identifier in template introduction list, "
+ "got keyword: %s" % identifier)
+ identifier = ASTIdentifier(identifier)
+ params.append(ASTTemplateIntroductionParameter(identifier, parameterPack))
+
+ self.skip_ws()
+ if self.skip_string('}'):
break
- params = self._parse_template_parameter_list()
+ elif self.skip_string(','):
+ continue
+ else:
+ self.fail("Error in template introduction list. "
+ 'Expected ",", or "}".')
+ return ASTTemplateIntroduction(concept, params)
+
+ def _parse_template_declaration_prefix(self, objectType):
+ templates = []
+ while 1:
+ self.skip_ws()
+ # the saved position is only used to provide a better error message
+ pos = self.pos
+ if self.skip_word("template"):
+ params = self._parse_template_parameter_list()
+ else:
+ params = self._parse_template_introduction()
+ if not params:
+ break
+ if objectType == 'concept' and len(templates) > 0:
+ self.pos = pos
+ self.fail("More than 1 template parameter list for concept.")
templates.append(params)
+ if len(templates) == 0 and objectType == 'concept':
+ self.fail('Missing template parameter list for concept.')
if len(templates) == 0:
return None
else:
@@ -3594,7 +3968,7 @@ class DefinitionParser(object):
return templatePrefix
def parse_declaration(self, objectType):
- if objectType not in ('type', 'member',
+ if objectType not in ('type', 'concept', 'member',
'function', 'class', 'enum', 'enumerator'):
raise Exception('Internal error, unknown objectType "%s".' % objectType)
visibility = None
@@ -3605,8 +3979,8 @@ class DefinitionParser(object):
if self.match(_visibility_re):
visibility = self.matched_text
- if objectType in ('type', 'member', 'function', 'class'):
- templatePrefix = self._parse_template_declaration_prefix()
+ if objectType in ('type', 'concept', 'member', 'function', 'class'):
+ templatePrefix = self._parse_template_declaration_prefix(objectType)
if objectType == 'type':
prevErrors = []
@@ -3626,6 +4000,8 @@ class DefinitionParser(object):
prevErrors.append((e, "If type alias or template alias"))
header = "Error in type declaration."
raise self._make_multi_error(prevErrors, header)
+ elif objectType == 'concept':
+ declaration = self._parse_concept()
elif objectType == 'member':
declaration = self._parse_type_with_init(named=True, outer='member')
elif objectType == 'function':
@@ -3645,7 +4021,7 @@ class DefinitionParser(object):
templatePrefix, declaration)
def parse_namespace_object(self):
- templatePrefix = self._parse_template_declaration_prefix()
+ templatePrefix = self._parse_template_declaration_prefix(objectType="namespace")
name = self._parse_nested_name()
templatePrefix = self._check_template_consistency(name, templatePrefix,
fullSpecShorthand=False)
@@ -3654,7 +4030,7 @@ class DefinitionParser(object):
return res
def parse_xref_object(self):
- templatePrefix = self._parse_template_declaration_prefix()
+ templatePrefix = self._parse_template_declaration_prefix(objectType="xref")
name = self._parse_nested_name()
templatePrefix = self._check_template_consistency(name, templatePrefix,
fullSpecShorthand=True)
@@ -3746,7 +4122,12 @@ class CPPObject(ObjectDescription):
'report as bug (id=%s).' % (text_type(ast), newestId))
name = text_type(ast.symbol.get_full_nested_name()).lstrip(':')
- indexText = self.get_index_text(name)
+ strippedName = name
+ for prefix in self.env.config.cpp_index_common_prefix:
+ if name.startswith(prefix):
+ strippedName = strippedName[len(prefix):]
+ break
+ indexText = self.get_index_text(strippedName)
self.indexnode['entries'].append(('single', indexText, newestId, '', None))
if newestId not in self.state.document.ids:
@@ -3767,7 +4148,7 @@ class CPPObject(ObjectDescription):
continue
if id not in self.state.document.ids:
signode['ids'].append(id)
- signode['first'] = (not self.names) # hmm, what is this abound?
+ signode['first'] = (not self.names) # hmm, what is this about?
self.state.document.note_explicit_target(signode)
def parse_definition(self, parser):
@@ -3782,7 +4163,7 @@ class CPPObject(ObjectDescription):
self.env.ref_context['cpp:parent_symbol'] = root
parentSymbol = self.env.ref_context['cpp:parent_symbol']
- parser = DefinitionParser(sig, self)
+ parser = DefinitionParser(sig, self, self.env.config)
try:
ast = self.parse_definition(parser)
parser.assert_end()
@@ -3830,6 +4211,17 @@ class CPPTypeObject(CPPObject):
ast.describe_signature(signode, 'lastIsName', self.env)
+class CPPConceptObject(CPPObject):
+ def get_index_text(self, name):
+ return _('%s (C++ concept)') % name
+
+ def parse_definition(self, parser):
+ return parser.parse_declaration("concept")
+
+ def describe_signature(self, signode, ast):
+ ast.describe_signature(signode, 'lastIsName', self.env)
+
+
class CPPMemberObject(CPPObject):
def get_index_text(self, name):
return _('%s (C++ member)') % name
@@ -3917,7 +4309,7 @@ class CPPNamespaceObject(Directive):
symbol = rootSymbol
stack = []
else:
- parser = DefinitionParser(self.arguments[0], self)
+ parser = DefinitionParser(self.arguments[0], self, env.config)
try:
ast = parser.parse_namespace_object()
parser.assert_end()
@@ -3946,7 +4338,7 @@ class CPPNamespacePushObject(Directive):
env = self.state.document.settings.env
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
return
- parser = DefinitionParser(self.arguments[0], self)
+ parser = DefinitionParser(self.arguments[0], self, env.config)
try:
ast = parser.parse_namespace_object()
parser.assert_end()
@@ -4026,6 +4418,7 @@ class CPPDomain(Domain):
'function': ObjType(l_('function'), 'func'),
'member': ObjType(l_('member'), 'member'),
'type': ObjType(l_('type'), 'type'),
+ 'concept': ObjType(l_('concept'), 'concept'),
'enum': ObjType(l_('enum'), 'enum'),
'enumerator': ObjType(l_('enumerator'), 'enumerator')
}
@@ -4036,6 +4429,7 @@ class CPPDomain(Domain):
'member': CPPMemberObject,
'var': CPPMemberObject,
'type': CPPTypeObject,
+ 'concept': CPPConceptObject,
'enum': CPPEnumObject,
'enum-struct': CPPEnumObject,
'enum-class': CPPEnumObject,
@@ -4051,6 +4445,7 @@ class CPPDomain(Domain):
'member': CPPXRefRole(),
'var': CPPXRefRole(),
'type': CPPXRefRole(),
+ 'concept': CPPXRefRole(),
'enum': CPPXRefRole(),
'enumerator': CPPXRefRole()
}
@@ -4093,7 +4488,7 @@ class CPPDomain(Domain):
if emitWarnings:
env.warn_node(msg, node)
warner = Warner()
- parser = DefinitionParser(target, warner)
+ parser = DefinitionParser(target, warner, env.config)
try:
ast = parser.parse_xref_object()
parser.skip_ws()
@@ -4124,6 +4519,33 @@ class CPPDomain(Domain):
if s is None or s.declaration is None:
return None, None
+ if typ.startswith('cpp:'):
+ typ = typ[4:]
+ if typ == 'func':
+ typ = 'function'
+ declTyp = s.declaration.objectType
+
+ def checkType():
+ if typ == 'any':
+ return True
+ if declTyp == 'templateParam':
+ return True
+ if typ == 'var' or typ == 'member':
+ return declTyp in ['var', 'member']
+ if typ in ['enum', 'enumerator', 'function', 'class', 'concept']:
+ return declTyp == typ
+ validForType = ['enum', 'class', 'function', 'type']
+ if typ == 'typeOrConcept':
+ return declTyp == 'concept' or declTyp in validForType
+ if typ == 'type':
+ return declTyp in validForType
+ print("Type is %s" % typ)
+ assert False
+ if not checkType():
+ warner.warn("cpp:%s targets a %s (%s)."
+ % (typ, s.declaration.objectType,
+ s.get_full_nested_name()))
+
declaration = s.declaration
fullNestedName = s.get_full_nested_name()
name = text_type(fullNestedName).lstrip(':')
@@ -4163,3 +4585,10 @@ class CPPDomain(Domain):
docname = symbol.docname
newestId = symbol.declaration.get_newest_id()
yield (name, name, objectType, docname, newestId, 1)
+
+
+def setup(app):
+ app.add_domain(CPPDomain)
+ app.add_config_value("cpp_index_common_prefix", [], 'env')
+ app.add_config_value("cpp_id_attributes", [], 'env')
+ app.add_config_value("cpp_paren_attributes", [], 'env')
diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py
index b5f64022a..ade6e4224 100644
--- a/sphinx/domains/javascript.py
+++ b/sphinx/domains/javascript.py
@@ -234,3 +234,7 @@ class JavaScriptDomain(Domain):
for refname, (docname, type) in list(self.data['objects'].items()):
yield refname, refname, type, docname, \
refname.replace('$', '_S_'), 1
+
+
+def setup(app):
+ app.add_domain(JavaScriptDomain)
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index 1639d8288..d37e55fa3 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -101,11 +101,36 @@ class PyXrefMixin(object):
break
return result
+ def make_xrefs(self, rolename, domain, target, innernode=nodes.emphasis,
+ contnode=None):
+ delims = '(\s*[\[\]\(\),](?:\s*or\s)?\s*|\s+or\s+)'
+ delims_re = re.compile(delims)
+ sub_targets = re.split(delims, target)
+
+ split_contnode = bool(contnode and contnode.astext() == target)
+
+ results = []
+ for sub_target in sub_targets:
+ if split_contnode:
+ contnode = nodes.Text(sub_target)
+
+ if delims_re.match(sub_target):
+ results.append(contnode or innernode(sub_target, sub_target))
+ else:
+ results.append(self.make_xref(rolename, domain, sub_target,
+ innernode, contnode))
+
+ return results
+
class PyField(PyXrefMixin, Field):
pass
+class PyGroupedField(PyXrefMixin, GroupedField):
+ pass
+
+
class PyTypedField(PyXrefMixin, TypedField):
pass
@@ -130,9 +155,9 @@ class PyObject(ObjectDescription):
names=('var', 'ivar', 'cvar'),
typerolename='obj', typenames=('vartype',),
can_collapse=True),
- GroupedField('exceptions', label=l_('Raises'), rolename='exc',
- names=('raises', 'raise', 'exception', 'except'),
- can_collapse=True),
+ PyGroupedField('exceptions', label=l_('Raises'), rolename='exc',
+ names=('raises', 'raise', 'exception', 'except'),
+ can_collapse=True),
Field('returnvalue', label=l_('Returns'), has_arg=False,
names=('returns', 'return')),
PyField('returntype', label=l_('Return type'), has_arg=False,
@@ -771,3 +796,7 @@ class PythonDomain(Domain):
for refname, (docname, type) in iteritems(self.data['objects']):
if type != 'module': # modules are already handled
yield (refname, refname, type, docname, refname, 1)
+
+
+def setup(app):
+ app.add_domain(PythonDomain)
diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py
index b11c9450b..526ae18a7 100644
--- a/sphinx/domains/rst.py
+++ b/sphinx/domains/rst.py
@@ -156,3 +156,7 @@ class ReSTDomain(Domain):
def get_objects(self):
for (typ, name), docname in iteritems(self.data['objects']):
yield name, name, typ, docname, typ + '-' + name, 1
+
+
+def setup(app):
+ app.add_domain(ReSTDomain)
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index 997d95ba3..b7f2597d4 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -14,7 +14,6 @@ import unicodedata
from six import iteritems
from docutils import nodes
-from docutils.nodes import fully_normalize_name
from docutils.parsers.rst import directives
from docutils.statemachine import ViewList
@@ -29,7 +28,7 @@ from sphinx.util.compat import Directive
# RE for option descriptions
-option_desc_re = re.compile(r'((?:/|--|-|\+)?[-?@#_a-zA-Z0-9]+)(=?\s*.*)')
+option_desc_re = re.compile(r'((?:/|--|-|\+)?[-\.?@#_a-zA-Z0-9]+)(=?\s*.*)')
# RE for grammar tokens
token_re = re.compile('`(\w+)`', re.U)
@@ -175,16 +174,18 @@ class Cmdoption(ObjectDescription):
if currprogram:
targetname = '-' + currprogram + targetname
targetname = 'cmdoption' + targetname
- signode['ids'].append(targetname)
- self.state.document.note_explicit_target(signode)
+ signode['names'].append(targetname)
+
+ self.state.document.note_explicit_target(signode)
+ for optname in signode.get('allnames', []):
self.env.domaindata['std']['progoptions'][currprogram, optname] = \
- self.env.docname, targetname
+ self.env.docname, signode['ids'][0]
# create only one index entry for the whole option
if optname == firstname:
self.indexnode['entries'].append(
('pair', _('%scommand line option; %s') %
((currprogram and currprogram + ' ' or ''), sig),
- targetname, '', None))
+ signode['ids'][0], '', None))
class Program(Directive):
@@ -467,6 +468,7 @@ class StandardDomain(Domain):
initial_data = {
'progoptions': {}, # (program, name) -> docname, labelid
'objects': {}, # (type, name) -> docname, labelid
+ 'citations': {}, # name -> docname, labelid
'labels': { # labelname -> docname, labelid, sectionname
'genindex': ('genindex', '', l_('Index')),
'modindex': ('py-modindex', '', l_('Module Index')),
@@ -486,6 +488,7 @@ class StandardDomain(Domain):
'numref': 'undefined label: %(target)s',
'keyword': 'unknown keyword: %(target)s',
'option': 'unknown option: %(target)s',
+ 'citation': 'citation not found: %(target)s',
}
enumerable_nodes = { # node_class -> (figtype, title_getter)
@@ -501,6 +504,9 @@ class StandardDomain(Domain):
for key, (fn, _l) in list(self.data['objects'].items()):
if fn == docname:
del self.data['objects'][key]
+ for key, (fn, _l) in list(self.data['citations'].items()):
+ if fn == docname:
+ del self.data['citations'][key]
for key, (fn, _l, _l) in list(self.data['labels'].items()):
if fn == docname:
del self.data['labels'][key]
@@ -516,6 +522,9 @@ class StandardDomain(Domain):
for key, data in otherdata['objects'].items():
if data[0] in docnames:
self.data['objects'][key] = data
+ for key, data in otherdata['citations'].items():
+ if data[0] in docnames:
+ self.data['citations'][key] = data
for key, data in otherdata['labels'].items():
if data[0] in docnames:
self.data['labels'][key] = data
@@ -524,6 +533,19 @@ class StandardDomain(Domain):
self.data['anonlabels'][key] = data
def process_doc(self, env, docname, document):
+ self.note_citations(env, docname, document)
+ self.note_labels(env, docname, document)
+
+ def note_citations(self, env, docname, document):
+ for node in document.traverse(nodes.citation):
+ label = node[0].astext()
+ if label in self.data['citations']:
+ path = env.doc2path(self.data['citations'][0])
+ env.warn_node('duplicate citation %s, other instance in %s' %
+ (label, path), node)
+ self.data['citations'][label] = (docname, node['ids'][0])
+
+ def note_labels(self, env, docname, document):
labels, anonlabels = self.data['labels'], self.data['anonlabels']
for name, explicit in iteritems(document.nametypes):
if not explicit:
@@ -585,106 +607,163 @@ class StandardDomain(Domain):
newnode.append(innernode)
return newnode
- def resolve_xref(self, env, fromdocname, builder,
- typ, target, node, contnode):
+ def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
if typ == 'ref':
- if node['refexplicit']:
- # reference to anonymous label; the reference uses
- # the supplied link caption
- docname, labelid = self.data['anonlabels'].get(target, ('', ''))
- sectname = node.astext()
- else:
- # reference to named label; the final node will
- # contain the section name after the label
- docname, labelid, sectname = self.data['labels'].get(target,
- ('', '', ''))
- if not docname:
- return None
-
- return self.build_reference_node(fromdocname, builder,
- docname, labelid, sectname, 'ref')
+ resolver = self._resolve_ref_xref
elif typ == 'numref':
+ resolver = self._resolve_numref_xref
+ elif typ == 'keyword':
+ resolver = self._resolve_keyword_xref
+ elif typ == 'option':
+ resolver = self._resolve_option_xref
+ elif typ == 'citation':
+ resolver = self._resolve_citation_xref
+ else:
+ resolver = self._resolve_obj_xref
+
+ return resolver(env, fromdocname, builder, typ, target, node, contnode)
+
+ def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
+ if node['refexplicit']:
+ # reference to anonymous label; the reference uses
+ # the supplied link caption
docname, labelid = self.data['anonlabels'].get(target, ('', ''))
- if not docname:
- return None
+ sectname = node.astext()
+ else:
+ # reference to named label; the final node will
+ # contain the section name after the label
+ docname, labelid, sectname = self.data['labels'].get(target,
+ ('', '', ''))
+ if not docname:
+ return None
+
+ return self.build_reference_node(fromdocname, builder,
+ docname, labelid, sectname, 'ref')
+
+ def _resolve_numref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
+ if target in self.data['labels']:
+ docname, labelid, figname = self.data['labels'].get(target, ('', '', ''))
+ else:
+ docname, labelid = self.data['anonlabels'].get(target, ('', ''))
+ figname = None
- if env.config.numfig is False:
- env.warn(fromdocname, 'numfig is disabled. :numref: is ignored.',
- lineno=node.line)
- return contnode
+ if not docname:
+ return None
- target_node = env.get_doctree(docname).ids.get(labelid)
- figtype = self.get_figtype(target_node)
- if figtype is None:
- return None
+ if env.config.numfig is False:
+ env.warn_node('numfig is disabled. :numref: is ignored.', node)
+ return contnode
- try:
- figure_id = target_node['ids'][0]
- fignumber = env.toc_fignumbers[docname][figtype][figure_id]
- except (KeyError, IndexError):
- # target_node is found, but fignumber is not assigned.
- # Maybe it is defined in orphaned document.
- env.warn(fromdocname, "no number is assigned for %s: %s" % (figtype, labelid),
- lineno=node.line)
+ target_node = env.get_doctree(docname).ids.get(labelid)
+ figtype = self.get_figtype(target_node)
+ if figtype is None:
+ return None
+
+ try:
+ fignumber = self.get_fignumber(env, builder, figtype, docname, target_node)
+ if fignumber is None:
return contnode
+ except ValueError:
+ env.warn_node("no number is assigned for %s: %s" % (figtype, labelid), node)
+ return contnode
- title = contnode.astext()
- if target == fully_normalize_name(title):
+ try:
+ if node['refexplicit']:
+ title = contnode.astext()
+ else:
title = env.config.numfig_format.get(figtype, '')
- try:
- newtitle = title % '.'.join(map(str, fignumber))
- except TypeError:
- env.warn(fromdocname, 'invalid numfig_format: %s' % title,
- lineno=node.line)
- return None
-
- return self.build_reference_node(fromdocname, builder,
- docname, labelid, newtitle, 'numref',
- nodeclass=addnodes.number_reference,
- title=title)
- elif typ == 'keyword':
- # keywords are oddballs: they are referenced by named labels
- docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
- if not docname:
- return None
- return make_refnode(builder, fromdocname, docname,
- labelid, contnode)
- elif typ == 'option':
- progname = node.get('std:program')
- target = target.strip()
- docname, labelid = self.data['progoptions'].get((progname, target), ('', ''))
- if not docname:
- commands = []
- while ws_re.search(target):
- subcommand, target = ws_re.split(target, 1)
- commands.append(subcommand)
- progname = "-".join(commands)
-
- docname, labelid = self.data['progoptions'].get((progname, target),
- ('', ''))
- if docname:
- break
+ if figname is None and '%{name}' in title:
+ env.warn_node('the link has no caption: %s' % title, node)
+ return contnode
+ else:
+ fignum = '.'.join(map(str, fignumber))
+ if '{name}' in title or 'number' in title:
+ # new style format (cf. "Fig.%{number}")
+ if figname:
+ newtitle = title.format(name=figname, number=fignum)
+ else:
+ newtitle = title.format(number=fignum)
else:
- return None
-
- return make_refnode(builder, fromdocname, docname,
- labelid, contnode)
- else:
- objtypes = self.objtypes_for_role(typ) or []
- for objtype in objtypes:
- if (objtype, target) in self.data['objects']:
- docname, labelid = self.data['objects'][objtype, target]
+ # old style format (cf. "Fig.%s")
+ newtitle = title % fignum
+ except KeyError as exc:
+ env.warn_node('invalid numfig_format: %s (%r)' % (title, exc), node)
+ return contnode
+ except TypeError:
+ env.warn_node('invalid numfig_format: %s' % title, node)
+ return contnode
+
+ return self.build_reference_node(fromdocname, builder,
+ docname, labelid, newtitle, 'numref',
+ nodeclass=addnodes.number_reference,
+ title=title)
+
+ def _resolve_keyword_xref(self, env, fromdocname, builder, typ, target, node, contnode):
+ # keywords are oddballs: they are referenced by named labels
+ docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
+ if not docname:
+ return None
+ return make_refnode(builder, fromdocname, docname,
+ labelid, contnode)
+
+ def _resolve_option_xref(self, env, fromdocname, builder, typ, target, node, contnode):
+ progname = node.get('std:program')
+ target = target.strip()
+ docname, labelid = self.data['progoptions'].get((progname, target), ('', ''))
+ if not docname:
+ commands = []
+ while ws_re.search(target):
+ subcommand, target = ws_re.split(target, 1)
+ commands.append(subcommand)
+ progname = "-".join(commands)
+
+ docname, labelid = self.data['progoptions'].get((progname, target),
+ ('', ''))
+ if docname:
break
else:
- docname, labelid = '', ''
- if not docname:
return None
+
+ return make_refnode(builder, fromdocname, docname,
+ labelid, contnode)
+
+ def _resolve_citation_xref(self, env, fromdocname, builder, typ, target, node, contnode):
+ from sphinx.environment import NoUri
+
+ docname, labelid = self.data['citations'].get(target, ('', ''))
+ if not docname:
+ if 'ids' in node:
+ # remove ids attribute that annotated at
+ # transforms.CitationReference.apply.
+ del node['ids'][:]
+ return None
+
+ try:
return make_refnode(builder, fromdocname, docname,
labelid, contnode)
+ except NoUri:
+ # remove the ids we added in the CitationReferences
+ # transform since they can't be transfered to
+ # the contnode (if it's a Text node)
+ if not isinstance(contnode, nodes.Element):
+ del node['ids'][:]
+ raise
+
+ def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contnode):
+ objtypes = self.objtypes_for_role(typ) or []
+ for objtype in objtypes:
+ if (objtype, target) in self.data['objects']:
+ docname, labelid = self.data['objects'][objtype, target]
+ break
+ else:
+ docname, labelid = '', ''
+ if not docname:
+ return None
+ return make_refnode(builder, fromdocname, docname,
+ labelid, contnode)
- def resolve_any_xref(self, env, fromdocname, builder, target,
- node, contnode):
+ def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
results = []
ltarget = target.lower() # :ref: lowercases its target automatically
for role in ('ref', 'option'): # do not try "keyword"
@@ -747,7 +826,9 @@ class StandardDomain(Domain):
def has_child(node, cls):
return any(isinstance(child, cls) for child in node)
- if isinstance(node, nodes.container):
+ if isinstance(node, nodes.section):
+ return 'section'
+ elif isinstance(node, nodes.container):
if node.get('literal_block') and has_child(node, nodes.literal_block):
return 'code-block'
else:
@@ -755,3 +836,29 @@ class StandardDomain(Domain):
else:
figtype, _ = self.enumerable_nodes.get(node.__class__, (None, None))
return figtype
+
+ def get_fignumber(self, env, builder, figtype, docname, target_node):
+ if figtype == 'section':
+ if builder.name == 'latex':
+ return tuple()
+ elif docname not in env.toc_secnumbers:
+ raise ValueError # no number assigned
+ else:
+ anchorname = '#' + target_node['ids'][0]
+ if anchorname not in env.toc_secnumbers[docname]:
+ # try first heading which has no anchor
+ return env.toc_secnumbers[docname].get('')
+ else:
+ return env.toc_secnumbers[docname].get(anchorname)
+ else:
+ try:
+ figure_id = target_node['ids'][0]
+ return env.toc_fignumbers[docname][figtype][figure_id]
+ except (KeyError, IndexError):
+ # target_node is found, but fignumber is not assigned.
+ # Maybe it is defined in orphaned document.
+ raise ValueError
+
+
+def setup(app):
+ app.add_domain(StandardDomain)
diff --git a/sphinx/environment.py b/sphinx/environment/__init__.py
index e71d8c585..d750b0284 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment/__init__.py
@@ -14,50 +14,40 @@ import os
import sys
import time
import types
-import bisect
import codecs
-import string
import fnmatch
-import unicodedata
from os import path
from glob import glob
-from itertools import groupby
-from six import iteritems, itervalues, text_type, class_types, next
+from six import iteritems, itervalues, class_types, next
from six.moves import cPickle as pickle
from docutils import nodes
from docutils.io import NullOutput
from docutils.core import Publisher
from docutils.utils import Reporter, relative_path, get_source_line
-from docutils.parsers.rst import roles, directives
+from docutils.parsers.rst import roles
from docutils.parsers.rst.languages import en as english
-from docutils.parsers.rst.directives.html import MetaBody
from docutils.frontend import OptionParser
from sphinx import addnodes
from sphinx.io import SphinxStandaloneReader, SphinxDummyWriter, SphinxFileInput
-from sphinx.util import url_re, get_matching_docs, docname_join, split_into, \
- FilenameUniqDict, split_index_msg
-from sphinx.util.nodes import clean_astext, make_refnode, WarningStream, is_translatable
+from sphinx.util import get_matching_docs, docname_join, FilenameUniqDict
+from sphinx.util.nodes import clean_astext, WarningStream, is_translatable, \
+ process_only_nodes
from sphinx.util.osutil import SEP, getcwd, fs_encoding, ensuredir
from sphinx.util.images import guess_mimetype
from sphinx.util.i18n import find_catalog_files, get_image_filename_for_language, \
search_image_for_language
from sphinx.util.console import bold, purple
+from sphinx.util.docutils import sphinx_domains
from sphinx.util.matching import compile_matchers
from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks
from sphinx.util.websupport import is_commentable
from sphinx.errors import SphinxError, ExtensionError
-from sphinx.locale import _
from sphinx.versioning import add_uids, merge_doctrees
from sphinx.transforms import SphinxContentsFilter
-
-orig_role_function = roles.role
-orig_directive_function = directives.directive
-
-
-class ElementLookupError(Exception):
- pass
+from sphinx.environment.managers.indexentries import IndexEntries
+from sphinx.environment.managers.toctree import Toctree
default_settings = {
@@ -76,7 +66,7 @@ default_settings = {
# or changed to properly invalidate pickle files.
#
# NOTE: increase base version by 2 to have distinct numbers for Py2 and 3
-ENV_VERSION = 49 + (sys.version_info[0] - 2)
+ENV_VERSION = 50 + (sys.version_info[0] - 2)
dummy_reporter = Reporter('', 4, 4)
@@ -93,7 +83,7 @@ class NoUri(Exception):
pass
-class BuildEnvironment:
+class BuildEnvironment(object):
"""
The environment in which the ReST files are translated.
Stores an inventory of cross-file targets and provides doctree
@@ -104,11 +94,8 @@ class BuildEnvironment:
@staticmethod
def frompickle(srcdir, config, filename):
- picklefile = open(filename, 'rb')
- try:
+ with open(filename, 'rb') as picklefile:
env = pickle.load(picklefile)
- finally:
- picklefile.close()
if env.version != ENV_VERSION:
raise IOError('build environment version not current')
if env.srcdir != srcdir:
@@ -124,7 +111,7 @@ class BuildEnvironment:
del self.config.values
domains = self.domains
del self.domains
- picklefile = open(filename, 'wb')
+ managers = self.detach_managers()
# remove potentially pickling-problematic values from config
for key, val in list(vars(self.config).items()):
if key.startswith('_') or \
@@ -132,11 +119,10 @@ class BuildEnvironment:
isinstance(val, types.FunctionType) or \
isinstance(val, class_types):
del self.config[key]
- try:
+ with open(filename, 'wb') as picklefile:
pickle.dump(self, picklefile, pickle.HIGHEST_PROTOCOL)
- finally:
- picklefile.close()
# reset attributes
+ self.attach_managers(managers)
self.domains = domains
self.config.values = values
self.set_warnfunc(warnfunc)
@@ -205,7 +191,6 @@ class BuildEnvironment:
self.domaindata = {} # domainname -> domain-specific dict
# Other inventories
- self.citations = {} # citation name -> docname, labelid
self.indexentries = {} # docname -> list of
# (type, string, target, aliasname)
self.versionchanges = {} # version -> list of (type, docname,
@@ -222,6 +207,27 @@ class BuildEnvironment:
# attributes of "any" cross references
self.ref_context = {}
+ self.managers = {}
+ self.init_managers()
+
+ def init_managers(self):
+ managers = {}
+ for manager_class in [IndexEntries, Toctree]:
+ managers[manager_class.name] = manager_class(self)
+ self.attach_managers(managers)
+
+ def attach_managers(self, managers):
+ for name, manager in iteritems(managers):
+ self.managers[name] = manager
+ manager.attach(self)
+
+ def detach_managers(self):
+ managers = self.managers
+ self.managers = {}
+ for _, manager in iteritems(managers):
+ manager.detach(self)
+ return managers
+
def set_warnfunc(self, func):
self._warnfunc = func
self.settings['warning_stream'] = WarningStream(func)
@@ -267,28 +273,16 @@ class BuildEnvironment:
self.dependencies.pop(docname, None)
self.titles.pop(docname, None)
self.longtitles.pop(docname, None)
- self.tocs.pop(docname, None)
- self.toc_secnumbers.pop(docname, None)
- self.toc_fignumbers.pop(docname, None)
- self.toc_num_entries.pop(docname, None)
- self.toctree_includes.pop(docname, None)
- self.indexentries.pop(docname, None)
- self.glob_toctrees.discard(docname)
- self.numbered_toctrees.discard(docname)
self.images.purge_doc(docname)
self.dlfiles.purge_doc(docname)
- for subfn, fnset in list(self.files_to_rebuild.items()):
- fnset.discard(docname)
- if not fnset:
- del self.files_to_rebuild[subfn]
- for key, (fn, _ignore) in list(self.citations.items()):
- if fn == docname:
- del self.citations[key]
for version, changes in self.versionchanges.items():
new = [change for change in changes if change[1] != docname]
changes[:] = new
+ for manager in itervalues(self.managers):
+ manager.clear_doc(docname)
+
for domain in self.domains.values():
domain.clear_doc(docname)
@@ -308,30 +302,16 @@ class BuildEnvironment:
self.dependencies[docname] = other.dependencies[docname]
self.titles[docname] = other.titles[docname]
self.longtitles[docname] = other.longtitles[docname]
- self.tocs[docname] = other.tocs[docname]
- self.toc_num_entries[docname] = other.toc_num_entries[docname]
- # toc_secnumbers and toc_fignumbers are not assigned during read
- if docname in other.toctree_includes:
- self.toctree_includes[docname] = other.toctree_includes[docname]
- self.indexentries[docname] = other.indexentries[docname]
- if docname in other.glob_toctrees:
- self.glob_toctrees.add(docname)
- if docname in other.numbered_toctrees:
- self.numbered_toctrees.add(docname)
self.images.merge_other(docnames, other.images)
self.dlfiles.merge_other(docnames, other.dlfiles)
- for subfn, fnset in other.files_to_rebuild.items():
- self.files_to_rebuild.setdefault(subfn, set()).update(fnset & docnames)
- for key, data in other.citations.items():
- # XXX duplicates?
- if data[0] in docnames:
- self.citations[key] = data
for version, changes in other.versionchanges.items():
self.versionchanges.setdefault(version, []).extend(
change for change in changes if change[1] in docnames)
+ for manager in itervalues(self.managers):
+ manager.merge_other(docnames, other)
for domainname, domain in self.domains.items():
domain.merge_domaindata(docnames, other.domaindata[domainname])
app.emit('env-merge-info', self, docnames, other)
@@ -628,7 +608,8 @@ class BuildEnvironment:
self._warnfunc(*warning, **kwargs)
def check_dependents(self, already):
- to_rewrite = self.assign_section_numbers() + self.assign_figure_numbers()
+ to_rewrite = (self.toctree.assign_section_numbers() +
+ self.toctree.assign_figure_numbers())
for docname in set(to_rewrite):
if docname not in already:
yield docname
@@ -649,51 +630,6 @@ class BuildEnvironment:
error.object[error.end:lineend]), lineno)
return (u'?', error.end)
- def lookup_domain_element(self, type, name):
- """Lookup a markup element (directive or role), given its name which can
- be a full name (with domain).
- """
- name = name.lower()
- # explicit domain given?
- if ':' in name:
- domain_name, name = name.split(':', 1)
- if domain_name in self.domains:
- domain = self.domains[domain_name]
- element = getattr(domain, type)(name)
- if element is not None:
- return element, []
- # else look in the default domain
- else:
- def_domain = self.temp_data.get('default_domain')
- if def_domain is not None:
- element = getattr(def_domain, type)(name)
- if element is not None:
- return element, []
- # always look in the std domain
- element = getattr(self.domains['std'], type)(name)
- if element is not None:
- return element, []
- raise ElementLookupError
-
- def patch_lookup_functions(self):
- """Monkey-patch directive and role dispatch, so that domain-specific
- markup takes precedence.
- """
- def directive(name, lang_module, document):
- try:
- return self.lookup_domain_element('directive', name)
- except ElementLookupError:
- return orig_directive_function(name, lang_module, document)
-
- def role(name, lang_module, lineno, reporter):
- try:
- return self.lookup_domain_element('role', name)
- except ElementLookupError:
- return orig_role_function(name, lang_module, lineno, reporter)
-
- directives.directive = directive
- roles.role = role
-
def read_doc(self, docname, app=None):
"""Parse a file and add/update inventory entries for the doctree."""
@@ -707,52 +643,48 @@ class BuildEnvironment:
self.config.trim_footnote_reference_space
self.settings['gettext_compact'] = self.config.gettext_compact
- self.patch_lookup_functions()
-
docutilsconf = path.join(self.srcdir, 'docutils.conf')
# read docutils.conf from source dir, not from current dir
OptionParser.standard_config_files[1] = docutilsconf
if path.isfile(docutilsconf):
self.note_dependency(docutilsconf)
- if self.config.default_role:
- role_fn, messages = roles.role(self.config.default_role, english,
- 0, dummy_reporter)
- if role_fn:
- roles._roles[''] = role_fn
- else:
- self.warn(docname, 'default role %s not found' %
- self.config.default_role)
-
- codecs.register_error('sphinx', self.warn_and_replace)
-
- # publish manually
- reader = SphinxStandaloneReader(self.app, parsers=self.config.source_parsers)
- pub = Publisher(reader=reader,
- writer=SphinxDummyWriter(),
- destination_class=NullOutput)
- pub.set_components(None, 'restructuredtext', None)
- pub.process_programmatic_settings(None, self.settings, None)
- src_path = self.doc2path(docname)
- source = SphinxFileInput(app, self, source=None, source_path=src_path,
- encoding=self.config.source_encoding)
- pub.source = source
- pub.settings._source = src_path
- pub.set_destination(None, None)
- pub.publish()
- doctree = pub.document
+ with sphinx_domains(self):
+ if self.config.default_role:
+ role_fn, messages = roles.role(self.config.default_role, english,
+ 0, dummy_reporter)
+ if role_fn:
+ roles._roles[''] = role_fn
+ else:
+ self.warn(docname, 'default role %s not found' %
+ self.config.default_role)
+
+ codecs.register_error('sphinx', self.warn_and_replace)
+
+ # publish manually
+ reader = SphinxStandaloneReader(self.app, parsers=self.config.source_parsers)
+ pub = Publisher(reader=reader,
+ writer=SphinxDummyWriter(),
+ destination_class=NullOutput)
+ pub.set_components(None, 'restructuredtext', None)
+ pub.process_programmatic_settings(None, self.settings, None)
+ src_path = self.doc2path(docname)
+ source = SphinxFileInput(app, self, source=None, source_path=src_path,
+ encoding=self.config.source_encoding)
+ pub.source = source
+ pub.settings._source = src_path
+ pub.set_destination(None, None)
+ pub.publish()
+ doctree = pub.document
# post-processing
- self.filter_messages(doctree)
self.process_dependencies(docname, doctree)
self.process_images(docname, doctree)
self.process_downloads(docname, doctree)
self.process_metadata(docname, doctree)
- self.process_refonly_bullet_lists(docname, doctree)
self.create_title_from(docname, doctree)
- self.note_indexentries_from(docname, doctree)
- self.note_citations_from(docname, doctree)
- self.build_toc_from(docname, doctree)
+ for manager in itervalues(self.managers):
+ manager.process_doc(docname, doctree)
for domain in itervalues(self.domains):
domain.process_doc(self, docname, doctree)
@@ -772,12 +704,9 @@ class BuildEnvironment:
if self.versioning_compare:
# get old doctree
try:
- f = open(self.doc2path(docname,
- self.doctreedir, '.doctree'), 'rb')
- try:
+ with open(self.doc2path(docname,
+ self.doctreedir, '.doctree'), 'rb') as f:
old_doctree = pickle.load(f)
- finally:
- f.close()
except EnvironmentError:
pass
@@ -794,9 +723,6 @@ class BuildEnvironment:
doctree.settings.warning_stream = None
doctree.settings.env = None
doctree.settings.record_dependencies = None
- for metanode in doctree.traverse(MetaBody.meta):
- # docutils' meta nodes aren't picklable because the class is nested
- metanode.__class__ = addnodes.meta
# cleanup
self.temp_data.clear()
@@ -807,11 +733,8 @@ class BuildEnvironment:
doctree_filename = self.doc2path(docname, self.doctreedir,
'.doctree')
ensuredir(path.dirname(doctree_filename))
- f = open(doctree_filename, 'wb')
- try:
+ with open(doctree_filename, 'wb') as f:
pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL)
- finally:
- f.close()
# utilities to use while reading a document
@@ -876,14 +799,6 @@ class BuildEnvironment:
# post-processing of read doctrees
- def filter_messages(self, doctree):
- """Filter system messages from a doctree."""
- filterlevel = self.config.keep_warnings and 2 or 5
- for node in doctree.traverse(nodes.system_message):
- if node['level'] < filterlevel:
- self.app.debug('%s [filtered system message]', node.astext())
- node.parent.remove(node)
-
def process_dependencies(self, docname, doctree):
"""Process docutils-generated dependency info."""
cwd = getcwd()
@@ -1011,67 +926,6 @@ class BuildEnvironment:
del doctree[0]
- def process_refonly_bullet_lists(self, docname, doctree):
- """Change refonly bullet lists to use compact_paragraphs.
-
- Specifically implemented for 'Indices and Tables' section, which looks
- odd when html_compact_lists is false.
- """
- if self.config.html_compact_lists:
- return
-
- class RefOnlyListChecker(nodes.GenericNodeVisitor):
- """Raise `nodes.NodeFound` if non-simple list item is encountered.
-
- Here 'simple' means a list item containing only a paragraph with a
- single reference in it.
- """
-
- def default_visit(self, node):
- raise nodes.NodeFound
-
- def visit_bullet_list(self, node):
- pass
-
- def visit_list_item(self, node):
- children = []
- for child in node.children:
- if not isinstance(child, nodes.Invisible):
- children.append(child)
- if len(children) != 1:
- raise nodes.NodeFound
- if not isinstance(children[0], nodes.paragraph):
- raise nodes.NodeFound
- para = children[0]
- if len(para) != 1:
- raise nodes.NodeFound
- if not isinstance(para[0], addnodes.pending_xref):
- raise nodes.NodeFound
- raise nodes.SkipChildren
-
- def invisible_visit(self, node):
- """Invisible nodes should be ignored."""
- pass
-
- def check_refonly_list(node):
- """Check for list with only references in it."""
- visitor = RefOnlyListChecker(doctree)
- try:
- node.walk(visitor)
- except nodes.NodeFound:
- return False
- else:
- return True
-
- for node in doctree.traverse(nodes.bullet_list):
- if check_refonly_list(node):
- for item in node.traverse(nodes.list_item):
- para = item[0]
- ref = para[0]
- compact_para = addnodes.compact_paragraph()
- compact_para += ref
- item.replace(para, compact_para)
-
def create_title_from(self, docname, document):
"""Add a title node to the document (just copy the first section title),
and store that title in the environment.
@@ -1095,151 +949,19 @@ class BuildEnvironment:
self.titles[docname] = titlenode
self.longtitles[docname] = longtitlenode
- def note_indexentries_from(self, docname, document):
- entries = self.indexentries[docname] = []
- for node in document.traverse(addnodes.index):
- try:
- for entry in node['entries']:
- split_index_msg(entry[0], entry[1])
- except ValueError as exc:
- self.warn_node(exc, node)
- node.parent.remove(node)
- else:
- for entry in node['entries']:
- if len(entry) == 5:
- # Since 1.4: new index structure including index_key (5th column)
- entries.append(entry)
- else:
- entries.append(entry + (None,))
-
- def note_citations_from(self, docname, document):
- for node in document.traverse(nodes.citation):
- label = node[0].astext()
- if label in self.citations:
- self.warn_node('duplicate citation %s, ' % label +
- 'other instance in %s' % self.doc2path(
- self.citations[label][0]), node)
- self.citations[label] = (docname, node['ids'][0])
-
def note_toctree(self, docname, toctreenode):
"""Note a TOC tree directive in a document and gather information about
file relations from it.
"""
- if toctreenode['glob']:
- self.glob_toctrees.add(docname)
- if toctreenode.get('numbered'):
- self.numbered_toctrees.add(docname)
- includefiles = toctreenode['includefiles']
- for includefile in includefiles:
- # note that if the included file is rebuilt, this one must be
- # too (since the TOC of the included file could have changed)
- self.files_to_rebuild.setdefault(includefile, set()).add(docname)
- self.toctree_includes.setdefault(docname, []).extend(includefiles)
-
- def build_toc_from(self, docname, document):
- """Build a TOC from the doctree and store it in the inventory."""
- numentries = [0] # nonlocal again...
-
- def traverse_in_section(node, cls):
- """Like traverse(), but stay within the same section."""
- result = []
- if isinstance(node, cls):
- result.append(node)
- for child in node.children:
- if isinstance(child, nodes.section):
- continue
- result.extend(traverse_in_section(child, cls))
- return result
-
- def build_toc(node, depth=1):
- entries = []
- for sectionnode in node:
- # find all toctree nodes in this section and add them
- # to the toc (just copying the toctree node which is then
- # resolved in self.get_and_resolve_doctree)
- if isinstance(sectionnode, addnodes.only):
- onlynode = addnodes.only(expr=sectionnode['expr'])
- blist = build_toc(sectionnode, depth)
- if blist:
- onlynode += blist.children
- entries.append(onlynode)
- continue
- if not isinstance(sectionnode, nodes.section):
- for toctreenode in traverse_in_section(sectionnode,
- addnodes.toctree):
- item = toctreenode.copy()
- entries.append(item)
- # important: do the inventory stuff
- self.note_toctree(docname, toctreenode)
- continue
- title = sectionnode[0]
- # copy the contents of the section title, but without references
- # and unnecessary stuff
- visitor = SphinxContentsFilter(document)
- title.walkabout(visitor)
- nodetext = visitor.get_entry_text()
- if not numentries[0]:
- # for the very first toc entry, don't add an anchor
- # as it is the file's title anyway
- anchorname = ''
- else:
- anchorname = '#' + sectionnode['ids'][0]
- numentries[0] += 1
- # make these nodes:
- # list_item -> compact_paragraph -> reference
- reference = nodes.reference(
- '', '', internal=True, refuri=docname,
- anchorname=anchorname, *nodetext)
- para = addnodes.compact_paragraph('', '', reference)
- item = nodes.list_item('', para)
- sub_item = build_toc(sectionnode, depth + 1)
- item += sub_item
- entries.append(item)
- if entries:
- return nodes.bullet_list('', *entries)
- return []
- toc = build_toc(document)
- if toc:
- self.tocs[docname] = toc
- else:
- self.tocs[docname] = nodes.bullet_list('')
- self.toc_num_entries[docname] = numentries[0]
+ self.toctree.note_toctree(docname, toctreenode)
def get_toc_for(self, docname, builder):
"""Return a TOC nodetree -- for use on the same page only!"""
- tocdepth = self.metadata[docname].get('tocdepth', 0)
- try:
- toc = self.tocs[docname].deepcopy()
- self._toctree_prune(toc, 2, tocdepth)
- except KeyError:
- # the document does not exist anymore: return a dummy node that
- # renders to nothing
- return nodes.paragraph()
- self.process_only_nodes(toc, builder, docname)
- for node in toc.traverse(nodes.reference):
- node['refuri'] = node['anchorname'] or '#'
- return toc
+ return self.toctree.get_toc_for(docname, builder)
def get_toctree_for(self, docname, builder, collapse, **kwds):
"""Return the global TOC nodetree."""
- doctree = self.get_doctree(self.config.master_doc)
- toctrees = []
- if 'includehidden' not in kwds:
- kwds['includehidden'] = True
- if 'maxdepth' not in kwds:
- kwds['maxdepth'] = 0
- kwds['collapse'] = collapse
- for toctreenode in doctree.traverse(addnodes.toctree):
- toctree = self.resolve_toctree(docname, builder, toctreenode,
- prune=True, **kwds)
- if toctree:
- toctrees.append(toctree)
- if not toctrees:
- return None
- result = toctrees[0]
- for toctree in toctrees[1:]:
- result.extend(toctree.children)
- return result
+ return self.toctree.get_toctree_for(docname, builder, collapse, **kwds)
def get_domain(self, domainname):
"""Return the domain instance with the specified name.
@@ -1256,11 +978,8 @@ class BuildEnvironment:
def get_doctree(self, docname):
"""Read the doctree for a file from the pickle and return it."""
doctree_filename = self.doc2path(docname, self.doctreedir, '.doctree')
- f = open(doctree_filename, 'rb')
- try:
+ with open(doctree_filename, 'rb') as f:
doctree = pickle.load(f)
- finally:
- f.close()
doctree.settings.env = self
doctree.reporter = Reporter(self.doc2path(docname), 2, 5,
stream=WarningStream(self._warnfunc))
@@ -1289,39 +1008,6 @@ class BuildEnvironment:
return doctree
- def _toctree_prune(self, node, depth, maxdepth, collapse=False):
- """Utility: Cut a TOC at a specified depth."""
- for subnode in node.children[:]:
- if isinstance(subnode, (addnodes.compact_paragraph,
- nodes.list_item)):
- # for <p> and <li>, just recurse
- self._toctree_prune(subnode, depth, maxdepth, collapse)
- elif isinstance(subnode, nodes.bullet_list):
- # for <ul>, determine if the depth is too large or if the
- # entry is to be collapsed
- if maxdepth > 0 and depth > maxdepth:
- subnode.parent.replace(subnode, [])
- else:
- # cull sub-entries whose parents aren't 'current'
- if (collapse and depth > 1 and
- 'iscurrent' not in subnode.parent):
- subnode.parent.remove(subnode)
- else:
- # recurse on visible children
- self._toctree_prune(subnode, depth+1, maxdepth, collapse)
-
- def get_toctree_ancestors(self, docname):
- parent = {}
- for p, children in iteritems(self.toctree_includes):
- for child in children:
- parent[child] = p
- ancestors = []
- d = docname
- while d in parent and d not in ancestors:
- ancestors.append(d)
- d = parent[d]
- return ancestors
-
def resolve_toctree(self, docname, builder, toctree, prune=True, maxdepth=0,
titles_only=False, collapse=False, includehidden=False):
"""Resolve a *toctree* node into individual bullet lists with titles
@@ -1335,188 +1021,9 @@ class BuildEnvironment:
If *collapse* is True, all branches not containing docname will
be collapsed.
"""
- if toctree.get('hidden', False) and not includehidden:
- return None
-
- # For reading the following two helper function, it is useful to keep
- # in mind the node structure of a toctree (using HTML-like node names
- # for brevity):
- #
- # <ul>
- # <li>
- # <p><a></p>
- # <p><a></p>
- # ...
- # <ul>
- # ...
- # </ul>
- # </li>
- # </ul>
- #
- # The transformation is made in two passes in order to avoid
- # interactions between marking and pruning the tree (see bug #1046).
-
- toctree_ancestors = self.get_toctree_ancestors(docname)
-
- def _toctree_add_classes(node, depth):
- """Add 'toctree-l%d' and 'current' classes to the toctree."""
- for subnode in node.children:
- if isinstance(subnode, (addnodes.compact_paragraph,
- nodes.list_item)):
- # for <p> and <li>, indicate the depth level and recurse
- subnode['classes'].append('toctree-l%d' % (depth-1))
- _toctree_add_classes(subnode, depth)
- elif isinstance(subnode, nodes.bullet_list):
- # for <ul>, just recurse
- _toctree_add_classes(subnode, depth+1)
- elif isinstance(subnode, nodes.reference):
- # for <a>, identify which entries point to the current
- # document and therefore may not be collapsed
- if subnode['refuri'] == docname:
- if not subnode['anchorname']:
- # give the whole branch a 'current' class
- # (useful for styling it differently)
- branchnode = subnode
- while branchnode:
- branchnode['classes'].append('current')
- branchnode = branchnode.parent
- # mark the list_item as "on current page"
- if subnode.parent.parent.get('iscurrent'):
- # but only if it's not already done
- return
- while subnode:
- subnode['iscurrent'] = True
- subnode = subnode.parent
-
- def _entries_from_toctree(toctreenode, parents,
- separate=False, subtree=False):
- """Return TOC entries for a toctree node."""
- refs = [(e[0], e[1]) for e in toctreenode['entries']]
- entries = []
- for (title, ref) in refs:
- try:
- refdoc = None
- if url_re.match(ref):
- if title is None:
- title = ref
- reference = nodes.reference('', '', internal=False,
- refuri=ref, anchorname='',
- *[nodes.Text(title)])
- para = addnodes.compact_paragraph('', '', reference)
- item = nodes.list_item('', para)
- toc = nodes.bullet_list('', item)
- elif ref == 'self':
- # 'self' refers to the document from which this
- # toctree originates
- ref = toctreenode['parent']
- if not title:
- title = clean_astext(self.titles[ref])
- reference = nodes.reference('', '', internal=True,
- refuri=ref,
- anchorname='',
- *[nodes.Text(title)])
- para = addnodes.compact_paragraph('', '', reference)
- item = nodes.list_item('', para)
- # don't show subitems
- toc = nodes.bullet_list('', item)
- else:
- if ref in parents:
- self.warn(ref, 'circular toctree references '
- 'detected, ignoring: %s <- %s' %
- (ref, ' <- '.join(parents)))
- continue
- refdoc = ref
- toc = self.tocs[ref].deepcopy()
- maxdepth = self.metadata[ref].get('tocdepth', 0)
- if ref not in toctree_ancestors or (prune and maxdepth > 0):
- self._toctree_prune(toc, 2, maxdepth, collapse)
- self.process_only_nodes(toc, builder, ref)
- if title and toc.children and len(toc.children) == 1:
- child = toc.children[0]
- for refnode in child.traverse(nodes.reference):
- if refnode['refuri'] == ref and \
- not refnode['anchorname']:
- refnode.children = [nodes.Text(title)]
- if not toc.children:
- # empty toc means: no titles will show up in the toctree
- self.warn_node(
- 'toctree contains reference to document %r that '
- 'doesn\'t have a title: no link will be generated'
- % ref, toctreenode)
- except KeyError:
- # this is raised if the included file does not exist
- self.warn_node(
- 'toctree contains reference to nonexisting document %r'
- % ref, toctreenode)
- else:
- # if titles_only is given, only keep the main title and
- # sub-toctrees
- if titles_only:
- # delete everything but the toplevel title(s)
- # and toctrees
- for toplevel in toc:
- # nodes with length 1 don't have any children anyway
- if len(toplevel) > 1:
- subtrees = toplevel.traverse(addnodes.toctree)
- if subtrees:
- toplevel[1][:] = subtrees
- else:
- toplevel.pop(1)
- # resolve all sub-toctrees
- for subtocnode in toc.traverse(addnodes.toctree):
- if not (subtocnode.get('hidden', False) and
- not includehidden):
- i = subtocnode.parent.index(subtocnode) + 1
- for item in _entries_from_toctree(
- subtocnode, [refdoc] + parents,
- subtree=True):
- subtocnode.parent.insert(i, item)
- i += 1
- subtocnode.parent.remove(subtocnode)
- if separate:
- entries.append(toc)
- else:
- entries.extend(toc.children)
- if not subtree and not separate:
- ret = nodes.bullet_list()
- ret += entries
- return [ret]
- return entries
-
- maxdepth = maxdepth or toctree.get('maxdepth', -1)
- if not titles_only and toctree.get('titlesonly', False):
- titles_only = True
- if not includehidden and toctree.get('includehidden', False):
- includehidden = True
-
- # NOTE: previously, this was separate=True, but that leads to artificial
- # separation when two or more toctree entries form a logical unit, so
- # separating mode is no longer used -- it's kept here for history's sake
- tocentries = _entries_from_toctree(toctree, [], separate=False)
- if not tocentries:
- return None
-
- newnode = addnodes.compact_paragraph('', '')
- caption = toctree.attributes.get('caption')
- if caption:
- newnode += nodes.caption(caption, '', *[nodes.Text(caption)])
- newnode.extend(tocentries)
- newnode['toctree'] = True
-
- # prune the tree to maxdepth, also set toc depth and current classes
- _toctree_add_classes(newnode, 1)
- self._toctree_prune(newnode, 1, prune and maxdepth or 0, collapse)
-
- if len(newnode[-1]) == 0: # No titles found
- return None
-
- # set the target paths in the toctrees (they are not known at TOC
- # generation time)
- for refnode in newnode.traverse(nodes.reference):
- if not url_re.match(refnode['refuri']):
- refnode['refuri'] = builder.get_relative_uri(
- docname, refnode['refuri']) + refnode['anchorname']
- return newnode
+ return self.toctree.resolve_toctree(docname, builder, toctree, prune,
+ maxdepth, titles_only, collapse,
+ includehidden)
def resolve_references(self, doctree, fromdocname, builder):
for node in doctree.traverse(addnodes.pending_xref):
@@ -1539,11 +1046,9 @@ class BuildEnvironment:
typ, target, node, contnode)
# really hardwired reference types
elif typ == 'any':
- newnode = self._resolve_any_reference(builder, node, contnode)
+ newnode = self._resolve_any_reference(builder, refdoc, node, contnode)
elif typ == 'doc':
- newnode = self._resolve_doc_reference(builder, node, contnode)
- elif typ == 'citation':
- newnode = self._resolve_citation(builder, refdoc, node, contnode)
+ newnode = self._resolve_doc_reference(builder, refdoc, node, contnode)
# no new node found? try the missing-reference event
if newnode is None:
newnode = builder.app.emit_firstresult(
@@ -1557,7 +1062,7 @@ class BuildEnvironment:
node.replace_self(newnode or contnode)
# remove only-nodes that do not belong to our builder
- self.process_only_nodes(doctree, builder, fromdocname)
+ process_only_nodes(doctree, builder.tags, warn_node=self.warn_node)
# allow custom references to be resolved
builder.app.emit('doctree-resolved', doctree, fromdocname)
@@ -1580,8 +1085,6 @@ class BuildEnvironment:
msg = domain.dangling_warnings[typ]
elif typ == 'doc':
msg = 'unknown document: %(target)s'
- elif typ == 'citation':
- msg = 'citation not found: %(target)s'
elif node.get('refdomain', 'std') not in ('', 'std'):
msg = '%s:%s reference target not found: %%(target)s' % \
(node['refdomain'], typ)
@@ -1589,10 +1092,10 @@ class BuildEnvironment:
msg = '%r reference target not found: %%(target)s' % typ
self.warn_node(msg % {'target': target}, node, type='ref', subtype=typ)
- def _resolve_doc_reference(self, builder, node, contnode):
+ def _resolve_doc_reference(self, builder, refdoc, node, contnode):
# directly reference to document by source name;
# can be absolute or relative
- docname = docname_join(node['refdoc'], node['reftarget'])
+ docname = docname_join(refdoc, node['reftarget'])
if docname in self.all_docs:
if node['refexplicit']:
# reference with explicit title
@@ -1602,36 +1105,16 @@ class BuildEnvironment:
innernode = nodes.inline(caption, caption)
innernode['classes'].append('doc')
newnode = nodes.reference('', '', internal=True)
- newnode['refuri'] = builder.get_relative_uri(node['refdoc'], docname)
+ newnode['refuri'] = builder.get_relative_uri(refdoc, docname)
newnode.append(innernode)
return newnode
- def _resolve_citation(self, builder, fromdocname, node, contnode):
- docname, labelid = self.citations.get(node['reftarget'], ('', ''))
- if docname:
- try:
- newnode = make_refnode(builder, fromdocname,
- docname, labelid, contnode)
- return newnode
- except NoUri:
- # remove the ids we added in the CitationReferences
- # transform since they can't be transfered to
- # the contnode (if it's a Text node)
- if not isinstance(contnode, nodes.Element):
- del node['ids'][:]
- raise
- elif 'ids' in node:
- # remove ids attribute that annotated at
- # transforms.CitationReference.apply.
- del node['ids'][:]
-
- def _resolve_any_reference(self, builder, node, contnode):
+ def _resolve_any_reference(self, builder, refdoc, node, contnode):
"""Resolve reference generated by the "any" role."""
- refdoc = node['refdoc']
target = node['reftarget']
results = []
# first, try resolving as :doc:
- doc_ref = self._resolve_doc_reference(builder, node, contnode)
+ doc_ref = self._resolve_doc_reference(builder, refdoc, node, contnode)
if doc_ref:
results.append(('doc', doc_ref))
# next, do the standard domain (makes this a priority)
@@ -1668,280 +1151,9 @@ class BuildEnvironment:
newnode[0]['classes'].append(res_role.replace(':', '-'))
return newnode
- def process_only_nodes(self, doctree, builder, fromdocname=None):
- # A comment on the comment() nodes being inserted: replacing by [] would
- # result in a "Losing ids" exception if there is a target node before
- # the only node, so we make sure docutils can transfer the id to
- # something, even if it's just a comment and will lose the id anyway...
- for node in doctree.traverse(addnodes.only):
- try:
- ret = builder.tags.eval_condition(node['expr'])
- except Exception as err:
- self.warn_node('exception while evaluating only '
- 'directive expression: %s' % err, node)
- node.replace_self(node.children or nodes.comment())
- else:
- if ret:
- node.replace_self(node.children or nodes.comment())
- else:
- node.replace_self(nodes.comment())
-
- def assign_section_numbers(self):
- """Assign a section number to each heading under a numbered toctree."""
- # a list of all docnames whose section numbers changed
- rewrite_needed = []
-
- assigned = set()
- old_secnumbers = self.toc_secnumbers
- self.toc_secnumbers = {}
-
- def _walk_toc(node, secnums, depth, titlenode=None):
- # titlenode is the title of the document, it will get assigned a
- # secnumber too, so that it shows up in next/prev/parent rellinks
- for subnode in node.children:
- if isinstance(subnode, nodes.bullet_list):
- numstack.append(0)
- _walk_toc(subnode, secnums, depth-1, titlenode)
- numstack.pop()
- titlenode = None
- elif isinstance(subnode, nodes.list_item):
- _walk_toc(subnode, secnums, depth, titlenode)
- titlenode = None
- elif isinstance(subnode, addnodes.only):
- # at this stage we don't know yet which sections are going
- # to be included; just include all of them, even if it leads
- # to gaps in the numbering
- _walk_toc(subnode, secnums, depth, titlenode)
- titlenode = None
- elif isinstance(subnode, addnodes.compact_paragraph):
- numstack[-1] += 1
- if depth > 0:
- number = tuple(numstack)
- else:
- number = None
- secnums[subnode[0]['anchorname']] = \
- subnode[0]['secnumber'] = number
- if titlenode:
- titlenode['secnumber'] = number
- titlenode = None
- elif isinstance(subnode, addnodes.toctree):
- _walk_toctree(subnode, depth)
-
- def _walk_toctree(toctreenode, depth):
- if depth == 0:
- return
- for (title, ref) in toctreenode['entries']:
- if url_re.match(ref) or ref == 'self' or ref in assigned:
- # don't mess with those
- continue
- if ref in self.tocs:
- secnums = self.toc_secnumbers[ref] = {}
- assigned.add(ref)
- _walk_toc(self.tocs[ref], secnums, depth,
- self.titles.get(ref))
- if secnums != old_secnumbers.get(ref):
- rewrite_needed.append(ref)
-
- for docname in self.numbered_toctrees:
- assigned.add(docname)
- doctree = self.get_doctree(docname)
- for toctreenode in doctree.traverse(addnodes.toctree):
- depth = toctreenode.get('numbered', 0)
- if depth:
- # every numbered toctree gets new numbering
- numstack = [0]
- _walk_toctree(toctreenode, depth)
-
- return rewrite_needed
-
- def assign_figure_numbers(self):
- """Assign a figure number to each figure under a numbered toctree."""
-
- rewrite_needed = []
-
- assigned = set()
- old_fignumbers = self.toc_fignumbers
- self.toc_fignumbers = {}
- fignum_counter = {}
-
- def get_section_number(docname, section):
- anchorname = '#' + section['ids'][0]
- secnumbers = self.toc_secnumbers.get(docname, {})
- if anchorname in secnumbers:
- secnum = secnumbers.get(anchorname)
- else:
- secnum = secnumbers.get('')
-
- return secnum or tuple()
-
- def get_next_fignumber(figtype, secnum):
- counter = fignum_counter.setdefault(figtype, {})
-
- secnum = secnum[:self.config.numfig_secnum_depth]
- counter[secnum] = counter.get(secnum, 0) + 1
- return secnum + (counter[secnum],)
-
- def register_fignumber(docname, secnum, figtype, fignode):
- self.toc_fignumbers.setdefault(docname, {})
- fignumbers = self.toc_fignumbers[docname].setdefault(figtype, {})
- figure_id = fignode['ids'][0]
-
- fignumbers[figure_id] = get_next_fignumber(figtype, secnum)
-
- def _walk_doctree(docname, doctree, secnum):
- for subnode in doctree.children:
- if isinstance(subnode, nodes.section):
- next_secnum = get_section_number(docname, subnode)
- if next_secnum:
- _walk_doctree(docname, subnode, next_secnum)
- else:
- _walk_doctree(docname, subnode, secnum)
- continue
- elif isinstance(subnode, addnodes.toctree):
- for title, subdocname in subnode['entries']:
- if url_re.match(subdocname) or subdocname == 'self':
- # don't mess with those
- continue
-
- _walk_doc(subdocname, secnum)
-
- continue
-
- figtype = self.domains['std'].get_figtype(subnode)
- if figtype and subnode['ids']:
- register_fignumber(docname, secnum, figtype, subnode)
-
- _walk_doctree(docname, subnode, secnum)
-
- def _walk_doc(docname, secnum):
- if docname not in assigned:
- assigned.add(docname)
- doctree = self.get_doctree(docname)
- _walk_doctree(docname, doctree, secnum)
-
- if self.config.numfig:
- _walk_doc(self.config.master_doc, tuple())
- for docname, fignums in iteritems(self.toc_fignumbers):
- if fignums != old_fignumbers.get(docname):
- rewrite_needed.append(docname)
-
- return rewrite_needed
-
def create_index(self, builder, group_entries=True,
_fixre=re.compile(r'(.*) ([(][^()]*[)])')):
- """Create the real index from the collected index entries."""
- new = {}
-
- def add_entry(word, subword, link=True, dic=new, key=None):
- # Force the word to be unicode if it's a ASCII bytestring.
- # This will solve problems with unicode normalization later.
- # For instance the RFC role will add bytestrings at the moment
- word = text_type(word)
- entry = dic.get(word)
- if not entry:
- dic[word] = entry = [[], {}, key]
- if subword:
- add_entry(subword, '', link=link, dic=entry[1], key=key)
- elif link:
- try:
- uri = builder.get_relative_uri('genindex', fn) + '#' + tid
- except NoUri:
- pass
- else:
- # maintain links in sorted/deterministic order
- bisect.insort(entry[0], (main, uri))
-
- for fn, entries in iteritems(self.indexentries):
- # new entry types must be listed in directives/other.py!
- for type, value, tid, main, index_key in entries:
- try:
- if type == 'single':
- try:
- entry, subentry = split_into(2, 'single', value)
- except ValueError:
- entry, = split_into(1, 'single', value)
- subentry = ''
- add_entry(entry, subentry, key=index_key)
- elif type == 'pair':
- first, second = split_into(2, 'pair', value)
- add_entry(first, second, key=index_key)
- add_entry(second, first, key=index_key)
- elif type == 'triple':
- first, second, third = split_into(3, 'triple', value)
- add_entry(first, second+' '+third, key=index_key)
- add_entry(second, third+', '+first, key=index_key)
- add_entry(third, first+' '+second, key=index_key)
- elif type == 'see':
- first, second = split_into(2, 'see', value)
- add_entry(first, _('see %s') % second, link=False,
- key=index_key)
- elif type == 'seealso':
- first, second = split_into(2, 'see', value)
- add_entry(first, _('see also %s') % second, link=False,
- key=index_key)
- else:
- self.warn(fn, 'unknown index entry type %r' % type)
- except ValueError as err:
- self.warn(fn, str(err))
-
- # sort the index entries; put all symbols at the front, even those
- # following the letters in ASCII, this is where the chr(127) comes from
- def keyfunc(entry, lcletters=string.ascii_lowercase + '_'):
- lckey = unicodedata.normalize('NFD', entry[0].lower())
- if lckey[0:1] in lcletters:
- lckey = chr(127) + lckey
- # ensure a determinstic order *within* letters by also sorting on
- # the entry itself
- return (lckey, entry[0])
- newlist = sorted(new.items(), key=keyfunc)
-
- if group_entries:
- # fixup entries: transform
- # func() (in module foo)
- # func() (in module bar)
- # into
- # func()
- # (in module foo)
- # (in module bar)
- oldkey = ''
- oldsubitems = None
- i = 0
- while i < len(newlist):
- key, (targets, subitems, _key) = newlist[i]
- # cannot move if it has subitems; structure gets too complex
- if not subitems:
- m = _fixre.match(key)
- if m:
- if oldkey == m.group(1):
- # prefixes match: add entry as subitem of the
- # previous entry
- oldsubitems.setdefault(m.group(2), [[], {}, _key])[0].\
- extend(targets)
- del newlist[i]
- continue
- oldkey = m.group(1)
- else:
- oldkey = key
- oldsubitems = subitems
- i += 1
-
- # group the entries by letter
- def keyfunc2(item, letters=string.ascii_uppercase + '_'):
- # hack: mutating the subitems dicts to a list in the keyfunc
- k, v = item
- v[1] = sorted((si, se) for (si, (se, void, void)) in iteritems(v[1]))
- if v[2] is None:
- # now calculate the key
- letter = unicodedata.normalize('NFD', k[0])[0].upper()
- if letter in letters:
- return letter
- else:
- # get all other symbols under one heading
- return _('Symbols')
- else:
- return v[2]
- return [(key_, list(group))
- for (key_, group) in groupby(newlist, keyfunc2)]
+ return self.indices.create_index(builder, group_entries=group_entries, _fixre=_fixre)
def collect_relations(self):
traversed = set()
diff --git a/sphinx/environment/managers/__init__.py b/sphinx/environment/managers/__init__.py
new file mode 100644
index 000000000..963ec54b8
--- /dev/null
+++ b/sphinx/environment/managers/__init__.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.environment.managers
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Manager components for sphinx.environment.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+
+class EnvironmentManager(object):
+ """Base class for sphinx.environment managers."""
+ name = None
+
+ def __init__(self, env):
+ self.env = env
+
+ def attach(self, env):
+ self.env = env
+ if self.name:
+ setattr(env, self.name, self)
+
+ def detach(self, env):
+ self.env = None
+ if self.name:
+ delattr(env, self.name)
+
+ def clear_doc(self, docname):
+ raise NotImplementedError
+
+ def merge_other(self, docnames, other):
+ raise NotImplementedError
+
+ def process_doc(self, docname, doctree):
+ raise NotImplementedError
diff --git a/sphinx/environment/managers/indexentries.py b/sphinx/environment/managers/indexentries.py
new file mode 100644
index 000000000..c35a161b4
--- /dev/null
+++ b/sphinx/environment/managers/indexentries.py
@@ -0,0 +1,172 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.environment.managers.indexentries
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Index entries manager for sphinx.environment.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+import re
+import bisect
+import unicodedata
+import string
+from itertools import groupby
+
+from six import text_type
+
+from sphinx import addnodes
+from sphinx.util import iteritems, split_index_msg, split_into
+from sphinx.locale import _
+from sphinx.environment.managers import EnvironmentManager
+
+
+class IndexEntries(EnvironmentManager):
+ name = 'indices'
+
+ def __init__(self, env):
+ super(IndexEntries, self).__init__(env)
+ self.data = env.indexentries
+
+ def clear_doc(self, docname):
+ self.data.pop(docname, None)
+
+ def merge_other(self, docnames, other):
+ for docname in docnames:
+ self.data[docname] = other.indexentries[docname]
+
+ def process_doc(self, docname, doctree):
+ entries = self.data[docname] = []
+ for node in doctree.traverse(addnodes.index):
+ try:
+ for entry in node['entries']:
+ split_index_msg(entry[0], entry[1])
+ except ValueError as exc:
+ self.env.warn_node(exc, node)
+ node.parent.remove(node)
+ else:
+ for entry in node['entries']:
+ if len(entry) == 5:
+ # Since 1.4: new index structure including index_key (5th column)
+ entries.append(entry)
+ else:
+ entries.append(entry + (None,))
+
+ def create_index(self, builder, group_entries=True,
+ _fixre=re.compile(r'(.*) ([(][^()]*[)])')):
+ """Create the real index from the collected index entries."""
+ from sphinx.environment import NoUri
+
+ new = {}
+
+ def add_entry(word, subword, main, link=True, dic=new, key=None):
+ # Force the word to be unicode if it's a ASCII bytestring.
+ # This will solve problems with unicode normalization later.
+ # For instance the RFC role will add bytestrings at the moment
+ word = text_type(word)
+ entry = dic.get(word)
+ if not entry:
+ dic[word] = entry = [[], {}, key]
+ if subword:
+ add_entry(subword, '', main, link=link, dic=entry[1], key=key)
+ elif link:
+ try:
+ uri = builder.get_relative_uri('genindex', fn) + '#' + tid
+ except NoUri:
+ pass
+ else:
+ # maintain links in sorted/deterministic order
+ bisect.insort(entry[0], (main, uri))
+
+ for fn, entries in iteritems(self.data):
+ # new entry types must be listed in directives/other.py!
+ for type, value, tid, main, index_key in entries:
+ try:
+ if type == 'single':
+ try:
+ entry, subentry = split_into(2, 'single', value)
+ except ValueError:
+ entry, = split_into(1, 'single', value)
+ subentry = ''
+ add_entry(entry, subentry, main, key=index_key)
+ elif type == 'pair':
+ first, second = split_into(2, 'pair', value)
+ add_entry(first, second, main, key=index_key)
+ add_entry(second, first, main, key=index_key)
+ elif type == 'triple':
+ first, second, third = split_into(3, 'triple', value)
+ add_entry(first, second + ' ' + third, main, key=index_key)
+ add_entry(second, third + ', ' + first, main, key=index_key)
+ add_entry(third, first + ' ' + second, main, key=index_key)
+ elif type == 'see':
+ first, second = split_into(2, 'see', value)
+ add_entry(first, _('see %s') % second, None,
+ link=False, key=index_key)
+ elif type == 'seealso':
+ first, second = split_into(2, 'see', value)
+ add_entry(first, _('see also %s') % second, None,
+ link=False, key=index_key)
+ else:
+ self.env.warn(fn, 'unknown index entry type %r' % type)
+ except ValueError as err:
+ self.env.warn(fn, str(err))
+
+ # sort the index entries; put all symbols at the front, even those
+ # following the letters in ASCII, this is where the chr(127) comes from
+ def keyfunc(entry, lcletters=string.ascii_lowercase + '_'):
+ lckey = unicodedata.normalize('NFD', entry[0].lower())
+ if lckey[0:1] in lcletters:
+ lckey = chr(127) + lckey
+ # ensure a determinstic order *within* letters by also sorting on
+ # the entry itself
+ return (lckey, entry[0])
+ newlist = sorted(new.items(), key=keyfunc)
+
+ if group_entries:
+ # fixup entries: transform
+ # func() (in module foo)
+ # func() (in module bar)
+ # into
+ # func()
+ # (in module foo)
+ # (in module bar)
+ oldkey = ''
+ oldsubitems = None
+ i = 0
+ while i < len(newlist):
+ key, (targets, subitems, _key) = newlist[i]
+ # cannot move if it has subitems; structure gets too complex
+ if not subitems:
+ m = _fixre.match(key)
+ if m:
+ if oldkey == m.group(1):
+ # prefixes match: add entry as subitem of the
+ # previous entry
+ oldsubitems.setdefault(m.group(2), [[], {}, _key])[0].\
+ extend(targets)
+ del newlist[i]
+ continue
+ oldkey = m.group(1)
+ else:
+ oldkey = key
+ oldsubitems = subitems
+ i += 1
+
+ # group the entries by letter
+ def keyfunc2(item, letters=string.ascii_uppercase + '_'):
+ # hack: mutating the subitems dicts to a list in the keyfunc
+ k, v = item
+ v[1] = sorted((si, se) for (si, (se, void, void)) in iteritems(v[1]))
+ if v[2] is None:
+ # now calculate the key
+ letter = unicodedata.normalize('NFD', k[0])[0].upper()
+ if letter in letters:
+ return letter
+ else:
+ # get all other symbols under one heading
+ return _('Symbols')
+ else:
+ return v[2]
+ return [(key_, list(group))
+ for (key_, group) in groupby(newlist, keyfunc2)]
diff --git a/sphinx/environment/managers/toctree.py b/sphinx/environment/managers/toctree.py
new file mode 100644
index 000000000..d4848a72c
--- /dev/null
+++ b/sphinx/environment/managers/toctree.py
@@ -0,0 +1,561 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.environment.managers.toctree
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Toctree manager for sphinx.environment.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from six import iteritems
+from docutils import nodes
+
+from sphinx import addnodes
+from sphinx.util import url_re
+from sphinx.util.nodes import clean_astext, process_only_nodes
+from sphinx.transforms import SphinxContentsFilter
+from sphinx.environment.managers import EnvironmentManager
+
+
+class Toctree(EnvironmentManager):
+ name = 'toctree'
+
+ def __init__(self, env):
+ super(Toctree, self).__init__(env)
+
+ self.tocs = env.tocs
+ self.toc_num_entries = env.toc_num_entries
+ self.toc_secnumbers = env.toc_secnumbers
+ self.toc_fignumbers = env.toc_fignumbers
+ self.toctree_includes = env.toctree_includes
+ self.files_to_rebuild = env.files_to_rebuild
+ self.glob_toctrees = env.glob_toctrees
+ self.numbered_toctrees = env.numbered_toctrees
+
+ def clear_doc(self, docname):
+ self.tocs.pop(docname, None)
+ self.toc_secnumbers.pop(docname, None)
+ self.toc_fignumbers.pop(docname, None)
+ self.toc_num_entries.pop(docname, None)
+ self.toctree_includes.pop(docname, None)
+ self.glob_toctrees.discard(docname)
+ self.numbered_toctrees.discard(docname)
+
+ for subfn, fnset in list(self.files_to_rebuild.items()):
+ fnset.discard(docname)
+ if not fnset:
+ del self.files_to_rebuild[subfn]
+
+ def merge_other(self, docnames, other):
+ for docname in docnames:
+ self.tocs[docname] = other.tocs[docname]
+ self.toc_num_entries[docname] = other.toc_num_entries[docname]
+ if docname in other.toctree_includes:
+ self.toctree_includes[docname] = other.toctree_includes[docname]
+ if docname in other.glob_toctrees:
+ self.glob_toctrees.add(docname)
+ if docname in other.numbered_toctrees:
+ self.numbered_toctrees.add(docname)
+
+ for subfn, fnset in other.files_to_rebuild.items():
+ self.files_to_rebuild.setdefault(subfn, set()).update(fnset & docnames)
+
+ def process_doc(self, docname, doctree):
+ """Build a TOC from the doctree and store it in the inventory."""
+ numentries = [0] # nonlocal again...
+
+ def traverse_in_section(node, cls):
+ """Like traverse(), but stay within the same section."""
+ result = []
+ if isinstance(node, cls):
+ result.append(node)
+ for child in node.children:
+ if isinstance(child, nodes.section):
+ continue
+ result.extend(traverse_in_section(child, cls))
+ return result
+
+ def build_toc(node, depth=1):
+ entries = []
+ for sectionnode in node:
+ # find all toctree nodes in this section and add them
+ # to the toc (just copying the toctree node which is then
+ # resolved in self.get_and_resolve_doctree)
+ if isinstance(sectionnode, addnodes.only):
+ onlynode = addnodes.only(expr=sectionnode['expr'])
+ blist = build_toc(sectionnode, depth)
+ if blist:
+ onlynode += blist.children
+ entries.append(onlynode)
+ continue
+ if not isinstance(sectionnode, nodes.section):
+ for toctreenode in traverse_in_section(sectionnode,
+ addnodes.toctree):
+ item = toctreenode.copy()
+ entries.append(item)
+ # important: do the inventory stuff
+ self.note_toctree(docname, toctreenode)
+ continue
+ title = sectionnode[0]
+ # copy the contents of the section title, but without references
+ # and unnecessary stuff
+ visitor = SphinxContentsFilter(doctree)
+ title.walkabout(visitor)
+ nodetext = visitor.get_entry_text()
+ if not numentries[0]:
+ # for the very first toc entry, don't add an anchor
+ # as it is the file's title anyway
+ anchorname = ''
+ else:
+ anchorname = '#' + sectionnode['ids'][0]
+ numentries[0] += 1
+ # make these nodes:
+ # list_item -> compact_paragraph -> reference
+ reference = nodes.reference(
+ '', '', internal=True, refuri=docname,
+ anchorname=anchorname, *nodetext)
+ para = addnodes.compact_paragraph('', '', reference)
+ item = nodes.list_item('', para)
+ sub_item = build_toc(sectionnode, depth + 1)
+ item += sub_item
+ entries.append(item)
+ if entries:
+ return nodes.bullet_list('', *entries)
+ return []
+ toc = build_toc(doctree)
+ if toc:
+ self.tocs[docname] = toc
+ else:
+ self.tocs[docname] = nodes.bullet_list('')
+ self.toc_num_entries[docname] = numentries[0]
+
+ def note_toctree(self, docname, toctreenode):
+ """Note a TOC tree directive in a document and gather information about
+ file relations from it.
+ """
+ if toctreenode['glob']:
+ self.glob_toctrees.add(docname)
+ if toctreenode.get('numbered'):
+ self.numbered_toctrees.add(docname)
+ includefiles = toctreenode['includefiles']
+ for includefile in includefiles:
+ # note that if the included file is rebuilt, this one must be
+ # too (since the TOC of the included file could have changed)
+ self.files_to_rebuild.setdefault(includefile, set()).add(docname)
+ self.toctree_includes.setdefault(docname, []).extend(includefiles)
+
+ def get_toc_for(self, docname, builder):
+ """Return a TOC nodetree -- for use on the same page only!"""
+ tocdepth = self.env.metadata[docname].get('tocdepth', 0)
+ try:
+ toc = self.tocs[docname].deepcopy()
+ self._toctree_prune(toc, 2, tocdepth)
+ except KeyError:
+ # the document does not exist anymore: return a dummy node that
+ # renders to nothing
+ return nodes.paragraph()
+ process_only_nodes(toc, builder.tags, warn_node=self.env.warn_node)
+ for node in toc.traverse(nodes.reference):
+ node['refuri'] = node['anchorname'] or '#'
+ return toc
+
+ def get_toctree_for(self, docname, builder, collapse, **kwds):
+ """Return the global TOC nodetree."""
+ doctree = self.env.get_doctree(self.env.config.master_doc)
+ toctrees = []
+ if 'includehidden' not in kwds:
+ kwds['includehidden'] = True
+ if 'maxdepth' not in kwds:
+ kwds['maxdepth'] = 0
+ kwds['collapse'] = collapse
+ for toctreenode in doctree.traverse(addnodes.toctree):
+ toctree = self.env.resolve_toctree(docname, builder, toctreenode,
+ prune=True, **kwds)
+ if toctree:
+ toctrees.append(toctree)
+ if not toctrees:
+ return None
+ result = toctrees[0]
+ for toctree in toctrees[1:]:
+ result.extend(toctree.children)
+ return result
+
+ def resolve_toctree(self, docname, builder, toctree, prune=True, maxdepth=0,
+ titles_only=False, collapse=False, includehidden=False):
+ """Resolve a *toctree* node into individual bullet lists with titles
+ as items, returning None (if no containing titles are found) or
+ a new node.
+
+ If *prune* is True, the tree is pruned to *maxdepth*, or if that is 0,
+ to the value of the *maxdepth* option on the *toctree* node.
+ If *titles_only* is True, only toplevel document titles will be in the
+ resulting tree.
+ If *collapse* is True, all branches not containing docname will
+ be collapsed.
+ """
+ if toctree.get('hidden', False) and not includehidden:
+ return None
+
+ # For reading the following two helper function, it is useful to keep
+ # in mind the node structure of a toctree (using HTML-like node names
+ # for brevity):
+ #
+ # <ul>
+ # <li>
+ # <p><a></p>
+ # <p><a></p>
+ # ...
+ # <ul>
+ # ...
+ # </ul>
+ # </li>
+ # </ul>
+ #
+ # The transformation is made in two passes in order to avoid
+ # interactions between marking and pruning the tree (see bug #1046).
+
+ toctree_ancestors = self.get_toctree_ancestors(docname)
+
+ def _toctree_add_classes(node, depth):
+ """Add 'toctree-l%d' and 'current' classes to the toctree."""
+ for subnode in node.children:
+ if isinstance(subnode, (addnodes.compact_paragraph,
+ nodes.list_item)):
+ # for <p> and <li>, indicate the depth level and recurse
+ subnode['classes'].append('toctree-l%d' % (depth-1))
+ _toctree_add_classes(subnode, depth)
+ elif isinstance(subnode, nodes.bullet_list):
+ # for <ul>, just recurse
+ _toctree_add_classes(subnode, depth+1)
+ elif isinstance(subnode, nodes.reference):
+ # for <a>, identify which entries point to the current
+ # document and therefore may not be collapsed
+ if subnode['refuri'] == docname:
+ if not subnode['anchorname']:
+ # give the whole branch a 'current' class
+ # (useful for styling it differently)
+ branchnode = subnode
+ while branchnode:
+ branchnode['classes'].append('current')
+ branchnode = branchnode.parent
+ # mark the list_item as "on current page"
+ if subnode.parent.parent.get('iscurrent'):
+ # but only if it's not already done
+ return
+ while subnode:
+ subnode['iscurrent'] = True
+ subnode = subnode.parent
+
+ def _entries_from_toctree(toctreenode, parents,
+ separate=False, subtree=False):
+ """Return TOC entries for a toctree node."""
+ refs = [(e[0], e[1]) for e in toctreenode['entries']]
+ entries = []
+ for (title, ref) in refs:
+ try:
+ refdoc = None
+ if url_re.match(ref):
+ if title is None:
+ title = ref
+ reference = nodes.reference('', '', internal=False,
+ refuri=ref, anchorname='',
+ *[nodes.Text(title)])
+ para = addnodes.compact_paragraph('', '', reference)
+ item = nodes.list_item('', para)
+ toc = nodes.bullet_list('', item)
+ elif ref == 'self':
+ # 'self' refers to the document from which this
+ # toctree originates
+ ref = toctreenode['parent']
+ if not title:
+ title = clean_astext(self.titles[ref])
+ reference = nodes.reference('', '', internal=True,
+ refuri=ref,
+ anchorname='',
+ *[nodes.Text(title)])
+ para = addnodes.compact_paragraph('', '', reference)
+ item = nodes.list_item('', para)
+ # don't show subitems
+ toc = nodes.bullet_list('', item)
+ else:
+ if ref in parents:
+ self.env.warn(ref, 'circular toctree references '
+ 'detected, ignoring: %s <- %s' %
+ (ref, ' <- '.join(parents)))
+ continue
+ refdoc = ref
+ toc = self.tocs[ref].deepcopy()
+ maxdepth = self.env.metadata[ref].get('tocdepth', 0)
+ if ref not in toctree_ancestors or (prune and maxdepth > 0):
+ self._toctree_prune(toc, 2, maxdepth, collapse)
+ process_only_nodes(toc, builder.tags, warn_node=self.env.warn_node)
+ if title and toc.children and len(toc.children) == 1:
+ child = toc.children[0]
+ for refnode in child.traverse(nodes.reference):
+ if refnode['refuri'] == ref and \
+ not refnode['anchorname']:
+ refnode.children = [nodes.Text(title)]
+ if not toc.children:
+ # empty toc means: no titles will show up in the toctree
+ self.env.warn_node(
+ 'toctree contains reference to document %r that '
+ 'doesn\'t have a title: no link will be generated'
+ % ref, toctreenode)
+ except KeyError:
+ # this is raised if the included file does not exist
+ self.env.warn_node(
+ 'toctree contains reference to nonexisting document %r'
+ % ref, toctreenode)
+ else:
+ # if titles_only is given, only keep the main title and
+ # sub-toctrees
+ if titles_only:
+ # delete everything but the toplevel title(s)
+ # and toctrees
+ for toplevel in toc:
+ # nodes with length 1 don't have any children anyway
+ if len(toplevel) > 1:
+ subtrees = toplevel.traverse(addnodes.toctree)
+ if subtrees:
+ toplevel[1][:] = subtrees
+ else:
+ toplevel.pop(1)
+ # resolve all sub-toctrees
+ for subtocnode in toc.traverse(addnodes.toctree):
+ if not (subtocnode.get('hidden', False) and
+ not includehidden):
+ i = subtocnode.parent.index(subtocnode) + 1
+ for item in _entries_from_toctree(
+ subtocnode, [refdoc] + parents,
+ subtree=True):
+ subtocnode.parent.insert(i, item)
+ i += 1
+ subtocnode.parent.remove(subtocnode)
+ if separate:
+ entries.append(toc)
+ else:
+ entries.extend(toc.children)
+ if not subtree and not separate:
+ ret = nodes.bullet_list()
+ ret += entries
+ return [ret]
+ return entries
+
+ maxdepth = maxdepth or toctree.get('maxdepth', -1)
+ if not titles_only and toctree.get('titlesonly', False):
+ titles_only = True
+ if not includehidden and toctree.get('includehidden', False):
+ includehidden = True
+
+ # NOTE: previously, this was separate=True, but that leads to artificial
+ # separation when two or more toctree entries form a logical unit, so
+ # separating mode is no longer used -- it's kept here for history's sake
+ tocentries = _entries_from_toctree(toctree, [], separate=False)
+ if not tocentries:
+ return None
+
+ newnode = addnodes.compact_paragraph('', '')
+ caption = toctree.attributes.get('caption')
+ if caption:
+ caption_node = nodes.caption(caption, '', *[nodes.Text(caption)])
+ caption_node.line = toctree.line
+ caption_node.source = toctree.source
+ caption_node.rawsource = toctree['rawcaption']
+ if hasattr(toctree, 'uid'):
+ # move uid to caption_node to translate it
+ caption_node.uid = toctree.uid
+ del toctree.uid
+ newnode += caption_node
+ newnode.extend(tocentries)
+ newnode['toctree'] = True
+
+ # prune the tree to maxdepth, also set toc depth and current classes
+ _toctree_add_classes(newnode, 1)
+ self._toctree_prune(newnode, 1, prune and maxdepth or 0, collapse)
+
+ if len(newnode[-1]) == 0: # No titles found
+ return None
+
+ # set the target paths in the toctrees (they are not known at TOC
+ # generation time)
+ for refnode in newnode.traverse(nodes.reference):
+ if not url_re.match(refnode['refuri']):
+ refnode['refuri'] = builder.get_relative_uri(
+ docname, refnode['refuri']) + refnode['anchorname']
+ return newnode
+
+ def get_toctree_ancestors(self, docname):
+ parent = {}
+ for p, children in iteritems(self.toctree_includes):
+ for child in children:
+ parent[child] = p
+ ancestors = []
+ d = docname
+ while d in parent and d not in ancestors:
+ ancestors.append(d)
+ d = parent[d]
+ return ancestors
+
+ def _toctree_prune(self, node, depth, maxdepth, collapse=False):
+ """Utility: Cut a TOC at a specified depth."""
+ for subnode in node.children[:]:
+ if isinstance(subnode, (addnodes.compact_paragraph,
+ nodes.list_item)):
+ # for <p> and <li>, just recurse
+ self._toctree_prune(subnode, depth, maxdepth, collapse)
+ elif isinstance(subnode, nodes.bullet_list):
+ # for <ul>, determine if the depth is too large or if the
+ # entry is to be collapsed
+ if maxdepth > 0 and depth > maxdepth:
+ subnode.parent.replace(subnode, [])
+ else:
+ # cull sub-entries whose parents aren't 'current'
+ if (collapse and depth > 1 and
+ 'iscurrent' not in subnode.parent):
+ subnode.parent.remove(subnode)
+ else:
+ # recurse on visible children
+ self._toctree_prune(subnode, depth+1, maxdepth, collapse)
+
+ def assign_section_numbers(self):
+ """Assign a section number to each heading under a numbered toctree."""
+ # a list of all docnames whose section numbers changed
+ rewrite_needed = []
+
+ assigned = set()
+ old_secnumbers = self.toc_secnumbers
+ self.toc_secnumbers = self.env.toc_secnumbers = {}
+
+ def _walk_toc(node, secnums, depth, titlenode=None):
+ # titlenode is the title of the document, it will get assigned a
+ # secnumber too, so that it shows up in next/prev/parent rellinks
+ for subnode in node.children:
+ if isinstance(subnode, nodes.bullet_list):
+ numstack.append(0)
+ _walk_toc(subnode, secnums, depth-1, titlenode)
+ numstack.pop()
+ titlenode = None
+ elif isinstance(subnode, nodes.list_item):
+ _walk_toc(subnode, secnums, depth, titlenode)
+ titlenode = None
+ elif isinstance(subnode, addnodes.only):
+ # at this stage we don't know yet which sections are going
+ # to be included; just include all of them, even if it leads
+ # to gaps in the numbering
+ _walk_toc(subnode, secnums, depth, titlenode)
+ titlenode = None
+ elif isinstance(subnode, addnodes.compact_paragraph):
+ numstack[-1] += 1
+ if depth > 0:
+ number = tuple(numstack)
+ else:
+ number = None
+ secnums[subnode[0]['anchorname']] = \
+ subnode[0]['secnumber'] = number
+ if titlenode:
+ titlenode['secnumber'] = number
+ titlenode = None
+ elif isinstance(subnode, addnodes.toctree):
+ _walk_toctree(subnode, depth)
+
+ def _walk_toctree(toctreenode, depth):
+ if depth == 0:
+ return
+ for (title, ref) in toctreenode['entries']:
+ if url_re.match(ref) or ref == 'self' or ref in assigned:
+ # don't mess with those
+ continue
+ if ref in self.tocs:
+ secnums = self.toc_secnumbers[ref] = {}
+ assigned.add(ref)
+ _walk_toc(self.tocs[ref], secnums, depth,
+ self.env.titles.get(ref))
+ if secnums != old_secnumbers.get(ref):
+ rewrite_needed.append(ref)
+
+ for docname in self.numbered_toctrees:
+ assigned.add(docname)
+ doctree = self.env.get_doctree(docname)
+ for toctreenode in doctree.traverse(addnodes.toctree):
+ depth = toctreenode.get('numbered', 0)
+ if depth:
+ # every numbered toctree gets new numbering
+ numstack = [0]
+ _walk_toctree(toctreenode, depth)
+
+ return rewrite_needed
+
+ def assign_figure_numbers(self):
+ """Assign a figure number to each figure under a numbered toctree."""
+
+ rewrite_needed = []
+
+ assigned = set()
+ old_fignumbers = self.toc_fignumbers
+ self.toc_fignumbers = self.env.toc_fignumbers = {}
+ fignum_counter = {}
+
+ def get_section_number(docname, section):
+ anchorname = '#' + section['ids'][0]
+ secnumbers = self.toc_secnumbers.get(docname, {})
+ if anchorname in secnumbers:
+ secnum = secnumbers.get(anchorname)
+ else:
+ secnum = secnumbers.get('')
+
+ return secnum or tuple()
+
+ def get_next_fignumber(figtype, secnum):
+ counter = fignum_counter.setdefault(figtype, {})
+
+ secnum = secnum[:self.env.config.numfig_secnum_depth]
+ counter[secnum] = counter.get(secnum, 0) + 1
+ return secnum + (counter[secnum],)
+
+ def register_fignumber(docname, secnum, figtype, fignode):
+ self.toc_fignumbers.setdefault(docname, {})
+ fignumbers = self.toc_fignumbers[docname].setdefault(figtype, {})
+ figure_id = fignode['ids'][0]
+
+ fignumbers[figure_id] = get_next_fignumber(figtype, secnum)
+
+ def _walk_doctree(docname, doctree, secnum):
+ for subnode in doctree.children:
+ if isinstance(subnode, nodes.section):
+ next_secnum = get_section_number(docname, subnode)
+ if next_secnum:
+ _walk_doctree(docname, subnode, next_secnum)
+ else:
+ _walk_doctree(docname, subnode, secnum)
+ continue
+ elif isinstance(subnode, addnodes.toctree):
+ for title, subdocname in subnode['entries']:
+ if url_re.match(subdocname) or subdocname == 'self':
+ # don't mess with those
+ continue
+
+ _walk_doc(subdocname, secnum)
+
+ continue
+
+ figtype = self.env.domains['std'].get_figtype(subnode)
+ if figtype and subnode['ids']:
+ register_fignumber(docname, secnum, figtype, subnode)
+
+ _walk_doctree(docname, subnode, secnum)
+
+ def _walk_doc(docname, secnum):
+ if docname not in assigned:
+ assigned.add(docname)
+ doctree = self.env.get_doctree(docname)
+ _walk_doctree(docname, doctree, secnum)
+
+ if self.env.config.numfig:
+ _walk_doc(self.env.config.master_doc, tuple())
+ for docname, fignums in iteritems(self.toc_fignumbers):
+ if fignums != old_fignumbers.get(docname):
+ rewrite_needed.append(docname)
+
+ return rewrite_needed
diff --git a/sphinx/errors.py b/sphinx/errors.py
index 8d695c190..5fb77a135 100644
--- a/sphinx/errors.py
+++ b/sphinx/errors.py
@@ -67,7 +67,10 @@ class PycodeError(Exception):
return res
-class SphinxParallelError(Exception):
+class SphinxParallelError(SphinxError):
+
+ category = 'Sphinx parallel build error'
+
def __init__(self, orig_exc, traceback):
self.orig_exc = orig_exc
self.traceback = traceback
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index 405d24c88..59e585678 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -31,7 +31,7 @@ from sphinx.application import ExtensionError
from sphinx.util.nodes import nested_parse_with_titles
from sphinx.util.compat import Directive
from sphinx.util.inspect import getargspec, isdescriptor, safe_getmembers, \
- safe_getattr, object_description, is_builtin_class_method
+ safe_getattr, object_description, is_builtin_class_method, isenumattribute
from sphinx.util.docstrings import prepare_docstring
try:
@@ -86,17 +86,24 @@ class Options(dict):
class _MockModule(object):
"""Used by autodoc_mock_imports."""
+ __file__ = '/dev/null'
+ __path__ = '/dev/null'
+
def __init__(self, *args, **kwargs):
- pass
+ self.__all__ = []
def __call__(self, *args, **kwargs):
+ if args and type(args[0]) in [FunctionType, MethodType]:
+ # Appears to be a decorator, pass through unchanged
+ return args[0]
return _MockModule()
+ def _append_submodule(self, submod):
+ self.__all__.append(submod)
+
@classmethod
def __getattr__(cls, name):
- if name in ('__file__', '__path__'):
- return '/dev/null'
- elif name[0] == name[0].upper():
+ if name[0] == name[0].upper():
# Not very good, we assume Uppercase names are classes...
mocktype = type(name, (), {})
mocktype.__module__ = __name__
@@ -109,9 +116,12 @@ def mock_import(modname):
if '.' in modname:
pkg, _n, mods = modname.rpartition('.')
mock_import(pkg)
- mod = _MockModule()
- sys.modules[modname] = mod
- return mod
+ if isinstance(sys.modules[pkg], _MockModule):
+ sys.modules[pkg]._append_submodule(mods)
+
+ if modname not in sys.modules:
+ mod = _MockModule()
+ sys.modules[modname] = mod
ALL = object()
@@ -304,8 +314,9 @@ def format_annotation(annotation):
return '%s[%s]' % (qualified_name, param_str)
elif hasattr(typing, 'CallableMeta') and \
isinstance(annotation, typing.CallableMeta) and \
- hasattr(annotation, '__args__') and \
+ getattr(annotation, '__args__', None) is not None and \
hasattr(annotation, '__result__'):
+ # Skipped in the case of plain typing.Callable
args = annotation.__args__
if args is None:
return qualified_name
@@ -372,7 +383,9 @@ def formatargspec(function, args, varargs=None, varkw=None, defaults=None,
formatted.append('*' + format_arg_with_annotation(varargs))
if kwonlyargs:
- formatted.append('*')
+ if not varargs:
+ formatted.append('*')
+
for kwarg in kwonlyargs:
arg_fd = StringIO()
arg_fd.write(format_arg_with_annotation(kwarg))
@@ -524,7 +537,7 @@ class Documenter(object):
try:
dbg('[autodoc] import %s', self.modname)
for modname in self.env.config.autodoc_mock_imports:
- dbg('[autodoc] adding a mock module %s!', self.modname)
+ dbg('[autodoc] adding a mock module %s!', modname)
mock_import(modname)
__import__(self.modname)
parent = None
@@ -1284,7 +1297,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
u':class:`%s`' % b.__name__ or
u':class:`%s.%s`' % (b.__module__, b.__name__)
for b in self.object.__bases__]
- self.add_line(_(u' Bases: %s') % ', '.join(bases),
+ self.add_line(u' ' + _(u'Bases: %s') % ', '.join(bases),
sourcename)
def get_doc(self, encoding=None, ignore=1):
@@ -1479,6 +1492,8 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
def import_object(self):
ret = ClassLevelDocumenter.import_object(self)
+ if isenumattribute(self.object):
+ self.object = self.object.value
if isdescriptor(self.object) and \
not isinstance(self.object, self.method_types):
self._datadescriptor = True
diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py
index a941aa33a..030fec301 100644
--- a/sphinx/ext/autosummary/__init__.py
+++ b/sphinx/ext/autosummary/__init__.py
@@ -58,6 +58,7 @@ import re
import sys
import inspect
import posixpath
+from six import string_types
from types import ModuleType
from six import text_type
@@ -67,7 +68,7 @@ from docutils import nodes
import sphinx
from sphinx import addnodes
-from sphinx.util import rst
+from sphinx.util import import_object, rst
from sphinx.util.compat import Directive
from sphinx.pycode import ModuleAnalyzer, PycodeError
from sphinx.ext.autodoc import Options
@@ -136,7 +137,7 @@ def autosummary_table_visit_html(self, node):
# -- autodoc integration -------------------------------------------------------
-class FakeDirective:
+class FakeDirective(object):
env = {}
genopt = Options()
@@ -543,6 +544,22 @@ def autolink_role(typ, rawtext, etext, lineno, inliner,
return r
+def get_rst_suffix(app):
+ def get_supported_format(suffix):
+ parser_class = app.config.source_parsers.get(suffix)
+ if parser_class is None:
+ return ('restructuredtext',)
+ if isinstance(parser_class, string_types):
+ parser_class = import_object(parser_class, 'source parser')
+ return parser_class.supported
+
+ for suffix in app.config.source_suffix:
+ if 'restructuredtext' in get_supported_format(suffix):
+ return suffix
+
+ return None
+
+
def process_generate_options(app):
genfiles = app.config.autosummary_generate
@@ -556,12 +573,18 @@ def process_generate_options(app):
from sphinx.ext.autosummary.generate import generate_autosummary_docs
- ext = app.config.source_suffix[0]
- genfiles = [genfile + (not genfile.endswith(ext) and ext or '')
+ ext = app.config.source_suffix
+ genfiles = [genfile + (not genfile.endswith(tuple(ext)) and ext[0] or '')
for genfile in genfiles]
+ suffix = get_rst_suffix(app)
+ if suffix is None:
+ app.warn('autosummary generats .rst files internally. '
+ 'But your source_suffix does not contain .rst. Skipped.')
+ return
+
generate_autosummary_docs(genfiles, builder=app.builder,
- warn=app.warn, info=app.info, suffix=ext,
+ warn=app.warn, info=app.info, suffix=suffix,
base_path=app.srcdir)
diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py
index 78281bb85..c08b1e706 100644
--- a/sphinx/ext/coverage.py
+++ b/sphinx/ext/coverage.py
@@ -87,8 +87,7 @@ class CoverageBuilder(Builder):
c_objects = self.env.domaindata['c']['objects']
for filename in self.c_sourcefiles:
undoc = set()
- f = open(filename, 'r')
- try:
+ with open(filename, 'r') as f:
for line in f:
for key, regex in self.c_regexes:
match = regex.match(line)
@@ -101,15 +100,12 @@ class CoverageBuilder(Builder):
else:
undoc.add((key, name))
continue
- finally:
- f.close()
if undoc:
self.c_undoc[filename] = undoc
def write_c_coverage(self):
output_file = path.join(self.outdir, 'c.txt')
- op = open(output_file, 'w')
- try:
+ with open(output_file, 'w') as op:
if self.config.coverage_write_headline:
write_header(op, 'Undocumented C API elements', '=')
op.write('\n')
@@ -119,8 +115,6 @@ class CoverageBuilder(Builder):
for typ, name in sorted(undoc):
op.write(' * %-50s [%9s]\n' % (name, typ))
op.write('\n')
- finally:
- op.close()
def build_py_coverage(self):
objects = self.env.domaindata['py']['objects']
@@ -214,9 +208,8 @@ class CoverageBuilder(Builder):
def write_py_coverage(self):
output_file = path.join(self.outdir, 'python.txt')
- op = open(output_file, 'w')
failed = []
- try:
+ with open(output_file, 'w') as op:
if self.config.coverage_write_headline:
write_header(op, 'Undocumented Python objects', '=')
keys = sorted(self.py_undoc.keys())
@@ -247,17 +240,12 @@ class CoverageBuilder(Builder):
if failed:
write_header(op, 'Modules that failed to import')
op.writelines(' * %s -- %s\n' % x for x in failed)
- finally:
- op.close()
def finish(self):
# dump the coverage data to a pickle file too
picklepath = path.join(self.outdir, 'undoc.pickle')
- dumpfile = open(picklepath, 'wb')
- try:
+ with open(picklepath, 'wb') as dumpfile:
pickle.dump((self.py_undoc, self.c_undoc), dumpfile)
- finally:
- dumpfile.close()
def setup(app):
diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py
index 0f5241a19..244762b69 100644
--- a/sphinx/ext/doctest.py
+++ b/sphinx/ext/doctest.py
@@ -214,8 +214,7 @@ class DocTestBuilder(Builder):
def init(self):
# default options
- self.opt = doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.ELLIPSIS | \
- doctest.IGNORE_EXCEPTION_DETAIL
+ self.opt = self.config.doctest_default_flags
# HACK HACK HACK
# doctest compiles its snippets with type 'single'. That is nice
@@ -464,4 +463,8 @@ def setup(app):
app.add_config_value('doctest_test_doctest_blocks', 'default', False)
app.add_config_value('doctest_global_setup', '', False)
app.add_config_value('doctest_global_cleanup', '', False)
+ app.add_config_value(
+ 'doctest_default_flags',
+ doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.ELLIPSIS | doctest.IGNORE_EXCEPTION_DETAIL,
+ False)
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py
index 4e06677ca..5e76eb8ba 100644
--- a/sphinx/ext/graphviz.py
+++ b/sphinx/ext/graphviz.py
@@ -43,6 +43,8 @@ class graphviz(nodes.General, nodes.Inline, nodes.Element):
def figure_wrapper(directive, node, caption):
figure_node = nodes.figure('', node)
+ if 'align' in node:
+ figure_node['align'] = node.attributes.pop('align')
parsed = nodes.Element()
directive.state.nested_parse(ViewList([caption], source=''),
@@ -55,6 +57,10 @@ def figure_wrapper(directive, node, caption):
return figure_node
+def align_spec(argument):
+ return directives.choice(argument, ('left', 'center', 'right'))
+
+
class Graphviz(Directive):
"""
Directive to insert arbitrary dot markup.
@@ -65,6 +71,7 @@ class Graphviz(Directive):
final_argument_whitespace = False
option_spec = {
'alt': directives.unchanged,
+ 'align': align_spec,
'inline': directives.flag,
'caption': directives.unchanged,
'graphviz_dot': directives.unchanged,
@@ -82,11 +89,8 @@ class Graphviz(Directive):
rel_filename, filename = env.relfn2path(argument)
env.note_dependency(rel_filename)
try:
- fp = codecs.open(filename, 'r', 'utf-8')
- try:
+ with codecs.open(filename, 'r', 'utf-8') as fp:
dotcode = fp.read()
- finally:
- fp.close()
except (IOError, OSError):
return [document.reporter.warning(
'External Graphviz file %r not found or reading '
@@ -104,6 +108,8 @@ class Graphviz(Directive):
node['options']['graphviz_dot'] = self.options['graphviz_dot']
if 'alt' in self.options:
node['alt'] = self.options['alt']
+ if 'align' in self.options:
+ node['align'] = self.options['align']
if 'inline' in self.options:
node['inline'] = True
@@ -124,6 +130,7 @@ class GraphvizSimple(Directive):
final_argument_whitespace = False
option_spec = {
'alt': directives.unchanged,
+ 'align': align_spec,
'inline': directives.flag,
'caption': directives.unchanged,
'graphviz_dot': directives.unchanged,
@@ -138,6 +145,8 @@ class GraphvizSimple(Directive):
node['options']['graphviz_dot'] = self.options['graphviz_dot']
if 'alt' in self.options:
node['alt'] = self.options['alt']
+ if 'align' in self.options:
+ node['align'] = self.options['align']
if 'inline' in self.options:
node['inline'] = True
@@ -239,11 +248,11 @@ def render_dot_html(self, node, code, options, prefix='graphviz',
<p class="warning">%s</p></object>\n''' % (fname, alt)
self.body.append(svgtag)
else:
- mapfile = open(outfn + '.map', 'rb')
- try:
+ if 'align' in node:
+ self.body.append('<div align="%s" class="align-%s">' %
+ (node['align'], node['align']))
+ with open(outfn + '.map', 'rb') as mapfile:
imgmap = mapfile.readlines()
- finally:
- mapfile.close()
if len(imgmap) == 2:
# nothing in image map (the lines are <map> and </map>)
self.body.append('<img src="%s" alt="%s" %s/>\n' %
@@ -254,6 +263,8 @@ def render_dot_html(self, node, code, options, prefix='graphviz',
self.body.append('<img src="%s" alt="%s" usemap="#%s" %s/>\n' %
(fname, alt, mapname, imgcss))
self.body.extend([item.decode('utf-8') for item in imgmap])
+ if 'align' in node:
+ self.body.append('</div>\n')
raise nodes.SkipNode
@@ -277,8 +288,19 @@ def render_dot_latex(self, node, code, options, prefix='graphviz'):
para_separator = '\n'
if fname is not None:
+ post = None
+ if not is_inline and 'align' in node:
+ if node['align'] == 'left':
+ self.body.append('{')
+ post = '\\hspace*{\\fill}}'
+ elif node['align'] == 'right':
+ self.body.append('{\\hspace*{\\fill}')
+ post = '}'
self.body.append('%s\\includegraphics{%s}%s' %
(para_separator, fname, para_separator))
+ if post:
+ self.body.append(post)
+
raise nodes.SkipNode
diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py
index f8e402be3..e5b8b26c5 100644
--- a/sphinx/ext/imgmath.py
+++ b/sphinx/ext/imgmath.py
@@ -22,6 +22,7 @@ from six import text_type
from docutils import nodes
import sphinx
+from sphinx.locale import _
from sphinx.errors import SphinxError, ExtensionError
from sphinx.util.png import read_png_depth, write_png_depth
from sphinx.util.osutil import ensuredir, ENOENT, cd
@@ -253,7 +254,9 @@ def html_visit_displaymath(self, node):
self.body.append(self.starttag(node, 'div', CLASS='math'))
self.body.append('<p>')
if node['number']:
- self.body.append('<span class="eqno">(%s)</span>' % node['number'])
+ self.body.append('<span class="eqno">(%s)' % node['number'])
+ self.add_permalink_ref(node, _('Permalink to this equation'))
+ self.body.append('</span>')
if fname is None:
# something failed -- use text-only as a bad substitute
self.body.append('<span class="math">%s</span></p>\n</div>' %
diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py
index a06c4b17c..11af67dc5 100644
--- a/sphinx/ext/inheritance_diagram.py
+++ b/sphinx/ext/inheritance_diagram.py
@@ -52,7 +52,7 @@ from docutils.parsers.rst import directives
import sphinx
from sphinx.ext.graphviz import render_dot_html, render_dot_latex, \
- render_dot_texinfo
+ render_dot_texinfo, figure_wrapper
from sphinx.pycode import ModuleAnalyzer
from sphinx.util import force_decode
from sphinx.util.compat import Directive
@@ -297,6 +297,7 @@ class InheritanceDiagram(Directive):
option_spec = {
'parts': directives.nonnegative_int,
'private-bases': directives.flag,
+ 'caption': directives.unchanged,
}
def run(self):
@@ -330,6 +331,11 @@ class InheritanceDiagram(Directive):
# Store the graph object so we can use it to generate the
# dot file later
node['graph'] = graph
+
+ # wrap the result in figure node
+ caption = self.options.get('caption')
+ if caption:
+ node = figure_wrapper(self, node, caption)
return [node]
diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py
index 7b68b3bb0..4ef7e4b9b 100644
--- a/sphinx/ext/intersphinx.py
+++ b/sphinx/ext/intersphinx.py
@@ -34,7 +34,6 @@ from os import path
import re
from six import iteritems, string_types
-from six.moves.urllib import request
from six.moves.urllib.parse import urlsplit, urlunsplit
from docutils import nodes
from docutils.utils import relative_path
@@ -42,17 +41,9 @@ from docutils.utils import relative_path
import sphinx
from sphinx.locale import _
from sphinx.builders.html import INVENTORY_FILENAME
+from sphinx.util.requests import requests, useragent_header
-default_handlers = [request.ProxyHandler(), request.HTTPRedirectHandler(),
- request.HTTPHandler()]
-try:
- default_handlers.append(request.HTTPSHandler)
-except AttributeError:
- pass
-
-default_opener = request.build_opener(*default_handlers)
-
UTF8StreamReader = codecs.lookup('utf-8')[2]
@@ -125,6 +116,14 @@ def read_inventory_v2(f, uri, join, bufsize=16*1024):
return invdata
+def read_inventory(f, uri, join, bufsize=16*1024):
+ line = f.readline().rstrip().decode('utf-8')
+ if line == '# Sphinx inventory version 1':
+ return read_inventory_v1(f, uri, join)
+ elif line == '# Sphinx inventory version 2':
+ return read_inventory_v2(f, uri, join, bufsize=bufsize)
+
+
def _strip_basic_auth(url):
"""Returns *url* with basic auth credentials removed. Also returns the
basic auth username and password if they're present in *url*.
@@ -136,30 +135,17 @@ def _strip_basic_auth(url):
:param url: url which may or may not contain basic auth credentials
:type url: ``str``
- :return: 3-``tuple`` of:
-
- * (``str``) -- *url* with any basic auth creds removed
- * (``str`` or ``NoneType``) -- basic auth username or ``None`` if basic
- auth username not given
- * (``str`` or ``NoneType``) -- basic auth password or ``None`` if basic
- auth password not given
-
- :rtype: ``tuple``
+ :return: *url* with any basic auth creds removed
+ :rtype: ``str``
"""
- url_parts = urlsplit(url)
- username = url_parts.username
- password = url_parts.password
- frags = list(url_parts)
+ frags = list(urlsplit(url))
# swap out "user[:pass]@hostname" for "hostname"
- if url_parts.port:
- frags[1] = "%s:%s" % (url_parts.hostname, url_parts.port)
- else:
- frags[1] = url_parts.hostname
- url = urlunsplit(frags)
- return (url, username, password)
+ if '@' in frags[1]:
+ frags[1] = frags[1].split('@')[1]
+ return urlunsplit(frags)
-def _read_from_url(url):
+def _read_from_url(url, timeout=None):
"""Reads data from *url* with an HTTP *GET*.
This function supports fetching from resources which use basic HTTP auth as
@@ -175,48 +161,35 @@ def _read_from_url(url):
:return: data read from resource described by *url*
:rtype: ``file``-like object
"""
- url, username, password = _strip_basic_auth(url)
- if username is not None and password is not None:
- # case: url contains basic auth creds
- password_mgr = request.HTTPPasswordMgrWithDefaultRealm()
- password_mgr.add_password(None, url, username, password)
- handler = request.HTTPBasicAuthHandler(password_mgr)
- opener = request.build_opener(*(default_handlers + [handler]))
- else:
- opener = default_opener
-
- return opener.open(url)
+ r = requests.get(url, stream=True, timeout=timeout, headers=dict(useragent_header))
+ r.raise_for_status()
+ r.raw.url = r.url
+ return r.raw
def _get_safe_url(url):
"""Gets version of *url* with basic auth passwords obscured. This function
returns results suitable for printing and logging.
- E.g.: https://user:12345@example.com => https://user:********@example.com
-
- .. note::
-
- The number of astrisks is invariant in the length of the basic auth
- password, so minimal information is leaked.
+ E.g.: https://user:12345@example.com => https://user@example.com
:param url: a url
:type url: ``str``
- :return: *url* with password obscured
+ :return: *url* with password removed
:rtype: ``str``
"""
- safe_url = url
- url, username, _ = _strip_basic_auth(url)
- if username is not None:
- # case: url contained basic auth creds; obscure password
- url_parts = urlsplit(url)
- safe_netloc = '{0}@{1}'.format(username, url_parts.hostname)
- # replace original netloc w/ obscured version
- frags = list(url_parts)
- frags[1] = safe_netloc
- safe_url = urlunsplit(frags)
+ parts = urlsplit(url)
+ if parts.username is None:
+ return url
+ else:
+ frags = list(parts)
+ if parts.port:
+ frags[1] = '{0}@{1}:{2}'.format(parts.username, parts.hostname, parts.port)
+ else:
+ frags[1] = '{0}@{1}'.format(parts.username, parts.hostname)
- return safe_url
+ return urlunsplit(frags)
def fetch_inventory(app, uri, inv):
@@ -226,11 +199,10 @@ def fetch_inventory(app, uri, inv):
localuri = '://' not in uri
if not localuri:
# case: inv URI points to remote resource; strip any existing auth
- uri, _, _ = _strip_basic_auth(uri)
- join = localuri and path.join or posixpath.join
+ uri = _strip_basic_auth(uri)
try:
if '://' in inv:
- f = _read_from_url(inv)
+ f = _read_from_url(inv, timeout=app.config.intersphinx_timeout)
else:
f = open(path.join(app.srcdir, inv), 'rb')
except Exception as err:
@@ -238,25 +210,19 @@ def fetch_inventory(app, uri, inv):
'%s: %s' % (inv, err.__class__, err))
return
try:
- if hasattr(f, 'geturl'):
- newinv = f.geturl()
+ if hasattr(f, 'url'):
+ newinv = f.url
if inv != newinv:
app.info('intersphinx inventory has moved: %s -> %s' % (inv, newinv))
if uri in (inv, path.dirname(inv), path.dirname(inv) + '/'):
uri = path.dirname(newinv)
- line = f.readline().rstrip().decode('utf-8')
- try:
- if line == '# Sphinx inventory version 1':
- invdata = read_inventory_v1(f, uri, join)
- elif line == '# Sphinx inventory version 2':
- invdata = read_inventory_v2(f, uri, join)
- else:
- raise ValueError
- f.close()
- except ValueError:
- f.close()
- raise ValueError('unknown or unsupported inventory version')
+ with f:
+ try:
+ join = localuri and path.join or posixpath.join
+ invdata = read_inventory(f, uri, join)
+ except ValueError:
+ raise ValueError('unknown or unsupported inventory version')
except Exception as err:
app.warn('intersphinx inventory %r not readable due to '
'%s: %s' % (inv, err.__class__.__name__, err))
@@ -394,6 +360,7 @@ def missing_reference(app, env, node, contnode):
def setup(app):
app.add_config_value('intersphinx_mapping', {}, True)
app.add_config_value('intersphinx_cache_limit', 5, False)
+ app.add_config_value('intersphinx_timeout', None, False)
app.connect('missing-reference', missing_reference)
app.connect('builder-inited', load_mappings)
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py
index f36e12fed..9981ffd3a 100644
--- a/sphinx/ext/jsmath.py
+++ b/sphinx/ext/jsmath.py
@@ -13,6 +13,7 @@
from docutils import nodes
import sphinx
+from sphinx.locale import _
from sphinx.application import ExtensionError
from sphinx.ext.mathbase import setup_math as mathbase_setup
@@ -34,8 +35,9 @@ def html_visit_displaymath(self, node):
if i == 0:
# necessary to e.g. set the id property correctly
if node['number']:
- self.body.append('<span class="eqno">(%s)</span>' %
- node['number'])
+ self.body.append('<span class="eqno">(%s)' % node['number'])
+ self.add_permalink_ref(node, _('Permalink to this equation'))
+ self.body.append('</span>')
self.body.append(self.starttag(node, 'div', CLASS='math'))
else:
# but only once!
diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py
index 430813a64..ae4b439b7 100644
--- a/sphinx/ext/mathbase.py
+++ b/sphinx/ext/mathbase.py
@@ -12,7 +12,10 @@
from docutils import nodes, utils
from docutils.parsers.rst import directives
-from sphinx.util.nodes import set_source_info
+from sphinx.roles import XRefRole
+from sphinx.locale import _
+from sphinx.domains import Domain
+from sphinx.util.nodes import make_refnode, set_source_info
from sphinx.util.compat import Directive
@@ -28,6 +31,76 @@ class eqref(nodes.Inline, nodes.TextElement):
pass
+class EqXRefRole(XRefRole):
+ def result_nodes(self, document, env, node, is_ref):
+ node['refdomain'] = 'math'
+ return [node], []
+
+
+class MathDomain(Domain):
+ """Mathematics domain."""
+ name = 'math'
+ label = 'mathematics'
+
+ initial_data = {
+ 'objects': {}, # labelid -> (docname, eqno)
+ }
+ dangling_warnings = {
+ 'eq': 'equation not found: %(target)s',
+ }
+
+ def clear_doc(self, docname):
+ for labelid, (doc, eqno) in list(self.data['objects'].items()):
+ if doc == docname:
+ del self.data['objects'][labelid]
+
+ def merge_domaindata(self, docnames, otherdata):
+ for labelid, (doc, eqno) in otherdata['objects'].items():
+ if doc in docnames:
+ self.data['objects'][labelid] = doc
+
+ def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
+ assert typ == 'eq'
+ docname, number = self.data['objects'].get(target, (None, None))
+ if docname:
+ if builder.name == 'latex':
+ newnode = eqref('', **node.attributes)
+ newnode['docname'] = docname
+ newnode['target'] = target
+ return newnode
+ else:
+ title = nodes.Text("(%d)" % number)
+ return make_refnode(builder, fromdocname, docname,
+ "equation-" + target, title)
+ else:
+ return None
+
+ def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
+ refnode = self.resolve_xref(env, fromdocname, builder, 'eq', target, node, contnode)
+ if refnode is None:
+ return []
+ else:
+ return [refnode]
+
+ def get_objects(self):
+ return []
+
+ def add_equation(self, env, docname, labelid):
+ equations = self.data['objects']
+ if labelid in equations:
+ path = env.doc2path(equations[labelid][0])
+ msg = _('duplicate label of equation %s, other instance in %s') % (labelid, path)
+ raise UserWarning(msg)
+ else:
+ eqno = self.get_next_equation_number(docname)
+ equations[labelid] = (docname, eqno)
+ return eqno
+
+ def get_next_equation_number(self, docname):
+ targets = [eq for eq in self.data['objects'].values() if eq[0] == docname]
+ return len(targets) + 1
+
+
def wrap_displaymath(math, label, numbering):
def is_equation(part):
return part.strip()
@@ -68,13 +141,6 @@ def math_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
return [math(latex=latex)], []
-def eq_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
- text = utils.unescape(text)
- node = eqref('(?)', '(?)', target=text)
- node['docname'] = inliner.document.settings.env.docname
- return [node], []
-
-
def is_in_section_title(node):
"""Determine whether the node is in a section title"""
from sphinx.util.nodes import traverse_parent
@@ -104,21 +170,47 @@ class MathDirective(Directive):
latex = self.arguments[0] + '\n\n' + latex
node = displaymath()
node['latex'] = latex
- node['label'] = self.options.get('name', None)
- if node['label'] is None:
- node['label'] = self.options.get('label', None)
+ node['number'] = None
+ node['label'] = None
+ if 'name' in self.options:
+ node['label'] = self.options['name']
+ if 'label' in self.options:
+ node['label'] = self.options['label']
node['nowrap'] = 'nowrap' in self.options
node['docname'] = self.state.document.settings.env.docname
ret = [node]
set_source_info(self, node)
if hasattr(self, 'src'):
node.source = self.src
- if node['label']:
- tnode = nodes.target('', '', ids=['equation-' + node['label']])
- self.state.document.note_explicit_target(tnode)
- ret.insert(0, tnode)
+ self.add_target(ret)
return ret
+ def add_target(self, ret):
+ node = ret[0]
+ env = self.state.document.settings.env
+
+ # assign label automatically if math_number_all enabled
+ if node['label'] == '' or (env.config.math_number_all and not node['label']):
+ seq = env.new_serialno('sphinx.ext.math#equations')
+ node['label'] = "%s:%d" % (env.docname, seq)
+
+ # no targets and numbers are needed
+ if not node['label']:
+ return
+
+ # register label to domain
+ domain = env.get_domain('math')
+ try:
+ eqno = domain.add_equation(env, env.docname, node['label'])
+ node['number'] = eqno
+
+ # add target node
+ target = nodes.target('', '', ids=['equation-' + node['label']])
+ self.state.document.note_explicit_target(target)
+ ret.insert(0, target)
+ except UserWarning as exc:
+ self.state_machine.reporter.warning(exc.args[0], line=self.lineno)
+
def latex_visit_math(self, node):
if is_in_section_title(node):
@@ -131,7 +223,11 @@ def latex_visit_math(self, node):
def latex_visit_displaymath(self, node):
- label = node['label'] and node['docname'] + '-' + node['label'] or None
+ if not node['label']:
+ label = None
+ else:
+ label = "equation:%s:%s" % (node['docname'], node['label'])
+
if node['nowrap']:
if label:
self.body.append(r'\label{%s}' % label)
@@ -143,7 +239,8 @@ def latex_visit_displaymath(self, node):
def latex_visit_eqref(self, node):
- self.body.append('\\eqref{%s-%s}' % (node['docname'], node['target']))
+ label = "equation:%s:%s" % (node['docname'], node['target'])
+ self.body.append('\\eqref{%s}' % label)
raise nodes.SkipNode
@@ -159,11 +256,6 @@ def text_visit_displaymath(self, node):
raise nodes.SkipNode
-def text_visit_eqref(self, node):
- self.add_text(node['target'])
- raise nodes.SkipNode
-
-
def man_visit_math(self, node):
self.body.append(node['latex'])
raise nodes.SkipNode
@@ -177,11 +269,6 @@ def man_depart_displaymath(self, node):
self.depart_centered(node)
-def man_visit_eqref(self, node):
- self.body.append(node['target'])
- raise nodes.SkipNode
-
-
def texinfo_visit_math(self, node):
self.body.append('@math{' + self.escape_arg(node['latex']) + '}')
raise nodes.SkipNode
@@ -198,40 +285,9 @@ def texinfo_depart_displaymath(self, node):
pass
-def texinfo_visit_eqref(self, node):
- self.add_xref(node['docname'] + ':' + node['target'],
- node['target'], node)
- raise nodes.SkipNode
-
-
-def html_visit_eqref(self, node):
- self.body.append('<a href="#equation-%s">' % node['target'])
-
-
-def html_depart_eqref(self, node):
- self.body.append('</a>')
-
-
-def number_equations(app, doctree, docname):
- num = 0
- numbers = {}
- for node in doctree.traverse(displaymath):
- if node['label'] is not None or app.config.math_number_all:
- num += 1
- node['number'] = num
- if node['label'] is not None:
- numbers[node['label']] = num
- else:
- node['number'] = None
- for node in doctree.traverse(eqref):
- if node['target'] not in numbers:
- continue
- num = '(%d)' % numbers[node['target']]
- node[0] = nodes.Text(num, num)
-
-
def setup_math(app, htmlinlinevisitors, htmldisplayvisitors):
- app.add_config_value('math_number_all', False, 'html')
+ app.add_config_value('math_number_all', False, 'env')
+ app.add_domain(MathDomain)
app.add_node(math, override=True,
latex=(latex_visit_math, None),
text=(text_visit_math, None),
@@ -244,13 +300,7 @@ def setup_math(app, htmlinlinevisitors, htmldisplayvisitors):
man=(man_visit_displaymath, man_depart_displaymath),
texinfo=(texinfo_visit_displaymath, texinfo_depart_displaymath),
html=htmldisplayvisitors)
- app.add_node(eqref,
- latex=(latex_visit_eqref, None),
- text=(text_visit_eqref, None),
- man=(man_visit_eqref, None),
- texinfo=(texinfo_visit_eqref, None),
- html=(html_visit_eqref, html_depart_eqref))
+ app.add_node(eqref, latex=(latex_visit_eqref, None))
app.add_role('math', math_role)
- app.add_role('eq', eq_role)
+ app.add_role('eq', EqXRefRole(warn_dangling=True))
app.add_directive('math', MathDirective)
- app.connect('doctree-resolved', number_equations)
diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py
index bdaab55e0..2f414f4e7 100644
--- a/sphinx/ext/mathjax.py
+++ b/sphinx/ext/mathjax.py
@@ -14,6 +14,7 @@
from docutils import nodes
import sphinx
+from sphinx.locale import _
from sphinx.errors import ExtensionError
from sphinx.ext.mathbase import setup_math as mathbase_setup
@@ -35,7 +36,9 @@ def html_visit_displaymath(self, node):
# necessary to e.g. set the id property correctly
if node['number']:
- self.body.append('<span class="eqno">(%s)</span>' % node['number'])
+ self.body.append('<span class="eqno">(%s)' % node['number'])
+ self.add_permalink_ref(node, _('Permalink to this equation'))
+ self.body.append('</span>')
self.body.append(self.builder.config.mathjax_display[0])
parts = [prt for prt in node['latex'].split('\n\n') if prt.strip()]
if len(parts) > 1: # Add alignment if there are more than 1 equation
diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py
index 85c8acec8..651355c57 100644
--- a/sphinx/ext/napoleon/__init__.py
+++ b/sphinx/ext/napoleon/__init__.py
@@ -33,6 +33,7 @@ class Config(object):
# Napoleon settings
napoleon_google_docstring = True
napoleon_numpy_docstring = True
+ napoleon_include_init_with_doc = False
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = False
napoleon_use_admonition_for_examples = False
@@ -41,6 +42,7 @@ class Config(object):
napoleon_use_ivar = False
napoleon_use_param = True
napoleon_use_rtype = True
+ napoleon_use_keyword = True
.. _Google style:
http://google.github.io/styleguide/pyguide.html
@@ -49,13 +51,29 @@ class Config(object):
Attributes
----------
- napoleon_google_docstring : bool, defaults to True
+ napoleon_google_docstring : :obj:`bool` (Defaults to True)
True to parse `Google style`_ docstrings. False to disable support
for Google style docstrings.
- napoleon_numpy_docstring : bool, defaults to True
+ napoleon_numpy_docstring : :obj:`bool` (Defaults to True)
True to parse `NumPy style`_ docstrings. False to disable support
for NumPy style docstrings.
- napoleon_include_private_with_doc : bool, defaults to False
+ napoleon_include_init_with_doc : :obj:`bool` (Defaults to False)
+ True to list ``__init___`` docstrings separately from the class
+ docstring. False to fall back to Sphinx's default behavior, which
+ considers the ``__init___`` docstring as part of the class
+ documentation.
+
+ **If True**::
+
+ def __init__(self):
+ \"\"\"
+ This will be included in the docs because it has a docstring
+ \"\"\"
+
+ def __init__(self):
+ # This will NOT be included in the docs
+
+ napoleon_include_private_with_doc : :obj:`bool` (Defaults to False)
True to include private members (like ``_membername``) with docstrings
in the documentation. False to fall back to Sphinx's default behavior.
@@ -71,7 +89,7 @@ class Config(object):
# This will NOT be included in the docs
pass
- napoleon_include_special_with_doc : bool, defaults to False
+ napoleon_include_special_with_doc : :obj:`bool` (Defaults to False)
True to include special members (like ``__membername__``) with
docstrings in the documentation. False to fall back to Sphinx's
default behavior.
@@ -88,7 +106,7 @@ class Config(object):
# This will NOT be included in the docs
return unicode(self.__class__.__name__)
- napoleon_use_admonition_for_examples : bool, defaults to False
+ napoleon_use_admonition_for_examples : :obj:`bool` (Defaults to False)
True to use the ``.. admonition::`` directive for the **Example** and
**Examples** sections. False to use the ``.. rubric::`` directive
instead. One may look better than the other depending on what HTML
@@ -112,7 +130,7 @@ class Config(object):
This is just a quick example
- napoleon_use_admonition_for_notes : bool, defaults to False
+ napoleon_use_admonition_for_notes : :obj:`bool` (Defaults to False)
True to use the ``.. admonition::`` directive for **Notes** sections.
False to use the ``.. rubric::`` directive instead.
@@ -125,7 +143,7 @@ class Config(object):
--------
:attr:`napoleon_use_admonition_for_examples`
- napoleon_use_admonition_for_references : bool, defaults to False
+ napoleon_use_admonition_for_references : :obj:`bool` (Defaults to False)
True to use the ``.. admonition::`` directive for **References**
sections. False to use the ``.. rubric::`` directive instead.
@@ -133,7 +151,7 @@ class Config(object):
--------
:attr:`napoleon_use_admonition_for_examples`
- napoleon_use_ivar : bool, defaults to False
+ napoleon_use_ivar : :obj:`bool` (Defaults to False)
True to use the ``:ivar:`` role for instance variables. False to use
the ``.. attribute::`` directive instead.
@@ -157,7 +175,7 @@ class Config(object):
Description of `attr1`
- napoleon_use_param : bool, defaults to True
+ napoleon_use_param : :obj:`bool` (Defaults to True)
True to use a ``:param:`` role for each function parameter. False to
use a single ``:parameters:`` role for all the parameters.
@@ -184,7 +202,22 @@ class Config(object):
* **arg2** (*int, optional*) --
Description of `arg2`, defaults to 0
- napoleon_use_rtype : bool, defaults to True
+ napoleon_use_keyword : :obj:`bool` (Defaults to True)
+ True to use a ``:keyword:`` role for each function keyword argument.
+ False to use a single ``:keyword arguments:`` role for all the
+ keywords.
+
+ This behaves similarly to :attr:`napoleon_use_param`. Note unlike
+ docutils, ``:keyword:`` and ``:param:`` will not be treated the same
+ way - there will be a separate "Keyword Arguments" section, rendered
+ in the same fashion as "Parameters" section (type links created if
+ possible)
+
+ See Also
+ --------
+ :attr:`napoleon_use_param`
+
+ napoleon_use_rtype : :obj:`bool` (Defaults to True)
True to use the ``:rtype:`` role for the return type. False to output
the return type inline with the description.
@@ -208,6 +241,7 @@ class Config(object):
_config_values = {
'napoleon_google_docstring': (True, 'env'),
'napoleon_numpy_docstring': (True, 'env'),
+ 'napoleon_include_init_with_doc': (False, 'env'),
'napoleon_include_private_with_doc': (False, 'env'),
'napoleon_include_special_with_doc': (False, 'env'),
'napoleon_use_admonition_for_examples': (False, 'env'),
@@ -216,6 +250,7 @@ class Config(object):
'napoleon_use_ivar': (False, 'env'),
'napoleon_use_param': (True, 'env'),
'napoleon_use_rtype': (True, 'env'),
+ 'napoleon_use_keyword': (True, 'env')
}
def __init__(self, **settings):
@@ -251,6 +286,8 @@ def setup(app):
if not isinstance(app, Sphinx):
return # probably called by tests
+ _patch_python_domain()
+
app.connect('autodoc-process-docstring', _process_docstring)
app.connect('autodoc-skip-member', _skip_member)
@@ -259,6 +296,26 @@ def setup(app):
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
+def _patch_python_domain():
+ try:
+ from sphinx.domains.python import PyTypedField
+ except ImportError:
+ pass
+ else:
+ import sphinx.domains.python
+ import sphinx.locale
+ l_ = sphinx.locale.lazy_gettext
+ for doc_field in sphinx.domains.python.PyObject.doc_field_types:
+ if doc_field.name == 'parameter':
+ doc_field.names = ('param', 'parameter', 'arg', 'argument')
+ break
+ sphinx.domains.python.PyObject.doc_field_types.append(
+ PyTypedField('keyword', label=l_('Keyword Arguments'),
+ names=('keyword', 'kwarg', 'kwparam'),
+ typerolename='obj', typenames=('paramtype', 'kwtype'),
+ can_collapse=True))
+
+
def _process_docstring(app, what, name, obj, options, lines):
"""Process the docstring for a given python object.
@@ -311,8 +368,10 @@ def _skip_member(app, what, name, obj, skip, options):
"""Determine if private and special class members are included in docs.
The following settings in conf.py determine if private and special class
- members are included in the generated documentation:
+ members or init methods are included in the generated documentation:
+ * ``napoleon_include_init_with_doc`` --
+ include init methods if they have docstrings
* ``napoleon_include_private_with_doc`` --
include private members if they have docstrings
* ``napoleon_include_special_with_doc`` --
@@ -349,7 +408,7 @@ def _skip_member(app, what, name, obj, skip, options):
"""
has_doc = getattr(obj, '__doc__', False)
is_member = (what == 'class' or what == 'exception' or what == 'module')
- if name != '__weakref__' and name != '__init__' and has_doc and is_member:
+ if name != '__weakref__' and has_doc and is_member:
cls_is_owner = False
if what == 'class' or what == 'exception':
if PY2:
@@ -382,10 +441,16 @@ def _skip_member(app, what, name, obj, skip, options):
cls_is_owner = True
if what == 'module' or cls_is_owner:
- is_special = name.startswith('__') and name.endswith('__')
- is_private = not is_special and name.startswith('_')
+ is_init = (name == '__init__')
+ is_special = (not is_init and name.startswith('__') and
+ name.endswith('__'))
+ is_private = (not is_init and not is_special and
+ name.startswith('_'))
+ inc_init = app.config.napoleon_include_init_with_doc
inc_special = app.config.napoleon_include_special_with_doc
inc_private = app.config.napoleon_include_private_with_doc
- if (is_special and inc_special) or (is_private and inc_private):
+ if ((is_special and inc_special) or
+ (is_private and inc_private) or
+ (is_init and inc_init)):
return False
return skip
diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py
index 742a9fbba..e526a11ae 100644
--- a/sphinx/ext/napoleon/docstring.py
+++ b/sphinx/ext/napoleon/docstring.py
@@ -24,8 +24,9 @@ from sphinx.util.pycompat import UnicodeMixin
_directive_regex = re.compile(r'\.\. \S+::')
_google_section_regex = re.compile(r'^(\s|\w)+:\s*$')
-_google_typed_arg_regex = re.compile(r'\s*(.+?)\s*\(\s*(.+?)\s*\)')
+_google_typed_arg_regex = re.compile(r'\s*(.+?)\s*\(\s*(.*[^\s]+)\s*\)')
_numpy_section_regex = re.compile(r'^[=\-`:\'"~^_*+#<>]{2,}\s*$')
+_single_colon_regex = re.compile(r'(?<!:):(?!:)')
_xref_regex = re.compile(r'(:\w+:\S+:`.+?`|:\S+:`.+?`|`.+?`)')
_bullet_list_regex = re.compile(r'^(\*|\+|\-)(\s+\S|\s*$)')
_enumerated_list_regex = re.compile(
@@ -39,36 +40,34 @@ class GoogleDocstring(UnicodeMixin):
Parameters
----------
- docstring : str or List[str]
+ docstring : :obj:`str` or :obj:`list` of :obj:`str`
The docstring to parse, given either as a string or split into
individual lines.
- config : Optional[sphinx.ext.napoleon.Config or sphinx.config.Config]
+ config: :obj:`sphinx.ext.napoleon.Config` or :obj:`sphinx.config.Config`
The configuration settings to use. If not given, defaults to the
config object on `app`; or if `app` is not given defaults to the
- a new `sphinx.ext.napoleon.Config` object.
+ a new :class:`sphinx.ext.napoleon.Config` object.
- See Also
- --------
- :class:`sphinx.ext.napoleon.Config`
Other Parameters
----------------
- app : Optional[sphinx.application.Sphinx]
+ app : :class:`sphinx.application.Sphinx`, optional
Application object representing the Sphinx process.
- what : Optional[str]
+ what : :obj:`str`, optional
A string specifying the type of the object to which the docstring
belongs. Valid values: "module", "class", "exception", "function",
"method", "attribute".
- name : Optional[str]
+ name : :obj:`str`, optional
The fully qualified name of the object.
obj : module, class, exception, function, method, or attribute
The object to which the docstring belongs.
- options : Optional[sphinx.ext.autodoc.Options]
+ options : :class:`sphinx.ext.autodoc.Options`, optional
The options given to the directive: an object with attributes
inherited_members, undoc_members, show_inheritance and noindex that
are True if the flag option of same name was given to the auto
directive.
+
Example
-------
>>> from sphinx.ext.napoleon import Config
@@ -174,7 +173,7 @@ class GoogleDocstring(UnicodeMixin):
Returns
-------
- List[str]
+ list(str)
The lines of the docstring in a list.
"""
@@ -256,12 +255,7 @@ class GoogleDocstring(UnicodeMixin):
else:
_desc = lines[1:]
- match = _google_typed_arg_regex.match(before)
- if match:
- _name = match.group(1)
- _type = match.group(2)
- else:
- _type = before
+ _type = before
_desc = self.__class__(_desc, self._config).lines()
return [(_name, _type, _desc,)]
@@ -307,6 +301,19 @@ class GoogleDocstring(UnicodeMixin):
else:
return name
+ def _fix_field_desc(self, desc):
+ if self._is_list(desc):
+ desc = [''] + desc
+ elif desc[0].endswith('::'):
+ desc_block = desc[1:]
+ indent = self._get_indent(desc[0])
+ block_indent = self._get_initial_indent(desc_block)
+ if block_indent > indent:
+ desc = [''] + desc
+ else:
+ desc = ['', desc[0]] + self._indent(desc_block, 4)
+ return desc
+
def _format_admonition(self, admonition, lines):
lines = self._strip_empty(lines)
if len(lines) == 1:
@@ -333,6 +340,22 @@ class GoogleDocstring(UnicodeMixin):
else:
return [prefix]
+ def _format_docutils_params(self, fields, field_role='param',
+ type_role='type'):
+ lines = []
+ for _name, _type, _desc in fields:
+ _desc = self._strip_empty(_desc)
+ if any(_desc):
+ _desc = self._fix_field_desc(_desc)
+ field = ':%s %s: ' % (field_role, _name)
+ lines.extend(self._format_block(field, _desc))
+ else:
+ lines.append(':%s %s:' % (field_role, _name))
+
+ if _type:
+ lines.append(':%s %s: %s' % (type_role, _name, _type))
+ return lines + ['']
+
def _format_field(self, _name, _type, _desc):
_desc = self._strip_empty(_desc)
has_desc = any(_desc)
@@ -354,9 +377,11 @@ class GoogleDocstring(UnicodeMixin):
field = ''
if has_desc:
- if self._is_list(_desc):
- return [field, ''] + _desc
- return [field + _desc[0]] + _desc[1:]
+ _desc = self._fix_field_desc(_desc)
+ if _desc[0]:
+ return [field + _desc[0]] + _desc[1:]
+ else:
+ return [field] + _desc
else:
return [field]
@@ -393,6 +418,12 @@ class GoogleDocstring(UnicodeMixin):
return i
return len(line)
+ def _get_initial_indent(self, lines):
+ for line in lines:
+ if line:
+ return self._get_indent(line)
+ return 0
+
def _get_min_indent(self, lines):
min_indent = None
for line in lines:
@@ -527,7 +558,14 @@ class GoogleDocstring(UnicodeMixin):
return [header, '']
def _parse_keyword_arguments_section(self, section):
- return self._format_fields('Keyword Arguments', self._consume_fields())
+ fields = self._consume_fields()
+ if self._config.napoleon_use_keyword:
+ return self._format_docutils_params(
+ fields,
+ field_role="keyword",
+ type_role="kwtype")
+ else:
+ return self._format_fields('Keyword Arguments', fields)
def _parse_methods_section(self, section):
lines = []
@@ -552,21 +590,7 @@ class GoogleDocstring(UnicodeMixin):
def _parse_parameters_section(self, section):
fields = self._consume_fields()
if self._config.napoleon_use_param:
- lines = []
- for _name, _type, _desc in fields:
- _desc = self._strip_empty(_desc)
- if any(_desc):
- if self._is_list(_desc):
- _desc = [''] + _desc
- field = ':param %s: ' % _name
- lines.extend(self._format_block(field, _desc))
- else:
- lines.append(':param %s:' % _name)
-
- if _type:
- lines.append(':type %s: %s' % (_name, _type))
-
- return lines + ['']
+ return self._format_docutils_params(fields)
else:
return self._format_fields('Parameters', fields)
@@ -668,11 +692,12 @@ class GoogleDocstring(UnicodeMixin):
if found_colon:
after_colon.append(source)
else:
- if (i % 2) == 0 and ":" in source:
+ m = _single_colon_regex.search(source)
+ if (i % 2) == 0 and m:
found_colon = True
- before, colon, after = source.partition(":")
- before_colon.append(before)
- after_colon.append(after)
+ colon = source[m.start(): m.end()]
+ before_colon.append(source[:m.start()])
+ after_colon.append(source[m.end():])
else:
before_colon.append(source)
@@ -705,36 +730,34 @@ class NumpyDocstring(GoogleDocstring):
Parameters
----------
- docstring : str or List[str]
+ docstring : :obj:`str` or :obj:`list` of :obj:`str`
The docstring to parse, given either as a string or split into
individual lines.
- config : Optional[sphinx.ext.napoleon.Config or sphinx.config.Config]
+ config: :obj:`sphinx.ext.napoleon.Config` or :obj:`sphinx.config.Config`
The configuration settings to use. If not given, defaults to the
config object on `app`; or if `app` is not given defaults to the
- a new `sphinx.ext.napoleon.Config` object.
+ a new :class:`sphinx.ext.napoleon.Config` object.
- See Also
- --------
- :class:`sphinx.ext.napoleon.Config`
Other Parameters
----------------
- app : Optional[sphinx.application.Sphinx]
+ app : :class:`sphinx.application.Sphinx`, optional
Application object representing the Sphinx process.
- what : Optional[str]
+ what : :obj:`str`, optional
A string specifying the type of the object to which the docstring
belongs. Valid values: "module", "class", "exception", "function",
"method", "attribute".
- name : Optional[str]
+ name : :obj:`str`, optional
The fully qualified name of the object.
obj : module, class, exception, function, method, or attribute
The object to which the docstring belongs.
- options : Optional[sphinx.ext.autodoc.Options]
+ options : :class:`sphinx.ext.autodoc.Options`, optional
The options given to the directive: an object with attributes
inherited_members, undoc_members, show_inheritance and noindex that
are True if the flag option of same name was given to the auto
directive.
+
Example
-------
>>> from sphinx.ext.napoleon import Config
@@ -791,7 +814,7 @@ class NumpyDocstring(GoogleDocstring):
Returns
-------
- List[str]
+ list(str)
The lines of the docstring in a list.
"""
diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py
index a853ec93c..f3b526ce6 100644
--- a/sphinx/ext/todo.py
+++ b/sphinx/ext/todo.py
@@ -70,6 +70,8 @@ def process_todos(app, doctree):
if not hasattr(env, 'todo_all_todos'):
env.todo_all_todos = []
for node in doctree.traverse(todo_node):
+ app.emit('todo-defined', node)
+
try:
targetnode = node.parent[node.parent.index(node) - 1]
if not isinstance(targetnode, nodes.target):
@@ -86,6 +88,9 @@ def process_todos(app, doctree):
'target': targetnode,
})
+ if env.config.todo_emit_warnings:
+ env.warn_node("TODO entry found: %s" % node[1].astext(), node)
+
class TodoList(Directive):
"""
@@ -187,8 +192,10 @@ def depart_todo_node(self, node):
def setup(app):
+ app.add_event('todo-defined')
app.add_config_value('todo_include_todos', False, 'html')
app.add_config_value('todo_link_only', False, 'html')
+ app.add_config_value('todo_emit_warnings', False, 'html')
app.add_node(todolist)
app.add_node(todo_node,
diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py
index a071c5533..276a137d5 100644
--- a/sphinx/ext/viewcode.py
+++ b/sphinx/ext/viewcode.py
@@ -46,6 +46,10 @@ def doctree_read(app, doctree):
env = app.builder.env
if not hasattr(env, '_viewcode_modules'):
env._viewcode_modules = {}
+ if app.builder.name == "singlehtml":
+ return
+ if app.builder.name.startswith("epub") and not env.config.viewcode_enable_epub:
+ return
def has_tag(modname, fullname, docname, refname):
entry = env._viewcode_modules.get(modname, None)
@@ -215,6 +219,7 @@ def collect_pages(app):
def setup(app):
app.add_config_value('viewcode_import', True, False)
+ app.add_config_value('viewcode_enable_epub', False, False)
app.connect('doctree-read', doctree_read)
app.connect('env-merge-info', env_merge_info)
app.connect('html-collect-pages', collect_pages)
diff --git a/sphinx/io.py b/sphinx/io.py
index 56d133641..f1386c9a8 100644
--- a/sphinx/io.py
+++ b/sphinx/io.py
@@ -13,9 +13,15 @@ from docutils.readers import standalone
from docutils.writers import UnfilteredWriter
from six import string_types, text_type
-from sphinx.transforms import ApplySourceWorkaround, ExtraTranslatableNodes, Locale, \
- CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, \
- AutoNumbering, AutoIndexUpgrader, SortIds, RemoveTranslatableInline
+from sphinx.transforms import (
+ ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
+ DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds,
+ AutoNumbering, AutoIndexUpgrader, FilterSystemMessages,
+)
+from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform
+from sphinx.transforms.i18n import (
+ PreserveTranslatableMessages, Locale, RemoveTranslatableInline,
+)
from sphinx.util import import_object, split_docinfo
@@ -57,9 +63,11 @@ class SphinxStandaloneReader(SphinxBaseReader):
"""
Add our own transforms.
"""
- transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, Locale, CitationReferences,
- DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
- AutoNumbering, AutoIndexUpgrader, SortIds, RemoveTranslatableInline]
+ transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, PreserveTranslatableMessages,
+ Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets,
+ HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds,
+ RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages,
+ RefOnlyBulletListTransform]
class SphinxI18nReader(SphinxBaseReader):
@@ -72,7 +80,8 @@ class SphinxI18nReader(SphinxBaseReader):
transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
- AutoNumbering, SortIds, RemoveTranslatableInline]
+ AutoNumbering, SortIds, RemoveTranslatableInline,
+ FilterSystemMessages, RefOnlyBulletListTransform]
def __init__(self, *args, **kwargs):
SphinxBaseReader.__init__(self, *args, **kwargs)
@@ -112,10 +121,9 @@ class SphinxFileInput(FileInput):
return data.decode(self.encoding, 'sphinx') # py2: decoding
def read(self):
- def get_parser_type(docname):
- path = self.env.doc2path(docname)
+ def get_parser_type(source_path):
for suffix in self.env.config.source_parsers:
- if path.endswith(suffix):
+ if source_path.endswith(suffix):
parser_class = self.env.config.source_parsers[suffix]
if isinstance(parser_class, string_types):
parser_class = import_object(parser_class, 'source parser')
@@ -129,7 +137,7 @@ class SphinxFileInput(FileInput):
self.app.emit('source-read', self.env.docname, arg)
data = arg[0]
docinfo, data = split_docinfo(data)
- if 'restructuredtext' in get_parser_type(self.env.docname):
+ if 'restructuredtext' in get_parser_type(self.source_path):
if self.env.config.rst_epilog:
data = data + '\n' + self.env.config.rst_epilog + '\n'
if self.env.config.rst_prolog:
diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py
index df1aa490c..6e2ef7186 100644
--- a/sphinx/jinja2glue.py
+++ b/sphinx/jinja2glue.py
@@ -91,10 +91,8 @@ class SphinxFileSystemLoader(FileSystemLoader):
f = open_if_exists(filename)
if f is None:
continue
- try:
+ with f:
contents = f.read().decode(self.encoding)
- finally:
- f.close()
mtime = path.getmtime(filename)
diff --git a/sphinx/locale/sphinx.pot b/sphinx/locale/sphinx.pot
index 9707a65cc..f63434cc2 100644
--- a/sphinx/locale/sphinx.pot
+++ b/sphinx/locale/sphinx.pot
@@ -6,61 +6,42 @@
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: Sphinx 1.4b1\n"
+"Project-Id-Version: Sphinx 1.5b1\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2016-03-06 21:58+0900\n"
+"POT-Creation-Date: 2016-11-06 22:40+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 2.2.0\n"
+"Generated-By: Babel 2.3.4\n"
-#: sphinx/config.py:91
+#: sphinx/config.py:109
#, python-format
-msgid "Fig. %s"
-msgstr ""
-
-#: sphinx/config.py:92
-#, python-format
-msgid "Table %s"
-msgstr ""
-
-#: sphinx/config.py:93
-#, python-format
-msgid "Listing %s"
+msgid "Section %s"
msgstr ""
-#: sphinx/config.py:100
+#: sphinx/config.py:110
#, python-format
-msgid "%s %s documentation"
+msgid "Fig. %s"
msgstr ""
-#: sphinx/environment.py:1829
+#: sphinx/config.py:111
#, python-format
-msgid "see %s"
+msgid "Table %s"
msgstr ""
-#: sphinx/environment.py:1833
+#: sphinx/config.py:112
#, python-format
-msgid "see also %s"
-msgstr ""
-
-#: sphinx/environment.py:1893
-msgid "Symbols"
+msgid "Listing %s"
msgstr ""
-#: sphinx/roles.py:193
+#: sphinx/roles.py:187
#, python-format
msgid "Python Enhancement Proposals; PEP %s"
msgstr ""
-#: sphinx/transforms.py:56 sphinx/writers/latex.py:374
-#: sphinx/writers/manpage.py:101 sphinx/writers/texinfo.py:222
-msgid "MMMM dd, YYYY"
-msgstr ""
-
#: sphinx/builders/changes.py:75
msgid "Builtins"
msgstr ""
@@ -69,8 +50,11 @@ msgstr ""
msgid "Module level"
msgstr ""
-#: sphinx/builders/html.py:295
-msgid "MMM dd, YYYY"
+#: sphinx/builders/html.py:294 sphinx/transforms/__init__.py:46
+#: sphinx/writers/latex.py:393 sphinx/writers/manpage.py:100
+#: sphinx/writers/texinfo.py:221
+#, python-format
+msgid "%b %d, %Y"
msgstr ""
#: sphinx/builders/html.py:315 sphinx/themes/basic/defindex.html:30
@@ -81,18 +65,28 @@ msgstr ""
msgid "index"
msgstr ""
-#: sphinx/builders/html.py:376
+#: sphinx/builders/html.py:377
msgid "next"
msgstr ""
-#: sphinx/builders/html.py:385
+#: sphinx/builders/html.py:386
msgid "previous"
msgstr ""
-#: sphinx/builders/latex.py:180 sphinx/builders/texinfo.py:199
+#: sphinx/builders/html.py:1222
+#, python-format
+msgid "%s %s documentation"
+msgstr ""
+
+#: sphinx/builders/latex.py:177 sphinx/builders/texinfo.py:199
msgid " (in "
msgstr ""
+#: sphinx/directives/code.py:140 sphinx/directives/code.py:370
+#, python-format
+msgid "Invalid caption: %s"
+msgstr ""
+
#: sphinx/directives/other.py:149
msgid "Section author: "
msgstr ""
@@ -109,23 +103,23 @@ msgstr ""
msgid "Author: "
msgstr ""
-#: sphinx/domains/__init__.py:275
+#: sphinx/domains/__init__.py:277
#, python-format
msgid "%s %s"
msgstr ""
-#: sphinx/domains/c.py:58 sphinx/domains/cpp.py:3605
-#: sphinx/domains/python.py:124
+#: sphinx/domains/c.py:58 sphinx/domains/cpp.py:4051
+#: sphinx/domains/python.py:149
msgid "Parameters"
msgstr ""
-#: sphinx/domains/c.py:61 sphinx/domains/cpp.py:3614
-#: sphinx/domains/javascript.py:128 sphinx/domains/python.py:136
+#: sphinx/domains/c.py:61 sphinx/domains/cpp.py:4060
+#: sphinx/domains/javascript.py:128 sphinx/domains/python.py:161
msgid "Returns"
msgstr ""
#: sphinx/domains/c.py:63 sphinx/domains/javascript.py:130
-#: sphinx/domains/python.py:138
+#: sphinx/domains/python.py:163
msgid "Return type"
msgstr ""
@@ -154,12 +148,12 @@ msgstr ""
msgid "%s (C variable)"
msgstr ""
-#: sphinx/domains/c.py:242 sphinx/domains/cpp.py:3953
-#: sphinx/domains/javascript.py:164 sphinx/domains/python.py:589
+#: sphinx/domains/c.py:242 sphinx/domains/cpp.py:4418
+#: sphinx/domains/javascript.py:164 sphinx/domains/python.py:614
msgid "function"
msgstr ""
-#: sphinx/domains/c.py:243 sphinx/domains/cpp.py:3954
+#: sphinx/domains/c.py:243 sphinx/domains/cpp.py:4419
msgid "member"
msgstr ""
@@ -167,7 +161,7 @@ msgstr ""
msgid "macro"
msgstr ""
-#: sphinx/domains/c.py:245 sphinx/domains/cpp.py:3955
+#: sphinx/domains/c.py:245 sphinx/domains/cpp.py:4420
msgid "type"
msgstr ""
@@ -175,63 +169,72 @@ msgstr ""
msgid "variable"
msgstr ""
-#: sphinx/domains/cpp.py:3608
+#: sphinx/domains/cpp.py:4054
msgid "Template Parameters"
msgstr ""
-#: sphinx/domains/cpp.py:3611 sphinx/domains/javascript.py:125
+#: sphinx/domains/cpp.py:4057 sphinx/domains/javascript.py:125
msgid "Throws"
msgstr ""
-#: sphinx/domains/cpp.py:3733
+#: sphinx/domains/cpp.py:4205
#, python-format
msgid "%s (C++ type)"
msgstr ""
-#: sphinx/domains/cpp.py:3744
+#: sphinx/domains/cpp.py:4216
+#, python-format
+msgid "%s (C++ concept)"
+msgstr ""
+
+#: sphinx/domains/cpp.py:4227
#, python-format
msgid "%s (C++ member)"
msgstr ""
-#: sphinx/domains/cpp.py:3755
+#: sphinx/domains/cpp.py:4238
#, python-format
msgid "%s (C++ function)"
msgstr ""
-#: sphinx/domains/cpp.py:3766
+#: sphinx/domains/cpp.py:4249
#, python-format
msgid "%s (C++ class)"
msgstr ""
-#: sphinx/domains/cpp.py:3786
+#: sphinx/domains/cpp.py:4260
#, python-format
msgid "%s (C++ enum)"
msgstr ""
-#: sphinx/domains/cpp.py:3816
+#: sphinx/domains/cpp.py:4281
#, python-format
msgid "%s (C++ enumerator)"
msgstr ""
-#: sphinx/domains/cpp.py:3952 sphinx/domains/javascript.py:165
-#: sphinx/domains/python.py:591
+#: sphinx/domains/cpp.py:4417 sphinx/domains/javascript.py:165
+#: sphinx/domains/python.py:616
msgid "class"
msgstr ""
-#: sphinx/domains/cpp.py:3956
+#: sphinx/domains/cpp.py:4421
+msgid "concept"
+msgstr ""
+
+#: sphinx/domains/cpp.py:4422
msgid "enum"
msgstr ""
-#: sphinx/domains/cpp.py:3957
+#: sphinx/domains/cpp.py:4423
msgid "enumerator"
msgstr ""
-#: sphinx/domains/javascript.py:106 sphinx/domains/python.py:282
+#: sphinx/domains/javascript.py:106 sphinx/domains/python.py:307
#, python-format
msgid "%s() (built-in function)"
msgstr ""
-#: sphinx/domains/javascript.py:107 sphinx/domains/python.py:346
+#: sphinx/domains/javascript.py:107 sphinx/domains/python.py:371
#, python-format
msgid "%s() (%s method)"
msgstr ""
@@ -246,7 +249,7 @@ msgstr ""
msgid "%s (global variable or constant)"
msgstr ""
-#: sphinx/domains/javascript.py:113 sphinx/domains/python.py:384
+#: sphinx/domains/javascript.py:113 sphinx/domains/python.py:409
#, python-format
msgid "%s (%s attribute)"
msgstr ""
@@ -255,116 +258,116 @@ msgstr ""
msgid "Arguments"
msgstr ""
-#: sphinx/domains/javascript.py:166 sphinx/domains/python.py:590
+#: sphinx/domains/javascript.py:166 sphinx/domains/python.py:615
msgid "data"
msgstr ""
-#: sphinx/domains/javascript.py:167 sphinx/domains/python.py:596
+#: sphinx/domains/javascript.py:167 sphinx/domains/python.py:621
msgid "attribute"
msgstr ""
-#: sphinx/domains/python.py:129
+#: sphinx/domains/python.py:154
msgid "Variables"
msgstr ""
-#: sphinx/domains/python.py:133
+#: sphinx/domains/python.py:158
msgid "Raises"
msgstr ""
-#: sphinx/domains/python.py:283 sphinx/domains/python.py:340
-#: sphinx/domains/python.py:352 sphinx/domains/python.py:365
+#: sphinx/domains/python.py:308 sphinx/domains/python.py:365
+#: sphinx/domains/python.py:377 sphinx/domains/python.py:390
#, python-format
msgid "%s() (in module %s)"
msgstr ""
-#: sphinx/domains/python.py:286
+#: sphinx/domains/python.py:311
#, python-format
msgid "%s (built-in variable)"
msgstr ""
-#: sphinx/domains/python.py:287 sphinx/domains/python.py:378
+#: sphinx/domains/python.py:312 sphinx/domains/python.py:403
#, python-format
msgid "%s (in module %s)"
msgstr ""
-#: sphinx/domains/python.py:303
+#: sphinx/domains/python.py:328
#, python-format
msgid "%s (built-in class)"
msgstr ""
-#: sphinx/domains/python.py:304
+#: sphinx/domains/python.py:329
#, python-format
msgid "%s (class in %s)"
msgstr ""
-#: sphinx/domains/python.py:344
+#: sphinx/domains/python.py:369
#, python-format
msgid "%s() (%s.%s method)"
msgstr ""
-#: sphinx/domains/python.py:356
+#: sphinx/domains/python.py:381
#, python-format
msgid "%s() (%s.%s static method)"
msgstr ""
-#: sphinx/domains/python.py:359
+#: sphinx/domains/python.py:384
#, python-format
msgid "%s() (%s static method)"
msgstr ""
-#: sphinx/domains/python.py:369
+#: sphinx/domains/python.py:394
#, python-format
msgid "%s() (%s.%s class method)"
msgstr ""
-#: sphinx/domains/python.py:372
+#: sphinx/domains/python.py:397
#, python-format
msgid "%s() (%s class method)"
msgstr ""
-#: sphinx/domains/python.py:382
+#: sphinx/domains/python.py:407
#, python-format
msgid "%s (%s.%s attribute)"
msgstr ""
-#: sphinx/domains/python.py:463
+#: sphinx/domains/python.py:488
#, python-format
msgid "%s (module)"
msgstr ""
-#: sphinx/domains/python.py:520
+#: sphinx/domains/python.py:545
msgid "Python Module Index"
msgstr ""
-#: sphinx/domains/python.py:521
+#: sphinx/domains/python.py:546
msgid "modules"
msgstr ""
-#: sphinx/domains/python.py:567
+#: sphinx/domains/python.py:592
msgid "Deprecated"
msgstr ""
-#: sphinx/domains/python.py:592 sphinx/locale/__init__.py:183
+#: sphinx/domains/python.py:617 sphinx/locale/__init__.py:183
msgid "exception"
msgstr ""
-#: sphinx/domains/python.py:593
+#: sphinx/domains/python.py:618
msgid "method"
msgstr ""
-#: sphinx/domains/python.py:594
+#: sphinx/domains/python.py:619
msgid "class method"
msgstr ""
-#: sphinx/domains/python.py:595
+#: sphinx/domains/python.py:620
msgid "static method"
msgstr ""
-#: sphinx/domains/python.py:597 sphinx/locale/__init__.py:179
+#: sphinx/domains/python.py:622 sphinx/locale/__init__.py:179
msgid "module"
msgstr ""
-#: sphinx/domains/python.py:762
+#: sphinx/domains/python.py:787
msgid " (deprecated)"
msgstr ""
@@ -386,120 +389,147 @@ msgstr ""
msgid "role"
msgstr ""
-#: sphinx/domains/std.py:73 sphinx/domains/std.py:89
+#: sphinx/domains/std.py:72 sphinx/domains/std.py:88
#, python-format
msgid "environment variable; %s"
msgstr ""
-#: sphinx/domains/std.py:185
+#: sphinx/domains/std.py:186
#, python-format
msgid "%scommand line option; %s"
msgstr ""
-#: sphinx/domains/std.py:433
+#: sphinx/domains/std.py:434
msgid "glossary term"
msgstr ""
-#: sphinx/domains/std.py:434
+#: sphinx/domains/std.py:435
msgid "grammar token"
msgstr ""
-#: sphinx/domains/std.py:435
+#: sphinx/domains/std.py:436
msgid "reference label"
msgstr ""
-#: sphinx/domains/std.py:437
+#: sphinx/domains/std.py:438
msgid "environment variable"
msgstr ""
-#: sphinx/domains/std.py:438
+#: sphinx/domains/std.py:439
msgid "program option"
msgstr ""
-#: sphinx/domains/std.py:471 sphinx/themes/basic/genindex-single.html:32
-#: sphinx/themes/basic/genindex-single.html:57
+#: sphinx/domains/std.py:473 sphinx/themes/basic/genindex-single.html:30
+#: sphinx/themes/basic/genindex-single.html:55
#: sphinx/themes/basic/genindex-split.html:11
#: sphinx/themes/basic/genindex-split.html:14
-#: sphinx/themes/basic/genindex.html:32 sphinx/themes/basic/genindex.html:35
-#: sphinx/themes/basic/genindex.html:68 sphinx/themes/basic/layout.html:134
-#: sphinx/writers/latex.py:363 sphinx/writers/texinfo.py:481
+#: sphinx/themes/basic/genindex.html:30 sphinx/themes/basic/genindex.html:33
+#: sphinx/themes/basic/genindex.html:66 sphinx/themes/basic/layout.html:135
+#: sphinx/writers/latex.py:381 sphinx/writers/texinfo.py:480
msgid "Index"
msgstr ""
-#: sphinx/domains/std.py:472
+#: sphinx/domains/std.py:474
msgid "Module Index"
msgstr ""
-#: sphinx/domains/std.py:473 sphinx/themes/basic/defindex.html:25
+#: sphinx/domains/std.py:475 sphinx/themes/basic/defindex.html:25
msgid "Search Page"
msgstr ""
-#: sphinx/ext/autodoc.py:1265
+#: sphinx/environment/managers/indexentries.py:104
+#, python-format
+msgid "see %s"
+msgstr ""
+
+#: sphinx/environment/managers/indexentries.py:108
+#, python-format
+msgid "see also %s"
+msgstr ""
+
+#: sphinx/environment/managers/indexentries.py:168
+msgid "Symbols"
+msgstr ""
+
+#: sphinx/ext/autodoc.py:1297
#, python-format
-msgid " Bases: %s"
+msgid "Bases: %s"
msgstr ""
-#: sphinx/ext/autodoc.py:1318
+#: sphinx/ext/autodoc.py:1350
#, python-format
msgid "alias of :class:`%s`"
msgstr ""
-#: sphinx/ext/graphviz.py:309 sphinx/ext/graphviz.py:318
+#: sphinx/ext/graphviz.py:331 sphinx/ext/graphviz.py:340
#, python-format
msgid "[graph: %s]"
msgstr ""
-#: sphinx/ext/graphviz.py:311 sphinx/ext/graphviz.py:320
+#: sphinx/ext/graphviz.py:333 sphinx/ext/graphviz.py:342
msgid "[graph]"
msgstr ""
-#: sphinx/ext/intersphinx.py:359
+#: sphinx/ext/imgmath.py:258 sphinx/ext/jsmath.py:39 sphinx/ext/mathjax.py:40
+msgid "Permalink to this equation"
+msgstr ""
+
+#: sphinx/ext/intersphinx.py:337
#, python-format
msgid "(in %s v%s)"
msgstr ""
-#: sphinx/ext/linkcode.py:69 sphinx/ext/viewcode.py:99
+#: sphinx/ext/linkcode.py:69 sphinx/ext/viewcode.py:103
msgid "[source]"
msgstr ""
+#: sphinx/ext/mathbase.py:92
+#, python-format
+msgid "duplicate label of equation %s, other instance in %s"
+msgstr ""
+
#: sphinx/ext/todo.py:56
msgid "Todo"
msgstr ""
-#: sphinx/ext/todo.py:129
+#: sphinx/ext/todo.py:134
msgid "<<original entry>>"
msgstr ""
-#: sphinx/ext/todo.py:132
+#: sphinx/ext/todo.py:137
#, python-format
msgid "(The <<original entry>> is located in %s, line %d.)"
msgstr ""
-#: sphinx/ext/todo.py:141
+#: sphinx/ext/todo.py:146
msgid "original entry"
msgstr ""
-#: sphinx/ext/viewcode.py:162
+#: sphinx/ext/viewcode.py:166
msgid "[docs]"
msgstr ""
-#: sphinx/ext/viewcode.py:176
+#: sphinx/ext/viewcode.py:180
msgid "Module code"
msgstr ""
-#: sphinx/ext/viewcode.py:182
+#: sphinx/ext/viewcode.py:186
#, python-format
msgid "<h1>Source code for %s</h1>"
msgstr ""
-#: sphinx/ext/viewcode.py:208
+#: sphinx/ext/viewcode.py:212
msgid "Overview: module code"
msgstr ""
-#: sphinx/ext/viewcode.py:209
+#: sphinx/ext/viewcode.py:213
msgid "<h1>All modules for which code is available</h1>"
msgstr ""
+#: sphinx/ext/napoleon/__init__.py:313
+msgid "Keyword Arguments"
+msgstr ""
+
#: sphinx/locale/__init__.py:159
msgid "Attention"
msgstr ""
@@ -580,7 +610,7 @@ msgstr ""
msgid "Table Of Contents"
msgstr ""
-#: sphinx/themes/agogo/layout.html:51 sphinx/themes/basic/layout.html:137
+#: sphinx/themes/agogo/layout.html:51 sphinx/themes/basic/layout.html:138
#: sphinx/themes/basic/search.html:11 sphinx/themes/basic/search.html:23
#: sphinx/themes/basic/searchresults.html:10
msgid "Search"
@@ -638,15 +668,15 @@ msgstr ""
msgid "all functions, classes, terms"
msgstr ""
-#: sphinx/themes/basic/genindex-single.html:35
+#: sphinx/themes/basic/genindex-single.html:33
#, python-format
msgid "Index &ndash; %(key)s"
msgstr ""
-#: sphinx/themes/basic/genindex-single.html:63
+#: sphinx/themes/basic/genindex-single.html:61
#: sphinx/themes/basic/genindex-split.html:24
#: sphinx/themes/basic/genindex-split.html:38
-#: sphinx/themes/basic/genindex.html:74
+#: sphinx/themes/basic/genindex.html:72
msgid "Full index on one page"
msgstr ""
@@ -662,35 +692,35 @@ msgstr ""
msgid "Navigation"
msgstr ""
-#: sphinx/themes/basic/layout.html:122
+#: sphinx/themes/basic/layout.html:123
#, python-format
msgid "Search within %(docstitle)s"
msgstr ""
-#: sphinx/themes/basic/layout.html:131
+#: sphinx/themes/basic/layout.html:132
msgid "About these documents"
msgstr ""
-#: sphinx/themes/basic/layout.html:140
+#: sphinx/themes/basic/layout.html:141
msgid "Copyright"
msgstr ""
-#: sphinx/themes/basic/layout.html:189
+#: sphinx/themes/basic/layout.html:186
#, python-format
-msgid "&copy; <a href=\"%(path)s\">Copyright</a> %(copyright)s."
+msgid "&#169; <a href=\"%(path)s\">Copyright</a> %(copyright)s."
msgstr ""
-#: sphinx/themes/basic/layout.html:191
+#: sphinx/themes/basic/layout.html:188
#, python-format
-msgid "&copy; Copyright %(copyright)s."
+msgid "&#169; Copyright %(copyright)s."
msgstr ""
-#: sphinx/themes/basic/layout.html:195
+#: sphinx/themes/basic/layout.html:192
#, python-format
msgid "Last updated on %(last_updated)s."
msgstr ""
-#: sphinx/themes/basic/layout.html:198
+#: sphinx/themes/basic/layout.html:195
#, python-format
msgid ""
"Created using <a href=\"http://sphinx-doc.org/\">Sphinx</a> "
@@ -737,12 +767,12 @@ msgid "search"
msgstr ""
#: sphinx/themes/basic/search.html:43 sphinx/themes/basic/searchresults.html:21
-#: sphinx/themes/basic/static/searchtools.js_t:282
+#: sphinx/themes/basic/static/searchtools.js_t:287
msgid "Search Results"
msgstr ""
#: sphinx/themes/basic/search.html:45 sphinx/themes/basic/searchresults.html:23
-#: sphinx/themes/basic/static/searchtools.js_t:284
+#: sphinx/themes/basic/static/searchtools.js_t:289
msgid ""
"Your search did not match any documents. Please make sure that all words "
"are spelled correctly and that you've selected enough categories."
@@ -759,12 +789,12 @@ msgstr ""
#: sphinx/themes/basic/changes/frameset.html:5
#: sphinx/themes/basic/changes/versionchanges.html:12
#, python-format
-msgid "Changes in Version %(version)s &mdash; %(docstitle)s"
+msgid "Changes in Version %(version)s &#8212; %(docstitle)s"
msgstr ""
#: sphinx/themes/basic/changes/rstsource.html:5
#, python-format
-msgid "%(filename)s &mdash; %(docstitle)s"
+msgid "%(filename)s &#8212; %(docstitle)s"
msgstr ""
#: sphinx/themes/basic/changes/versionchanges.html:17
@@ -784,12 +814,13 @@ msgstr ""
msgid "Other changes"
msgstr ""
-#: sphinx/themes/basic/static/doctools.js_t:169 sphinx/writers/html.py:668
-#: sphinx/writers/html.py:673
+#: sphinx/themes/basic/static/doctools.js_t:169 sphinx/writers/html.py:708
+#: sphinx/writers/html.py:713
msgid "Permalink to this headline"
msgstr ""
-#: sphinx/themes/basic/static/doctools.js_t:175 sphinx/writers/html.py:105
+#: sphinx/themes/basic/static/doctools.js_t:175 sphinx/writers/html.py:108
+#: sphinx/writers/html.py:117
msgid "Permalink to this definition"
msgstr ""
@@ -805,12 +836,12 @@ msgstr ""
msgid "Preparing search..."
msgstr ""
-#: sphinx/themes/basic/static/searchtools.js_t:286
+#: sphinx/themes/basic/static/searchtools.js_t:291
#, python-format
msgid "Search finished, found %s page(s) matching the search query."
msgstr ""
-#: sphinx/themes/basic/static/searchtools.js_t:338
+#: sphinx/themes/basic/static/searchtools.js_t:344
msgid ", in "
msgstr ""
@@ -827,49 +858,54 @@ msgstr ""
msgid "Contents"
msgstr ""
-#: sphinx/writers/html.py:349
+#: sphinx/writers/html.py:389
msgid "Permalink to this code"
msgstr ""
-#: sphinx/writers/html.py:353
+#: sphinx/writers/html.py:393
msgid "Permalink to this image"
msgstr ""
-#: sphinx/writers/html.py:355
+#: sphinx/writers/html.py:395
msgid "Permalink to this toctree"
msgstr ""
-#: sphinx/writers/html.py:677
+#: sphinx/writers/html.py:717
msgid "Permalink to this table"
msgstr ""
-#: sphinx/writers/latex.py:361
+#: sphinx/writers/latex.py:380
msgid "Release"
msgstr ""
-#: sphinx/writers/latex.py:427
+#: sphinx/writers/latex.py:483
msgid "page"
msgstr ""
-#: sphinx/writers/latex.py:920 sphinx/writers/manpage.py:233
-#: sphinx/writers/texinfo.py:620
+#: sphinx/writers/latex.py:528
+#, python-format
+msgid "Unknown configure key: latex_elements[%r] is ignored."
+msgstr ""
+
+#: sphinx/writers/latex.py:1003 sphinx/writers/manpage.py:238
+#: sphinx/writers/texinfo.py:619
msgid "Footnotes"
msgstr ""
-#: sphinx/writers/latex.py:1022
+#: sphinx/writers/latex.py:1112
msgid "continued from previous page"
msgstr ""
-#: sphinx/writers/latex.py:1028
+#: sphinx/writers/latex.py:1118
msgid "Continued on next page"
msgstr ""
-#: sphinx/writers/manpage.py:282 sphinx/writers/text.py:582
+#: sphinx/writers/manpage.py:287 sphinx/writers/text.py:591
#, python-format
msgid "[image: %s]"
msgstr ""
-#: sphinx/writers/manpage.py:283 sphinx/writers/text.py:583
+#: sphinx/writers/manpage.py:288 sphinx/writers/text.py:592
msgid "[image]"
msgstr ""
diff --git a/sphinx/make_mode.py b/sphinx/make_mode.py
index 75c5ab8b2..28316458e 100644
--- a/sphinx/make_mode.py
+++ b/sphinx/make_mode.py
@@ -29,30 +29,30 @@ proj_name = os.getenv('SPHINXPROJ', '<project>')
BUILDERS = [
- ("", "html", "to make standalone HTML files"),
- ("", "dirhtml", "to make HTML files named index.html in directories"),
- ("", "singlehtml", "to make a single large HTML file"),
- ("", "pickle", "to make pickle files"),
- ("", "json", "to make JSON files"),
- ("", "htmlhelp", "to make HTML files and a HTML help project"),
- ("", "qthelp", "to make HTML files and a qthelp project"),
- ("", "devhelp", "to make HTML files and a Devhelp project"),
- ("", "epub", "to make an epub"),
- ("", "latex", "to make LaTeX files, you can set PAPER=a4 or PAPER=letter"),
- ("posix", "latexpdf", "to make LaTeX files and run them through pdflatex"),
- ("posix", "latexpdfja", "to make LaTeX files and run them through platex/dvipdfmx"),
- ("", "text", "to make text files"),
- ("", "man", "to make manual pages"),
- ("", "texinfo", "to make Texinfo files"),
- ("posix", "info", "to make Texinfo files and run them through makeinfo"),
- ("", "gettext", "to make PO message catalogs"),
- ("", "changes", "to make an overview of all changed/added/deprecated items"),
- ("", "xml", "to make Docutils-native XML files"),
- ("", "pseudoxml", "to make pseudoxml-XML files for display purposes"),
- ("", "linkcheck", "to check all external links for integrity"),
- ("", "doctest", "to run all doctests embedded in the documentation "
- "(if enabled)"),
- ("", "coverage", "to run coverage check of the documentation (if enabled)"),
+ ("", "html", "to make standalone HTML files"),
+ ("", "dirhtml", "to make HTML files named index.html in directories"),
+ ("", "singlehtml", "to make a single large HTML file"),
+ ("", "pickle", "to make pickle files"),
+ ("", "json", "to make JSON files"),
+ ("", "htmlhelp", "to make HTML files and an HTML help project"),
+ ("", "qthelp", "to make HTML files and a qthelp project"),
+ ("", "devhelp", "to make HTML files and a Devhelp project"),
+ ("", "epub", "to make an epub"),
+ ("", "latex", "to make LaTeX files, you can set PAPER=a4 or PAPER=letter"),
+ ("posix", "latexpdf", "to make LaTeX and PDF files (default pdflatex)"),
+ ("posix", "latexpdfja", "to make LaTeX files and run them through platex/dvipdfmx"),
+ ("", "text", "to make text files"),
+ ("", "man", "to make manual pages"),
+ ("", "texinfo", "to make Texinfo files"),
+ ("posix", "info", "to make Texinfo files and run them through makeinfo"),
+ ("", "gettext", "to make PO message catalogs"),
+ ("", "changes", "to make an overview of all changed/added/deprecated items"),
+ ("", "xml", "to make Docutils-native XML files"),
+ ("", "pseudoxml", "to make pseudoxml-XML files for display purposes"),
+ ("", "linkcheck", "to check all external links for integrity"),
+ ("", "doctest", "to run all doctests embedded in the documentation "
+ "(if enabled)"),
+ ("", "coverage", "to run coverage check of the documentation (if enabled)"),
]
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index 7746e11b1..baf5c0068 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -33,7 +33,7 @@ pydriver = driver.Driver(pygrammar, convert=nodes.convert)
# an object with attributes corresponding to token and symbol names
-class sym:
+class sym(object):
pass
diff --git a/sphinx/pycode/pgen2/driver.py b/sphinx/pycode/pgen2/driver.py
index c531edb34..90476ed00 100644
--- a/sphinx/pycode/pgen2/driver.py
+++ b/sphinx/pycode/pgen2/driver.py
@@ -92,11 +92,8 @@ class Driver(object):
def parse_file(self, filename, debug=False):
"""Parse a file and return the syntax tree."""
- stream = open(filename)
- try:
+ with open(filename) as stream:
return self.parse_stream(stream, debug)
- finally:
- stream.close()
def parse_string(self, text, debug=False):
"""Parse a string and return the syntax tree."""
@@ -112,27 +109,36 @@ def generate_lines(text):
yield ""
-def load_grammar(gt="Grammar.txt", gp=None,
- save=True, force=False, logger=None):
+def get_compiled_path(filename):
+ head, tail = os.path.splitext(filename)
+ if tail == ".txt":
+ tail = ""
+ return "%s%s.pickle" % (head, tail)
+
+
+def compile_grammar(gt='Grammar.txt', logger=None):
+ """Compile the grammer."""
+ if logger is None:
+ logger = logging.getLogger()
+
+ logger.info("Generating grammar tables from %s", gt)
+ g = pgen.generate_grammar(gt)
+ gp = get_compiled_path(gt)
+ logger.info("Writing grammar tables to %s", gp)
+ try:
+ g.dump(gp)
+ except IOError as e:
+ logger.info("Writing failed:"+str(e))
+
+
+def load_grammar(gt="Grammar.txt", logger=None):
"""Load the grammar (maybe from a pickle)."""
if logger is None:
logger = logging.getLogger()
- if gp is None:
- head, tail = os.path.splitext(gt)
- if tail == ".txt":
- tail = ""
- # embed Sphinx major version for the case we ever change the grammar...
- gp = head + tail + "-sphinx" + \
- ".".join(map(str, sphinx.version_info[:2])) + ".pickle"
- if force or not _newer(gp, gt):
+ gp = get_compiled_path(gt)
+ if not os.path.exists(gp):
logger.info("Generating grammar tables from %s", gt)
g = pgen.generate_grammar(gt)
- if save:
- logger.info("Writing grammar tables to %s", gp)
- try:
- g.dump(gp)
- except IOError as e:
- logger.info("Writing failed:"+str(e))
else:
g = grammar.Grammar()
g.load(gp)
diff --git a/sphinx/pycode/pgen2/pgen.py b/sphinx/pycode/pgen2/pgen.py
index 85a1bcc4d..7598e6abc 100644
--- a/sphinx/pycode/pgen2/pgen.py
+++ b/sphinx/pycode/pgen2/pgen.py
@@ -4,10 +4,7 @@
from __future__ import print_function
from six import iteritems
-try:
- from collections import OrderedDict
-except ImportError: # Fallback for Python 2.6
- OrderedDict = dict
+from collections import OrderedDict
# Pgen imports
diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py
index 108e59352..3c7ab3d97 100644
--- a/sphinx/quickstart.py
+++ b/sphinx/quickstart.py
@@ -34,10 +34,11 @@ from six.moves import input
from six.moves.urllib.parse import quote as urlquote
from docutils.utils import column_width
-from sphinx import __display_version__
+from sphinx import __display_version__, package_dir
from sphinx.util.osutil import make_filename
from sphinx.util.console import purple, bold, red, turquoise, \
nocolor, color_terminal
+from sphinx.util.template import SphinxRenderer
from sphinx.util import texescape
TERM_ENCODING = getattr(sys.stdin, 'encoding', None)
@@ -65,1047 +66,6 @@ EXTENSIONS = ('autodoc', 'doctest', 'intersphinx', 'todo', 'coverage',
PROMPT_PREFIX = '> '
-if PY3:
- # prevents that the file is checked for being written in Python 2.x syntax
- QUICKSTART_CONF = u'#!/usr/bin/env python3\n'
-else:
- QUICKSTART_CONF = u''
-
-QUICKSTART_CONF += u'''\
-# -*- coding: utf-8 -*-
-#
-# %(project)s documentation build configuration file, created by
-# sphinx-quickstart on %(now)s.
-#
-# This file is execfile()d with the current directory set to its
-# containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# 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('.'))
-
-# -- General configuration ------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-#
-# needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
-extensions = [%(extensions)s]
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['%(dot)stemplates']
-
-# The suffix(es) of source filenames.
-# You can specify multiple suffix as a list of string:
-#
-# source_suffix = ['.rst', '.md']
-source_suffix = '%(suffix)s'
-
-# The encoding of source files.
-#
-# source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = '%(master_str)s'
-
-# General information about the project.
-project = u'%(project_str)s'
-copyright = u'%(copyright_str)s'
-author = u'%(author_str)s'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = u'%(version_str)s'
-# The full version, including alpha/beta/rc tags.
-release = u'%(release_str)s'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#
-# This is also used if you do content translation via gettext catalogs.
-# Usually you set "language" from the command line for these cases.
-language = %(language)r
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#
-# today = ''
-#
-# Else, today_fmt is used as the format for a strftime call.
-#
-# today_fmt = '%%B %%d, %%Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This patterns also effect to html_static_path and html_extra_path
-exclude_patterns = [%(exclude_patterns)s]
-
-# The reST default role (used for this markup: `text`) to use for all
-# documents.
-#
-# default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#
-# add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#
-# add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#
-# show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-# modindex_common_prefix = []
-
-# If true, keep warnings as "system message" paragraphs in the built documents.
-# keep_warnings = False
-
-# If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = %(ext_todo)s
-
-
-# -- Options for HTML output ----------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-#
-html_theme = 'alabaster'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#
-# html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-# html_theme_path = []
-
-# The name for this set of Sphinx documents.
-# "<project> v<release> documentation" by default.
-#
-# html_title = u'%(project_str)s v%(release_str)s'
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#
-# html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#
-# html_logo = None
-
-# The name of an image file (relative to this directory) to use as a favicon of
-# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#
-# html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['%(dot)sstatic']
-
-# Add any extra paths that contain custom files (such as robots.txt or
-# .htaccess) here, relative to this directory. These files are copied
-# directly to the root of the documentation.
-#
-# html_extra_path = []
-
-# If not None, a 'Last updated on:' timestamp is inserted at every page
-# bottom, using the given strftime format.
-# The empty string is equivalent to '%%b %%d, %%Y'.
-#
-# html_last_updated_fmt = None
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#
-# html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#
-# html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#
-# html_additional_pages = {}
-
-# If false, no module index is generated.
-#
-# html_domain_indices = True
-
-# If false, no index is generated.
-#
-# html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#
-# html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#
-# html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#
-# html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#
-# html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#
-# html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-# html_file_suffix = None
-
-# Language to be used for generating the HTML full-text search index.
-# Sphinx supports the following languages:
-# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
-# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
-#
-# html_search_language = 'en'
-
-# A dictionary with options for the search language support, empty by default.
-# 'ja' uses this config value.
-# 'zh' user can custom change `jieba` dictionary path.
-#
-# html_search_options = {'type': 'default'}
-
-# The name of a javascript file (relative to the configuration directory) that
-# implements a search results scorer. If empty, the default will be used.
-#
-# html_search_scorer = 'scorer.js'
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = '%(project_fn)sdoc'
-
-# -- Options for LaTeX output ---------------------------------------------
-
-latex_elements = {
- # The paper size ('letterpaper' or 'a4paper').
- #
- # 'papersize': 'letterpaper',
-
- # The font size ('10pt', '11pt' or '12pt').
- #
- # 'pointsize': '10pt',
-
- # Additional stuff for the LaTeX preamble.
- #
- # 'preamble': '',
-
- # Latex figure (float) alignment
- #
- # 'figure_align': 'htbp',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title,
-# author, documentclass [howto, manual, or own class]).
-latex_documents = [
- (master_doc, '%(project_fn)s.tex', u'%(project_doc_texescaped_str)s',
- u'%(author_texescaped_str)s', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#
-# latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#
-# latex_use_parts = False
-
-# If true, show page references after internal links.
-#
-# latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#
-# latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#
-# latex_appendices = []
-
-# It false, will not define \strong, \code, \titleref, \crossref ... but only
-# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added
-# packages.
-#
-# latex_keep_old_macro_names = True
-
-# If false, no module index is generated.
-#
-# latex_domain_indices = True
-
-
-# -- Options for manual page output ---------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- (master_doc, '%(project_manpage)s', u'%(project_doc_str)s',
- [author], 1)
-]
-
-# If true, show URL addresses after external links.
-#
-# man_show_urls = False
-
-
-# -- Options for Texinfo output -------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- (master_doc, '%(project_fn)s', u'%(project_doc_str)s',
- author, '%(project_fn)s', 'One line description of project.',
- 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#
-# texinfo_appendices = []
-
-# If false, no module index is generated.
-#
-# texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#
-# texinfo_show_urls = 'footnote'
-
-# If true, do not generate a @detailmenu in the "Top" node's menu.
-#
-# texinfo_no_detailmenu = False
-'''
-
-EPUB_CONFIG = u'''
-
-# -- Options for Epub output ----------------------------------------------
-
-# Bibliographic Dublin Core info.
-epub_title = project
-epub_author = author
-epub_publisher = author
-epub_copyright = copyright
-
-# The basename for the epub file. It defaults to the project name.
-# epub_basename = project
-
-# The HTML theme for the epub output. Since the default themes are not
-# optimized for small screen space, using the same theme for HTML and epub
-# output is usually not wise. This defaults to 'epub', a theme designed to save
-# visual space.
-#
-# epub_theme = 'epub'
-
-# The language of the text. It defaults to the language option
-# or 'en' if the language is not set.
-#
-# epub_language = ''
-
-# The scheme of the identifier. Typical schemes are ISBN or URL.
-# epub_scheme = ''
-
-# The unique identifier of the text. This can be a ISBN number
-# or the project homepage.
-#
-# epub_identifier = ''
-
-# A unique identification for the text.
-#
-# epub_uid = ''
-
-# A tuple containing the cover image and cover page html template filenames.
-#
-# epub_cover = ()
-
-# A sequence of (type, uri, title) tuples for the guide element of content.opf.
-#
-# epub_guide = ()
-
-# HTML files that should be inserted before the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#
-# epub_pre_files = []
-
-# HTML files that should be inserted after the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-#
-# epub_post_files = []
-
-# A list of files that should not be packed into the epub file.
-epub_exclude_files = ['search.html']
-
-# The depth of the table of contents in toc.ncx.
-#
-# epub_tocdepth = 3
-
-# Allow duplicate toc entries.
-#
-# epub_tocdup = True
-
-# Choose between 'default' and 'includehidden'.
-#
-# epub_tocscope = 'default'
-
-# Fix unsupported image types using the Pillow.
-#
-# epub_fix_images = False
-
-# Scale large images.
-#
-# epub_max_image_width = 0
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#
-# epub_show_urls = 'inline'
-
-# If false, no index is generated.
-#
-# epub_use_index = True
-'''
-
-INTERSPHINX_CONFIG = u'''
-
-# Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'https://docs.python.org/': None}
-'''
-
-MASTER_FILE = u'''\
-.. %(project)s documentation master file, created by
- sphinx-quickstart on %(now)s.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-Welcome to %(project)s's documentation!
-===========%(project_underline)s=================
-
-Contents:
-
-.. toctree::
- :maxdepth: %(mastertocmaxdepth)s
-
-%(mastertoctree)s
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
-'''
-
-MAKEFILE = u'''\
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR = %(rbuilddir)s
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) \
-$(SPHINXOPTS) %(rsrcdir)s
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) %(rsrcdir)s
-
-.PHONY: help
-help:
-\t@echo "Please use \\`make <target>' where <target> is one of"
-\t@echo " html to make standalone HTML files"
-\t@echo " dirhtml to make HTML files named index.html in directories"
-\t@echo " singlehtml to make a single large HTML file"
-\t@echo " pickle to make pickle files"
-\t@echo " json to make JSON files"
-\t@echo " htmlhelp to make HTML files and a HTML help project"
-\t@echo " qthelp to make HTML files and a qthelp project"
-\t@echo " applehelp to make an Apple Help Book"
-\t@echo " devhelp to make HTML files and a Devhelp project"
-\t@echo " epub to make an epub"
-\t@echo " epub3 to make an epub3"
-\t@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
-\t@echo " latexpdf to make LaTeX files and run them through pdflatex"
-\t@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
-\t@echo " text to make text files"
-\t@echo " man to make manual pages"
-\t@echo " texinfo to make Texinfo files"
-\t@echo " info to make Texinfo files and run them through makeinfo"
-\t@echo " gettext to make PO message catalogs"
-\t@echo " changes to make an overview of all changed/added/deprecated items"
-\t@echo " xml to make Docutils-native XML files"
-\t@echo " pseudoxml to make pseudoxml-XML files for display purposes"
-\t@echo " linkcheck to check all external links for integrity"
-\t@echo " doctest to run all doctests embedded in the documentation \
-(if enabled)"
-\t@echo " coverage to run coverage check of the documentation (if enabled)"
-\t@echo " dummy to check syntax errors of document sources"
-
-.PHONY: clean
-clean:
-\trm -rf $(BUILDDIR)/*
-
-.PHONY: html
-html:
-\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
-\t@echo
-\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-.PHONY: dirhtml
-dirhtml:
-\t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
-\t@echo
-\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-.PHONY: singlehtml
-singlehtml:
-\t$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
-\t@echo
-\t@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-.PHONY: pickle
-pickle:
-\t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
-\t@echo
-\t@echo "Build finished; now you can process the pickle files."
-
-.PHONY: json
-json:
-\t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
-\t@echo
-\t@echo "Build finished; now you can process the JSON files."
-
-.PHONY: htmlhelp
-htmlhelp:
-\t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
-\t@echo
-\t@echo "Build finished; now you can run HTML Help Workshop with the" \\
-\t ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-.PHONY: qthelp
-qthelp:
-\t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
-\t@echo
-\t@echo "Build finished; now you can run "qcollectiongenerator" with the" \\
-\t ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
-\t@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/%(project_fn)s.qhcp"
-\t@echo "To view the help file:"
-\t@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/%(project_fn)s.qhc"
-
-.PHONY: applehelp
-applehelp:
-\t$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
-\t@echo
-\t@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
-\t@echo "N.B. You won't be able to view it unless you put it in" \\
-\t "~/Library/Documentation/Help or install it in your application" \\
-\t "bundle."
-
-.PHONY: devhelp
-devhelp:
-\t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
-\t@echo
-\t@echo "Build finished."
-\t@echo "To view the help file:"
-\t@echo "# mkdir -p $$HOME/.local/share/devhelp/%(project_fn)s"
-\t@echo "# ln -s $(BUILDDIR)/devhelp\
- $$HOME/.local/share/devhelp/%(project_fn)s"
-\t@echo "# devhelp"
-
-.PHONY: epub
-epub:
-\t$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
-\t@echo
-\t@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-.PHONY: epub3
-epub3:
-\t$(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
-\t@echo
-\t@echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
-
-.PHONY: latex
-latex:
-\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-\t@echo
-\t@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
-\t@echo "Run \\`make' in that directory to run these through (pdf)latex" \\
-\t "(use \\`make latexpdf' here to do that automatically)."
-
-.PHONY: latexpdf
-latexpdf:
-\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-\t@echo "Running LaTeX files through pdflatex..."
-\t$(MAKE) -C $(BUILDDIR)/latex all-pdf
-\t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-.PHONY: latexpdfja
-latexpdfja:
-\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-\t@echo "Running LaTeX files through platex and dvipdfmx..."
-\t$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
-\t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-.PHONY: text
-text:
-\t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
-\t@echo
-\t@echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-.PHONY: man
-man:
-\t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
-\t@echo
-\t@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-.PHONY: texinfo
-texinfo:
-\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-\t@echo
-\t@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
-\t@echo "Run \\`make' in that directory to run these through makeinfo" \\
-\t "(use \\`make info' here to do that automatically)."
-
-.PHONY: info
-info:
-\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-\t@echo "Running Texinfo files through makeinfo..."
-\tmake -C $(BUILDDIR)/texinfo info
-\t@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-.PHONY: gettext
-gettext:
-\t$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
-\t@echo
-\t@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-.PHONY: changes
-changes:
-\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
-\t@echo
-\t@echo "The overview file is in $(BUILDDIR)/changes."
-
-.PHONY: linkcheck
-linkcheck:
-\t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
-\t@echo
-\t@echo "Link check complete; look for any errors in the above output " \\
-\t "or in $(BUILDDIR)/linkcheck/output.txt."
-
-.PHONY: doctest
-doctest:
-\t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
-\t@echo "Testing of doctests in the sources finished, look at the " \\
-\t "results in $(BUILDDIR)/doctest/output.txt."
-
-.PHONY: coverage
-coverage:
-\t$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
-\t@echo "Testing of coverage in the sources finished, look at the " \\
-\t "results in $(BUILDDIR)/coverage/python.txt."
-
-.PHONY: xml
-xml:
-\t$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
-\t@echo
-\t@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
-
-.PHONY: pseudoxml
-pseudoxml:
-\t$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
-\t@echo
-\t@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
-
-.PHONY: dummy
-dummy:
-\t$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
-\t@echo
-\t@echo "Build finished. Dummy builder generates no files."
-'''
-
-BATCHFILE = u'''\
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%%SPHINXBUILD%%" == "" (
-\tset SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=%(rbuilddir)s
-set ALLSPHINXOPTS=-d %%BUILDDIR%%/doctrees %%SPHINXOPTS%% %(rsrcdir)s
-set I18NSPHINXOPTS=%%SPHINXOPTS%% %(rsrcdir)s
-if NOT "%%PAPER%%" == "" (
-\tset ALLSPHINXOPTS=-D latex_paper_size=%%PAPER%% %%ALLSPHINXOPTS%%
-\tset I18NSPHINXOPTS=-D latex_paper_size=%%PAPER%% %%I18NSPHINXOPTS%%
-)
-
-if "%%1" == "" goto help
-
-if "%%1" == "help" (
-\t:help
-\techo.Please use `make ^<target^>` where ^<target^> is one of
-\techo. html to make standalone HTML files
-\techo. dirhtml to make HTML files named index.html in directories
-\techo. singlehtml to make a single large HTML file
-\techo. pickle to make pickle files
-\techo. json to make JSON files
-\techo. htmlhelp to make HTML files and a HTML help project
-\techo. qthelp to make HTML files and a qthelp project
-\techo. devhelp to make HTML files and a Devhelp project
-\techo. epub to make an epub
-\techo. epub3 to make an epub3
-\techo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
-\techo. text to make text files
-\techo. man to make manual pages
-\techo. texinfo to make Texinfo files
-\techo. gettext to make PO message catalogs
-\techo. changes to make an overview over all changed/added/deprecated items
-\techo. xml to make Docutils-native XML files
-\techo. pseudoxml to make pseudoxml-XML files for display purposes
-\techo. linkcheck to check all external links for integrity
-\techo. doctest to run all doctests embedded in the documentation if enabled
-\techo. coverage to run coverage check of the documentation if enabled
-\techo. dummy to check syntax errors of document sources
-\tgoto end
-)
-
-if "%%1" == "clean" (
-\tfor /d %%%%i in (%%BUILDDIR%%\*) do rmdir /q /s %%%%i
-\tdel /q /s %%BUILDDIR%%\*
-\tgoto end
-)
-
-
-REM Check if sphinx-build is available and fallback to Python version if any
-%%SPHINXBUILD%% 1>NUL 2>NUL
-if errorlevel 9009 goto sphinx_python
-goto sphinx_ok
-
-:sphinx_python
-
-set SPHINXBUILD=python -m sphinx.__init__
-%%SPHINXBUILD%% 2> nul
-if errorlevel 9009 (
-\techo.
-\techo.The 'sphinx-build' command was not found. Make sure you have Sphinx
-\techo.installed, then set the SPHINXBUILD environment variable to point
-\techo.to the full path of the 'sphinx-build' executable. Alternatively you
-\techo.may add the Sphinx directory to PATH.
-\techo.
-\techo.If you don't have Sphinx installed, grab it from
-\techo.http://sphinx-doc.org/
-\texit /b 1
-)
-
-:sphinx_ok
-
-
-if "%%1" == "html" (
-\t%%SPHINXBUILD%% -b html %%ALLSPHINXOPTS%% %%BUILDDIR%%/html
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The HTML pages are in %%BUILDDIR%%/html.
-\tgoto end
-)
-
-if "%%1" == "dirhtml" (
-\t%%SPHINXBUILD%% -b dirhtml %%ALLSPHINXOPTS%% %%BUILDDIR%%/dirhtml
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The HTML pages are in %%BUILDDIR%%/dirhtml.
-\tgoto end
-)
-
-if "%%1" == "singlehtml" (
-\t%%SPHINXBUILD%% -b singlehtml %%ALLSPHINXOPTS%% %%BUILDDIR%%/singlehtml
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The HTML pages are in %%BUILDDIR%%/singlehtml.
-\tgoto end
-)
-
-if "%%1" == "pickle" (
-\t%%SPHINXBUILD%% -b pickle %%ALLSPHINXOPTS%% %%BUILDDIR%%/pickle
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished; now you can process the pickle files.
-\tgoto end
-)
-
-if "%%1" == "json" (
-\t%%SPHINXBUILD%% -b json %%ALLSPHINXOPTS%% %%BUILDDIR%%/json
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished; now you can process the JSON files.
-\tgoto end
-)
-
-if "%%1" == "htmlhelp" (
-\t%%SPHINXBUILD%% -b htmlhelp %%ALLSPHINXOPTS%% %%BUILDDIR%%/htmlhelp
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %%BUILDDIR%%/htmlhelp.
-\tgoto end
-)
-
-if "%%1" == "qthelp" (
-\t%%SPHINXBUILD%% -b qthelp %%ALLSPHINXOPTS%% %%BUILDDIR%%/qthelp
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %%BUILDDIR%%/qthelp, like this:
-\techo.^> qcollectiongenerator %%BUILDDIR%%\\qthelp\\%(project_fn)s.qhcp
-\techo.To view the help file:
-\techo.^> assistant -collectionFile %%BUILDDIR%%\\qthelp\\%(project_fn)s.ghc
-\tgoto end
-)
-
-if "%%1" == "devhelp" (
-\t%%SPHINXBUILD%% -b devhelp %%ALLSPHINXOPTS%% %%BUILDDIR%%/devhelp
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished.
-\tgoto end
-)
-
-if "%%1" == "epub" (
-\t%%SPHINXBUILD%% -b epub %%ALLSPHINXOPTS%% %%BUILDDIR%%/epub
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The epub file is in %%BUILDDIR%%/epub.
-\tgoto end
-)
-
-if "%%1" == "epub3" (
-\t%%SPHINXBUILD%% -b epub3 %%ALLSPHINXOPTS%% %%BUILDDIR%%/epub3
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The epub3 file is in %%BUILDDIR%%/epub3.
-\tgoto end
-)
-
-if "%%1" == "latex" (
-\t%%SPHINXBUILD%% -b latex %%ALLSPHINXOPTS%% %%BUILDDIR%%/latex
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished; the LaTeX files are in %%BUILDDIR%%/latex.
-\tgoto end
-)
-
-if "%%1" == "latexpdf" (
-\t%%SPHINXBUILD%% -b latex %%ALLSPHINXOPTS%% %%BUILDDIR%%/latex
-\tcd %%BUILDDIR%%/latex
-\tmake all-pdf
-\tcd %%~dp0
-\techo.
-\techo.Build finished; the PDF files are in %%BUILDDIR%%/latex.
-\tgoto end
-)
-
-if "%%1" == "latexpdfja" (
-\t%%SPHINXBUILD%% -b latex %%ALLSPHINXOPTS%% %%BUILDDIR%%/latex
-\tcd %%BUILDDIR%%/latex
-\tmake all-pdf-ja
-\tcd %%~dp0
-\techo.
-\techo.Build finished; the PDF files are in %%BUILDDIR%%/latex.
-\tgoto end
-)
-
-if "%%1" == "text" (
-\t%%SPHINXBUILD%% -b text %%ALLSPHINXOPTS%% %%BUILDDIR%%/text
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The text files are in %%BUILDDIR%%/text.
-\tgoto end
-)
-
-if "%%1" == "man" (
-\t%%SPHINXBUILD%% -b man %%ALLSPHINXOPTS%% %%BUILDDIR%%/man
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The manual pages are in %%BUILDDIR%%/man.
-\tgoto end
-)
-
-if "%%1" == "texinfo" (
-\t%%SPHINXBUILD%% -b texinfo %%ALLSPHINXOPTS%% %%BUILDDIR%%/texinfo
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The Texinfo files are in %%BUILDDIR%%/texinfo.
-\tgoto end
-)
-
-if "%%1" == "gettext" (
-\t%%SPHINXBUILD%% -b gettext %%I18NSPHINXOPTS%% %%BUILDDIR%%/locale
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The message catalogs are in %%BUILDDIR%%/locale.
-\tgoto end
-)
-
-if "%%1" == "changes" (
-\t%%SPHINXBUILD%% -b changes %%ALLSPHINXOPTS%% %%BUILDDIR%%/changes
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.The overview file is in %%BUILDDIR%%/changes.
-\tgoto end
-)
-
-if "%%1" == "linkcheck" (
-\t%%SPHINXBUILD%% -b linkcheck %%ALLSPHINXOPTS%% %%BUILDDIR%%/linkcheck
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Link check complete; look for any errors in the above output ^
-or in %%BUILDDIR%%/linkcheck/output.txt.
-\tgoto end
-)
-
-if "%%1" == "doctest" (
-\t%%SPHINXBUILD%% -b doctest %%ALLSPHINXOPTS%% %%BUILDDIR%%/doctest
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Testing of doctests in the sources finished, look at the ^
-results in %%BUILDDIR%%/doctest/output.txt.
-\tgoto end
-)
-
-if "%%1" == "coverage" (
-\t%%SPHINXBUILD%% -b coverage %%ALLSPHINXOPTS%% %%BUILDDIR%%/coverage
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Testing of coverage in the sources finished, look at the ^
-results in %%BUILDDIR%%/coverage/python.txt.
-\tgoto end
-)
-
-if "%%1" == "xml" (
-\t%%SPHINXBUILD%% -b xml %%ALLSPHINXOPTS%% %%BUILDDIR%%/xml
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The XML files are in %%BUILDDIR%%/xml.
-\tgoto end
-)
-
-if "%%1" == "pseudoxml" (
-\t%%SPHINXBUILD%% -b pseudoxml %%ALLSPHINXOPTS%% %%BUILDDIR%%/pseudoxml
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. The pseudo-XML files are in %%BUILDDIR%%/pseudoxml.
-\tgoto end
-)
-
-if "%%1" == "dummy" (
-\t%%SPHINXBUILD%% -b dummy %%ALLSPHINXOPTS%% %%BUILDDIR%%/dummy
-\tif errorlevel 1 exit /b 1
-\techo.
-\techo.Build finished. Dummy builder generates no files.
-\tgoto end
-)
-
-:end
-'''
-
-# This will become the Makefile template for Sphinx 1.5.
-MAKEFILE_NEW = u'''\
-# Minimal makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-SPHINXPROJ = %(project_fn)s
-SOURCEDIR = %(rsrcdir)s
-BUILDDIR = %(rbuilddir)s
-
-# Has to be explicit, otherwise we don't get "make" without targets right.
-help:
-\t@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-
-# You can add custom targets here.
-
-# Catch-all target: route all unknown targets to Sphinx using the new
-# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
-%%:
-\t@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-'''
-
-# This will become the make.bat template for Sphinx 1.5.
-BATCHFILE_NEW = u'''\
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%%SPHINXBUILD%%" == "" (
-\tset SPHINXBUILD=sphinx-build
-)
-set SOURCEDIR=%(rsrcdir)s
-set BUILDDIR=%(rbuilddir)s
-set SPHINXPROJ=%(project_fn)s
-
-if "%%1" == "" goto help
-
-%%SPHINXBUILD%% >NUL 2>NUL
-if errorlevel 9009 (
-\techo.
-\techo.The 'sphinx-build' command was not found. Make sure you have Sphinx
-\techo.installed, then set the SPHINXBUILD environment variable to point
-\techo.to the full path of the 'sphinx-build' executable. Alternatively you
-\techo.may add the Sphinx directory to PATH.
-\techo.
-\techo.If you don't have Sphinx installed, grab it from
-\techo.http://sphinx-doc.org/
-\texit /b 1
-)
-
-%%SPHINXBUILD%% -M %%1 %%SOURCEDIR%% %%BUILDDIR%% %%SPHINXOPTS%%
-goto end
-
-:help
-%%SPHINXBUILD%% -M help %%SOURCEDIR%% %%BUILDDIR%% %%SPHINXOPTS%%
-
-:end
-'''
-
def mkdir_p(dir):
if path.isdir(dir):
@@ -1124,6 +84,10 @@ def is_path(x):
return x
+def allow_empty(x):
+ return x
+
+
def nonempty(x):
if not x:
raise ValidationError("Please enter some text.")
@@ -1178,7 +142,7 @@ def term_decode(text):
def do_prompt(d, key, text, default=None, validator=nonempty):
while True:
- if default:
+ if default is not None:
prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default)
else:
prompt = PROMPT_PREFIX + text + ': '
@@ -1210,15 +174,25 @@ def do_prompt(d, key, text, default=None, validator=nonempty):
d[key] = x
-if PY3:
+def convert_python_source(source, rex=re.compile(r"[uU]('.*?')")):
# remove Unicode literal prefixes
- def _convert_python_source(source, rex=re.compile(r"[uU]('.*?')")):
+ if PY3:
return rex.sub('\\1', source)
+ else:
+ return source
+
- for f in ['QUICKSTART_CONF', 'EPUB_CONFIG', 'INTERSPHINX_CONFIG']:
- globals()[f] = _convert_python_source(globals()[f])
+class QuickstartRenderer(SphinxRenderer):
+ def __init__(self, templatedir):
+ self.templatedir = templatedir or ''
+ super(QuickstartRenderer, self).__init__()
- del _convert_python_source
+ def render(self, template_name, context):
+ user_template = path.join(self.templatedir, path.basename(template_name))
+ if self.templatedir and path.exists(user_template):
+ return self.render_from_file(user_template, context)
+ else:
+ return super(QuickstartRenderer, self).render(template_name, context)
def ask_user(d):
@@ -1296,9 +270,9 @@ software. Each version can have multiple releases. For example, for
Python the version is something like 2.5 or 3.0, while the release is
something like 2.5.1 or 3.0a1. If you don't need this dual structure,
just set both to the same value.''')
- do_prompt(d, 'version', 'Project version')
+ do_prompt(d, 'version', 'Project version', '', allow_empty)
if 'release' not in d:
- do_prompt(d, 'release', 'Project release', d['version'])
+ do_prompt(d, 'release', 'Project release', d['version'], allow_empty)
if 'language' not in d:
print('''
@@ -1396,8 +370,9 @@ directly.''')
print()
-def generate(d, overwrite=True, silent=False):
+def generate(d, overwrite=True, silent=False, templatedir=None):
"""Generate project based on values in *d*."""
+ template = QuickstartRenderer(templatedir=templatedir)
texescape.init()
indent = ' ' * 4
@@ -1407,19 +382,17 @@ def generate(d, overwrite=True, silent=False):
if 'mastertocmaxdepth' not in d:
d['mastertocmaxdepth'] = 2
+ d['PY3'] = PY3
d['project_fn'] = make_filename(d['project'])
d['project_url'] = urlquote(d['project'].encode('idna'))
d['project_manpage'] = d['project_fn'].lower()
d['now'] = time.asctime()
d['project_underline'] = column_width(d['project']) * '='
- extensions = (',\n' + indent).join(
- repr('sphinx.ext.' + name)
- for name in EXTENSIONS
- if d.get('ext_' + name))
- if extensions:
- d['extensions'] = '\n' + indent + extensions + ',\n'
- else:
- d['extensions'] = extensions
+ d.setdefault('extensions', [])
+ for name in EXTENSIONS:
+ if d.get('ext_' + name):
+ d['extensions'].append('sphinx.ext.' + name)
+ d['extensions'] = (',\n' + indent).join(repr(name) for name in d['extensions'])
d['copyright'] = time.strftime('%Y') + ', ' + d['author']
d['author_texescaped'] = text_type(d['author']).\
translate(texescape.tex_escape_map)
@@ -1457,42 +430,38 @@ def generate(d, overwrite=True, silent=False):
def write_file(fpath, content, newline=None):
if overwrite or not path.isfile(fpath):
print('Creating file %s.' % fpath)
- f = open(fpath, 'wt', encoding='utf-8', newline=newline)
- try:
+ with open(fpath, 'wt', encoding='utf-8', newline=newline) as f:
f.write(content)
- finally:
- f.close()
else:
print('File %s already exists, skipping.' % fpath)
- conf_text = QUICKSTART_CONF % d
- if d['epub']:
- conf_text += EPUB_CONFIG % d
- if d.get('ext_intersphinx'):
- conf_text += INTERSPHINX_CONFIG
+ with open(os.path.join(package_dir, 'templates', 'quickstart', 'conf.py_t')) as f:
+ conf_text = convert_python_source(f.read())
- write_file(path.join(srcdir, 'conf.py'), conf_text)
+ write_file(path.join(srcdir, 'conf.py'), template.render_string(conf_text, d))
masterfile = path.join(srcdir, d['master'] + d['suffix'])
- write_file(masterfile, MASTER_FILE % d)
+ write_file(masterfile, template.render('quickstart/master_doc.rst_t', d))
if d.get('make_mode') is True:
- makefile_template = MAKEFILE_NEW
- batchfile_template = BATCHFILE_NEW
+ makefile_template = 'quickstart/Makefile.new_t'
+ batchfile_template = 'quickstart/make.bat.new_t'
else:
- makefile_template = MAKEFILE
- batchfile_template = BATCHFILE
+ makefile_template = 'quickstart/Makefile_t'
+ batchfile_template = 'quickstart/make.bat_t'
if d['makefile'] is True:
d['rsrcdir'] = d['sep'] and 'source' or '.'
d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build'
# use binary mode, to avoid writing \r\n on Windows
- write_file(path.join(d['path'], 'Makefile'), makefile_template % d, u'\n')
+ write_file(path.join(d['path'], 'Makefile'),
+ template.render(makefile_template, d), u'\n')
if d['batchfile'] is True:
d['rsrcdir'] = d['sep'] and 'source' or '.'
d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build'
- write_file(path.join(d['path'], 'make.bat'), batchfile_template % d, u'\r\n')
+ write_file(path.join(d['path'], 'make.bat'),
+ template.render(batchfile_template, d), u'\r\n')
if silent:
return
@@ -1610,6 +579,8 @@ def main(argv=sys.argv):
group.add_option('--ext-' + ext, action='store_true',
dest='ext_' + ext, default=False,
help='enable %s extension' % ext)
+ group.add_option('--extensions', metavar='EXTENSIONS', dest='extensions',
+ action='append', help='enable extensions')
group = parser.add_option_group('Makefile and Batchfile creation')
group.add_option('--makefile', action='store_true', dest='makefile',
@@ -1627,11 +598,18 @@ def main(argv=sys.argv):
group.add_option('-M', '--no-use-make-mode', action='store_false', dest='make_mode',
help='not use make-mode for Makefile/make.bat')
group.add_option('-m', '--use-make-mode', action='store_true', dest='make_mode',
+ default=True,
help='use make-mode for Makefile/make.bat')
+ group = parser.add_option_group('Project templating')
+ group.add_option('-t', '--templatedir', metavar='TEMPLATEDIR', dest='templatedir',
+ help='template directory for template files')
+ group.add_option('-d', metavar='NAME=VALUE', action='append', dest='variables',
+ help='define a template variable')
+
# parse options
try:
- opts, args = parser.parse_args()
+ opts, args = parser.parse_args(argv[1:])
except SystemExit as err:
return err.code
@@ -1644,13 +622,14 @@ def main(argv=sys.argv):
try:
if 'quiet' in d:
- if not set(['project', 'author', 'version']).issubset(d):
- print('''"quiet" is specified, but any of "project", \
-"author" or "version" is not specified.''')
+ if not set(['project', 'author']).issubset(d):
+ print('''"quiet" is specified, but any of "project" or \
+"author" is not specified.''')
return 1
- if set(['quiet', 'project', 'author', 'version']).issubset(d):
+ if set(['quiet', 'project', 'author']).issubset(d):
# quiet mode with all required params satisfied, use default
+ d.setdefault('version', '')
d.setdefault('release', d['version'])
d2 = DEFAULT_VALUE.copy()
d2.update(dict(("ext_"+ext, False) for ext in EXTENSIONS))
@@ -1680,7 +659,22 @@ def main(argv=sys.argv):
if isinstance(value, binary_type):
d[key] = term_decode(value)
- generate(d)
+ # parse extensions list
+ d.setdefault('extensions', [])
+ for ext in d['extensions'][:]:
+ if ',' in ext:
+ d['extensions'].remove(ext)
+ for modname in ext.split(','):
+ d['extensions'].append(modname)
+
+ for variable in d.get('variables', []):
+ try:
+ name, value = variable.split('=')
+ d[name] = value
+ except ValueError:
+ print('Invalid template variable: %s' % variable)
+
+ generate(d, templatedir=opts.templatedir)
if __name__ == '__main__':
diff --git a/sphinx/roles.py b/sphinx/roles.py
index a6583a6ea..6e8de3b4a 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -13,7 +13,6 @@ import re
from six import iteritems
from docutils import nodes, utils
-from docutils.parsers.rst import roles
from sphinx import addnodes
from sphinx.locale import _
@@ -36,11 +35,6 @@ generic_docroles = {
'regexp': nodes.literal,
}
-for rolename, nodeclass in iteritems(generic_docroles):
- generic = roles.GenericRole(rolename, nodeclass)
- role = roles.CustomRole(rolename, generic, {'classes': [rolename]})
- roles.register_local_role(rolename, role)
-
# -- generic cross-reference role ----------------------------------------------
@@ -344,5 +338,14 @@ specific_docroles = {
'index': index_role,
}
-for rolename, func in iteritems(specific_docroles):
- roles.register_local_role(rolename, func)
+
+def setup(app):
+ from docutils.parsers.rst import roles
+
+ for rolename, nodeclass in iteritems(generic_docroles):
+ generic = roles.GenericRole(rolename, nodeclass)
+ role = roles.CustomRole(rolename, generic, {'classes': [rolename]})
+ roles.register_local_role(rolename, role)
+
+ for rolename, func in iteritems(specific_docroles):
+ roles.register_local_role(rolename, func)
diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py
index 1fedc5352..d3c6c0eba 100644
--- a/sphinx/search/__init__.py
+++ b/sphinx/search/__init__.py
@@ -15,6 +15,7 @@ from six.moves import cPickle as pickle
from docutils.nodes import raw, comment, title, Text, NodeVisitor, SkipNode
from os import path
+import sphinx
from sphinx.util import jsdump, rpartition
from sphinx.util.pycompat import htmlescape
@@ -180,23 +181,38 @@ class WordCollector(NodeVisitor):
self.found_title_words = []
self.lang = lang
+ def is_meta_keywords(self, node, nodetype):
+ if isinstance(node, sphinx.addnodes.meta) and node.get('name') == 'keywords':
+ meta_lang = node.get('lang')
+ if meta_lang is None: # lang not specified
+ return True
+ elif meta_lang == self.lang.lang: # matched to html_search_language
+ return True
+
+ return False
+
def dispatch_visit(self, node):
nodetype = type(node)
if issubclass(nodetype, comment):
raise SkipNode
if issubclass(nodetype, raw):
- # Some people might put content in raw HTML that should be searched,
- # so we just amateurishly strip HTML tags and index the remaining
- # content
- nodetext = re.sub(r'(?is)<style.*?</style>', '', node.astext())
- nodetext = re.sub(r'(?is)<script.*?</script>', '', nodetext)
- nodetext = re.sub(r'<[^<]+?>', '', nodetext)
- self.found_words.extend(self.lang.split(nodetext))
+ if 'html' in node.get('format', '').split():
+ # Some people might put content in raw HTML that should be searched,
+ # so we just amateurishly strip HTML tags and index the remaining
+ # content
+ nodetext = re.sub(r'(?is)<style.*?</style>', '', node.astext())
+ nodetext = re.sub(r'(?is)<script.*?</script>', '', nodetext)
+ nodetext = re.sub(r'<[^<]+?>', '', nodetext)
+ self.found_words.extend(self.lang.split(nodetext))
raise SkipNode
if issubclass(nodetype, Text):
self.found_words.extend(self.lang.split(node.astext()))
elif issubclass(nodetype, title):
self.found_title_words.extend(self.lang.split(node.astext()))
+ elif self.is_meta_keywords(node, nodetype):
+ keywords = node['content']
+ keywords = [keyword.strip() for keyword in keywords.split(',')]
+ self.found_words.extend(keywords)
class IndexBuilder(object):
@@ -211,11 +227,13 @@ class IndexBuilder(object):
def __init__(self, env, lang, options, scoring):
self.env = env
- # filename -> title
+ # docname -> title
self._titles = {}
- # stemmed word -> set(filenames)
+ # docname -> filename
+ self._filenames = {}
+ # stemmed word -> set(docname)
self._mapping = {}
- # stemmed words in titles -> set(filenames)
+ # stemmed words in titles -> set(docname)
self._title_mapping = {}
# word -> stemmed word
self._stem_cache = {}
@@ -323,15 +341,16 @@ class IndexBuilder(object):
def freeze(self):
"""Create a usable data structure for serializing."""
- filenames, titles = zip(*sorted(self._titles.items()))
- fn2index = dict((f, i) for (i, f) in enumerate(filenames))
+ docnames, titles = zip(*sorted(self._titles.items()))
+ filenames = [self._filenames.get(docname) for docname in docnames]
+ fn2index = dict((f, i) for (i, f) in enumerate(docnames))
terms, title_terms = self.get_terms(fn2index)
objects = self.get_objects(fn2index) # populates _objtypes
objtypes = dict((v, k[0] + ':' + k[1])
for (k, v) in iteritems(self._objtypes))
objnames = self._objnames
- return dict(filenames=filenames, titles=titles, terms=terms,
+ return dict(docnames=docnames, filenames=filenames, titles=titles, terms=terms,
objects=objects, objtypes=objtypes, objnames=objnames,
titleterms=title_terms, envversion=self.env.version)
@@ -350,9 +369,10 @@ class IndexBuilder(object):
for wordnames in itervalues(self._title_mapping):
wordnames.intersection_update(filenames)
- def feed(self, filename, title, doctree):
+ def feed(self, docname, filename, title, doctree):
"""Feed a doctree to the index."""
- self._titles[filename] = title
+ self._titles[docname] = title
+ self._filenames[docname] = filename
visitor = WordCollector(doctree, self.lang)
doctree.walk(visitor)
@@ -367,14 +387,20 @@ class IndexBuilder(object):
_filter = self.lang.word_filter
for word in visitor.found_title_words:
- word = stem(word)
- if _filter(word):
- self._title_mapping.setdefault(word, set()).add(filename)
+ stemmed_word = stem(word)
+ if _filter(stemmed_word):
+ self._title_mapping.setdefault(stemmed_word, set()).add(docname)
+ elif _filter(word): # stemmer must not remove words from search index
+ self._title_mapping.setdefault(word, set()).add(docname)
for word in visitor.found_words:
- word = stem(word)
- if word not in self._title_mapping and _filter(word):
- self._mapping.setdefault(word, set()).add(filename)
+ stemmed_word = stem(word)
+ # again, stemmer must not remove words from search index
+ if not _filter(stemmed_word) and _filter(word):
+ stemmed_word = word
+ already_indexed = docname in self._title_mapping.get(stemmed_word, [])
+ if _filter(stemmed_word) and not already_indexed:
+ self._mapping.setdefault(stemmed_word, set()).add(docname)
def context_for_searchtool(self):
return dict(
diff --git a/sphinx/search/en.py b/sphinx/search/en.py
index 39c328760..d5259bed7 100644
--- a/sphinx/search/en.py
+++ b/sphinx/search/en.py
@@ -242,4 +242,4 @@ class SearchEnglish(SearchLanguage):
self.stemmer = Stemmer()
def stem(self, word):
- return self.stemmer.stem(word)
+ return self.stemmer.stem(word.lower())
diff --git a/tests/roots/test-html_extra_path/extra/.htaccess b/sphinx/search/test
index e69de29bb..e69de29bb 100644
--- a/tests/roots/test-html_extra_path/extra/.htaccess
+++ b/sphinx/search/test
diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py
index 128c1415c..c23f22228 100644
--- a/sphinx/setup_command.py
+++ b/sphinx/setup_command.py
@@ -15,13 +15,15 @@ from __future__ import print_function
import sys
import os
-from distutils.cmd import Command
-from distutils.errors import DistutilsOptionError, DistutilsExecError
from six import StringIO, string_types
+from distutils.cmd import Command
+from distutils.errors import DistutilsOptionError, DistutilsExecError
from sphinx.application import Sphinx
-from sphinx.util.console import darkred, nocolor, color_terminal
+from sphinx.cmdline import handle_exception
+from sphinx.util.console import nocolor, color_terminal
+from sphinx.util.docutils import docutils_namespace
from sphinx.util.osutil import abspath
@@ -71,6 +73,7 @@ class BuildDoc(Command):
('build-dir=', None, 'Build directory'),
('config-dir=', 'c', 'Location of the configuration directory'),
('builder=', 'b', 'The builder to use. Defaults to "html"'),
+ ('warning-is-error', 'W', 'Turn warning into errors'),
('project=', None, 'The documented project\'s name'),
('version=', None, 'The short X.Y version'),
('release=', None, 'The full version, including alpha/beta/rc tags'),
@@ -78,13 +81,17 @@ class BuildDoc(Command):
'replacement for |today|'),
('link-index', 'i', 'Link index.html to the master doc'),
('copyright', None, 'The copyright string'),
+ ('pdb', None, 'Start pdb on exception'),
]
- boolean_options = ['fresh-env', 'all-files', 'link-index']
+ boolean_options = ['fresh-env', 'all-files', 'warning-is-error',
+ 'link-index']
def initialize_options(self):
self.fresh_env = self.all_files = False
+ self.pdb = False
self.source_dir = self.build_dir = None
self.builder = 'html'
+ self.warning_is_error = False
self.project = ''
self.version = ''
self.release = ''
@@ -92,6 +99,8 @@ class BuildDoc(Command):
self.config_dir = None
self.link_index = False
self.copyright = ''
+ self.verbosity = 0
+ self.traceback = False
def _guess_source_dir(self):
for guess in ('doc', 'docs'):
@@ -155,24 +164,22 @@ class BuildDoc(Command):
confoverrides['today'] = self.today
if self.copyright:
confoverrides['copyright'] = self.copyright
- app = Sphinx(self.source_dir, self.config_dir,
- self.builder_target_dir, self.doctree_dir,
- self.builder, confoverrides, status_stream,
- freshenv=self.fresh_env)
try:
- app.build(force_all=self.all_files)
- if app.statuscode:
- raise DistutilsExecError(
- 'caused by %s builder.' % app.builder.name)
- except Exception as err:
- from docutils.utils import SystemMessage
- if isinstance(err, SystemMessage):
- print(darkred('reST markup error:'), file=sys.stderr)
- print(err.args[0].encode('ascii', 'backslashreplace'),
- file=sys.stderr)
- else:
- raise
+ with docutils_namespace():
+ app = Sphinx(self.source_dir, self.config_dir,
+ self.builder_target_dir, self.doctree_dir,
+ self.builder, confoverrides, status_stream,
+ freshenv=self.fresh_env,
+ warningiserror=self.warning_is_error)
+ app.build(force_all=self.all_files)
+ if app.statuscode:
+ raise DistutilsExecError(
+ 'caused by %s builder.' % app.builder.name)
+ except Exception as exc:
+ handle_exception(app, self, exc, sys.stderr)
+ if not self.pdb:
+ raise SystemExit(1)
if self.link_index:
src = app.config.master_doc + app.builder.out_suffix
diff --git a/sphinx/templates/latex/content.tex_t b/sphinx/templates/latex/content.tex_t
new file mode 100644
index 000000000..e35c83648
--- /dev/null
+++ b/sphinx/templates/latex/content.tex_t
@@ -0,0 +1,52 @@
+%% Generated by Sphinx.
+\def\sphinxdocclass{<%= docclass %>}
+<% if latex_engine == 'lualatex' -%>
+\IfFileExists{luatex85.sty}
+ {\RequirePackage{luatex85}}
+ {\ifdefined\luatexversion\ifnum\luatexversion>84\relax
+ \PackageError{sphinx}
+ {** With this LuaTeX (\the\luatexversion),Sphinx requires luatex85.sty **}
+ {** Add the LaTeX package luatex85 to your TeX installation, and try again **}
+ \endinput\fi\fi}
+<% endif -%>
+\documentclass[<%= papersize %>,<%= pointsize %><%= classoptions %>]{<%= wrapperclass %>}
+\ifdefined\pdfpxdimen
+ \let\sphinxpxdimen\pdfpxdimen\else\newdimen\sphinxpxdimen
+\fi \sphinxpxdimen=<%= pxunit %>\relax
+<%= passoptionstopackages %>
+<%= geometry %>
+<%= inputenc %>
+<%= utf8extra %>
+<%= cmappkg %>
+<%= fontenc %>
+<%= amsmath %>
+<%= multilingual %>
+<%= fontpkg %>
+<%= fncychap %>
+<%= longtable %>
+\usepackage<%= sphinxpkgoptions %>{sphinx}
+<%= sphinxsetup %>
+\usepackage{multirow}
+\usepackage{eqparbox}
+<%= usepackages %>
+<%= hyperref %>
+<%= contentsname %>
+<%= numfig_format %>
+<%= pageautorefname %>
+<%= tocdepth %>
+<%= secnumdepth %>
+<%= preamble %>
+
+\title{<%= title %>}
+\date{<%= date %>}
+\release{<%= release %>}
+\author{<%= author %>}
+\newcommand{\sphinxlogo}{<%= logo %>}
+\renewcommand{\releasename}{<%= releasename %>}
+<%= makeindex %>
+<%= body %>
+<%= atendofbody %>
+<%= indices %>
+\renewcommand{\indexname}{<%= indexname %>}
+<%= printindex %>
+\end{document}
diff --git a/sphinx/templates/quickstart/Makefile.new_t b/sphinx/templates/quickstart/Makefile.new_t
new file mode 100644
index 000000000..c7cd62dda
--- /dev/null
+++ b/sphinx/templates/quickstart/Makefile.new_t
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+SPHINXPROJ = {{ project_fn }}
+SOURCEDIR = {{ rsrcdir }}
+BUILDDIR = {{ rbuilddir }}
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/sphinx/templates/quickstart/Makefile_t b/sphinx/templates/quickstart/Makefile_t
new file mode 100644
index 000000000..5505f23f5
--- /dev/null
+++ b/sphinx/templates/quickstart/Makefile_t
@@ -0,0 +1,242 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = {{ rbuilddir }}
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_elements.papersize=a4
+PAPEROPT_letter = -D latex_elements.papersize=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) {{ rsrcdir }}
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) {{ rsrcdir }}
+
+.PHONY: help
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and an HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " applehelp to make an Apple Help Book"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " epub3 to make an epub3"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+ @echo " lualatexpdf to make LaTeX files and run them through lualatex"
+ @echo " xelatexpdf to make LaTeX files and run them through xelatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " xml to make Docutils-native XML files"
+ @echo " pseudoxml to make pseudoxml-XML files for display purposes"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+ @echo " coverage to run coverage check of the documentation (if enabled)"
+ @echo " dummy to check syntax errors of document sources"
+
+.PHONY: clean
+clean:
+ rm -rf $(BUILDDIR)/*
+
+.PHONY: html
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+.PHONY: dirhtml
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+.PHONY: singlehtml
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+.PHONY: pickle
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+.PHONY: json
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+.PHONY: htmlhelp
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+.PHONY: qthelp
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/{{ project_fn }}.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/{{ project_fn }}.qhc"
+
+.PHONY: applehelp
+applehelp:
+ $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
+ @echo
+ @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
+ @echo "N.B. You won't be able to view it unless you put it in" \
+ "~/Library/Documentation/Help or install it in your application" \
+ "bundle."
+
+.PHONY: devhelp
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/{{ project_fn }}"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/{{ project_fn }}"
+ @echo "# devhelp"
+
+.PHONY: epub
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+.PHONY: epub3
+epub3:
+ $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
+ @echo
+ @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
+
+.PHONY: latex
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+.PHONY: latexpdf
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: latexpdfja
+latexpdfja:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through platex and dvipdfmx..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: lualatexpdf
+lualatexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through lualatex..."
+ $(MAKE) PDFLATEX=lualatex -C $(BUILDDIR)/latex all-pdf
+ @echo "lualatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: xelatexpdf
+xelatexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through xelatex..."
+ $(MAKE) PDFLATEX=xelatex -C $(BUILDDIR)/latex all-pdf
+ @echo "xelatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: text
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+.PHONY: man
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+.PHONY: texinfo
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+.PHONY: info
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+.PHONY: gettext
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+.PHONY: changes
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+.PHONY: linkcheck
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+.PHONY: doctest
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+.PHONY: coverage
+coverage:
+ $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
+ @echo "Testing of coverage in the sources finished, look at the " \
+ "results in $(BUILDDIR)/coverage/python.txt."
+
+.PHONY: xml
+xml:
+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+ @echo
+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+.PHONY: pseudoxml
+pseudoxml:
+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+ @echo
+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
+
+.PHONY: dummy
+dummy:
+ $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
+ @echo
+ @echo "Build finished. Dummy builder generates no files."
+
diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t
new file mode 100644
index 000000000..60a8f5cdc
--- /dev/null
+++ b/sphinx/templates/quickstart/conf.py_t
@@ -0,0 +1,193 @@
+{% if PY3 -%}
+#!/usr/bin/env python3
+{% endif -%}
+# -*- coding: utf-8 -*-
+#
+# {{ project }} documentation build configuration file, created by
+# sphinx-quickstart on {{ now }}.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# 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.
+#
+{% if append_syspath -%}
+import os
+import sys
+sys.path.insert(0, u'{{ module_path }}')
+{% else -%}
+# import os
+# import sys
+{% if module_path -%}
+# sys.path.insert(0, u'{{ module_path }}')
+{% else -%}
+# sys.path.insert(0, os.path.abspath('.'))
+{% endif -%}
+{% endif %}
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [{{ extensions }}]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['{{ dot }}templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '{{ suffix }}'
+
+# The master toctree document.
+master_doc = '{{ master_str }}'
+
+# General information about the project.
+project = u'{{ project_str }}'
+copyright = u'{{ copyright_str }}'
+author = u'{{ author_str }}'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = u'{{ version_str }}'
+# The full version, including alpha/beta/rc tags.
+release = u'{{ release_str }}'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = {{ language | repr }}
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = [{{ exclude_patterns }}]
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = {{ ext_todo }}
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['{{ dot }}static']
+
+
+# -- Options for HTMLHelp output ------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = '{{ project_fn }}doc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, '{{ project_fn }}.tex', u'{{ project_doc_texescaped_str }}',
+ u'{{ author_texescaped_str }}', 'manual'),
+]
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, '{{ project_manpage }}', u'{{ project_doc_str }}',
+ [author], 1)
+]
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, '{{ project_fn }}', u'{{ project_doc_str }}',
+ author, '{{ project_fn }}', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+{% if epub %}
+
+# -- Options for Epub output ----------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = project
+epub_author = author
+epub_publisher = author
+epub_copyright = copyright
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#
+# epub_identifier = ''
+
+# A unique identification for the text.
+#
+# epub_uid = ''
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ['search.html']
+{% endif %}
+
+{% if ext_intersphinx %}
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'https://docs.python.org/': None}
+{% endif %}
diff --git a/sphinx/templates/quickstart/make.bat.new_t b/sphinx/templates/quickstart/make.bat.new_t
new file mode 100644
index 000000000..4ed82305c
--- /dev/null
+++ b/sphinx/templates/quickstart/make.bat.new_t
@@ -0,0 +1,34 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR={{ rsrcdir }}
+set BUILDDIR={{ rbuilddir }}
+set SPHINXPROJ={{ project_fn }}
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
+
+:end
+
diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t
new file mode 100644
index 000000000..dd9379d25
--- /dev/null
+++ b/sphinx/templates/quickstart/make.bat_t
@@ -0,0 +1,282 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR={{ rbuilddir }}
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% {{ rsrcdir }}
+set I18NSPHINXOPTS=%SPHINXOPTS% {{ rsrcdir }}
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and an HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. epub3 to make an epub3
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. xml to make Docutils-native XML files
+ echo. pseudoxml to make pseudoxml-XML files for display purposes
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ echo. coverage to run coverage check of the documentation if enabled
+ echo. dummy to check syntax errors of document sources
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+
+REM Check if sphinx-build is available and fallback to Python version if any
+%SPHINXBUILD% 1>NUL 2>NUL
+if errorlevel 9009 goto sphinx_python
+goto sphinx_ok
+
+:sphinx_python
+
+set SPHINXBUILD=python -m sphinx.__init__
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+:sphinx_ok
+
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\{{ project_fn }}.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\{{ project_fn }}.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "epub3" (
+ %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub3 file is in %BUILDDIR%/epub3.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdf" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf
+ cd %~dp0
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdfja" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf-ja
+ cd %~dp0
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+if "%1" == "coverage" (
+ %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of coverage in the sources finished, look at the ^
+results in %BUILDDIR%/coverage/python.txt.
+ goto end
+)
+
+if "%1" == "xml" (
+ %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The XML files are in %BUILDDIR%/xml.
+ goto end
+)
+
+if "%1" == "pseudoxml" (
+ %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+ goto end
+)
+
+if "%1" == "dummy" (
+ %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. Dummy builder generates no files.
+ goto end
+)
+
+:end
+
diff --git a/sphinx/templates/quickstart/master_doc.rst_t b/sphinx/templates/quickstart/master_doc.rst_t
new file mode 100644
index 000000000..3aa98af08
--- /dev/null
+++ b/sphinx/templates/quickstart/master_doc.rst_t
@@ -0,0 +1,21 @@
+.. {{ project }} documentation master file, created by
+ sphinx-quickstart on {{ now }}.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to {{ project }}'s documentation!
+==========={{ project_underline }}=================
+
+.. toctree::
+ :maxdepth: {{ mastertocmaxdepth }}
+ :caption: Contents:
+
+{{ mastertoctree }}
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/sphinx/texinputs/Makefile b/sphinx/texinputs/Makefile_t
index d748006cc..ffec3662c 100644
--- a/sphinx/texinputs/Makefile
+++ b/sphinx/texinputs/Makefile_t
@@ -3,6 +3,7 @@
ALLDOCS = $(basename $(wildcard *.tex))
ALLPDF = $(addsuffix .pdf,$(ALLDOCS))
ALLDVI = $(addsuffix .dvi,$(ALLDOCS))
+ALLPS = $(addsuffix .ps,$(ALLDOCS))
# Prefix for archive names
ARCHIVEPRREFIX =
@@ -12,14 +13,18 @@ LATEXOPTS =
FMT = pdf
LATEX = latex
-PDFLATEX = pdflatex
+PDFLATEX = {{ latex_engine }}
MAKEINDEX = makeindex
+{% if latex_engine == 'platex' %}
+all: all-pdf-ja
+all-pdf: all-pdf-ja
+{% else %}
all: $(ALLPDF)
all-pdf: $(ALLPDF)
+{% endif -%}
all-dvi: $(ALLDVI)
-all-ps: all-dvi
- for f in *.dvi; do dvips $$f; done
+all-ps: $(ALLPS)
all-pdf-ja:
for f in *.pdf *.png *.gif *.jpg *.jpeg; do extractbb $$f; done
@@ -70,6 +75,9 @@ xz: tar
$(PDFLATEX) $(LATEXOPTS) '$<'
$(PDFLATEX) $(LATEXOPTS) '$<'
+%.ps: %.dvi
+ dvips '$<'
+
clean:
rm -f *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ps *.tar *.tar.gz *.tar.bz2 *.tar.xz $(ALLPDF) $(ALLDVI)
diff --git a/sphinx/texinputs/fncychap.sty b/sphinx/texinputs/fncychap.sty
deleted file mode 100644
index 9a56c04ed..000000000
--- a/sphinx/texinputs/fncychap.sty
+++ /dev/null
@@ -1,683 +0,0 @@
-%%% Copyright Ulf A. Lindgren
-%%%
-%%% Note Premission is granted to modify this file under
-%%% the condition that it is saved using another
-%%% file and package name.
-%%%
-%%% Revision 1.1 (1997)
-%%%
-%%% Jan. 8th Modified package name base date option
-%%% Jan. 22th Modified FmN and FmTi for error in book.cls
-%%% \MakeUppercase{#}->{\MakeUppercase#}
-%%% Apr. 6th Modified Lenny option to prevent undesired
-%%% skip of line.
-%%% Nov. 8th Fixed \@chapapp for AMS
-%%%
-%%% Revision 1.2 (1998)
-%%%
-%%% Feb. 11th Fixed appendix problem related to Bjarne
-%%% Aug. 11th Fixed problem related to 11pt and 12pt
-%%% suggested by Tomas Lundberg. THANKS!
-%%%
-%%% Revision 1.3 (2004)
-%%% Sep. 20th problem with frontmatter, mainmatter and
-%%% backmatter, pointed out by Lapo Mori
-%%%
-%%% Revision 1.31 (2004)
-%%% Sep. 21th problem with the Rejne definition streched text
-%%% caused ugly gaps in the vrule aligned with the title
-%%% text. Kindly pointed out to me by Hendri Adriaens
-%%%
-%%% Revision 1.32 (2005)
-%%% Jun. 23th compatibility problem with the KOMA class 'scrbook.cls'
-%%% a remedy is a redefinition of '\@schapter' in
-%%% line with that used in KOMA. The problem was pointed
-%%% out to me by Mikkel Holm Olsen
-%%%
-%%% Revision 1.33 (2005)
-%%% Aug. 9th misspelled ``TWELV'' corrected, the error was pointed
-%%% out to me by George Pearson
-%%%
-%%% Revision 1.34 (2007)
-%%% Added an alternative to Lenny provided by Peter
-%%% Osborne (2005-11-28)
-%%% Corrected front, main and back matter, based on input
-%%% from Bas van Gils (2006-04-24)
-%%% Jul. 30th Added Bjornstrup option provided by Jean-Marc
-%%% Francois (2007-01-05).
-%%% Reverted to \MakeUppercase{#} see rev 1.1, solved
-%%% problem with MakeUppercase and MakeLowercase pointed
-%%% out by Marco Feuerstein (2007-06-06)
-
-
-%%% Last modified Jul. 2007
-
-\NeedsTeXFormat{LaTeX2e}[1995/12/01]
-\ProvidesPackage{fncychap}
- [2007/07/30 v1.34
- LaTeX package (Revised chapters)]
-
-%%%% For conditional inclusion of color
-\newif\ifusecolor
-\usecolorfalse
-
-
-
-%%%% DEFINITION OF Chapapp variables
-\newcommand{\CNV}{\huge\bfseries}
-\newcommand{\ChNameVar}[1]{\renewcommand{\CNV}{#1}}
-
-
-%%%% DEFINITION OF TheChapter variables
-\newcommand{\CNoV}{\huge\bfseries}
-\newcommand{\ChNumVar}[1]{\renewcommand{\CNoV}{#1}}
-
-\newif\ifUCN
-\UCNfalse
-\newif\ifLCN
-\LCNfalse
-\def\ChNameLowerCase{\LCNtrue\UCNfalse}
-\def\ChNameUpperCase{\UCNtrue\LCNfalse}
-\def\ChNameAsIs{\UCNfalse\LCNfalse}
-
-%%%%% Fix for AMSBook 971008
-
-\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{}
-
-
-%%%%% Fix for Bjarne and appendix 980211
-
-\newif\ifinapp
-\inappfalse
-\renewcommand\appendix{\par
- \setcounter{chapter}{0}%
- \setcounter{section}{0}%
- \inapptrue%
- \renewcommand\@chapapp{\appendixname}%
- \renewcommand\thechapter{\@Alph\c@chapter}}
-
-%%%%% Fix for frontmatter, mainmatter, and backmatter 040920
-
-\@ifundefined{@mainmatter}{\newif\if@mainmatter \@mainmattertrue}{}
-
-%%%%%
-
-
-
-\newcommand{\FmN}[1]{%
-\ifUCN
- {\MakeUppercase{#1}}\LCNfalse
-\else
- \ifLCN
- {\MakeLowercase{#1}}\UCNfalse
- \else #1
- \fi
-\fi}
-
-
-%%%% DEFINITION OF Title variables
-\newcommand{\CTV}{\Huge\bfseries}
-\newcommand{\ChTitleVar}[1]{\renewcommand{\CTV}{#1}}
-
-%%%% DEFINITION OF the basic rule width
-\newlength{\RW}
-\setlength{\RW}{1pt}
-\newcommand{\ChRuleWidth}[1]{\setlength{\RW}{#1}}
-
-\newif\ifUCT
-\UCTfalse
-\newif\ifLCT
-\LCTfalse
-\def\ChTitleLowerCase{\LCTtrue\UCTfalse}
-\def\ChTitleUpperCase{\UCTtrue\LCTfalse}
-\def\ChTitleAsIs{\UCTfalse\LCTfalse}
-\newcommand{\FmTi}[1]{%
-\ifUCT
- {\MakeUppercase{#1}}\LCTfalse
-\else
- \ifLCT
- {\MakeLowercase{#1}}\UCTfalse
- \else {#1}
- \fi
-\fi}
-
-
-
-\newlength{\mylen}
-\newlength{\myhi}
-\newlength{\px}
-\newlength{\py}
-\newlength{\pyy}
-\newlength{\pxx}
-
-
-\def\mghrulefill#1{\leavevmode\leaders\hrule\@height #1\hfill\kern\z@}
-
-\newcommand{\DOCH}{%
- \CNV\FmN{\@chapapp}\space \CNoV\thechapter
- \par\nobreak
- \vskip 20\p@
- }
-\newcommand{\DOTI}[1]{%
- \CTV\FmTi{#1}\par\nobreak
- \vskip 40\p@
- }
-\newcommand{\DOTIS}[1]{%
- \CTV\FmTi{#1}\par\nobreak
- \vskip 40\p@
- }
-
-%%%%%% SONNY DEF
-
-\DeclareOption{Sonny}{%
- \ChNameVar{\Large\sf}
- \ChNumVar{\Huge}
- \ChTitleVar{\Large\sf}
- \ChRuleWidth{0.5pt}
- \ChNameUpperCase
- \renewcommand{\DOCH}{%
- \raggedleft
- \CNV\FmN{\@chapapp}\space \CNoV\thechapter
- \par\nobreak
- \vskip 40\p@}
- \renewcommand{\DOTI}[1]{%
- \CTV\raggedleft\mghrulefill{\RW}\par\nobreak
- \vskip 5\p@
- \CTV\FmTi{#1}\par\nobreak
- \mghrulefill{\RW}\par\nobreak
- \vskip 40\p@}
- \renewcommand{\DOTIS}[1]{%
- \CTV\raggedleft\mghrulefill{\RW}\par\nobreak
- \vskip 5\p@
- \CTV\FmTi{#1}\par\nobreak
- \mghrulefill{\RW}\par\nobreak
- \vskip 40\p@}
-}
-
-%%%%%% LENNY DEF
-
-\DeclareOption{Lenny}{%
-
- \ChNameVar{\fontsize{14}{16}\usefont{OT1}{phv}{m}{n}\selectfont}
- \ChNumVar{\fontsize{60}{62}\usefont{OT1}{ptm}{m}{n}\selectfont}
- \ChTitleVar{\Huge\bfseries\rm}
- \ChRuleWidth{1pt}
- \renewcommand{\DOCH}{%
- \settowidth{\px}{\CNV\FmN{\@chapapp}}
- \addtolength{\px}{2pt}
- \settoheight{\py}{\CNV\FmN{\@chapapp}}
- \addtolength{\py}{1pt}
-
- \settowidth{\mylen}{\CNV\FmN{\@chapapp}\space\CNoV\thechapter}
- \addtolength{\mylen}{1pt}
- \settowidth{\pxx}{\CNoV\thechapter}
- \addtolength{\pxx}{-1pt}
-
- \settoheight{\pyy}{\CNoV\thechapter}
- \addtolength{\pyy}{-2pt}
- \setlength{\myhi}{\pyy}
- \addtolength{\myhi}{-1\py}
- \par
- \parbox[b]{\textwidth}{%
- \rule[\py]{\RW}{\myhi}%
- \hskip -\RW%
- \rule[\pyy]{\px}{\RW}%
- \hskip -\px%
- \raggedright%
- \CNV\FmN{\@chapapp}\space\CNoV\thechapter%
- \hskip1pt%
- \mghrulefill{\RW}%
- \rule{\RW}{\pyy}\par\nobreak%
- \vskip -\baselineskip%
- \vskip -\pyy%
- \hskip \mylen%
- \mghrulefill{\RW}\par\nobreak%
- \vskip \pyy}%
- \vskip 20\p@}
-
-
- \renewcommand{\DOTI}[1]{%
- \raggedright
- \CTV\FmTi{#1}\par\nobreak
- \vskip 40\p@}
-
- \renewcommand{\DOTIS}[1]{%
- \raggedright
- \CTV\FmTi{#1}\par\nobreak
- \vskip 40\p@}
- }
-
-%%%%%% Peter Osbornes' version of LENNY DEF
-
-\DeclareOption{PetersLenny}{%
-
-% five new lengths
-\newlength{\bl} % bottom left : orig \space
-\setlength{\bl}{6pt}
-\newcommand{\BL}[1]{\setlength{\bl}{#1}}
-\newlength{\br} % bottom right : orig 1pt
-\setlength{\br}{1pt}
-\newcommand{\BR}[1]{\setlength{\br}{#1}}
-\newlength{\tl} % top left : orig 2pt
-\setlength{\tl}{2pt}
-\newcommand{\TL}[1]{\setlength{\tl}{#1}}
-\newlength{\trr} % top right :orig 1pt
-\setlength{\trr}{1pt}
-\newcommand{\TR}[1]{\setlength{\trr}{#1}}
-\newlength{\blrule} % top right :orig 1pt
-\setlength{\trr}{0pt}
-\newcommand{\BLrule}[1]{\setlength{\blrule}{#1}}
-
-
- \ChNameVar{\fontsize{14}{16}\usefont{OT1}{phv}{m}{n}\selectfont}
- \ChNumVar{\fontsize{60}{62}\usefont{OT1}{ptm}{m}{n}\selectfont}
- \ChTitleVar{\Huge\bfseries\rm}
- \ChRuleWidth{1pt}
-\renewcommand{\DOCH}{%
-
-
-%%%%%%% tweaks for 1--9 and A--Z
-\ifcase\c@chapter\relax%
-\or\BL{-3pt}\TL{-4pt}\BR{0pt}\TR{-6pt}%1
-\or\BL{0pt}\TL{-4pt}\BR{2pt}\TR{-4pt}%2
-\or\BL{0pt}\TL{-4pt}\BR{2pt}\TR{-4pt}%3
-\or\BL{0pt}\TL{5pt}\BR{2pt}\TR{-4pt}%4
-\or\BL{0pt}\TL{3pt}\BR{2pt}\TR{-4pt}%5
-\or\BL{-1pt}\TL{0pt}\BR{2pt}\TR{-2pt}%6
-\or\BL{0pt}\TL{-3pt}\BR{2pt}\TR{-2pt}%7
-\or\BL{0pt}\TL{-3pt}\BR{2pt}\TR{-2pt}%8
-\or\BL{0pt}\TL{-3pt}\BR{-4pt}\TR{-2pt}%9
-\or\BL{-3pt}\TL{-3pt}\BR{2pt}\TR{-7pt}%10
-\or\BL{-6pt}\TL{-6pt}\BR{0pt}\TR{-9pt}%11
-\or\BL{-6pt}\TL{-6pt}\BR{2pt}\TR{-7pt}%12
-\or\BL{-5pt}\TL{-5pt}\BR{0pt}\TR{-9pt}%13
-\or\BL{-6pt}\TL{-6pt}\BR{0pt}\TR{-9pt}%14
-\or\BL{-3pt}\TL{-3pt}\BR{3pt}\TR{-6pt}%15
-\or\BL{-3pt}\TL{-3pt}\BR{3pt}\TR{-6pt}%16
-\or\BL{-5pt}\TL{-3pt}\BR{-8pt}\TR{-6pt}%17
-\or\BL{-5pt}\TL{-5pt}\BR{0pt}\TR{-9pt}%18
-\or\BL{-3pt}\TL{-3pt}\BR{-6pt}\TR{-9pt}%19
-\or\BL{0pt}\TL{0pt}\BR{0pt}\TR{-5pt}%20
-\fi
-
-\ifinapp\ifcase\c@chapter\relax%
-\or\BL{0pt}\TL{14pt}\BR{5pt}\TR{-19pt}%A
-\or\BL{0pt}\TL{-5pt}\BR{-3pt}\TR{-8pt}%B
-\or\BL{-3pt}\TL{-2pt}\BR{1pt}\TR{-6pt}\BLrule{0pt}%C
-\or\BL{0pt}\TL{-5pt}\BR{-3pt}\TR{-8pt}\BLrule{0pt}%D
-\or\BL{0pt}\TL{-5pt}\BR{2pt}\TR{-3pt}%E
-\or\BL{0pt}\TL{-5pt}\BR{-10pt}\TR{-1pt}%F
-\or\BL{-3pt}\TL{0pt}\BR{0pt}\TR{-7pt}%G
-\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}%H
-\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}%I
-\or\BL{2pt}\TL{0pt}\BR{-3pt}\TR{1pt}%J
-\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}%K
-\or\BL{0pt}\TL{-5pt}\BR{2pt}\TR{-19pt}%L
-\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}%M
-\or\BL{0pt}\TL{-5pt}\BR{-2pt}\TR{-1pt}%N
-\or\BL{-3pt}\TL{-2pt}\BR{-3pt}\TR{-11pt}%O
-\or\BL{0pt}\TL{-5pt}\BR{-9pt}\TR{-3pt}%P
-\or\BL{-3pt}\TL{-2pt}\BR{-3pt}\TR{-11pt}%Q
-\or\BL{0pt}\TL{-5pt}\BR{4pt}\TR{-8pt}%R
-\or\BL{-2pt}\TL{-2pt}\BR{-2pt}\TR{-7pt}%S
-\or\BL{-3pt}\TL{0pt}\BR{-5pt}\TR{4pt}\BLrule{8pt}%T
-\or\BL{-7pt}\TL{-11pt}\BR{-5pt}\TR{-7pt}\BLrule{0pt}%U
-\or\BL{-14pt}\TL{-5pt}\BR{-14pt}\TR{-1pt}\BLrule{14pt}%V
-\or\BL{-10pt}\TL{-9pt}\BR{-13pt}\TR{-3pt}\BLrule{7pt}%W
-\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}\BLrule{0pt}%X
-\or\BL{-6pt}\TL{-4pt}\BR{-7pt}\TR{1pt}\BLrule{7pt}%Y
-\or\BL{0pt}\TL{-5pt}\BR{3pt}\TR{-1pt}\BLrule{0pt}%Z
-\fi\fi
-%%%%%%%
- \settowidth{\px}{\CNV\FmN{\@chapapp}}
- \addtolength{\px}{\tl} %MOD change 2pt to \tl
- \settoheight{\py}{\CNV\FmN{\@chapapp}}
- \addtolength{\py}{1pt}
-
- \settowidth{\mylen}{\CNV\FmN{\@chapapp}\space\CNoV\thechapter}
- \addtolength{\mylen}{\trr}% MOD change 1pt to \tr
- \settowidth{\pxx}{\CNoV\thechapter}
- \addtolength{\pxx}{-1pt}
-
- \settoheight{\pyy}{\CNoV\thechapter}
- \addtolength{\pyy}{-2pt}
- \setlength{\myhi}{\pyy}
- \addtolength{\myhi}{-1\py}
- \par
- \parbox[b]{\textwidth}{%
- \rule[\py]{\RW}{\myhi}%
- \hskip -\RW%
- \rule[\pyy]{\px}{\RW}%
- \hskip -\px%
- \raggedright%
- \CNV\FmN{\@chapapp}\rule{\blrule}{\RW}\hskip\bl\CNoV\thechapter%MOD
-% \CNV\FmN{\@chapapp}\space\CNoV\thechapter %ORIGINAL
- \hskip\br% %MOD 1pt to \br
- \mghrulefill{\RW}%
- \rule{\RW}{\pyy}\par\nobreak%
- \vskip -\baselineskip%
- \vskip -\pyy%
- \hskip \mylen%
- \mghrulefill{\RW}\par\nobreak%
- \vskip \pyy}%
- \vskip 20\p@}
-
-
- \renewcommand{\DOTI}[1]{%
- \raggedright
- \CTV\FmTi{#1}\par\nobreak
- \vskip 40\p@}
-
- \renewcommand{\DOTIS}[1]{%
- \raggedright
- \CTV\FmTi{#1}\par\nobreak
- \vskip 40\p@}
- }
-
-
-%
-
-
-%%%%%% BJORNSTRUP DEF
-
-\DeclareOption{Bjornstrup}{%
- \usecolortrue
- % pzc (Zapf Chancelery) is nice. ppl (Palatino) is cool too.
- \ChNumVar{\fontsize{76}{80}\usefont{OT1}{pzc}{m}{n}\selectfont}
- \ChTitleVar{\raggedleft\Large\sffamily\bfseries}
-
- \setlength{\myhi}{10pt} % Space between grey box border and text
- \setlength{\mylen}{\textwidth}
- \addtolength{\mylen}{-2\myhi}
- \renewcommand{\DOCH}{%
- \settowidth{\py}{\CNoV\thechapter}
- \addtolength{\py}{-10pt} % Amount of space by which the
-% % number is shifted right
- \fboxsep=0pt%
- \colorbox[gray]{.85}{\rule{0pt}{40pt}\parbox[b]{\textwidth}{\hfill}}%
- \kern-\py\raise20pt%
- \hbox{\color[gray]{.5}\CNoV\thechapter}\\%
- }
-
- \renewcommand{\DOTI}[1]{%
- \nointerlineskip\raggedright%
- \fboxsep=\myhi%
- \vskip-1ex%
- \colorbox[gray]{.85}{\parbox[t]{\mylen}{\CTV\FmTi{#1}}}\par\nobreak%
- \vskip 40\p@%
- }
-
- \renewcommand{\DOTIS}[1]{%
- \fboxsep=0pt
- \colorbox[gray]{.85}{\rule{0pt}{40pt}\parbox[b]{\textwidth}{\hfill}}\\%
- \nointerlineskip\raggedright%
- \fboxsep=\myhi%
- \colorbox[gray]{.85}{\parbox[t]{\mylen}{\CTV\FmTi{#1}}}\par\nobreak%
- \vskip 40\p@%
- }
-}
-
-
-%%%%%%% GLENN DEF
-
-
-\DeclareOption{Glenn}{%
- \ChNameVar{\bfseries\Large\sf}
- \ChNumVar{\Huge}
- \ChTitleVar{\bfseries\Large\rm}
- \ChRuleWidth{1pt}
- \ChNameUpperCase
- \ChTitleUpperCase
- \renewcommand{\DOCH}{%
- \settoheight{\myhi}{\CTV\FmTi{Test}}
- \setlength{\py}{\baselineskip}
- \addtolength{\py}{\RW}
- \addtolength{\py}{\myhi}
- \setlength{\pyy}{\py}
- \addtolength{\pyy}{-1\RW}
-
- \raggedright
- \CNV\FmN{\@chapapp}\space\CNoV\thechapter
- \hskip 3pt\mghrulefill{\RW}\rule[-1\pyy]{2\RW}{\py}\par\nobreak}
-
- \renewcommand{\DOTI}[1]{%
- \addtolength{\pyy}{-4pt}
- \settoheight{\myhi}{\CTV\FmTi{#1}}
- \addtolength{\myhi}{\py}
- \addtolength{\myhi}{-1\RW}
- \vskip -1\pyy
- \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt
- \raggedleft\CTV\FmTi{#1}\par\nobreak
- \vskip 80\p@}
-
-\newlength{\backskip}
- \renewcommand{\DOTIS}[1]{%
-% \setlength{\py}{10pt}
-% \setlength{\pyy}{\py}
-% \addtolength{\pyy}{\RW}
-% \setlength{\myhi}{\baselineskip}
-% \addtolength{\myhi}{\pyy}
-% \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak
-% \addtolength{}{}
-%\vskip -1\baselineskip
-% \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt
-% \raggedleft\CTV\FmTi{#1}\par\nobreak
-% \vskip 60\p@}
-%% Fix suggested by Tomas Lundberg
- \setlength{\py}{25pt} % eller vad man vill
- \setlength{\pyy}{\py}
- \setlength{\backskip}{\py}
- \addtolength{\backskip}{2pt}
- \addtolength{\pyy}{\RW}
- \setlength{\myhi}{\baselineskip}
- \addtolength{\myhi}{\pyy}
- \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak
- \vskip -1\backskip
- \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 3pt %
- \raggedleft\CTV\FmTi{#1}\par\nobreak
- \vskip 40\p@}
- }
-
-%%%%%%% CONNY DEF
-
-\DeclareOption{Conny}{%
- \ChNameUpperCase
- \ChTitleUpperCase
- \ChNameVar{\centering\Huge\rm\bfseries}
- \ChNumVar{\Huge}
- \ChTitleVar{\centering\Huge\rm}
- \ChRuleWidth{2pt}
-
- \renewcommand{\DOCH}{%
- \mghrulefill{3\RW}\par\nobreak
- \vskip -0.5\baselineskip
- \mghrulefill{\RW}\par\nobreak
- \CNV\FmN{\@chapapp}\space \CNoV\thechapter
- \par\nobreak
- \vskip -0.5\baselineskip
- }
- \renewcommand{\DOTI}[1]{%
- \mghrulefill{\RW}\par\nobreak
- \CTV\FmTi{#1}\par\nobreak
- \vskip 60\p@
- }
- \renewcommand{\DOTIS}[1]{%
- \mghrulefill{\RW}\par\nobreak
- \CTV\FmTi{#1}\par\nobreak
- \vskip 60\p@
- }
- }
-
-%%%%%%% REJNE DEF
-
-\DeclareOption{Rejne}{%
-
- \ChNameUpperCase
- \ChTitleUpperCase
- \ChNameVar{\centering\Large\rm}
- \ChNumVar{\Huge}
- \ChTitleVar{\centering\Huge\rm}
- \ChRuleWidth{1pt}
- \renewcommand{\DOCH}{%
- \settoheight{\py}{\CNoV\thechapter}
- \parskip=0pt plus 1pt % Set parskip to default, just in case v1.31
- \addtolength{\py}{-1pt}
- \CNV\FmN{\@chapapp}\par\nobreak
- \vskip 20\p@
- \setlength{\myhi}{2\baselineskip}
- \setlength{\px}{\myhi}
- \addtolength{\px}{-1\RW}
- \rule[-1\px]{\RW}{\myhi}\mghrulefill{\RW}\hskip
- 10pt\raisebox{-0.5\py}{\CNoV\thechapter}\hskip 10pt\mghrulefill{\RW}\rule[-1\px]{\RW}{\myhi}\par\nobreak
- \vskip -3\p@% Added -2pt vskip to correct for streched text v1.31
- }
- \renewcommand{\DOTI}[1]{%
- \setlength{\mylen}{\textwidth}
- \parskip=0pt plus 1pt % Set parskip to default, just in case v1.31
- \addtolength{\mylen}{-2\RW}
- {\vrule width\RW}\parbox{\mylen}{\CTV\FmTi{#1}}{\vrule width\RW}\par\nobreak%
- \vskip -3pt\rule{\RW}{2\baselineskip}\mghrulefill{\RW}\rule{\RW}{2\baselineskip}%
- \vskip 60\p@% Added -2pt in vskip to correct for streched text v1.31
- }
- \renewcommand{\DOTIS}[1]{%
- \setlength{\py}{\fboxrule}
- \setlength{\fboxrule}{\RW}
- \setlength{\mylen}{\textwidth}
- \addtolength{\mylen}{-2\RW}
- \fbox{\parbox{\mylen}{\vskip 2\baselineskip\CTV\FmTi{#1}\par\nobreak\vskip \baselineskip}}
- \setlength{\fboxrule}{\py}
- \vskip 60\p@
- }
- }
-
-
-%%%%%%% BJARNE DEF
-
-\DeclareOption{Bjarne}{%
- \ChNameUpperCase
- \ChTitleUpperCase
- \ChNameVar{\raggedleft\normalsize\rm}
- \ChNumVar{\raggedleft \bfseries\Large}
- \ChTitleVar{\raggedleft \Large\rm}
- \ChRuleWidth{1pt}
-
-
-%% Note thechapter -> c@chapter fix appendix bug
-%% Fixed misspelled 12
-
- \newcounter{AlphaCnt}
- \newcounter{AlphaDecCnt}
- \newcommand{\AlphaNo}{%
- \ifcase\number\theAlphaCnt
- \ifnum\c@chapter=0
- ZERO\else{}\fi
- \or ONE\or TWO\or THREE\or FOUR\or FIVE
- \or SIX\or SEVEN\or EIGHT\or NINE\or TEN
- \or ELEVEN\or TWELVE\or THIRTEEN\or FOURTEEN\or FIFTEEN
- \or SIXTEEN\or SEVENTEEN\or EIGHTEEN\or NINETEEN\fi
-}
-
- \newcommand{\AlphaDecNo}{%
- \setcounter{AlphaDecCnt}{0}
- \@whilenum\number\theAlphaCnt>0\do
- {\addtocounter{AlphaCnt}{-10}
- \addtocounter{AlphaDecCnt}{1}}
- \ifnum\number\theAlphaCnt=0
- \else
- \addtocounter{AlphaDecCnt}{-1}
- \addtocounter{AlphaCnt}{10}
- \fi
-
-
- \ifcase\number\theAlphaDecCnt\or TEN\or TWENTY\or THIRTY\or
- FORTY\or FIFTY\or SIXTY\or SEVENTY\or EIGHTY\or NINETY\fi
- }
- \newcommand{\TheAlphaChapter}{%
-
- \ifinapp
- \thechapter
- \else
- \setcounter{AlphaCnt}{\c@chapter}
- \ifnum\c@chapter<20
- \AlphaNo
- \else
- \AlphaDecNo\AlphaNo
- \fi
- \fi
- }
- \renewcommand{\DOCH}{%
- \mghrulefill{\RW}\par\nobreak
- \CNV\FmN{\@chapapp}\par\nobreak
- \CNoV\TheAlphaChapter\par\nobreak
- \vskip -1\baselineskip\vskip 5pt\mghrulefill{\RW}\par\nobreak
- \vskip 20\p@
- }
- \renewcommand{\DOTI}[1]{%
- \CTV\FmTi{#1}\par\nobreak
- \vskip 40\p@
- }
- \renewcommand{\DOTIS}[1]{%
- \CTV\FmTi{#1}\par\nobreak
- \vskip 40\p@
- }
-}
-
-\DeclareOption*{%
- \PackageWarning{fancychapter}{unknown style option}
- }
-
-\ProcessOptions* \relax
-
-\ifusecolor
- \RequirePackage{color}
-\fi
-\def\@makechapterhead#1{%
- \vspace*{50\p@}%
- {\parindent \z@ \raggedright \normalfont
- \ifnum \c@secnumdepth >\m@ne
- \if@mainmatter%%%%% Fix for frontmatter, mainmatter, and backmatter 040920
- \DOCH
- \fi
- \fi
- \interlinepenalty\@M
- \if@mainmatter%%%%% Fix for frontmatter, mainmatter, and backmatter 060424
- \DOTI{#1}%
- \else%
- \DOTIS{#1}%
- \fi
- }}
-
-
-%%% Begin: To avoid problem with scrbook.cls (fncychap version 1.32)
-
-%%OUT:
-%\def\@schapter#1{\if@twocolumn
-% \@topnewpage[\@makeschapterhead{#1}]%
-% \else
-% \@makeschapterhead{#1}%
-% \@afterheading
-% \fi}
-
-%%IN:
-\def\@schapter#1{%
-\if@twocolumn%
- \@makeschapterhead{#1}%
-\else%
- \@makeschapterhead{#1}%
- \@afterheading%
-\fi}
-
-%%% End: To avoid problem with scrbook.cls (fncychap version 1.32)
-
-\def\@makeschapterhead#1{%
- \vspace*{50\p@}%
- {\parindent \z@ \raggedright
- \normalfont
- \interlinepenalty\@M
- \DOTIS{#1}
- \vskip 40\p@
- }}
-
-\endinput
-
-
diff --git a/sphinx/texinputs/footnotehyper-sphinx.sty b/sphinx/texinputs/footnotehyper-sphinx.sty
new file mode 100644
index 000000000..a714f211d
--- /dev/null
+++ b/sphinx/texinputs/footnotehyper-sphinx.sty
@@ -0,0 +1,156 @@
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{footnotehyper-sphinx}%
+ [2016/10/27 v0.9f hyperref aware footnote.sty for sphinx (JFB)]
+%%
+%% Package: footnotehyper-sphinx
+%% Version: based on footnotehyper.sty v0.9f (2016/10/03)
+%% as available at http://www.ctan.org/pkg/footnotehyper
+%% License: the one applying to Sphinx
+%%
+%% Differences from footnotehyper v0.9f (2016/10/03):
+%% 1. hyperref is assumed in use (with default hyperfootnotes=true),
+%% 2. no need to check if footnote.sty was loaded,
+%% 3. a special tabulary compatibility layer added, (partial but enough for
+%% Sphinx),
+%% 4. \sphinxfootnotemark, and use of \spx@opt@BeforeFootnote from sphinx.sty.
+%% Note: with \footnotemark[N]/\footnotetext[N] syntax, hyperref
+%% does not insert an hyperlink. This is _not_ improved here.
+%%
+\DeclareOption*{\PackageWarning{footnotehyper}{Option `\CurrentOption' is unknown}}%
+\ProcessOptions\relax
+\let\FNH@@makefntext\@makefntext\let\@makefntext\@firstofone
+\RequirePackage{footnote}
+\let\fnparbox\parbox\let\parbox\fn@parbox\let\@makefntext\FNH@@makefntext
+\let\FNH@fn@footnote \footnote % buggy footnote.sty's \footnote
+\let\FNH@fn@footnotetext\footnotetext % will be redefined later
+\let\footnote \fn@latex@@footnote % meaning of \footnote before footnote.sty
+\let\footnotetext\fn@latex@@footnotetext
+\def\fn@endnote {\color@endgroup}%
+\AtBeginDocument {%
+ \let\fn@latex@@footnote \footnote % meaning of \footnote at end of preamble
+ \let\fn@latex@@footnotetext\footnotetext
+ \let\fn@fntext \FNH@hyper@fntext
+ \let\spewnotes \FNH@hyper@spewnotes
+ \let\endsavenotes\spewnotes
+ \let\fn@endfntext\FNH@fixed@endfntext
+ \let\footnote \FNH@fixed@footnote
+ \let\footnotetext\FNH@fixed@footnotetext
+ \let\endfootnote\fn@endfntext
+ \let\endfootnotetext\endfootnote
+}%
+\def\FNH@hyper@fntext {%
+%% amsmath compatibility
+ \ifx\ifmeasuring@\undefined\expandafter\@secondoftwo
+ \else\expandafter\@firstofone\fi
+ {\ifmeasuring@\expandafter\@gobbletwo\else\expandafter\@firstofone\fi}%
+%% partial tabulary compatibility, [N] must be used, but Sphinx does it
+ {\ifx\equation$\expandafter\@gobbletwo\fi\FNH@hyper@fntext@i }%$
+}%
+\long\def\FNH@hyper@fntext@i #1{\global\setbox\fn@notes\vbox
+ {\unvbox\fn@notes
+ \fn@startnote
+ \@makefntext
+ {\rule\z@\footnotesep\ignorespaces
+ \ifHy@nesting\expandafter\ltx@firstoftwo
+ \else\expandafter\ltx@secondoftwo
+ \fi
+ {\expandafter\hyper@@anchor\expandafter{\Hy@footnote@currentHref}{#1}}%
+ {\Hy@raisedlink
+ {\expandafter\hyper@@anchor\expandafter{\Hy@footnote@currentHref}%
+ {\relax}}%
+ \let\@currentHref\Hy@footnote@currentHref
+ \let\@currentlabelname\@empty
+ #1}%
+ \@finalstrut\strutbox }%
+ \fn@endnote }%
+}%
+\def\FNH@hyper@spewnotes {\endgroup
+ \if@savingnotes\else\ifvoid\fn@notes\else
+ \begingroup\let\@makefntext\@empty
+ \let\@finalstrut\@gobble
+ \let\rule\@gobbletwo
+ \H@@footnotetext{\unvbox\fn@notes}%
+ \endgroup\fi\fi
+}%
+\def\FNH@fixed@endfntext {%
+ \@finalstrut\strutbox
+ \fn@postfntext
+ \fn@endnote
+ \egroup\FNH@endfntext@next % will decide if link or no link
+}%
+\def\FNH@endfntext@link {\begingroup
+ \let\@makefntext\@empty\let\@finalstrut\@gobble\let\rule\@gobbletwo
+ \@footnotetext {\unvbox\z@}%
+ \endgroup
+}%
+\def\FNH@endfntext@nolink {\begingroup
+ \let\@makefntext\@empty\let\@finalstrut\@gobble
+ \let\rule\@gobbletwo
+ \if@savingnotes\expandafter\fn@fntext\else\expandafter\H@@footnotetext\fi
+ {\unvbox\z@}\endgroup
+}%
+%% \spx@opt@BeforeFootnote is defined in sphinx.sty
+\def\FNH@fixed@footnote {\spx@opt@BeforeFootnote\ifx\@currenvir\fn@footnote
+ \expandafter\FNH@footnoteenv\else\expandafter\fn@latex@@footnote\fi }%
+\def\FNH@footnoteenv {\@ifnextchar[\FNH@xfootnoteenv%]
+ {\stepcounter\@mpfn
+ \protected@xdef\@thefnmark{\thempfn}\@footnotemark
+ \def\FNH@endfntext@next{\FNH@endfntext@link}\fn@startfntext}}%
+\def\FNH@xfootnoteenv [#1]{%
+ \begingroup
+ \csname c@\@mpfn\endcsname #1\relax
+ \unrestored@protected@xdef\@thefnmark{\thempfn}%
+ \endgroup\@footnotemark\def\FNH@endfntext@next{\FNH@endfntext@link}%
+ \fn@startfntext}%
+\def\FNH@fixed@footnotetext {\ifx\@currenvir\fn@footnotetext
+ \expandafter\FNH@footnotetextenv\else\expandafter\fn@latex@@footnotetext\fi}%
+\def\FNH@footnotetextenv {\@ifnextchar[\FNH@xfootnotetextenv%]
+ {\protected@xdef\@thefnmark{\thempfn}%
+ \def\FNH@endfntext@next{\FNH@endfntext@link}\fn@startfntext}}%
+\def\FNH@xfootnotetextenv [#1]{%
+ \begingroup
+ \csname c@\@mpfn\endcsname #1\relax
+ \unrestored@protected@xdef\@thefnmark{\thempfn}%
+ \endgroup\def\FNH@endfntext@next{\FNH@endfntext@nolink}%
+ \fn@startfntext }%
+% Now some checks in case some package has modified \@makefntext.
+\AtBeginDocument
+{% compatibility with French module of LaTeX babel
+ \ifx\@makefntextFB\undefined
+ \expandafter\@gobble\else\expandafter\@firstofone\fi
+ {\ifFBFrenchFootnotes \let\FNH@@makefntext\@makefntextFB \else
+ \let\FNH@@makefntext\@makefntextORI\fi}%
+ \expandafter\FNH@check@a\FNH@@makefntext{1.2!3?4,}\FNH@@@1.2!3?4,\FNH@@@\relax
+}%
+\long\def\FNH@check@a #11.2!3?4,#2\FNH@@@#3%
+{%
+ \ifx\relax#3\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
+ \FNH@bad@footnote@env
+ {\def\fn@prefntext{#1}\def\fn@postfntext{#2}\FNH@check@b}%
+}%
+\def\FNH@check@b #1\relax
+{%
+ \expandafter\expandafter\expandafter\FNH@check@c
+ \expandafter\meaning\expandafter\fn@prefntext
+ \meaning\fn@postfntext1.2!3?4,\FNH@check@c\relax
+}%
+\def\FNH@check@c #11.2!3?4,#2#3\relax
+ {\ifx\FNH@check@c#2\expandafter\@gobble\fi\FNH@bad@footnote@env}%
+\def\FNH@bad@footnote@env
+{\PackageWarningNoLine{footnotehyper}%
+ {The footnote environment from package footnote^^J
+ will be dysfunctional, sorry (not my fault...). You may try to make a bug^^J
+ report at https://github.com/sphinx-doc/sphinx including the next lines:}%
+ \typeout{\meaning\@makefntext}%
+ \let\fn@prefntext\@empty\let\fn@postfntext\@empty
+}%
+%% \sphinxfootnotemark: usable in section titles and silently removed from
+%% TOCs.
+\def\sphinxfootnotemark [#1]%
+ {\ifx\thepage\relax\else \protect\spx@opt@BeforeFootnote
+ \protect\footnotemark[#1]\fi}%
+\AtBeginDocument % let hyperref less complain
+ {\pdfstringdefDisableCommands{\def\sphinxfootnotemark [#1]{}}}%
+\endinput
+%%
+%% End of file `footnotehyper-sphinx.sty'.
diff --git a/sphinx/texinputs/iftex.sty b/sphinx/texinputs/iftex.sty
deleted file mode 100755
index 765146644..000000000
--- a/sphinx/texinputs/iftex.sty
+++ /dev/null
@@ -1,97 +0,0 @@
-%%
-%% This is file `iftex.sty',
-
-%%
-%% __________________________________
-%% Copyright © 2010–2013 Persian TeX Group
-%%
-%% License information appended.
-%%
-%%
-\csname iftexloaded\endcsname
-\let\iftexloaded\endinput
-\expandafter\ifx\csname ProvidesPackage\endcsname\relax\else
- \ProvidesPackage{iftex}
- [2013/04/04 v0.2 Provides if(tex) conditional for PDFTeX, XeTeX, and LuaTeX]
-\fi
-\def\RequirePDFTeX{%
- \ifPDFTeX\else
- \begingroup
- \errorcontextlines=-1\relax
- \newlinechar=10\relax
- \errmessage{^^J
- ********************************************^^J
- * PDFTeX is required to compile this document.^^J
- * Sorry!^^J
- ********************************************}%
- \endgroup
- \fi}
-\def\RequireXeTeX{%
- \ifXeTeX\else
- \begingroup
- \errorcontextlines=-1\relax
- \newlinechar=10\relax
- \errmessage{^^J
- ********************************************^^J
- * XeTeX is required to compile this document.^^J
- * Sorry!^^J
- ********************************************}%
- \endgroup
- \fi}
-\def\RequireLuaTeX{%
- \ifLuaTeX\else
- \begingroup
- \errorcontextlines=-1\relax
- \newlinechar=10\relax
- \errmessage{^^J
- ********************************************^^J
- * LuaTeX is required to compile this document.^^J
- * Sorry!^^J
- ********************************************}%
- \endgroup
- \fi}
-\expandafter\ifx\csname ifPDFTeX\endcsname\relax\else
- \expandafter\endinput
-\fi
-\expandafter\ifx\csname ifXeTeX\endcsname\relax\else
- \expandafter\endinput
-\fi
-\expandafter\ifx\csname ifLuaTeX\endcsname\relax\else
- \expandafter\endinput
-\fi
-\newif\ifPDFTeX
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname pdfmatch\endcsname\relax
- \PDFTeXfalse
-\else
- \PDFTeXtrue
-\fi
-\newif\ifXeTeX
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname XeTeXinterchartoks\endcsname\relax
- \XeTeXfalse
-\else
- \XeTeXtrue
-\fi
-\newif\ifLuaTeX
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname directlua\endcsname\relax
- \LuaTeXfalse
-\else
- \LuaTeXtrue
-\fi
-%%
-%% Copyright © 2010–2013 by Persian TeX Group <persian-tex@tug.org>
-%%
-%% Distributable under the LaTeX Project Public License,
-%% version 1.3c or higher (your choice). The latest version of
-%% this license is at: http://www.latex-project.org/lppl.txt
-%%
-%% This work is "maintained" (as per LPPL maintenance status)
-%% by Persian TeX Group.
-%%
-%%
-%%
-%%
-%%
-%% End of file `iftex.sty'.
diff --git a/sphinx/texinputs/newfloat.sty b/sphinx/texinputs/newfloat.sty
deleted file mode 100644
index 47ac5e568..000000000
--- a/sphinx/texinputs/newfloat.sty
+++ /dev/null
@@ -1,737 +0,0 @@
-%%
-%% This is file `newfloat.sty',
-%% generated with the docstrip utility.
-%%
-%% The original source files were:
-%%
-%% newfloat.dtx (with options: `package')
-%%
-%% Copyright (C) 1994-2016 Axel Sommerfeldt (axel.sommerfeldt@f-m.fm)
-%%
-%% http://sourceforge.net/projects/latex-caption/
-%%
-%% --------------------------------------------------------------------------
-%%
-%% This work may be distributed and/or modified under the
-%% conditions of the LaTeX Project Public License, either version 1.3
-%% of this license or (at your option) any later version.
-%% The latest version of this license is in
-%% http://www.latex-project.org/lppl.txt
-%% and version 1.3 or later is part of all distributions of LaTeX
-%% version 2003/12/01 or later.
-%%
-%% This work has the LPPL maintenance status "maintained".
-%%
-%% This Current Maintainer of this work is Axel Sommerfeldt.
-%%
-%% This work consists of the files
-%% CHANGELOG, README, SUMMARY, caption.ins,
-%% caption.dtx, caption2.dtx, caption3.dtx,
-%% bicaption.dtx, ltcaption.dtx, subcaption.dtx,
-%% newfloat.dtx, and totalcount.dtx
-%% the derived files
-%% caption.sty, caption2.sty, caption3.sty,
-%% bicaption.sty, ltcaption.sty, subcaption.sty,
-%% newfloat.sty, and totalcount.sty
-%% and the user manuals
-%% caption-deu.tex, caption-eng.tex, and caption-rus.tex.
-%%
-\NeedsTeXFormat{LaTeX2e}[1994/12/01]
-\def\caption@tempa$Id: #1 #2 #3-#4-#5 #6${%
- \def\caption@tempa{#3/#4/#5 }\def\caption@tempb{#2 }}
-\caption@tempa $Id: newfloat.dtx 109 2015-09-17 09:29:07Z sommerfeldt $
-\ProvidesPackage{newfloat}[\caption@tempa v1.1-\caption@tempb Defining new floating environments (AR)]
-\newcommand*\newfloat@Info[1]{%
- \PackageInfo{newfloat}{#1}}
-\newcommand*\newfloat@InfoNoLine[1]{%
- \newfloat@Info{#1\@gobble}}
-\newcommand*\newfloat@Error[1]{%
- \PackageError{newfloat}{#1}\newfloat@eh}
-\newcommand*\newfloat@eh{%
- If you do not understand this error, please take a closer look\MessageBreak
- at the documentation of the `newfloat' package.\MessageBreak\@ehc}
-\RequirePackage{keyval}[1997/11/10]
-\newcommand*\newfloat@def[2]{%
- \newfloat@ifundefined{#1}{%
- \@namedef{#1}{#2}}}
-\newcommand*\newfloat@let[2]{%
- \newfloat@ifundefined{#1}{%
- \expandafter\let\csname #1\endcsname#2}}
-\newcommand*\newfloat@ifundefined[2]{%
- \@ifundefined{#1}{#2}{%
- \newfloat@Info{%
- \expandafter\string\csname#1\endcsname\space is already defined}}}
-\newcommand*\DeclareFloatingEnvironment{%
- \@testopt\@DeclareFloatingEnvironment{}}
-\@onlypreamble\DeclareFloatingEnvironment
-\def\@DeclareFloatingEnvironment[#1]#2{%
- \newfloat@Info{New float `#2' with options `#1'}%
- \newfloat@ifundefined{c@#2}{\newcounter{#2}}%
- \ifdefined\c@float@type % from float package
- \expandafter\edef\csname ftype@#2\endcsname{\the\value{float@type}}%
- \addtocounter{float@type}{\value{float@type}}%
- \else\ifdefined\c@newflo@tctr % from memoir document class
- \expandafter\edef\csname ftype@#2\endcsname{\the\c@newflo@tctr}%
- \advance\c@newflo@tctr \c@newflo@tctr
- \else
- \ifdefined\newfloat@ftype \else
- \newcount\newfloat@ftype
- \newfloat@ftype=8\relax
- \fi
- \expandafter\xdef\csname ftype@#2\endcsname{\the\newfloat@ftype}%
- \advance\newfloat@ftype\newfloat@ftype
- \fi\fi
- \newfloat@Info{float type `#2'=\@nameuse{ftype@#2}}%
- \newfloat@def{fnum@#2}%
- {\@nameuse{#2name}\nobreakspace\@nameuse{the#2}\@nameuse{autodot}}%
- \newfloat@capitalize\newfloat@Type{#2}%
- \newfloat@let{#2name}{\newfloat@Type}%
- \newfloat@def{fleg#2}{\@nameuse{#2name}}% legend naming (memoir)
- \newfloat@ifundefined{flegtoc#2}{\@namedef{flegtoc#2}##1{}}%
- \ifcsname @tufte@float\endcsname
- \newenvironment{#2}[1][htbp]%
- {\begin{@tufte@float}[##1]{#2}{}}%
- {\end{@tufte@float}}%
- \newenvironment{#2*}[1][htbp]%
- {\begin{@tufte@float}[##1]{#2}{star}}%
- {\end{@tufte@float}}%
- \else
- \newenvironment{#2}{\@float{#2}}{\end@float}%
- \newenvironment{#2*}{\@dblfloat{#2}}{\end@dblfloat}%
- \fi
- \newfloat@def{listof#2}{\newfloat@listof{#2}}%
- \newfloat@def{listof#2s}{\@nameuse{listof#2}}%
- \newfloat@def{listof#2es}{\@nameuse{listof#2s}}%
- \newfloat@def{newfloat@listof#2@hook}{}%
- \ifdefined\l@figure
- \newfloat@let{l@#2}{\l@figure}%
- \else
- \newfloat@def{l@#2}{\@dottedtocline{1}{1.5em}{2.3em}}%
- \fi
- \edef\newfloat@tempa{List of \newfloat@Type s}%
- \newfloat@let{list#2name}{\newfloat@tempa}%
- \expandafter\let\csname fst@#2\endcsname\@undefined
- \newfloat@ifundefined{fps@#2}{\newfloat@setplacement{#2}{tbp}}%
- \newfloat@ifundefined{ext@#2}{\newfloat@setfileext{#2}{lo#2}}%
- \newfloat@setoptions*{#2}{#1}%
- \@expandtwoargs\newfloat@announce{#2}{\@nameuse{ext@#2}}%
- \@ifnextchar[\newfloat@DFE@setname\relax}
-\@onlypreamble\@DeclareFloatingEnvironment
-\def\newfloat@DFE@setname[#1]{%
- \KV@@newfloat@name{#1}%
- \@ifnextchar[\newfloat@DFE@setlistname\relax}
-\@onlypreamble\newfloat@DFE@setname
-\def\newfloat@DFE@setlistname[#1]{%
- \KV@@newfloat@listname{#1}}
-\@onlypreamble\newfloat@DFE@setlistname
-\newcommand*\newfloat@capitalize[2]{%
- \edef\newfloat@tempa{\gdef\noexpand#1{\@car#2\@nil}}%
- \uppercase\expandafter{\newfloat@tempa}%
- \edef\newfloat@tempa{%
- \noexpand\g@addto@macro\noexpand#1{\@cdr#2\@nil}}%
- \newfloat@tempa}
-\newcommand*\newfloat@listof[1]{%
- \@expandtwoargs\newfloat@list@of{#1}{\@nameuse{ext@#1}}}
-\newcommand*\newfloat@list@of[2]{%
- \begingroup
- \expandafter\let\expandafter\listfigurename\csname list#1name\endcsname
- \def\ext@figure{#2}%
- \let\newfloat@starttoc\@starttoc
- \def\@starttoc##1{\newfloat@starttoc{#2}}%
- \let\newfloat@listoftoc\listoftoc
- \def\listoftoc##1{\newfloat@listoftoc{#2}}%
- \@nameuse{newfloat@listof#1@hook}%
- \listoffigures
- \endgroup}
-\newcommand*\newfloat@setoptions{%
- \@ifstar
- {\newfloat@@setoptions\@firstofone}%
- {\newfloat@@setoptions\@gobble}}
-\newcommand*\newfloat@@setoptions[3]{%
- \let\newfloat@within@value\@undefined
- \let\newfloat@chapterlistsgaps@value\@undefined
- #1{\KV@@newfloat@within\newfloat@within@default}% set default value for new floats
- \def\newfloat@type{#2}%
- \setkeys{@newfloat}{#3}%
- \ifx\newfloat@within@value\@undefined \else
- \newfloat@setoption{within}\newfloat@within@value
- \fi
- \ifx\newfloat@chapterlistsgaps@value\@undefined \else
- \newfloat@setoption{chapterlistsgaps}\newfloat@chapterlistsgaps@value
- \fi}
-\newcommand*\newfloat@within@default{%
- \ifcsname c@chapter\endcsname chapter\else none\fi}
-\@onlypreamble\newfloat@within@default
-\newcommand*\newfloat@setoption[1]{%
- \edef\caption@tempa{\noexpand\@nameuse{newfloat@set#1}{\newfloat@type}}%
- \caption@tempa}
-\newcommand*\newfloat@setfileext[2]{%
- \@namedef{ext@#1}{#2}}
-\define@key{@newfloat}{fileext}{%
- \newfloat@setoption{fileext}{#1}}
-\newcommand*\newfloat@setlistname[2]{%
- \@namedef{list#1name}{#2}}
-\define@key{@newfloat}{listname}{%
- \newfloat@setoption{listname}{#1}}
-\newcommand*\newfloat@setname[2]{%
- \newfloat@@setname{#1}{#2}%
- \begingroup
- \ifcsname languagename\endcsname
- \ifcsname captions\languagename\endcsname
- \expandafter\g@addto@macro\csname captions\languagename\endcsname
- {\newfloat@@setname{#1}{#2}}%
- \fi
- \fi
- \endgroup}
-%%\AtBeginDocument{\let\newfloat@setname\newfloat@@setname}
-\newcommand*\newfloat@@setname[2]{%
- \@namedef{#1name}{#2}}
-\define@key{@newfloat}{name}{%
- \newfloat@setoption{name}{#1}}
-\newcommand*\newfloat@setplacement[2]{%
- \@namedef{fps@#1}{#2}}
-\define@key{@newfloat}{placement}{%
- \newfloat@setoption{placement}{#1}}
-\newcommand*\newfloat@setwithin[2]{%
- \ifcsname c@chapter\endcsname
- \@removefromreset{#1}{chapter}%
- \fi
- \@removefromreset{#1}{section}%
- \edef\@tempa{#2}%
- \ifx\@tempa\@empty
- \def\@tempa{none}%
- \fi
- \def\@tempb{none}%
- \ifx\@tempa\@tempb
- \ifcsname c@chapter\endcsname
- \@chapterlistsgap@off{#1}%
- \fi
- \newfloat@@setwithin{#1}{}{}%
- \else
- \def\@tempb{chapter}%
- \ifx\@tempa\@tempb
- \@addtoreset{#1}{chapter}%
- \@chapterlistsgap@on{#1}%
- \newfloat@@setwithin{#1}{\ifnum\c@chapter>\z@ \thechapter.\fi}{\theHchapter.}%
- \else
- \def\@tempb{section}%
- \ifx\@tempa\@tempb
- \@addtoreset{#1}{section}%
- \ifcsname c@chapter\endcsname
- \@addtoreset{#1}{chapter}%
- \@chapterlistsgap@on{#1}%
- \newfloat@@setwithin{#1}{\thesection.}{\theHsection.}%
- \else
- \newfloat@@setwithin{#1}{\ifnum\c@section>\z@ \thesection.\fi}{\theHsection.}%
- \fi
- \else
- \newfloat@Error{Invalid value `#2' for option `within'}%
- \fi
- \fi
- \fi}
-\newcommand*\newfloat@@setwithin[3]{%
- \global\@namedef{the#1}{#2\arabic{#1}}%
- \global\@namedef{theH#1}{#3\arabic{#1}}}
-\define@key{@newfloat}{within}{%
- \def\newfloat@within@value{#1}}
-\newcommand*\newfloat@setwithout[1]{%
- \newfloat@setwithin{#1}{none}}
-\define@key{@newfloat}{without}[]{%
- \def\newfloat@within@value{none}}
-\newcommand*\newfloat@setchapterlistsgaps[2]{%
- \edef\@tempa{#2}%
- \def\@tempb{off}%
- \ifx\@tempa\@tempb
- \@chapterlistsgap@off{#1}%
- \else
- \def\@tempb{on}%
- \ifx\@tempa\@tempb
- \@chapterlistsgap@on{#1}%
- \else
- \newfloat@Error{Invalid value `#2' for option `chapterlistsgaps'}%
- \fi
- \fi}
-\define@key{@newfloat}{chapterlistsgaps}{%
- \def\newfloat@chapterlistsgaps@value{#1}}
-\providecommand*\@removefromreset[2]{{%
- \expandafter\let\csname c@#1\endcsname\@removefromreset
- \def\@elt##1{%
- \expandafter\ifx\csname c@##1\endcsname\@removefromreset
- \else
- \noexpand\@elt{##1}%
- \fi}%
- \expandafter\xdef\csname cl@#2\endcsname{%
- \csname cl@#2\endcsname}}}
-\newcommand*\newfloat@announce[2]{%
- \@cons\newfloat@list{{#1}}%
- \@cons\newfloat@@list{{#1}}%
- \newfloat@ifundefined{newfloat@ext@#2}{%
- \@namedef{newfloat@ext@#2}{#1}%
- \ifcsname c@lofdepth\endcsname
- \newfloat@ifundefined{c@#2depth}{%
- \newcounter{#2depth}%
- \setcounter{#2depth}{1}}%
- \fi
- \ifcsname addtotoclist\endcsname
- \addtotoclist[float]{#2}%
- \newfloat@def{listof#2name}{\@nameuse{list#1name}}%
- \fi
- }%
- \ifcsname contentsuse\endcsname
- \contentsuse{#1}{#2}%
- \fi
- \newfloat@hook{#1}}
-\@onlypreamble\newfloat@announce
-\newcommand*\newfloat@@list{}
-\newcommand*\SetupFloatingEnvironment[1]{%
- \newfloat@addtolist{#1}%
- \newfloat@setoptions{#1}}
-\newcommand\ForEachFloatingEnvironment{%
- \@ifstar
- {\@ForEachFloatingEnvironment\@gobble}%
- {\@ForEachFloatingEnvironment\@iden}}
-\newcommand\@ForEachFloatingEnvironment[2]{%
- \def\@elt##1{#2}%
- \newfloat@list
- \let\@elt\relax
- #1{\newfloat@addtohook{#2}}}
-\providecommand\newfloat@addtohook[1]{%
- \toks@=\expandafter{\newfloat@hook{##1}#1}%
- \edef\@tempa{\def\noexpand\newfloat@hook####1{\the\toks@}}%
- \@tempa}
-\providecommand*\newfloat@hook[1]{}
-\newcommand\PrepareListOf[1]{%
- \expandafter\g@addto@macro\csname newfloat@listof#1@hook\endcsname}
-\@onlypreamble\PrepareListOf
-\newcommand*\newfloat@list{}
-\newcommand*\newfloat@addtolist[1]{%
- \newfloat@ifinlist{#1}{}{%
- \ifcsname ext@#1\endcsname
- \@cons\newfloat@list{{#1}}%
- \@namedef{newfloat@ext@\@nameuse{ext@#1}}{#1}%
- \newfloat@let{@ifchapterlistsgap@#1}{\@iden}%
- \else
- \newfloat@Error{`#1' does not seem to be a floating environment}%
- \fi}}
-\newcommand*\newfloat@ifinlist[1]{%
- \let\next\@secondoftwo
- \begingroup
- \expandafter\let\csname c@#1\endcsname\newfloat@ifinlist
- \def\@elt##1{%
- \expandafter\ifx\csname c@##1\endcsname\newfloat@ifinlist
- \global\let\next\@firstoftwo
- \fi}%
- \newfloat@list
- \endgroup
- \next}
-\ifcsname ext@figure\endcsname
- \newfloat@addtolist{figure}
-\fi
-\ifcsname ext@table\endcsname
- \newfloat@addtolist{table}
-\fi
-\ifcsname @chapter\endcsname
- \providecommand*\@chapterlistsgap{10\p@}%
- \providecommand*\@addchapterlistsgap[2]{%
- \@nameuse{@ifchapterlistsgap@#1}{% if switched on
- \@@addchapterlistsgap{#1}{#2}}}
- \providecommand*\@@addchapterlistsgap[2]{%
- \@ifundefined{@addchapterlistsgap@#2}{% only once per extension
- \@namedef{@addchapterlistsgap@#2}{#1}%
- \@@@addchapterlistsgap{#2}}{}}
- \providecommand*\@@@addchapterlistsgap[1]{%
- \ifdim \@chapterlistsgap>\z@
- \addtocontents{#1}{\protect\addvspace{\@chapterlistsgap}}%
- \fi}
- \providecommand*\@addchapterlistsgaps{%
- \begingroup
- \def\@elt##1{%
- \@expandtwoargs\@addchapterlistsgap{##1}{\@nameuse{ext@##1}}}%
- \newfloat@list
- \endgroup}
- \providecommand*\@chapterlistsgap@off[1]{%
- \expandafter\let\csname @ifchapterlistsgap@#1\endcsname\@gobble
- \ifcsname unsettoc\endcsname
- \@expandtwoargs\unsettoc{\@nameuse{ext@#1}}{chapteratlist}%
- \fi}
- \providecommand*\@chapterlistsgap@on[1]{%
- \expandafter\let\csname @ifchapterlistsgap@#1\endcsname\@iden
- \ifcsname setuptoc\endcsname
- \@expandtwoargs\setuptoc{\@nameuse{ext@#1}}{chapteratlist}%
- \fi}
-\fi
-\define@key{newfloat}{chapterlistsgap}{%
- \renewcommand*\@chapterlistsgap{#1}}
-\define@key{newfloat}{within}{%
- \def\newfloat@within@default{#1}% set new default value
- \def\@elt##1{\newfloat@setwithin{##1}{#1}}%
- \newfloat@list
- \let\@elt\relax}
-\define@key{newfloat}{without}[]{%
- \KV@newfloat@within{none}}
-\def\@elt#1{%
- \define@key{newfloat}{#1name}{%
- \newfloat@setname{#1}{##1}}%
- \define@key{newfloat}{list#1name}{%
- \newfloat@setname{list#1}{##1}}%
- \define@key{newfloat}{#1within}{%
- \newfloat@setwithin{#1}{##1}}%
- \define@key{newfloat}{#1without}[]{%
- \newfloat@setwithout{#1}}%
-}%
-\newfloat@list
-\let\@elt\relax
-\define@key{newfloat}{planb}[true]{%
- \def\@tempa{#1}%
- \def\@tempb{false}%
- \ifx\@tempa\@tempb
- \let\newfloat@ifplanb\@gobble
- \else
- \def\@tempb{true}%
- \ifx\@tempa\@tempb
- \let\newfloat@ifplanb\@iden
- \else
- \newfloat@Error{Invalid value `#1' for option `planb'}%
- \fi
- \fi}
-\define@key{newfloat}{planb-fileext}{%
- \newfloat@Info{Setting Plan B file extension to `#1'}
- \xdef\newfloat@addtocontents@ext{#1}}
-
-\let\@tempc\relax
-\@expandtwoargs\setkeys{newfloat}{planb,\@ptionlist{\@currname.\@currext}}%
-\AtEndOfPackage{\let\@unprocessedoptions\relax}
-\newcommand*\newfloatsetup{\setkeys{newfloat}}
-\newcommand\newfloat@replace@chapter[2]{%
- \begingroup
- \let\if@twocolumn\iffalse
- \let\if@mainmatter\iffalse
- \let\if@thema\iffalse
- \def\@tempa[##1]##2{#1}%
- \ifx\@tempa\@chapter
- \gdef\@chapter[##1]##2{#2}%
- \global\let\newfloat@replace@chapter\@gobbletwo
- \else\ifx\@tempa\Hy@org@chapter
- \gdef\Hy@org@chapter[##1]##2{#2}%
- \global\let\newfloat@replace@chapter\@gobbletwo
- \fi\fi
- \endgroup}
-\ifcsname @chapter\endcsname \else
- \let\newfloat@replace@chapter\@gobbletwo
-\fi
-\newfloat@replace@chapter{%
- \ifnum \c@secnumdepth >\m@ne
- \refstepcounter{chapter}%
- \typeout{\@chapapp\space\thechapter.}%
- \addcontentsline{toc}{chapter}%
- {\protect\numberline{\thechapter}#1}%
- \else
- \addcontentsline{toc}{chapter}{#1}%
- \fi
- \chaptermark{#1}%
- \addtocontents{lof}{\protect\addvspace{10\p@}}%
- \addtocontents{lot}{\protect\addvspace{10\p@}}%
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]%
- \else
- \@makechapterhead{#2}%
- \@afterheading
- \fi
-}{%
- \ifnum \c@secnumdepth >\m@ne
- \refstepcounter{chapter}%
- \typeout{\@chapapp\space\thechapter.}%
- \addcontentsline{toc}{chapter}%
- {\protect\numberline{\thechapter}#1}%
- \else
- \addcontentsline{toc}{chapter}{#1}%
- \fi
- \chaptermark{#1}%
- \@addchapterlistsgaps
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]%
- \else
- \@makechapterhead{#2}%
- \@afterheading
- \fi}
-\newfloat@replace@chapter{%
- \ifnum \c@secnumdepth >\m@ne
- \if@mainmatter
- \refstepcounter{chapter}%
- \typeout{\@chapapp\space\thechapter.}%
- \addcontentsline{toc}{chapter}%
- {\protect\numberline{\thechapter}#1}%
- \else
- \addcontentsline{toc}{chapter}{#1}%
- \fi
- \else
- \addcontentsline{toc}{chapter}{#1}%
- \fi
- \chaptermark{#1}%
- \addtocontents{lof}{\protect\addvspace{10\p@}}%
- \addtocontents{lot}{\protect\addvspace{10\p@}}%
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]%
- \else
- \@makechapterhead{#2}%
- \@afterheading
- \fi
-}{%
- \ifnum \c@secnumdepth >\m@ne
- \if@mainmatter
- \refstepcounter{chapter}%
- \typeout{\@chapapp\space\thechapter.}%
- \addcontentsline{toc}{chapter}%
- {\protect\numberline{\thechapter}#1}%
- \else
- \addcontentsline{toc}{chapter}{#1}%
- \fi
- \else
- \addcontentsline{toc}{chapter}{#1}%
- \fi
- \chaptermark{#1}%
- \@addchapterlistsgaps
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]%
- \else
- \@makechapterhead{#2}%
- \@afterheading
- \fi}
-\newfloat@replace@chapter{%
- \refstepcounter{chapter}%
- \ifnum\c@secnumdepth<\z@ \let\@secnumber\@empty
- \else \let\@secnumber\thechapter \fi
- \typeout{\chaptername\space\@secnumber}%
- \def\@toclevel{0}%
- \ifx\chaptername\appendixname \@tocwriteb\tocappendix{chapter}{#2}%
- \else \@tocwriteb\tocchapter{chapter}{#2}\fi
- \chaptermark{#1}%
- \addtocontents{lof}{\protect\addvspace{10\p@}}%
- \addtocontents{lot}{\protect\addvspace{10\p@}}%
- \@makechapterhead{#2}\@afterheading
-}{%
- \refstepcounter{chapter}%
- \ifnum\c@secnumdepth<\z@ \let\@secnumber\@empty
- \else \let\@secnumber\thechapter \fi
- \typeout{\chaptername\space\@secnumber}%
- \def\@toclevel{0}%
- \ifx\chaptername\appendixname \@tocwriteb\tocappendix{chapter}{#2}%
- \else \@tocwriteb\tocchapter{chapter}{#2}\fi
- \chaptermark{#1}%
- \@addchapterlistsgaps
- \@makechapterhead{#2}\@afterheading}
-\@ifpackageloaded{tocbasic}{%
- \let\newfloat@replace@chapter\@gobbletwo}{}
-\ifcsname insertchapterspace\endcsname
- \renewcommand*\insertchapterspace{\@addchapterlistsgaps}
- \let\newfloat@replace@chapter\@gobbletwo
-\fi
-\newfloat@replace@chapter{%
- \ifnum \c@secnumdepth >\m@ne
- \refstepcounter{chapter}%
- \typeout{\@chapapp\space\thechapter.}%
- \addcontentsline{toc}{chapter}%
- {\protect\numberline{\thechapter}\toc@font0 #1}%
- \else
- \addcontentsline{toc}{chapter}{\toc@font0 #1}%
- \fi
- \chaptermark{#1}%
- \addtocontents{lof}{\protect\addvspace{10\p@}}%
- \addtocontents{lot}{\protect\addvspace{10\p@}}%
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]%
- \else
- \@makechapterhead{#2}%
- \@afterheading
- \fi
-}{%
- \ifnum \c@secnumdepth >\m@ne
- \refstepcounter{chapter}%
- \typeout{\@chapapp\space\thechapter.}%
- \addcontentsline{toc}{chapter}%
- {\protect\numberline{\thechapter}\toc@font0 #1}%
- \else
- \addcontentsline{toc}{chapter}{\toc@font0 #1}%
- \fi
- \chaptermark{#1}%
- \@addchapterlistsgaps
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]%
- \else
- \@makechapterhead{#2}%
- \@afterheading
- \fi}
- % boek(3).cls [2004/06/07 v2.1a NTG LaTeX document class]
-\newfloat@replace@chapter{%
- \ifnum \c@secnumdepth >\m@ne
- \if@mainmatter
- \refstepcounter{chapter}%
- \typeout{\@chapapp\space\thechapter.}%
- \addcontentsline{toc}{chapter}%
- {\protect\numberline{\thechapter}\toc@font0 #1}%
- \else
- \addcontentsline{toc}{chapter}{\toc@font0 #1}%
- \fi
- \else
- \addcontentsline{toc}{chapter}{\toc@font0 #1}%
- \fi
- \chaptermark{#1}%
- \addtocontents{lof}{\protect\addvspace{10\p@}}%
- \addtocontents{lot}{\protect\addvspace{10\p@}}%
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]%
- \else
- \@makechapterhead{#2}%
- \@afterheading
- \fi
-}{%
- \ifnum \c@secnumdepth >\m@ne
- \if@mainmatter
- \refstepcounter{chapter}%
- \typeout{\@chapapp\space\thechapter.}%
- \addcontentsline{toc}{chapter}%
- {\protect\numberline{\thechapter}\toc@font0 #1}%
- \else
- \addcontentsline{toc}{chapter}{\toc@font0 #1}%
- \fi
- \else
- \addcontentsline{toc}{chapter}{\toc@font0 #1}%
- \fi
- \chaptermark{#1}%
- \@addchapterlistsgaps
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]%
- \else
- \@makechapterhead{#2}%
- \@afterheading
- \fi}
-\newfloat@replace@chapter{%
- \ifnum \c@secnumdepth >\m@ne
- \if@mainmatter
- \refstepcounter{chapter}%
- \typeout{\chaptername\space\thechapter.}
- \if@thema
- \ifx\@shortauthor\@empty
- \addcontentsline{toc}{chapter}{%
- \protect\numberline{\thechapter.}#1}%
- \else
- \addcontentsline{toc}{chapter}{%
- \protect\numberline{\thechapter.}%
- \@shortauthor\hfill\mbox{}\vskip\normallineskip #1}%
- \fi
- \else
- \addcontentsline{toc}{chapter}{%
- \protect\numberline{\thechapter.}#1}%
- \fi
- \else
- \addcontentsline{toc}{chapter}{#1}
- \fi
- \else
- \addcontentsline{toc}{chapter}{#1}
- \fi
- \chaptermark{#1}
- \addtocontents{lof}{\protect\addvspace{10pt}}
- \addtocontents{lot}{\protect\addvspace{10pt}}
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]
- \else
- \@makechapterhead{#2}
- \@afterheading
- \fi
-}{%
- \ifnum \c@secnumdepth >\m@ne
- \if@mainmatter
- \refstepcounter{chapter}%
- \typeout{\chaptername\space\thechapter.}%
- \if@thema
- \ifx\@shortauthor\@empty
- \addcontentsline{toc}{chapter}{%
- \protect\numberline{\thechapter.}#1}%
- \else
- \addcontentsline{toc}{chapter}{%
- \protect\numberline{\thechapter.}%
- \@shortauthor\hfill\mbox{}\vskip\normallineskip #1}%
- \fi
- \else
- \addcontentsline{toc}{chapter}{%
- \protect\numberline{\thechapter.}#1}%
- \fi
- \else
- \addcontentsline{toc}{chapter}{#1}%
- \fi
- \else
- \addcontentsline{toc}{chapter}{#1}%
- \fi
- \chaptermark{#1}%
- \@addchapterlistsgaps
- \if@twocolumn
- \@topnewpage[\@makechapterhead{#2}]%
- \else
- \@makechapterhead{#2}%
- \@afterheading
- \fi}
-\ifx\newfloat@replace@chapter\@gobbletwo \else
- \newfloat@InfoNoLine{%
- Unsupported document class, or \noexpand\@chapter\MessageBreak
- was already redefined by another package}
- \newfloat@InfoNoLine{\string\@chapter\space=\space\meaning\@chapter}
- \newfloat@InfoNoLine{\string\Hy@org@chapter\space=\space\meaning\Hy@org@chapter}
- \newfloat@ifplanb{%
- \newfloat@InfoNoLine{Trying Plan B..}%
- \let\newfloat@addtocontents@ORI\addtocontents
- \long\def\addtocontents#1#2{%
- \newfloat@addtocontents{#1}{#2}#2\addvspace\newfloat@nil}%
- \long\def\newfloat@addtocontents#1#2#3\addvspace#4\newfloat@nil{%
- \def\newfloat@tempa{#4}%
- \ifx\newfloat@tempa\@empty
- \newfloat@addtocontents@ORI{#1}{#2}%
- \else
- \ifx\newfloat@addtocontents@ext\@undefined
- \newfloat@Info{Setting Plan B file extension to `#1'...}%
- \xdef\newfloat@addtocontents@ext{#1}%
- \fi
- \edef\newfloat@tempa{#1}%
- \ifx\newfloat@tempa\newfloat@addtocontents@ext
- \begingroup
- \let\addtocontents\newfloat@addtocontents@ORI
- \@addchapterlistsgaps
- \endgroup
- \fi
- \fi}}
-\fi
-\newcommand\newfloat@ForEachNew[2][newfloat@@list]{%
- \AtBeginDocument{%
- \ifcsname#1\endcsname
- \def\@elt##1{#2}%
- \newfloat@@list
- \let\@elt\relax
- \fi}}%
-\@onlypreamble\newfloat@ForEachNew
-%% \begin{macrocode}
-\newfloat@ForEachNew[float@exts]{%
- \@nameuse{@ifchapterlistsgap@#1}{% if switched on
- \let\float@do=\relax
- \edef\@tempa{%
- \noexpand\float@exts{\the\float@exts\float@do{\@nameuse{ext@#1}}}}%
- \@tempa}}
-\newfloat@ForEachNew[FP@floatBegin]{%
- \newcounter{FP@#1C}%
- \newenvironment{FP#1}{\FP@floatBegin{#1}}{\FP@floatEnd}}
-\providecommand*\ext@lstlisting{lol}%
-\newfloat@ForEachNew[@rotfloat]{%
- \newenvironment{sideways#1}{\@rotfloat{#1}}{\end@rotfloat}%
- \newenvironment{sideways#1*}{\@rotdblfloat{#1}}{\end@rotdblfloat}}
-\newcommand*\newfloat@For@SC[2]{%
- \def#1{b}% = \sidecaptionvpos{#2}{b} (v1.6)
- \newenvironment{SC#2}%
- {\SC@float[#1]{#2}}{\endSC@float}%
- \newenvironment{SC#2*}%
- {\SC@dblfloat[#1]{#2}}{\endSC@dblfloat}}
-\@onlypreamble\newfloat@For@SC
-\newfloat@ForEachNew[SC@float]{%
- \expandafter\newfloat@For@SC\csname SC@#1@vpos\endcsname{#1}}
-\newfloat@ForEachNew[wrapfloat]{%
- \newenvironment{wrap#1}{\wrapfloat{#1}}{\endwrapfloat}}
-\endinput
-%%
-%% End of file `newfloat.sty'.
diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty
index d025a0797..b89ffa64e 100644
--- a/sphinx/texinputs/sphinx.sty
+++ b/sphinx/texinputs/sphinx.sty
@@ -6,38 +6,22 @@
%
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
-\ProvidesPackage{sphinx}[2010/01/15 LaTeX package (Sphinx markup)]
+\ProvidesPackage{sphinx}[2016/10/29 v1.5 LaTeX package (Sphinx markup)]
-% this is the \ltx@ifundefined of ltxcmds.sty, which is loaded by
-% hyperref.sty, but we need it before, and initial ltxcmds.sty
-% as in TL2009/Debian had wrong definition.
-\newcommand{\spx@ifundefined}[1]{%
- \ifcsname #1\endcsname
- \expandafter\ifx\csname #1\endcsname\relax
- \expandafter\expandafter\expandafter\@firstoftwo
- \else
- \expandafter\expandafter\expandafter\@secondoftwo
- \fi
- \else
- \expandafter\@firstoftwo
- \fi
-}
+% we delay handling of options to after having loaded packages, because
+% of the need to use \definecolor.
+\RequirePackage{graphicx}
\@ifclassloaded{memoir}{}{\RequirePackage{fancyhdr}}
% for \text macro and \iffirstchoice@ conditional even if amsmath not loaded
\RequirePackage{amstext}
\RequirePackage{textcomp}
-% fancybox not used anymore and will be removed at Sphinx-1.5
-\RequirePackage{fancybox}
\RequirePackage{titlesec}
\RequirePackage{tabulary}
\RequirePackage{makeidx}
% For framing code-blocks and warning type notices, and shadowing topics
\RequirePackage{framed}
-\newif\ifspx@inframed % flag set if we are in a framed environment
-% ifthen not used anymore and will be removed at Sphinx-1.5
-\RequirePackage{ifthen}
% The xcolor package draws better fcolorboxes around verbatim code
\IfFileExists{xcolor.sty}{
\RequirePackage{xcolor}
@@ -46,12 +30,20 @@
}
% For highlighted code.
\RequirePackage{fancyvrb}
+\fvset{fontsize=\small}
% For table captions.
\RequirePackage{threeparttable}
-% Handle footnotes in tables.
-\RequirePackage{footnote}
+% For hyperlinked footnotes in tables; also for gathering footnotes from
+% topic and warning blocks. Also to allow code-blocks in footnotes.
+\RequirePackage{footnotehyper-sphinx}
\makesavenoteenv{tabulary}
-% For floating figures in the text.
+\makesavenoteenv{tabular}
+\makesavenoteenv{threeparttable}
+% (longtable is hyperref compatible and needs no special treatment here.)
+% For the H specifier. Do not \restylefloat{figure}, it breaks Sphinx code
+% for allowing figures in tables.
+\RequirePackage{float}
+% For floating figures in the text. Better to load after float.
\RequirePackage{wrapfig}
% Separate paragraphs by space by default.
\RequirePackage{parskip}
@@ -59,33 +51,131 @@
\RequirePackage{alltt}
% Display "real" single quotes in literal blocks.
\RequirePackage{upquote}
-% For the H specifier. Do not \restylefloat{figure}, it breaks Sphinx code
-% for allowing figures in tables.
-\RequirePackage{float}
-% Redefine these colors to your liking in the preamble.
-\definecolor{TitleColor}{rgb}{0.126,0.263,0.361}
-\definecolor{InnerLinkColor}{rgb}{0.208,0.374,0.486}
-\definecolor{OuterLinkColor}{rgb}{0.216,0.439,0.388}
-% Redefine these colors to something if you want to have colored
-% background and border for code examples.
-\definecolor{VerbatimColor}{rgb}{1,1,1}
-\definecolor{VerbatimBorderColor}{rgb}{0,0,0}
-
-% Uncomment these two lines to ignore the paper size and make the page
-% size more like a typical published manual.
-%\renewcommand{\paperheight}{9in}
-%\renewcommand{\paperwidth}{8.5in} % typical squarish manual
-%\renewcommand{\paperwidth}{7in} % O'Reilly ``Programmming Python''
+% Handle options via "kvoptions" (later loaded by hyperref anyhow)
+\RequirePackage{kvoptions}
+\SetupKeyvalOptions{prefix=spx@opt@} % use \spx@opt@ prefix
+
+\DeclareBoolOption{dontkeepoldnames} % \ifspx@opt@dontkeepoldnames = \iffalse
+\DeclareStringOption[0]{maxlistdepth}% \newcommand*\spx@opt@maxlistdepth{0}
+
+% dimensions, we declare the \dimen registers here.
+\newdimen\sphinxverbatimsep
+\newdimen\sphinxverbatimborder
+\newdimen\sphinxshadowsep
+\newdimen\sphinxshadowsize
+\newdimen\sphinxshadowrule
+% \DeclareStringOption is not convenient for the handling of these dimensions
+% because we want to assign the values to the corresponding registers. Even if
+% we added the code to the key handler it would be too late for the initial
+% set-up and we would need to do initial assignments explicitely. We end up
+% using \define@key directly.
+% verbatim
+\sphinxverbatimsep=\fboxsep
+ \define@key{sphinx}{verbatimsep}{\sphinxverbatimsep\dimexpr #1\relax}
+\sphinxverbatimborder=\fboxrule
+ \define@key{sphinx}{verbatimborder}{\sphinxverbatimborder\dimexpr #1\relax}
+% topic boxes
+\sphinxshadowsep =5pt
+ \define@key{sphinx}{shadowsep}{\sphinxshadowsep\dimexpr #1\relax}
+\sphinxshadowsize=4pt
+ \define@key{sphinx}{shadowsize}{\sphinxshadowsize\dimexpr #1\relax}
+\sphinxshadowrule=\fboxrule
+ \define@key{sphinx}{shadowrule}{\sphinxshadowrule\dimexpr #1\relax}
+% verbatim
+\DeclareBoolOption[true]{verbatimwithframe}
+\DeclareBoolOption[true]{verbatimwrapslines}
+\DeclareBoolOption[true]{inlineliteralwraps}
+% \textvisiblespace for compatibility with fontspec+XeTeX/LuaTeX
+\DeclareStringOption[\textcolor{red}{\textvisiblespace}]{verbatimvisiblespace}
+\DeclareStringOption % must use braces to hide the brackets
+ [{\makebox[2\fontcharwd\font`\x][r]{\textcolor{red}{\tiny$\m@th\hookrightarrow$}}}]%
+ {verbatimcontinued}
+% notices/admonitions
+% the dimensions for notices/admonitions are kept as macros and assigned to
+% \spx@notice@border at time of use, hence \DeclareStringOption is ok for this
+\newdimen\spx@notice@border
+\DeclareStringOption[0.5pt]{noteborder}
+\DeclareStringOption[0.5pt]{hintborder}
+\DeclareStringOption[0.5pt]{importantborder}
+\DeclareStringOption[0.5pt]{tipborder}
+\DeclareStringOption[1pt]{warningborder}
+\DeclareStringOption[1pt]{cautionborder}
+\DeclareStringOption[1pt]{attentionborder}
+\DeclareStringOption[1pt]{dangerborder}
+\DeclareStringOption[1pt]{errorborder}
+% footnotes
+\DeclareStringOption[\mbox{ }]{AtStartFootnote}
+% we need a public macro name for direct use in latex file
+\newcommand*{\sphinxAtStartFootnote}{\spx@opt@AtStartFootnote}
+% no such need for this one, as it is used inside other macros
+\DeclareStringOption[\leavevmode\unskip]{BeforeFootnote}
+% some font styling.
+\DeclareStringOption[\sffamily\bfseries]{HeaderFamily}
+% colours
+% same problems as for dimensions: we want the key handler to use \definecolor
+% first, some colours with no prefix, for backwards compatibility
+\newcommand*{\sphinxDeclareColorOption}[2]{%
+ \definecolor{#1}#2%
+ \define@key{sphinx}{#1}{\definecolor{#1}##1}%
+}%
+\sphinxDeclareColorOption{TitleColor}{{rgb}{0.126,0.263,0.361}}
+\sphinxDeclareColorOption{InnerLinkColor}{{rgb}{0.208,0.374,0.486}}
+\sphinxDeclareColorOption{OuterLinkColor}{{rgb}{0.216,0.439,0.388}}
+\sphinxDeclareColorOption{VerbatimColor}{{rgb}{1,1,1}}
+\sphinxDeclareColorOption{VerbatimBorderColor}{{rgb}{0,0,0}}
+% now the colours defined with "sphinx" prefix in their names
+\newcommand*{\sphinxDeclareSphinxColorOption}[2]{%
+ % set the initial default
+ \definecolor{sphinx#1}#2%
+ % set the key handler. The "value" ##1 must be acceptable by \definecolor.
+ \define@key{sphinx}{#1}{\definecolor{sphinx#1}##1}%
+}%
+% admonition boxes, "light" style
+\sphinxDeclareSphinxColorOption{noteBorderColor}{{rgb}{0,0,0}}
+\sphinxDeclareSphinxColorOption{hintBorderColor}{{rgb}{0,0,0}}
+\sphinxDeclareSphinxColorOption{importantBorderColor}{{rgb}{0,0,0}}
+\sphinxDeclareSphinxColorOption{tipBorderColor}{{rgb}{0,0,0}}
+% admonition boxes, "heavy" style
+\sphinxDeclareSphinxColorOption{warningBorderColor}{{rgb}{0,0,0}}
+\sphinxDeclareSphinxColorOption{cautionBorderColor}{{rgb}{0,0,0}}
+\sphinxDeclareSphinxColorOption{attentionBorderColor}{{rgb}{0,0,0}}
+\sphinxDeclareSphinxColorOption{dangerBorderColor}{{rgb}{0,0,0}}
+\sphinxDeclareSphinxColorOption{errorBorderColor}{{rgb}{0,0,0}}
+\sphinxDeclareSphinxColorOption{warningBgColor}{{rgb}{1,1,1}}
+\sphinxDeclareSphinxColorOption{cautionBgColor}{{rgb}{1,1,1}}
+\sphinxDeclareSphinxColorOption{attentionBgColor}{{rgb}{1,1,1}}
+\sphinxDeclareSphinxColorOption{dangerBgColor}{{rgb}{1,1,1}}
+\sphinxDeclareSphinxColorOption{errorBgColor}{{rgb}{1,1,1}}
+
+\DeclareDefaultOption{\@unknownoptionerror}
+\ProcessKeyvalOptions*
+% don't allow use of maxlistdepth via \sphinxsetup.
+\DisableKeyvalOption{sphinx}{maxlistdepth}
+% user interface: options can be changed midway in a document!
+\newcommand\sphinxsetup[1]{\setkeys{sphinx}{#1}}
+% this is the \ltx@ifundefined of ltxcmds.sty, which is loaded by
+% hyperref.sty, but we need it before, and the first release of
+% ltxcmds.sty as in TL2009/Debian has wrong definition.
+\newcommand{\spx@ifundefined}[1]{%
+ \ifcsname #1\endcsname
+ \expandafter\ifx\csname #1\endcsname\relax
+ \expandafter\expandafter\expandafter\@firstoftwo
+ \else
+ \expandafter\expandafter\expandafter\@secondoftwo
+ \fi
+ \else
+ \expandafter\@firstoftwo
+ \fi
+}
+% FIXME: the reasons might be obsolete (better color drivers now?)
% use pdfoutput for pTeX and dvipdfmx
% when pTeX (\kanjiskip is defined), set pdfoutput to evade \include{pdfcolor}
\ifx\kanjiskip\undefined\else
\newcount\pdfoutput\pdfoutput=0
\fi
-\RequirePackage{graphicx}
-
% for PDF output, use colors and maximal compression
\newif\ifsphinxpdfoutput % used in \maketitle
\ifx\pdfoutput\undefined\else
@@ -107,24 +197,6 @@
\def\py@TitleColor{\color{TitleColor}}
\fi
-% Increase printable page size (copied from fullpage.sty)
-\topmargin 0pt
-\advance \topmargin by -\headheight
-\advance \topmargin by -\headsep
-
-% attempt to work a little better for A4 users
-\textheight \paperheight
-\advance\textheight by -2in
-
-\oddsidemargin 0pt
-\evensidemargin 0pt
-%\evensidemargin -.25in % for ``manual size'' documents
-\marginparwidth 0.5in
-
-\textwidth \paperwidth
-\advance\textwidth by -2in
-
-
% Style parameters and macros used by most documents here
\raggedbottom
\sloppy
@@ -133,8 +205,7 @@
\pagestyle{empty} % start this way
% Use this to set the font family for headers and other decor:
-\newcommand{\py@HeaderFamily}{\sffamily\bfseries}
-\newcommand{\sphinxSetHeaderFamily}[1]{\renewcommand{\py@HeaderFamily}{#1}}
+\newcommand{\py@HeaderFamily}{\spx@opt@HeaderFamily}
% Redefine the 'normal' header/footer style when using "fancyhdr" package:
\spx@ifundefined{fancyhf}{}{
@@ -163,32 +234,61 @@
}
% Some custom font markup commands.
-% *** the macros without \sphinx prefix are still defined at bottom of file ***
-\newcommand{\sphinxstrong}[1]{{\textbf{#1}}}
-% let \sphinxcode and \sphinxbfcode use straight quotes. \@noligs patched by upquote,
-% but needs protection in "moving arguments" such as for captions.
-% Use \scantokens to handle e.g. \item[{\sphinxcode{'fontenc'}}]
-\DeclareRobustCommand{\sphinxcode}[1]{{\@noligs\scantokens{\texttt{#1}\relax}}}
-\newcommand{\sphinxbfcode}[1]{\sphinxcode{\bfseries#1}}
-\newcommand{\sphinxemail}[1]{\textsf{#1}}
-\newcommand{\sphinxtablecontinued}[1]{\textsf{#1}}
-\newcommand{\sphinxtitleref}[1]{\emph{#1}}
-\newcommand{\sphinxmenuselection}[1]{\emph{#1}}
-\newcommand{\sphinxaccelerator}[1]{\underline{#1}}
-\newcommand{\sphinxcrossref}[1]{\emph{#1}}
-\newcommand{\sphinxtermref}[1]{\emph{#1}}
-
-% miscellaneous related to footnotes
-\newcommand*{\sphinxAtStartFootnote}{\mbox{ }}
-% Support large numbered footnotes in minipage (cf. admonitions)
+% *** the macros without \sphinx prefix are still defined near end of file ***
+\long\protected\def\sphinxstrong#1{{\textbf{#1}}}
+% to obtain straight quotes we execute \@noligs as patched by upquote, and
+% \scantokens is needed in cases where it would be too late for the macro to
+% first set catcodes and then fetch its argument. We also make the contents
+% breakable at non-escaped . , ; ? ! / using \sphinxbreaksviaactive.
+% the macro must be protected if it ends up used in moving arguments,
+% in 'alltt' \@noligs is done already, and the \scantokens must be avoided.
+\long\protected\def\sphinxcode#1{{\def\@tempa{alltt}%
+ \ifx\@tempa\@currenvir\else
+ \ifspx@opt@inlineliteralwraps
+ \sphinxbreaksviaactive\let\sphinxafterbreak\empty
+ % do not overwrite the comma set-up
+ \let\verbatim@nolig@list\sphinx@literal@nolig@list
+ \fi
+ % fix a space-gobbling issue due to LaTeX's original \do@noligs
+ \let\do@noligs\sphinx@do@noligs
+ \@noligs\endlinechar\m@ne\everyeof{\noexpand}%
+ \expandafter\scantokens
+ \fi {\texttt{#1}}}}
+\def\sphinx@do@noligs #1{\catcode`#1\active\begingroup\lccode`\~`#1\relax
+ \lowercase{\endgroup\def~{\leavevmode\kern\z@\char`#1 }}}
+\def\sphinx@literal@nolig@list {\do\`\do\<\do\>\do\'\do\-}%
+
+\long\protected\def\sphinxbfcode#1{\sphinxcode{\bfseries#1}}
+\long\protected\def\sphinxemail#1{\textsf{#1}}
+\long\protected\def\sphinxtablecontinued#1{\textsf{#1}}
+\long\protected\def\sphinxtitleref#1{\emph{#1}}
+\long\protected\def\sphinxmenuselection#1{\emph{#1}}
+\long\protected\def\sphinxaccelerator#1{\underline{#1}}
+\long\protected\def\sphinxcrossref#1{\emph{#1}}
+\long\protected\def\sphinxtermref#1{\emph{#1}}
+
+% Support large numbered footnotes in minipage
+% But now obsolete due to systematic use of \savenotes/\spewnotes
+% when minipages are in use in the various macro definitions next.
\def\thempfootnote{\arabic{mpfootnote}}
-% Redefine the Verbatim environment to allow border and background colors
-% and to handle the top caption in a non separable by pagebreak way.
-% The original environment is still used for verbatims within tables.
-\let\OriginalVerbatim=\Verbatim
-\let\endOriginalVerbatim=\endVerbatim
+% Code-blocks
+% Based on use of "fancyvrb.sty"'s Verbatim.
+% - with framing allowing page breaks ("framed.sty")
+% - with breaking of long lines (exploits Pygments mark-up),
+% - with possibly of a top caption, non-separable by pagebreak.
+% - and usable inside tables or footnotes ("footnotehyper-sphinx").
+
+% For maintaining compatibility with Sphinx < 1.5, we define and use these
+% when (unmodified) Verbatim will be needed. But Sphinx >= 1.5 does not modify
+% original Verbatim anyhow.
+\let\OriginalVerbatim \Verbatim
+\let\endOriginalVerbatim\endVerbatim
+
+\newif\ifspx@inframed % flag set if we are already in a framed environment
+% if forced use of minipage encapsulation is needed (e.g. table cells)
+\newif\ifsphinxverbatimwithminipage \sphinxverbatimwithminipagefalse
\newcommand\spx@colorbox [2]{%
% #1 will be \fcolorbox or, for first part of frame: \spx@fcolorbox
% let the framing obey the current indentation (adapted from framed.sty's code).
@@ -202,12 +302,14 @@
\def\spx@fcolorbox #1#2%
{\color@b@x {\fboxsep\z@\color{#1}\spx@VerbatimFBox}{\color{#2}}}%
-% The title is specified from outside as macro \sphinxVerbatimTitle.
+% The title (caption) is specified from outside as macro \sphinxVerbatimTitle.
% \sphinxVerbatimTitle is reset to empty after each use of Verbatim.
\newcommand*\sphinxVerbatimTitle {}
+% This box to typeset the caption before framed.sty multiple passes for framing.
+\newbox\spx@VerbatimTitleBox
% Holder macro for labels of literal blocks. Set-up by LaTeX writer.
\newcommand*\sphinxLiteralBlockLabel {}
-\newcommand*\sphinxSetupCaptionForVerbatim [2]
+\newcommand*\sphinxSetupCaptionForVerbatim [1]
{%
\needspace{\sphinxliteralblockneedspace}%
% insert a \label via \sphinxLiteralBlockLabel
@@ -215,31 +317,31 @@
% the caption inserts \abovecaptionskip whitespace above itself (usually 10pt)
% there is also \belowcaptionskip but it is usually zero, hence the \smallskip
\def\sphinxVerbatimTitle
- {\py@NormalColor\captionof{#1}{\sphinxLiteralBlockLabel #2}\smallskip }%
+ {\py@NormalColor
+ \captionof{literalblock}{\sphinxLiteralBlockLabel #1}\smallskip }%
}
+\newcommand*\sphinxSetupCodeBlockInFootnote {%
+ \fvset{fontsize=\footnotesize}\let\caption\sphinxfigcaption
+ \sphinxverbatimwithminipagetrue % reduces vertical spaces
+ % we counteract float.sty's \caption which does \@normalsize
+ \let\normalsize\footnotesize\let\@parboxrestore\relax
+ \abovecaptionskip \smallskipamount \belowcaptionskip \z@skip}
% Inspired and adapted from framed.sty's \CustomFBox with extra handling
-% of a non separable by pagebreak caption, and controlled counter stepping.
-\newif\ifspx@myfirstframedpass
+% of a non separable by pagebreak caption.
\long\def\spx@VerbatimFBox#1{%
\leavevmode
\begingroup
- % framed.sty does some measuring but this macro adds possibly a caption
- % use amsmath conditional to inhibit the caption counter stepping after
- % first pass
- \ifspx@myfirstframedpass\else\firstchoice@false\fi
\setbox\@tempboxa\hbox{\kern\fboxsep{#1}\kern\fboxsep}%
\hbox
{\lower\dimexpr\fboxrule+\fboxsep+\dp\@tempboxa
\hbox{%
- \vbox{\ifx\sphinxVerbatimTitle\empty\else
+ \vbox{\ifvoid\spx@VerbatimTitleBox\else
% add the caption in a centered way above possibly indented frame
% hide its width from framed.sty's measuring step
% note that the caption brings \abovecaptionskip top vertical space
\moveright\dimexpr\fboxrule+.5\wd\@tempboxa
- \hb@xt@\z@{\hss\begin{minipage}{\wd\@tempboxa}%
- \sphinxVerbatimTitle
- \end{minipage}\hss}\fi
+ \hb@xt@\z@{\hss\unhcopy\spx@VerbatimTitleBox\hss}\fi
% draw frame border _latest_ to avoid pdf viewer issue
\kern\fboxrule
\hbox{\kern\fboxrule
@@ -255,63 +357,60 @@
\hrule\@height\fboxrule}%
}}%
\endgroup
- \global\spx@myfirstframedpassfalse
}
% For linebreaks inside Verbatim environment from package fancyvrb.
\newbox\sphinxcontinuationbox
\newbox\sphinxvisiblespacebox
-% These are user customizable e.g. from latex_elements's preamble key.
-% Use of \textvisiblespace for compatibility with XeTeX/LuaTeX/fontspec.
-\newcommand*\sphinxvisiblespace {\textcolor{red}{\textvisiblespace}}
-\newcommand*\sphinxcontinuationsymbol {\textcolor{red}{\llap{\tiny$\m@th\hookrightarrow$}}}
-\newcommand*\sphinxcontinuationindent {3ex }
-\newcommand*\sphinxafterbreak {\kern\sphinxcontinuationindent\copy\sphinxcontinuationbox}
+\newcommand*\sphinxafterbreak {\copy\sphinxcontinuationbox}
% Take advantage of the already applied Pygments mark-up to insert
% potential linebreaks for TeX processing.
% {, <, #, %, $, ' and ": go to next line.
% _, }, ^, &, >, - and ~: stay at end of broken line.
% Use of \textquotesingle for straight quote.
+% FIXME: convert this to package options
+\newcommand*\sphinxbreaksbeforelist {%
+ \do\PYGZob\{\do\PYGZlt\<\do\PYGZsh\#\do\PYGZpc\%% {, <, #, %,
+ \do\PYGZdl\$\do\PYGZdq\"% $, "
+ \def\PYGZsq
+ {\discretionary{}{\sphinxafterbreak\textquotesingle}{\textquotesingle}}% '
+}
+\newcommand*\sphinxbreaksafterlist {%
+ \do\PYGZus\_\do\PYGZcb\}\do\PYGZca\^\do\PYGZam\&% _, }, ^, &,
+ \do\PYGZgt\>\do\PYGZhy\-\do\PYGZti\~% >, -, ~
+}
\newcommand*\sphinxbreaksatspecials {%
- \def\PYGZus{\discretionary{\char`\_}{\sphinxafterbreak}{\char`\_}}%
- \def\PYGZob{\discretionary{}{\sphinxafterbreak\char`\{}{\char`\{}}%
- \def\PYGZcb{\discretionary{\char`\}}{\sphinxafterbreak}{\char`\}}}%
- \def\PYGZca{\discretionary{\char`\^}{\sphinxafterbreak}{\char`\^}}%
- \def\PYGZam{\discretionary{\char`\&}{\sphinxafterbreak}{\char`\&}}%
- \def\PYGZlt{\discretionary{}{\sphinxafterbreak\char`\<}{\char`\<}}%
- \def\PYGZgt{\discretionary{\char`\>}{\sphinxafterbreak}{\char`\>}}%
- \def\PYGZsh{\discretionary{}{\sphinxafterbreak\char`\#}{\char`\#}}%
- \def\PYGZpc{\discretionary{}{\sphinxafterbreak\char`\%}{\char`\%}}%
- \def\PYGZdl{\discretionary{}{\sphinxafterbreak\char`\$}{\char`\$}}%
- \def\PYGZhy{\discretionary{\char`\-}{\sphinxafterbreak}{\char`\-}}%
- \def\PYGZsq{\discretionary{}{\sphinxafterbreak\textquotesingle}{\textquotesingle}}%
- \def\PYGZdq{\discretionary{}{\sphinxafterbreak\char`\"}{\char`\"}}%
- \def\PYGZti{\discretionary{\char`\~}{\sphinxafterbreak}{\char`\~}}%
+ \def\do##1##2%
+ {\def##1{\discretionary{}{\sphinxafterbreak\char`##2}{\char`##2}}}%
+ \sphinxbreaksbeforelist
+ \def\do##1##2%
+ {\def##1{\discretionary{\char`##2}{\sphinxafterbreak}{\char`##2}}}%
+ \sphinxbreaksafterlist
}
\def\sphinx@verbatim@nolig@list {\do \`}%
% Some characters . , ; ? ! / are not pygmentized.
% This macro makes them "active" and they will insert potential linebreaks
-\newcommand*\sphinxbreaksatpunct {%
- \lccode`\~`\.\lowercase{\def~}{\discretionary{\char`\.}{\sphinxafterbreak}{\char`\.}}%
- \lccode`\~`\,\lowercase{\def~}{\discretionary{\char`\,}{\sphinxafterbreak}{\char`\,}}%
- \lccode`\~`\;\lowercase{\def~}{\discretionary{\char`\;}{\sphinxafterbreak}{\char`\;}}%
- \lccode`\~`\:\lowercase{\def~}{\discretionary{\char`\:}{\sphinxafterbreak}{\char`\:}}%
- \lccode`\~`\?\lowercase{\def~}{\discretionary{\char`\?}{\sphinxafterbreak}{\char`\?}}%
- \lccode`\~`\!\lowercase{\def~}{\discretionary{\char`\!}{\sphinxafterbreak}{\char`\!}}%
- \lccode`\~`\/\lowercase{\def~}{\discretionary{\char`\/}{\sphinxafterbreak}{\char`\/}}%
- \catcode`\.\active
- \catcode`\,\active
- \catcode`\;\active
- \catcode`\:\active
- \catcode`\?\active
- \catcode`\!\active
- \catcode`\/\active
+\newcommand*\sphinxbreaksbeforeactivelist {}% none
+\newcommand*\sphinxbreaksafteractivelist {\do\.\do\,\do\;\do\?\do\!\do\/}
+\newcommand*\sphinxbreaksviaactive {%
+ \def\do##1{\lccode`\~`##1%
+ \lowercase{\def~}{\discretionary{}{\sphinxafterbreak\char`##1}{\char`##1}}%
+ \catcode`##1\active}%
+ \sphinxbreaksbeforeactivelist
+ \def\do##1{\lccode`\~`##1%
+ \lowercase{\def~}{\discretionary{\char`##1}{\sphinxafterbreak}{\char`##1}}%
+ \catcode`##1\active}%
+ \sphinxbreaksafteractivelist
\lccode`\~`\~
}
-\renewcommand{\Verbatim}[1][1]{%
+% needed to create wrapper environments of fancyvrb's Verbatim
+\newcommand*{\sphinxVerbatimEnvironment}{\gdef\FV@EnvironName{sphinxVerbatim}}
+% Sphinx <1.5 optional argument was in fact mandatory. It is now really
+% optional and handled by original Verbatim.
+\newenvironment{sphinxVerbatim}{%
% quit horizontal mode if we are still in a paragraph
\par
% list starts new par, but we don't want it to be set apart vertically
@@ -327,16 +426,25 @@
\needspace{\sphinxliteralblockwithoutcaptionneedspace}%
\phantomsection\sphinxLiteralBlockLabel
\fi
- \fi
+ \setbox\spx@VerbatimTitleBox\box\voidb@x
+ \else
% non-empty \sphinxVerbatimTitle has label inside it (in case there is one)
+ \setbox\spx@VerbatimTitleBox
+ \hbox{\begin{minipage}{\linewidth}%
+ \sphinxVerbatimTitle
+ \end{minipage}}%
+ \fi
+ \fboxsep\sphinxverbatimsep \fboxrule\sphinxverbatimborder
+ % setting borderwidth to zero is simplest for no-frame effect with same pagebreaks
+ \ifspx@opt@verbatimwithframe\else\fboxrule\z@\fi
% Customize framed.sty \MakeFramed to glue caption to literal block
- \global\spx@myfirstframedpasstrue
% via \spx@fcolorbox, will use \spx@VerbatimFBox which inserts title
\def\FrameCommand {\spx@colorbox\spx@fcolorbox }%
\let\FirstFrameCommand\FrameCommand
% for mid pages and last page portion of (long) split frame:
\def\MidFrameCommand{\spx@colorbox\fcolorbox }%
\let\LastFrameCommand\MidFrameCommand
+ \ifspx@opt@verbatimwrapslines
% fancyvrb's Verbatim puts each input line in (unbreakable) horizontal boxes.
% This customization wraps each line from the input in a \vtop, thus
% allowing it to wrap and display on two or more lines in the latex output.
@@ -345,8 +453,9 @@
% to achieve this without extensive rewrite of fancyvrb.
% - The (not used in sphinx) obeytabs option to Verbatim is
% broken by this change (showtabs and tabspace work).
- \sbox\sphinxcontinuationbox {\sphinxcontinuationsymbol}%
- \sbox\sphinxvisiblespacebox {\FV@SetupFont\sphinxvisiblespace}%
+ \expandafter\def\expandafter\FV@SetupFont\expandafter
+ {\FV@SetupFont\sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}%
+ \sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}}%
\def\FancyVerbFormatLine ##1{\hsize\linewidth
\vtop{\raggedright\hyphenpenalty\z@\exhyphenpenalty\z@
\doublehyphendemerits\z@\finalhyphendemerits\z@
@@ -360,12 +469,15 @@
\discretionary{\copy\sphinxvisiblespacebox}{\sphinxafterbreak}
{\kern\fontdimen2\font}%
}%
- % go around fancyvrb's check of @currenvir (for case of minipage below)
- \renewcommand*{\VerbatimEnvironment}{\gdef\FV@EnvironName{Verbatim}}%
- % go around fancyvrb's check of current list depth
- \def\@toodeep {\advance\@listdepth\@ne}%
% Allow breaks at special characters using \PYG... macros.
\sphinxbreaksatspecials
+ % Breaks at punctuation characters . , ; ? ! and / (needs catcode activation)
+ \def\FancyVerbCodes{\sphinxbreaksviaactive}%
+ \fi % end of conditional code for wrapping long code lines
+ % go around fancyvrb's check of \@currenvir
+ \let\VerbatimEnvironment\sphinxVerbatimEnvironment
+ % go around fancyvrb's check of current list depth
+ \def\@toodeep {\advance\@listdepth\@ne}%
% The list environment is needed to control perfectly the vertical space.
% Note: \OuterFrameSep used by framed.sty is later set to \topsep hence 0pt.
% - if caption: vertical space above caption = (\abovecaptionskip + D) with
@@ -379,34 +491,48 @@
\rightmargin\z@
\parindent \z@% becomes \itemindent. Default zero, but perhaps overwritten.
\trivlist\item\relax
- % use a minipage if we are already inside a framed environment
+ \ifsphinxverbatimwithminipage\spx@inframedtrue\fi
+ % use a minipage if we are already inside a framed environment
\ifspx@inframed\noindent\begin{minipage}{\linewidth}\fi
\MakeFramed {% adapted over from framed.sty's snugshade environment
- \advance\hsize-\width\@totalleftmargin\z@\linewidth\hsize
- \@setminipage }%
- \small
+ \advance\hsize-\width\@totalleftmargin\z@\linewidth\hsize\@setminipage
+ }%
% For grid placement from \strut's in \FancyVerbFormatLine
\lineskip\z@skip
- % Breaks at punctuation characters . , ; ? ! and / need catcode=\active
- % and the active comma should not be overwritten by \@noligs
- \let\verbatim@nolig@list \sphinx@verbatim@nolig@list
- \OriginalVerbatim[#1,codes*=\sphinxbreaksatpunct]%
+ % active comma should not be overwritten by \@noligs
+ \ifspx@opt@verbatimwrapslines
+ \let\verbatim@nolig@list \sphinx@verbatim@nolig@list
+ \fi
+ % will fetch its optional arguments if any
+ \OriginalVerbatim
}
-\renewcommand{\endVerbatim}{%
+{%
\endOriginalVerbatim
- \par\unskip\@minipagefalse\endMakeFramed
+ \par\unskip\@minipagefalse\endMakeFramed % from framed.sty snugshade
\ifspx@inframed\end{minipage}\fi
\endtrivlist
}
-
-% define macro to frame contents and add shadow on right and bottom
-% use public names for customizable lengths
-\newlength\sphinxshadowsep \setlength\sphinxshadowsep {5pt}
-\newlength\sphinxshadowsize \setlength\sphinxshadowsize {4pt}
-\newlength\sphinxshadowrule
-% this uses \fboxrule value at loading time of sphinx.sty (0.4pt normally)
-\setlength\sphinxshadowrule {\fboxrule}
-
+\newenvironment {sphinxVerbatimNoFrame}
+ {\spx@opt@verbatimwithframefalse
+ % needed for fancyvrb as literal code will end in \end{sphinxVerbatimNoFrame}
+ \def\sphinxVerbatimEnvironment{\gdef\FV@EnvironName{sphinxVerbatimNoFrame}}%
+ \begin{sphinxVerbatim}}
+ {\end{sphinxVerbatim}}
+\newenvironment {sphinxVerbatimintable}
+ {% don't use a frame if in a table cell
+ \spx@opt@verbatimwithframefalse
+ \sphinxverbatimwithminipagetrue
+ % counteract longtable redefinition of caption
+ \let\caption\sphinxfigcaption
+ % reduce above caption space if in a table cell
+ \abovecaptionskip\smallskipamount
+ \def\sphinxVerbatimEnvironment{\gdef\FV@EnvironName{sphinxVerbatimintable}}%
+ \begin{sphinxVerbatim}}
+ {\end{sphinxVerbatim}}
+
+% Topic boxes
+
+% Again based on use of "framed.sty", this allows breakable framed boxes.
\long\def\spx@ShadowFBox#1{%
\leavevmode\begingroup
% first we frame the box #1
@@ -451,6 +577,8 @@
% imitate closely the layout from Sphinx <= 1.4.1; the \FrameHeightAdjust
% will put top part of frame on this baseline.
\def\FrameHeightAdjust {\baselineskip}%
+ % use package footnote to handle footnotes
+ \savenotes
\trivlist\item\noindent
% use a minipage if we are already inside a framed environment
\ifspx@inframed\begin{minipage}{\linewidth}\fi
@@ -464,9 +592,6 @@
% itemize/enumerate are therein typeset more tightly, we want to keep
% that). We copy-paste from LaTeX source code but don't do a real minipage.
\@pboxswfalse
- % for footnotes, but Sphinx inactivates footnotes in topics
- \def\@mpfn{mpfootnote}\def\thempfn{\thempfootnote}\c@mpfootnote\z@
- \let\@footnotetext\@mpfootnotetext
\let\@listdepth\@mplistdepth \@mplistdepth\z@
\@minipagerestore
\@setminipage
@@ -474,14 +599,12 @@
}%
{% insert the "endminipage" code
\par\unskip
- % handle (currently non existing) minipage style footnotes
- \ifvoid\@mpfootins\else
- \vskip\skip\@mpfootins\normalcolor\footnoterule\unvbox\@mpfootins
- \fi
\@minipagefalse
\endMakeFramed
\ifspx@inframed\end{minipage}\fi
\endtrivlist
+ % output the stored footnotes
+ \spewnotes
}
@@ -509,13 +632,13 @@
% {fulllineitems} is the main environment for object descriptions.
%
\newcommand{\py@itemnewline}[1]{%
- \@tempdima\linewidth%
+ \@tempdima\linewidth
\advance\@tempdima \leftmargin\makebox[\@tempdima][l]{#1}%
}
\newenvironment{fulllineitems}{
- \begin{list}{}{\labelwidth \leftmargin \labelsep 0pt
- \rightmargin 0pt \topsep -\parskip \partopsep \parskip
+ \begin{list}{}{\labelwidth \leftmargin \labelsep \z@
+ \rightmargin \z@ \topsep -\parskip \partopsep \parskip
\itemsep -\parsep
\let\makelabel=\py@itemnewline}
}{\end{list}}
@@ -527,35 +650,71 @@
\newlength{\py@argswidth}
\newcommand{\py@sigparams}[2]{%
\parbox[t]{\py@argswidth}{#1\sphinxcode{)}#2}}
-\newcommand{\pysigline}[1]{\item[#1]\nopagebreak}
+\newcommand{\pysigline}[1]{\item[{#1}]\nopagebreak}
\newcommand{\pysiglinewithargsret}[3]{%
\settowidth{\py@argswidth}{#1\sphinxcode{(}}%
\addtolength{\py@argswidth}{-2\py@argswidth}%
\addtolength{\py@argswidth}{\linewidth}%
- \item[#1\sphinxcode{(}\py@sigparams{#2}{#3}]}
+ \item[{#1\sphinxcode{(}\py@sigparams{#2}{#3}}]}
% Production lists
%
-\newenvironment{productionlist}{
+\newenvironment{productionlist}{%
% \def\sphinxoptional##1{{\Large[}##1{\Large]}}
- \def\production##1##2{\\\sphinxcode{##1}&::=&\sphinxcode{##2}}
- \def\productioncont##1{\\& &\sphinxcode{##1}}
+ \def\production##1##2{\\\sphinxcode{##1}&::=&\sphinxcode{##2}}%
+ \def\productioncont##1{\\& &\sphinxcode{##1}}%
\parindent=2em
\indent
- \setlength{\LTpre}{0pt}
- \setlength{\LTpost}{0pt}
+ \setlength{\LTpre}{0pt}%
+ \setlength{\LTpost}{0pt}%
\begin{longtable}[l]{lcl}
}{%
\end{longtable}
}
% Notices / Admonitions
-%
+% Some are quite plain
+% the spx@notice@bordercolor etc are set in the sphinxadmonition environment
+\newenvironment{sphinxlightbox}{%
+ \par\allowbreak
+ \noindent{\color{spx@notice@bordercolor}%
+ \rule{\linewidth}{\spx@notice@border}}\par\nobreak
+ {\parskip\z@skip\noindent}%
+ }
+ {%
+ \par
+ % counteract previous possible negative skip (French lists!):
+ % (we can't cancel that any earlier \vskip introduced a potential pagebreak)
+ \ifdim\lastskip<\z@\vskip-\lastskip\fi
+ \nobreak\vbox{\noindent\kern\@totalleftmargin
+ {\color{spx@notice@bordercolor}%
+ \rule[\dimexpr.4\baselineskip-\spx@notice@border\relax]
+ {\linewidth}{\spx@notice@border}}\hss}\allowbreak
+ }% end of sphinxlightbox environment definition
+% may be renewenvironment'd by user for complete customization
+\newenvironment{sphinxnote}[1]
+ {\begin{sphinxlightbox}\sphinxstrong{#1} }{\end{sphinxlightbox}}
+\newenvironment{sphinxhint}[1]
+ {\begin{sphinxlightbox}\sphinxstrong{#1} }{\end{sphinxlightbox}}
+\newenvironment{sphinximportant}[1]
+ {\begin{sphinxlightbox}\sphinxstrong{#1} }{\end{sphinxlightbox}}
+\newenvironment{sphinxtip}[1]
+ {\begin{sphinxlightbox}\sphinxstrong{#1} }{\end{sphinxlightbox}}
+% or just use the package options
+% these are needed for common handling by notice environment of lightbox
+% and heavybox but they are currently not used by lightbox environment
+% and there is consequently no corresponding package option
+\definecolor{sphinxnoteBgColor}{rgb}{1,1,1}
+\definecolor{sphinxhintBgColor}{rgb}{1,1,1}
+\definecolor{sphinimportantBgColor}{rgb}{1,1,1}
+\definecolor{sphinxtipBgColor}{rgb}{1,1,1}
+
+% Others get more distinction
% Code adapted from framed.sty's "snugshade" environment.
% Nesting works (inner frames do not allow page breaks).
-\newcommand{\py@heavybox}{\par
- \setlength{\FrameRule}{\p@}% 1pt
+\newenvironment{sphinxheavybox}{\par
+ \setlength{\FrameRule}{\spx@notice@border}%
\setlength{\FrameSep}{\dimexpr.6\baselineskip-\FrameRule\relax}
% configure framed.sty's parameters to obtain same vertical spacing
% as for "light" boxes. We need for this to manually insert parskip glue and
@@ -564,8 +723,10 @@
\vspace{\FrameHeightAdjust}
% copied/adapted from framed.sty's snugshade
\def\FrameCommand##1{\hskip\@totalleftmargin
- \fboxsep\FrameSep \fboxrule\FrameRule\fbox{##1}%
+ \fboxsep\FrameSep \fboxrule\FrameRule
+ \fcolorbox{spx@notice@bordercolor}{spx@notice@bgcolor}{##1}%
\hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth}%
+ \savenotes
% use a minipage if we are already inside a framed environment
\ifspx@inframed
\noindent\begin{minipage}{\linewidth}
@@ -581,67 +742,53 @@
\advance\hsize-\width \@totalleftmargin\z@ \linewidth\hsize
% minipage initialization copied from LaTeX source code.
\@pboxswfalse
- % for footnotes
- \def\@mpfn{mpfootnote}\def\thempfn{\thempfootnote}\c@mpfootnote\z@
- \let\@footnotetext\@mpfootnotetext
\let\@listdepth\@mplistdepth \@mplistdepth\z@
\@minipagerestore
\@setminipage }%
}
-\newcommand{\py@endheavybox}{%
+ {%
\par\unskip
- % handles footnotes
- \ifvoid\@mpfootins\else
- \vskip\skip\@mpfootins\normalcolor\footnoterule\unvbox\@mpfootins
- \fi
\@minipagefalse
\endMakeFramed
\ifspx@inframed\end{minipage}\fi
+ % set footnotes at bottom of page
+ \spewnotes
% arrange for similar spacing below frame as for "light" boxes.
\vskip .4\baselineskip
- }
-
-\newcommand{\py@lightbox}{%
- \par\allowbreak
- \noindent\rule{\linewidth}{0.5pt}\par\nobreak
- {\parskip\z@skip\noindent}%
- }
-\newcommand{\py@endlightbox}{%
- \par
- % counteract previous possible negative skip (French lists!):
- % (we can't cancel that any earlier \vskip introduced a potential pagebreak)
- \ifdim\lastskip<\z@\vskip-\lastskip\fi
- \nobreak\vbox{\noindent\kern\@totalleftmargin
- \rule[.4\baselineskip]{\linewidth}{0.5pt}\hss}\allowbreak
- }
-
-% Some are quite plain:
-\newcommand{\py@noticestart@note}{\py@lightbox}
-\newcommand{\py@noticeend@note}{\py@endlightbox}
-\newcommand{\py@noticestart@hint}{\py@lightbox}
-\newcommand{\py@noticeend@hint}{\py@endlightbox}
-\newcommand{\py@noticestart@important}{\py@lightbox}
-\newcommand{\py@noticeend@important}{\py@endlightbox}
-\newcommand{\py@noticestart@tip}{\py@lightbox}
-\newcommand{\py@noticeend@tip}{\py@endlightbox}
-
-% Others gets more visible distinction:
-\newcommand{\py@noticestart@warning}{\py@heavybox}
-\newcommand{\py@noticeend@warning}{\py@endheavybox}
-\newcommand{\py@noticestart@caution}{\py@heavybox}
-\newcommand{\py@noticeend@caution}{\py@endheavybox}
-\newcommand{\py@noticestart@attention}{\py@heavybox}
-\newcommand{\py@noticeend@attention}{\py@endheavybox}
-\newcommand{\py@noticestart@danger}{\py@heavybox}
-\newcommand{\py@noticeend@danger}{\py@endheavybox}
-\newcommand{\py@noticestart@error}{\py@heavybox}
-\newcommand{\py@noticeend@error}{\py@endheavybox}
-
-\newenvironment{notice}[2]{
- \def\py@noticetype{#1}
- \csname py@noticestart@#1\endcsname
- \sphinxstrong{#2} % <- legacy code creates a space after {#2}
-}{\csname py@noticeend@\py@noticetype\endcsname}
+ }% end of sphinxheavybox environment definition
+% may be renewenvironment'd by user for complete customization
+\newenvironment{sphinxwarning}[1]
+ {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}}
+\newenvironment{sphinxcaution}[1]
+ {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}}
+\newenvironment{sphinxattention}[1]
+ {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}}
+\newenvironment{sphinxdanger}[1]
+ {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}}
+\newenvironment{sphinxerror}[1]
+ {\begin{sphinxheavybox}\sphinxstrong{#1} }{\end{sphinxheavybox}}
+% or just use package options
+
+% the \colorlet of xcolor (if at all loaded) is overkill for our use case
+\newcommand{\sphinxcolorlet}[2]
+ {\expandafter\let\csname\@backslashchar color@#1\expandafter\endcsname
+ \csname\@backslashchar color@#2\endcsname }
+
+% the main dispatch for all types of notices
+\newenvironment{sphinxadmonition}{\begin{notice}}{\end{notice}}
+% use of ``notice'' is for backwards compatibility and will be removed in
+% future release; sphinxadmonition environment will be defined directly.
+\newenvironment{notice}[2]{% #1=type, #2=heading
+ % can't use #1 directly in definition of end part
+ \def\spx@noticetype {#1}%
+ % set parameters of heavybox/lightbox
+ \sphinxcolorlet{spx@notice@bordercolor}{sphinx#1BorderColor}%
+ \sphinxcolorlet{spx@notice@bgcolor}{sphinx#1BgColor}%
+ \spx@notice@border \dimexpr\csname spx@opt@#1border\endcsname\relax
+ % start specific environment, passing the heading as argument
+ \begin{sphinx#1}{#2}}
+ % in end part, need to go around a LaTeX's "feature"
+ {\edef\spx@temp{\noexpand\end{sphinx\spx@noticetype}}\spx@temp}
% Allow the release number to be specified independently of the
% \date{}. This allows the date to reflect the document's date and
@@ -670,28 +817,33 @@
% This sets up the fancy chapter headings that make the documents look
% at least a little better than the usual LaTeX output.
%
-\spx@ifundefined{ChTitleVar}{}{
- \ChNameVar{\raggedleft\normalsize\py@HeaderFamily}
- \ChNumVar{\raggedleft \bfseries\Large\py@HeaderFamily}
- \ChTitleVar{\raggedleft \textrm{\Huge\py@HeaderFamily}}
- % This creates chapter heads without the leading \vspace*{}:
+\@ifpackagewith{fncychap}{Bjarne}{
+ \ChNameVar {\raggedleft\normalsize \py@HeaderFamily}
+ \ChNumVar {\raggedleft\Large \py@HeaderFamily}
+ \ChTitleVar{\raggedleft\Large \py@HeaderFamily}
+ % This creates (numbered) chapter heads without the leading \vspace*{}:
\def\@makechapterhead#1{%
{\parindent \z@ \raggedright \normalfont
\ifnum \c@secnumdepth >\m@ne
- \DOCH
+ \if@mainmatter
+ \DOCH
+ \fi
\fi
\interlinepenalty\@M
- \DOTI{#1}
- }
- }
-}
+ \if@mainmatter
+ \DOTI{#1}%
+ \else%
+ \DOTIS{#1}%
+ \fi
+ }}
+}{}% <-- "false" clause of \@ifpackagewith
% Redefine description environment so that it is usable inside fulllineitems.
%
\renewcommand{\description}{%
- \list{}{\labelwidth\z@%
- \itemindent-\leftmargin%
- \labelsep5pt%
+ \list{}{\labelwidth\z@
+ \itemindent-\leftmargin
+ \labelsep5pt\relax
\let\makelabel=\descriptionlabel}}
% Definition lists; requested by AMK for HOWTO documents. Probably useful
@@ -699,7 +851,7 @@
%
\newenvironment{definitions}{%
\begin{description}%
- \def\term##1{\item[##1]\mbox{}\\*[0mm]}
+ \def\term##1{\item[{##1}]\mbox{}\\*[0mm]}%
}{%
\end{description}%
}
@@ -707,7 +859,6 @@
% Tell TeX about pathological hyphenation cases:
\hyphenation{Base-HTTP-Re-quest-Hand-ler}
-
% The following is stuff copied from docutils' latex writer.
%
\newcommand{\optionlistlabel}[1]{\normalfont\bfseries #1 \hfill}% \bf deprecated
@@ -728,27 +879,31 @@
{\setlength{\partopsep}{\parskip}
\addtolength{\partopsep}{\baselineskip}
\topsep0pt\itemsep0.15\baselineskip\parsep0pt
- \leftmargin#1}
+ \leftmargin#1\relax}
\raggedright}
{\end{list}}
-% Re-define \includegraphics to resize images larger than the line width
-% if the size is not specified.
+% Redefine \includegraphics to resize images larger than the line width,
+% except if height or width option present.
+%
+% If scale is present, rescale before fitting to line width. (since 1.5)
+%
% Warning: future version of Sphinx will not modify original \includegraphics,
-% Below custom code will be direct definition of \sphinxincludegraphics, with
-% \py@Oldincludegraphics replaced by direct use of original \includegraphics.
+% below code will be definition only of \sphinxincludegraphics.
\let\py@Oldincludegraphics\includegraphics
\newbox\spx@image@box
-\renewcommand*{\includegraphics}[2][\@empty]{%
- \ifx\@empty #1% attention, #1 could be bb.., bad if first after \ifx
- \setbox\spx@image@box=\hbox{\py@Oldincludegraphics{#2}}%
+\renewcommand*{\includegraphics}[2][]{%
+ \in@{height}{#1}\ifin@\else\in@{width}{#1}\fi
+ \ifin@ % height or width present
+ \py@Oldincludegraphics[#1]{#2}%
+ \else % no height nor width (but #1 may be "scale=...")
+ \setbox\spx@image@box\hbox{\py@Oldincludegraphics[#1,draft]{#2}}%
\ifdim \wd\spx@image@box>\linewidth
- \py@Oldincludegraphics[width=\linewidth]{#2}%
+ \setbox\spx@image@box\box\voidb@x % clear memory
+ \py@Oldincludegraphics[#1,width=\linewidth]{#2}%
\else
- \leavevmode\box\spx@image@box
+ \py@Oldincludegraphics[#1]{#2}%
\fi
- \else
- \py@Oldincludegraphics[#1]{#2}%
\fi
}
% Writer will put \sphinxincludegraphics in LaTeX source, and with this,
@@ -774,32 +929,26 @@
\fi
\fi
-% Include hyperref last.
-\RequirePackage[colorlinks,breaklinks,
- linkcolor=InnerLinkColor,filecolor=OuterLinkColor,
- menucolor=OuterLinkColor,urlcolor=OuterLinkColor,
- citecolor=InnerLinkColor]{hyperref}
-% Fix anchor placement for figures with captions.
-% (Note: we don't use a package option here; instead, we give an explicit
-% \capstart for figures that actually have a caption.)
-\RequirePackage{hypcap}
-
-% Set up styles of URL: it should be placed after hyperref
-\urlstyle{same}
+% These options can be overriden inside 'hyperref' key
+% or by later use of \hypersetup.
+\PassOptionsToPackage{colorlinks,breaklinks,%
+ linkcolor=InnerLinkColor,filecolor=OuterLinkColor,%
+ menucolor=OuterLinkColor,urlcolor=OuterLinkColor,%
+ citecolor=InnerLinkColor}{hyperref}
% From docutils.writers.latex2e
% inline markup (custom roles)
% \DUrole{#1}{#2} tries \DUrole#1{#2}
\providecommand*{\DUrole}[2]{%
- \ifcsname DUrole#1\endcsname%
+ \ifcsname DUrole#1\endcsname
\csname DUrole#1\endcsname{#2}%
\else% backwards compatibility: try \docutilsrole#1{#2}
- \ifcsname docutilsrole#1\endcsname%
+ \ifcsname docutilsrole#1\endcsname
\csname docutilsrole#1\endcsname{#2}%
- \else%
+ \else
#2%
- \fi%
- \fi%
+ \fi
+ \fi
}
\providecommand*{\DUprovidelength}[2]{%
@@ -820,27 +969,11 @@
{\endlist}
\fi
-% From footmisc.sty: allows footnotes in titles
-\let\FN@sf@@footnote\footnote
-\def\footnote{\ifx\protect\@typeset@protect
- \expandafter\FN@sf@@footnote
- \else
- \expandafter\FN@sf@gobble@opt
- \fi
-}
-\edef\FN@sf@gobble@opt{\noexpand\protect
- \expandafter\noexpand\csname FN@sf@gobble@opt \endcsname}
-\expandafter\def\csname FN@sf@gobble@opt \endcsname{%
- \@ifnextchar[%]
- \FN@sf@gobble@twobracket
- \@gobble
-}
-\def\FN@sf@gobble@twobracket[#1]#2{}
-
% adjust the margins for footer,
% this works with the jsclasses only (Japanese standard document classes)
+% FIXME: rather, pass options to "geometry".
\ifx\@jsc@uplatextrue\undefined\else
- \hypersetup{setpagesize=false}
+ \PassOptionsToPackage{setpagesize=false}{hyperref}
\setlength\footskip{2\baselineskip}
\addtolength{\textheight}{-2\baselineskip}
\fi
@@ -848,16 +981,15 @@
% fix the double index and bibliography on the table of contents
% in jsclasses (Japanese standard document classes)
\ifx\@jsc@uplatextrue\undefined\else
- \renewcommand{\theindex}{
- \cleardoublepage
- \phantomsection
- \py@OldTheindex
- }
- \renewcommand{\thebibliography}[1]{
- \cleardoublepage
- \phantomsection
- \py@OldThebibliography{1}
- }
+ \renewenvironment{sphinxtheindex}
+ {\cleardoublepage\phantomsection
+ \begin{theindex}}
+ {\end{theindex}}
+
+ \renewenvironment{sphinxthebibliography}[1]
+ {\cleardoublepage\phantomsection
+ \begin{thebibliography}{1}}
+ {\end{thebibliography}}
\fi
% disable \@chappos in Appendix in pTeX
@@ -869,13 +1001,25 @@
}
\fi
-% Define literal-block environment
-\RequirePackage{newfloat}
-\DeclareFloatingEnvironment{literal-block}
+% for captions of literal blocks
+% with `\theH...` macros for hyperref
+\newcounter{literalblock}
\spx@ifundefined{c@chapter}
- {\SetupFloatingEnvironment{literal-block}{within=section,placement=h}}
- {\SetupFloatingEnvironment{literal-block}{within=chapter,placement=h}}
-\SetupFloatingEnvironment{literal-block}{name=List}
+ {\@addtoreset{literalblock}{section}
+ \def\theliteralblock {\ifnum\c@section>\z@ \thesection.\fi\arabic{literalblock}}
+ \def\theHliteralblock {\theHsection.\arabic{literalblock}}}
+ {\@addtoreset{literalblock}{chapter}
+ \def\theliteralblock {\ifnum\c@chapter>\z@ \thechapter.\fi\arabic{literalblock}}
+ \def\theHliteralblock {\theHchapter.\arabic{literalblock}}}
+% at start of caption title
+\newcommand*{\fnum@literalblock}{\literalblockname\nobreakspace\theliteralblock}
+% this will be overwritten in document preamble by Babel translation
+\newcommand*{\literalblockname}{Listing }
+% file extension needed for \caption's good functioning, the file is created
+% only if a \listof{literalblock}{foo} command is encountered, which is
+% analogous to \listoffigures, but for the code listings (foo = chosen title.)
+\newcommand*{\ext@literalblock}{lol}
+
% control caption around literal-block
\RequirePackage{capt-of}
\RequirePackage{needspace}
@@ -896,22 +1040,117 @@
\spx@originalcaption }
% by default, also define macros with the no-prefix names
-\ifsphinxKeepOldNames
+\ifspx@opt@dontkeepoldnames\else
\typeout{** (sphinx) defining (legacy) text style macros without \string\sphinx\space prefix}
- \typeout{** if clashes with packages, set latex_keep_old_macro_names=False in conf.py}
- \@for\@tempa:=strong,bfcode,email,tablecontinued,titleref,%
+ \typeout{** if clashes with packages, set latex_keep_old_macro_names=False
+ in conf.py}
+ \@for\@tempa:=code,strong,bfcode,email,tablecontinued,titleref,%
menuselection,accelerator,crossref,termref,optional\do
{% first, check if command with no prefix already exists
\expandafter\newcommand\csname\@tempa\endcsname{}%
- % if no error give it the meaning defined so far with \sphinx prefix
+ % give it the meaning defined so far with \sphinx prefix
\expandafter\let\csname\@tempa\expandafter\endcsname
\csname sphinx\@tempa\endcsname
% redefine the \sphinx prefixed macro to expand to non-prefixed one
\expandafter\def\csname sphinx\@tempa\expandafter\endcsname
\expandafter{\csname\@tempa\endcsname}%
-}
- % robustified case needs special treatment
- \newcommand\code{}\let\code\relax
- \DeclareRobustCommand{\code}[1]{{\@noligs\scantokens{\texttt{#1}\relax}}}
- \def\sphinxcode{\code}%
+}%
\fi
+
+% additional customizable styling
+% FIXME: convert this to package options ?
+\protected\def\sphinxstyleindexentry {\texttt}
+\long\protected\def\sphinxstyleindexextra #1{ \emph{(#1)}}
+\protected\def\sphinxstyleindexpageref {, \pageref}
+\long\protected\def\sphinxstyletopictitle #1{\textbf{#1}\par\medskip}
+\let\sphinxstylesidebartitle\sphinxstyletopictitle
+\protected\def\sphinxstyleothertitle {\textbf}
+\long\protected\def\sphinxstylesidebarsubtitle #1{~\\\textbf{#1} \smallskip}
+\protected\def\sphinxstylethead {\textsf}
+\protected\def\sphinxstyleemphasis {\emph}
+\long\protected\def\sphinxstyleliteralemphasis#1{\emph{\sphinxcode{#1}}}
+\protected\def\sphinxstylestrong {\textbf}
+\protected\def\sphinxstyleliteralstrong {\sphinxbfcode}
+\protected\def\sphinxstyleabbreviation {\textsc}
+\protected\def\sphinxstyleliteralintitle {\sphinxcode}
+
+% stylesheet for highlighting with pygments
+\RequirePackage{sphinxhighlight}
+
+% make commands known to non-Sphinx document classes
+\providecommand*{\sphinxtableofcontents}{\tableofcontents}
+\providecommand*{\sphinxthebibliography}{\thebibliography}
+\providecommand*{\sphinxtheindex}{\theindex}
+
+% remove LaTeX's cap on nesting depth if 'maxlistdepth' key used.
+% This is a hack, which works with the standard classes: it assumes \@toodeep
+% is always used in "true" branches: "\if ... \@toodeep \else .. \fi."
+
+% will force use the "false" branch (if there is one)
+\def\spx@toodeep@hack{\fi\iffalse}
+
+% do nothing if 'maxlistdepth' key not used or if package enumitem loaded.
+\ifnum\spx@opt@maxlistdepth=\z@\expandafter\@gobbletwo\fi
+\AtBeginDocument{%
+\@ifpackageloaded{enumitem}{\remove@to@nnil}{}%
+ \let\spx@toodeepORI\@toodeep
+ \def\@toodeep{%
+ \ifnum\@listdepth<\spx@opt@maxlistdepth\relax
+ \expandafter\spx@toodeep@hack
+ \else
+ \expandafter\spx@toodeepORI
+ \fi}%
+% define all missing \@list... macros
+ \count@\@ne
+ \loop
+ \spx@ifundefined{@list\romannumeral\the\count@}
+ {\iffalse}{\iftrue\advance\count@\@ne}%
+ \repeat
+ \loop
+ \ifnum\count@>\spx@opt@maxlistdepth\relax\else
+ \expandafter\let
+ \csname @list\romannumeral\the\count@\expandafter\endcsname
+ \csname @list\romannumeral\the\numexpr\count@-\@ne\endcsname
+ % higher \leftmargin... needed to fix issue with babel-french (v2.6--...)
+ \spx@ifundefined{leftmargin\romannumeral\the\count@}
+ {\expandafter\let
+ \csname leftmargin\romannumeral\the\count@\expandafter\endcsname
+ \csname leftmargin\romannumeral\the\numexpr\count@-\@ne\endcsname}{}%
+ \advance\count@\@ne
+ \repeat
+% define all missing enum... counters and \labelenum... macros and \p@enum..
+ \count@\@ne
+ \loop
+ \spx@ifundefined{c@enum\romannumeral\the\count@}
+ {\iffalse}{\iftrue\advance\count@\@ne}%
+ \repeat
+ \loop
+ \ifnum\count@>\spx@opt@maxlistdepth\relax\else
+ \newcounter{enum\romannumeral\the\count@}%
+ \expandafter\def
+ \csname labelenum\romannumeral\the\count@\expandafter\endcsname
+ \expandafter
+ {\csname theenum\romannumeral\the\numexpr\count@\endcsname.}%
+ \expandafter\def
+ \csname p@enum\romannumeral\the\count@\expandafter\endcsname
+ \expandafter
+ {\csname p@enum\romannumeral\the\numexpr\count@-\@ne\expandafter
+ \endcsname\csname theenum\romannumeral\the\numexpr\count@-\@ne\endcsname.}%
+ \advance\count@\@ne
+ \repeat
+% define all missing labelitem... macros
+ \count@\@ne
+ \loop
+ \spx@ifundefined{labelitem\romannumeral\the\count@}
+ {\iffalse}{\iftrue\advance\count@\@ne}%
+ \repeat
+ \loop
+ \ifnum\count@>\spx@opt@maxlistdepth\relax\else
+ \expandafter\let
+ \csname labelitem\romannumeral\the\count@\expandafter\endcsname
+ \csname labelitem\romannumeral\the\numexpr\count@-\@ne\endcsname
+ \advance\count@\@ne
+ \repeat
+ \PackageInfo{sphinx}{maximal list depth extended to \spx@opt@maxlistdepth}%
+\@gobble\@nnil
+}
diff --git a/sphinx/texinputs/sphinxhowto.cls b/sphinx/texinputs/sphinxhowto.cls
index 8d5c59232..3e34063ef 100644
--- a/sphinx/texinputs/sphinxhowto.cls
+++ b/sphinx/texinputs/sphinxhowto.cls
@@ -3,13 +3,7 @@
%
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
-\ProvidesClass{sphinxhowto}[2009/06/02 Document class (Sphinx HOWTO)]
-
-\ifx\directlua\undefined\else
-% if compiling with lualatex 0.85 or later load compatibility patch issued by
-% the LaTeX team for older packages relying on \pdf<name> named primitives.
- \IfFileExists{luatex85.sty}{\RequirePackage{luatex85}}{}
-\fi
+\ProvidesClass{sphinxhowto}[2016/10/12 v1.5 Document class (Sphinx HOWTO)]
% 'oneside' option overriding the 'twoside' default
\newif\if@oneside
@@ -70,11 +64,10 @@
%\gdef\@thanks{}\gdef\@author{}\gdef\@title{}
}
-\let\py@OldTableofcontents=\tableofcontents
-\renewcommand{\tableofcontents}{
+\newcommand{\sphinxtableofcontents}{
\begingroup
\parskip = 0mm
- \py@OldTableofcontents
+ \tableofcontents
\endgroup
\rule{\textwidth}{1pt}
\vspace{12pt}
@@ -91,21 +84,21 @@
% Contents.
% For an article document class this environment is a section,
% so no page break before it.
-\let\py@OldThebibliography=\thebibliography
-\renewcommand{\thebibliography}[1]{
+%
+% Note: \phantomsection is required for TeXLive 2009
+% http://tex.stackexchange.com/questions/44088/when-do-i-need-to-invoke-phantomsection#comment166081_44091
+\newenvironment{sphinxthebibliography}[1]{%
\phantomsection
- \py@OldThebibliography{1}
- \addcontentsline{toc}{section}{\bibname}
-}
+ \begin{thebibliography}{1}%
+ \addcontentsline{toc}{section}{\ifdefined\refname\refname\else\ifdefined\bibname\bibname\fi\fi}}{\end{thebibliography}}
+
% Same for the indices.
% The memoir class already does this, so we don't duplicate it in that case.
%
-\@ifclassloaded{memoir}{}{
- \let\py@OldTheindex=\theindex
- \renewcommand{\theindex}{
+\@ifclassloaded{memoir}
+ {\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}}
+ {\newenvironment{sphinxtheindex}{%
\phantomsection
- \py@OldTheindex
- \addcontentsline{toc}{section}{\indexname}
- }
-}
+ \begin{theindex}%
+ \addcontentsline{toc}{section}{\indexname}}{\end{theindex}}}
diff --git a/sphinx/texinputs/sphinxmanual.cls b/sphinx/texinputs/sphinxmanual.cls
index f20449449..3a48c6760 100644
--- a/sphinx/texinputs/sphinxmanual.cls
+++ b/sphinx/texinputs/sphinxmanual.cls
@@ -3,13 +3,7 @@
%
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
-\ProvidesClass{sphinxmanual}[2009/06/02 Document class (Sphinx manual)]
-
-\ifx\directlua\undefined\else
-% if compiling with lualatex 0.85 or later load compatibility patch issued by
-% the LaTeX team for older packages relying on \pdf<name> named primitives.
- \IfFileExists{luatex85.sty}{\RequirePackage{luatex85}}{}
-\fi
+\ProvidesClass{sphinxmanual}[2016/10/12 v1.5 Document class (Sphinx manual)]
% chapters starting at odd pages (overridden by 'openany' document option)
\PassOptionsToClass{openright}{\sphinxdocclass}
@@ -40,6 +34,9 @@
% ``Bjarne'' style a bit better.
%
\renewcommand{\maketitle}{%
+ \let\spx@tempa\relax
+ \ifHy@pageanchor\def\spx@tempa{\Hy@pageanchortrue}\fi
+ \hypersetup{pageanchor=false}% avoid duplicate destination warnings
\begin{titlepage}%
\let\footnotesize\small
\let\footnoterule\relax
@@ -80,24 +77,22 @@
\setcounter{footnote}{0}%
\let\thanks\relax\let\maketitle\relax
%\gdef\@thanks{}\gdef\@author{}\gdef\@title{}
+ \if@openright\cleardoublepage\else\clearpage\fi
+ \spx@tempa
}
-\let\py@OldTableofcontents=\tableofcontents
-\renewcommand{\tableofcontents}{%
- % before resetting page counter, let's do the right thing.
- \if@openright\cleardoublepage\else\clearpage\fi
+\newcommand{\sphinxtableofcontents}{%
\pagenumbering{roman}%
\pagestyle{plain}%
\begingroup
\parskip \z@skip
- \py@OldTableofcontents
+ \tableofcontents
\endgroup
% before resetting page counter, let's do the right thing.
\if@openright\cleardoublepage\else\clearpage\fi
\pagenumbering{arabic}%
\ifdefined\fancyhf\pagestyle{normal}\fi
}
-\pagenumbering{alph}% avoid hyperref "duplicate destination" warnings
% This is needed to get the width of the section # area wide enough in the
% library reference. Doing it here keeps it the same for all the manuals.
@@ -108,23 +103,22 @@
% Fix the bibliography environment to add an entry to the Table of
% Contents.
% For a report document class this environment is a chapter.
-\let\py@OldThebibliography=\thebibliography
-\renewcommand{\thebibliography}[1]{
+%
+% Note: \phantomsection is required for TeXLive 2009
+% http://tex.stackexchange.com/questions/44088/when-do-i-need-to-invoke-phantomsection#comment166081_44091
+\newenvironment{sphinxthebibliography}[1]{%
\if@openright\cleardoublepage\else\clearpage\fi
\phantomsection
- \py@OldThebibliography{1}
- \addcontentsline{toc}{chapter}{\bibname}
-}
+ \begin{thebibliography}{1}%
+ \addcontentsline{toc}{chapter}{\bibname}}{\end{thebibliography}}
% Same for the indices.
% The memoir class already does this, so we don't duplicate it in that case.
%
-\@ifclassloaded{memoir}{}{
- \let\py@OldTheindex=\theindex
- \renewcommand{\theindex}{
+\@ifclassloaded{memoir}
+ {\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}}
+ {\newenvironment{sphinxtheindex}{%
\if@openright\cleardoublepage\else\clearpage\fi
\phantomsection
- \py@OldTheindex
- \addcontentsline{toc}{chapter}{\indexname}
- }
-}
+ \begin{theindex}%
+ \addcontentsline{toc}{chapter}{\indexname}}{\end{theindex}}}
diff --git a/sphinx/texinputs/tabulary.sty b/sphinx/texinputs/tabulary.sty
deleted file mode 100644
index 11fdf7428..000000000
--- a/sphinx/texinputs/tabulary.sty
+++ /dev/null
@@ -1,452 +0,0 @@
-%%
-%% This is file `tabulary.sty',
-%% generated with the docstrip utility.
-%%
-%% The original source files were:
-%%
-%% tabulary.dtx (with options: `package')
-%% DRAFT VERSION
-%%
-%% File `tabulary.dtx'.
-%% Copyright (C) 1995 1996 2003 2008 David Carlisle
-%% This file may be distributed under the terms of the LPPL.
-%% See 00readme.txt for details.
-%%
-\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{tabulary}
- [2008/12/01 v0.9 tabulary package (DPC)]
-\RequirePackage{array}
-\catcode`\Z=14
-\DeclareOption{debugshow}{\catcode`\Z=9\relax}
-\ProcessOptions
-\def\arraybackslash{\let\\=\@arraycr}
-\def\@finalstrut#1{%
- \unskip\ifhmode\nobreak\fi\vrule\@width\z@\@height\z@\@depth\dp#1}
-\newcount\TY@count
-\def\tabulary{%
- \let\TY@final\tabular
- \let\endTY@final\endtabular
- \TY@tabular}
-\def\TY@tabular#1{%
- \edef\TY@{\@currenvir}%
- {\ifnum0=`}\fi
- \@ovxx\TY@linewidth
- \@ovyy\TY@tablewidth
- \count@\z@
- \@tempswatrue
- \@whilesw\if@tempswa\fi{%
- \advance\count@\@ne
- \expandafter\ifx\csname TY@F\the\count@\endcsname\relax
- \@tempswafalse
- \else
- \expandafter\let\csname TY@SF\the\count@\expandafter\endcsname
- \csname TY@F\the\count@\endcsname
- \global\expandafter\let\csname TY@F\the\count@\endcsname\relax
- \expandafter\let\csname TY@S\the\count@\expandafter\endcsname
- \csname TY@\the\count@\endcsname
- \fi}%
- \global\TY@count\@ne
- \TY@width\xdef{0pt}%
- \global\TY@tablewidth\z@
- \global\TY@linewidth#1\relax
-Z\message{^^J^^JTable^^J%
-Z Target Width: \the\TY@linewidth^^J%
-Z \string\tabcolsep: \the\tabcolsep\space
-Z \string\arrayrulewidth: \the\arrayrulewidth\space
-Z \string\doublerulesep: \the\doublerulesep^^J%
-Z \string\tymin: \the\tymin\space
-Z \string\tymax: \the\tymax^^J}%
- \let\@classz\TY@classz
- \let\verb\TX@verb
- \toks@{}\TY@get@body}
-\let\TY@@mkpream\@mkpream
-\def\TY@mkpream{%
- \def\@addamp{%
- \if@firstamp \@firstampfalse \else
- \global\advance\TY@count\@ne
- \edef\@preamble{\@preamble &}\fi
- \TY@width\xdef{0pt}}%
- \def\@acol{%
- \TY@subwidth\col@sep
- \@addtopreamble{\hskip\col@sep}}%
- \let\@arrayrule\TY@arrayrule
- \let\@classvi\TY@classvi
- \def\@classv{\save@decl
- \expandafter\NC@ecs\@nextchar\extracolsep{}\extracolsep\@@@
- \sbox\z@{\d@llarbegin\@nextchar\d@llarend}%
- \TY@subwidth{\wd\z@}%
- \@addtopreamble{\d@llarbegin\the@toks\the\count@\relax\d@llarend}%
- \prepnext@tok}%
- \global\let\@mkpream\TY@@mkpream
- \TY@@mkpream}
-\def\TY@arrayrule{%
- \TY@subwidth\arrayrulewidth
- \@addtopreamble \vline}
-\def\TY@classvi{\ifcase \@lastchclass
- \@acol \or
- \TY@subwidth\doublerulesep
- \@addtopreamble{\hskip \doublerulesep}\or
- \@acol \or
- \@classvii
- \fi}
-\def\TY@tab{%
- \setbox\z@\hbox\bgroup
- \let\[$\let\]$%
- \let\equation$\let\endequation$%
- \col@sep\tabcolsep
- \let\d@llarbegin\begingroup\let\d@llarend\endgroup
- \let\@mkpream\TY@mkpream
- \def\multicolumn##1##2##3{\multispan##1\relax}%
- \CT@start\TY@tabarray}
-\def\TY@tabarray{\@ifnextchar[{\TY@array}{\@array[t]}}
-\def\TY@array[#1]{\@array[t]}
-\def\TY@width#1{%
- \expandafter#1\csname TY@\the\TY@count\endcsname}
-\def\TY@subwidth#1{%
- \TY@width\dimen@
- \advance\dimen@-#1\relax
- \TY@width\xdef{\the\dimen@}%
- \global\advance\TY@linewidth-#1\relax}
-\def\endtabulary{%
- \gdef\@halignto{}%
- \let\TY@footnote\footnote%
- \def\footnote{}% prevent footnotes from doing anything
- \expandafter\TY@tab\the\toks@
- \crcr\omit
- {\xdef\TY@save@row{}%
- \loop
- \advance\TY@count\m@ne
- \ifnum\TY@count>\z@
- \xdef\TY@save@row{\TY@save@row&\omit}%
- \repeat}\TY@save@row
- \endarray\global\setbox1=\lastbox\setbox0=\vbox{\unvbox1
- \unskip\global\setbox1=\lastbox}\egroup
- \dimen@\TY@linewidth
- \divide\dimen@\TY@count
- \ifdim\dimen@<\tymin
- \TY@warn{tymin too large (\the\tymin), resetting to \the\dimen@}%
- \tymin\dimen@
- \fi
- \setbox\tw@=\hbox{\unhbox\@ne
- \loop
-\@tempdima=\lastskip
-\ifdim\@tempdima>\z@
-Z \message{ecs=\the\@tempdima^^J}%
- \global\advance\TY@linewidth-\@tempdima
-\fi
- \unskip
- \setbox\tw@=\lastbox
- \ifhbox\tw@
-Z \message{Col \the\TY@count: Initial=\the\wd\tw@\space}%
- \ifdim\wd\tw@>\tymax
- \wd\tw@\tymax
-Z \message{> max\space}%
-Z \else
-Z \message{ \@spaces\space}%
- \fi
- \TY@width\dimen@
-Z \message{\the\dimen@\space}%
- \advance\dimen@\wd\tw@
-Z \message{Final=\the\dimen@\space}%
- \TY@width\xdef{\the\dimen@}%
- \ifdim\dimen@<\tymin
-Z \message{< tymin}%
- \global\advance\TY@linewidth-\dimen@
- \expandafter\xdef\csname TY@F\the\TY@count\endcsname
- {\the\dimen@}%
- \else
- \expandafter\ifx\csname TY@F\the\TY@count\endcsname\z@
-Z \message{***}%
- \global\advance\TY@linewidth-\dimen@
- \expandafter\xdef\csname TY@F\the\TY@count\endcsname
- {\the\dimen@}%
- \else
-Z \message{> tymin}%
- \global\advance\TY@tablewidth\dimen@
- \global\expandafter\let\csname TY@F\the\TY@count\endcsname
- \maxdimen
- \fi\fi
- \advance\TY@count\m@ne
- \repeat}%
- \TY@checkmin
- \TY@checkmin
- \TY@checkmin
- \TY@checkmin
- \TY@count\z@
- \let\TY@box\TY@box@v
- \let\footnote\TY@footnote % restore footnotes
- {\expandafter\TY@final\the\toks@\endTY@final}%
- \count@\z@
- \@tempswatrue
- \@whilesw\if@tempswa\fi{%
- \advance\count@\@ne
- \expandafter\ifx\csname TY@SF\the\count@\endcsname\relax
- \@tempswafalse
- \else
- \global\expandafter\let\csname TY@F\the\count@\expandafter\endcsname
- \csname TY@SF\the\count@\endcsname
- \global\expandafter\let\csname TY@\the\count@\expandafter\endcsname
- \csname TY@S\the\count@\endcsname
- \fi}%
- \TY@linewidth\@ovxx
- \TY@tablewidth\@ovyy
- \ifnum0=`{\fi}}
-\def\TY@checkmin{%
- \let\TY@checkmin\relax
-\ifdim\TY@tablewidth>\z@
- \Gscale@div\TY@ratio\TY@linewidth\TY@tablewidth
- \ifdim\TY@tablewidth <\TY@linewidth
- \def\TY@ratio{1}%
- \fi
-\else
- \TY@warn{No suitable columns!}%
- \def\TY@ratio{1}%
-\fi
-\count@\z@
-Z \message{^^JLine Width: \the\TY@linewidth,
-Z Natural Width: \the\TY@tablewidth,
-Z Ratio: \TY@ratio^^J}%
-\@tempdima\z@
-\loop
-\ifnum\count@<\TY@count
-\advance\count@\@ne
- \ifdim\csname TY@F\the\count@\endcsname>\tymin
- \dimen@\csname TY@\the\count@\endcsname
- \dimen@\TY@ratio\dimen@
- \ifdim\dimen@<\tymin
-Z \message{Column \the\count@\space ->}%
- \global\expandafter\let\csname TY@F\the\count@\endcsname\tymin
- \global\advance\TY@linewidth-\tymin
- \global\advance\TY@tablewidth-\csname TY@\the\count@\endcsname
- \let\TY@checkmin\TY@@checkmin
- \else
- \expandafter\xdef\csname TY@F\the\count@\endcsname{\the\dimen@}%
- \advance\@tempdima\csname TY@F\the\count@\endcsname
- \fi
- \fi
-Z \dimen@\csname TY@F\the\count@\endcsname\message{\the\dimen@, }%
-\repeat
-Z \message{^^JTotal:\the\@tempdima^^J}%
-}
-\let\TY@@checkmin\TY@checkmin
-\newdimen\TY@linewidth
-\def\tyformat{\everypar{{\nobreak\hskip\z@skip}}}
-\newdimen\tymin
-\tymin=10pt
-\newdimen\tymax
-\tymax=2\textwidth
-\def\@testpach{\@chclass
- \ifnum \@lastchclass=6 \@ne \@chnum \@ne \else
- \ifnum \@lastchclass=7 5 \else
- \ifnum \@lastchclass=8 \tw@ \else
- \ifnum \@lastchclass=9 \thr@@
- \else \z@
- \ifnum \@lastchclass = 10 \else
- \edef\@nextchar{\expandafter\string\@nextchar}%
- \@chnum
- \if \@nextchar c\z@ \else
- \if \@nextchar l\@ne \else
- \if \@nextchar r\tw@ \else
- \if \@nextchar C7 \else
- \if \@nextchar L8 \else
- \if \@nextchar R9 \else
- \if \@nextchar J10 \else
- \z@ \@chclass
- \if\@nextchar |\@ne \else
- \if \@nextchar !6 \else
- \if \@nextchar @7 \else
- \if \@nextchar <8 \else
- \if \@nextchar >9 \else
- 10
- \@chnum
- \if \@nextchar m\thr@@\else
- \if \@nextchar p4 \else
- \if \@nextchar b5 \else
- \z@ \@chclass \z@ \@preamerr \z@ \fi \fi \fi \fi\fi \fi \fi\fi \fi
- \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi}
-\def\TY@classz{%
- \@classx
- \@tempcnta\count@
- \ifx\TY@box\TY@box@v
- \global\advance\TY@count\@ne
- \fi
- \let\centering c%
- \let\raggedright\noindent
- \let\raggedleft\indent
- \let\arraybackslash\relax
- \prepnext@tok
- \ifnum\@chnum<4
- \global\expandafter\let\csname TY@F\the\TY@count\endcsname\z@
- \fi
- \ifnum\@chnum=6
- \global\expandafter\let\csname TY@F\the\TY@count\endcsname\z@
- \fi
- \@addtopreamble{%
- \ifcase\@chnum
- \hfil \d@llarbegin\insert@column\d@llarend \hfil \or
- \kern\z@
- \d@llarbegin \insert@column \d@llarend \hfil \or
- \hfil\kern\z@ \d@llarbegin \insert@column \d@llarend \or
- $\vcenter\@startpbox{\@nextchar}\insert@column \@endpbox $\or
- \vtop \@startpbox{\@nextchar}\insert@column \@endpbox \or
- \vbox \@startpbox{\@nextchar}\insert@column \@endpbox \or
- \d@llarbegin \insert@column \d@llarend \or% dubious "s" case
- \TY@box\centering\or
- \TY@box\raggedright\or
- \TY@box\raggedleft\or
- \TY@box\relax
- \fi}\prepnext@tok}
-\def\TY@box#1{%
- \ifx\centering#1%
- \hfil \d@llarbegin\insert@column\d@llarend \hfil \else
- \ifx\raggedright#1%
- \kern\z@%<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- \d@llarbegin \insert@column \d@llarend \hfil \else
- \ifx\raggedleft#1%
- \hfil\kern\z@ \d@llarbegin \insert@column \d@llarend \else
- \ifx\relax#1%
- \d@llarbegin \insert@column \d@llarend
- \fi \fi \fi \fi}
-\def\TY@box@v#1{%
- \vtop \@startpbox{\csname TY@F\the\TY@count\endcsname}%
- #1\arraybackslash\tyformat
- \insert@column\@endpbox}
-\newdimen\TY@tablewidth
-\def\Gscale@div#1#2#3{%
- \setlength\dimen@{#3}%
- \ifdim\dimen@=\z@
- \PackageError{graphics}{Division by 0}\@eha
- \dimen@#2%
- \fi
- \edef\@tempd{\the\dimen@}%
- \setlength\dimen@{#2}%
- \count@65536\relax
- \ifdim\dimen@<\z@
- \dimen@-\dimen@
- \count@-\count@
- \fi
- \loop
- \ifdim\dimen@<8192\p@
- \dimen@\tw@\dimen@
- \divide\count@\tw@
- \repeat
- \dimen@ii=\@tempd\relax
- \divide\dimen@ii\count@
- \divide\dimen@\dimen@ii
- \edef#1{\strip@pt\dimen@}}
-\long\def\TY@get@body#1\end
- {\toks@\expandafter{\the\toks@#1}\TY@find@end}
-\def\TY@find@end#1{%
- \def\@tempa{#1}%
- \ifx\@tempa\TY@\def\@tempa{\end{#1}}\expandafter\@tempa
- \else\toks@\expandafter
- {\the\toks@\end{#1}}\expandafter\TY@get@body\fi}
-\def\TY@warn{%
- \PackageWarning{tabulary}}
-\catcode`\Z=11
-\AtBeginDocument{
-\@ifpackageloaded{colortbl}{%
-\expandafter\def\expandafter\@mkpream\expandafter#\expandafter1%
- \expandafter{%
- \expandafter\let\expandafter\CT@setup\expandafter\relax
- \expandafter\let\expandafter\CT@color\expandafter\relax
- \expandafter\let\expandafter\CT@do@color\expandafter\relax
- \expandafter\let\expandafter\color\expandafter\relax
- \expandafter\let\expandafter\CT@column@color\expandafter\relax
- \expandafter\let\expandafter\CT@row@color\expandafter\relax
- \@mkpream{#1}}
-\let\TY@@mkpream\@mkpream
-\def\TY@classz{%
- \@classx
- \@tempcnta\count@
- \ifx\TY@box\TY@box@v
- \global\advance\TY@count\@ne
- \fi
- \let\centering c%
- \let\raggedright\noindent
- \let\raggedleft\indent
- \let\arraybackslash\relax
- \prepnext@tok
-\expandafter\CT@extract\the\toks\@tempcnta\columncolor!\@nil
- \ifnum\@chnum<4
- \global\expandafter\let\csname TY@F\the\TY@count\endcsname\z@
- \fi
- \ifnum\@chnum=6
- \global\expandafter\let\csname TY@F\the\TY@count\endcsname\z@
- \fi
- \@addtopreamble{%
- \setbox\z@\hbox\bgroup\bgroup
- \ifcase\@chnum
- \hskip\stretch{.5}\kern\z@
- \d@llarbegin\insert@column\d@llarend\hskip\stretch{.5}\or
- \kern\z@%<<<<<<<<<<<<<<<<<<<<<<<<<<<
- \d@llarbegin \insert@column \d@llarend \hfill \or
- \hfill\kern\z@ \d@llarbegin \insert@column \d@llarend \or
- $\vcenter\@startpbox{\@nextchar}\insert@column \@endpbox $\or
- \vtop \@startpbox{\@nextchar}\insert@column \@endpbox \or
- \vbox \@startpbox{\@nextchar}\insert@column \@endpbox \or
- \d@llarbegin \insert@column \d@llarend \or% dubious s case
- \TY@box\centering\or
- \TY@box\raggedright\or
- \TY@box\raggedleft\or
- \TY@box\relax
- \fi
- \egroup\egroup
-\begingroup
- \CT@setup
- \CT@column@color
- \CT@row@color
- \CT@do@color
-\endgroup
- \@tempdima\ht\z@
- \advance\@tempdima\minrowclearance
- \vrule\@height\@tempdima\@width\z@
-\unhbox\z@
-}\prepnext@tok}%
- \def\TY@arrayrule{%
- \TY@subwidth\arrayrulewidth
- \@addtopreamble{{\CT@arc@\vline}}}%
- \def\TY@classvi{\ifcase \@lastchclass
- \@acol \or
- \TY@subwidth\doublerulesep
- \ifx\CT@drsc@\relax
- \@addtopreamble{\hskip\doublerulesep}%
- \else
- \@addtopreamble{{\CT@drsc@\vrule\@width\doublerulesep}}%
- \fi\or
- \@acol \or
- \@classvii
- \fi}%
-}{%
-\let\CT@start\relax
-}
-}
-{\uccode`\*=`\ %
-\uppercase{\gdef\TX@verb{%
- \leavevmode\null\TX@vwarn
- {\ifnum0=`}\fi\ttfamily\let\\\ignorespaces
- \@ifstar{\let~*\TX@vb}{\TX@vb}}}}
-\def\TX@vb#1{\def\@tempa##1#1{\toks@{##1}\edef\@tempa{\the\toks@}%
- \expandafter\TX@v\meaning\@tempa\\ \\\ifnum0=`{\fi}}\@tempa!}
-\def\TX@v#1!{\afterassignment\TX@vfirst\let\@tempa= }
-\begingroup
-\catcode`\*=\catcode`\#
-\catcode`\#=12
-\gdef\TX@vfirst{%
- \if\@tempa#%
- \def\@tempb{\TX@v@#}%
- \else
- \let\@tempb\TX@v@
- \if\@tempa\space~\else\@tempa\fi
- \fi
- \@tempb}
-\gdef\TX@v@*1 *2{%
- \TX@v@hash*1##\relax\if*2\\\else~\expandafter\TX@v@\fi*2}
-\gdef\TX@v@hash*1##*2{*1\ifx*2\relax\else#\expandafter\TX@v@hash\fi*2}
-\endgroup
-\def\TX@vwarn{%
- \@warning{\noexpand\verb may be unreliable inside tabularx/y}%
- \global\let\TX@vwarn\@empty}
-\endinput
-%%
-%% End of file `tabulary.sty'.
diff --git a/sphinx/themes/agogo/static/agogo.css_t b/sphinx/themes/agogo/static/agogo.css_t
index f3c8d67d5..0baec16fc 100644
--- a/sphinx/themes/agogo/static/agogo.css_t
+++ b/sphinx/themes/agogo/static/agogo.css_t
@@ -462,9 +462,14 @@ table.indextable td {
vertical-align: top;
}
-table.indextable dl, table.indextable dd {
+table.indextable ul {
margin-top: 0;
margin-bottom: 0;
+ list-style-type: none;
+}
+
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
}
table.indextable tr.pcap {
@@ -482,6 +487,13 @@ img.toggler {
cursor: pointer;
}
+/* -- domain module index --------------------------------------------------- */
+
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
/* -- viewcode extension ---------------------------------------------------- */
.viewcode-link {
diff --git a/sphinx/themes/agogo/static/bgfooter.png b/sphinx/themes/agogo/static/bgfooter.png
index 9ce5bdd90..b7c7cadd4 100644
--- a/sphinx/themes/agogo/static/bgfooter.png
+++ b/sphinx/themes/agogo/static/bgfooter.png
Binary files differ
diff --git a/sphinx/themes/agogo/static/bgtop.png b/sphinx/themes/agogo/static/bgtop.png
index a0d4709ba..05740880f 100644
--- a/sphinx/themes/agogo/static/bgtop.png
+++ b/sphinx/themes/agogo/static/bgtop.png
Binary files differ
diff --git a/sphinx/themes/basic/defindex.html b/sphinx/themes/basic/defindex.html
index 020f7e396..33becfa0d 100644
--- a/sphinx/themes/basic/defindex.html
+++ b/sphinx/themes/basic/defindex.html
@@ -18,13 +18,13 @@
</p>
{% block tables %}
<p><strong>{{ _('Indices and tables:') }}</strong></p>
- <table class="contentstable" align="center"><tr>
- <td width="50%">
+ <table class="contentstable"><tr>
+ <td style="width: 50%">
<p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">{{ _('Complete Table of Contents') }}</a><br>
<span class="linkdescr">{{ _('lists all sections and subsections') }}</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("search") }}">{{ _('Search Page') }}</a><br>
<span class="linkdescr">{{ _('search this documentation') }}</span></p>
- </td><td width="50%">
+ </td><td style="width: 50%">
<p class="biglink"><a class="biglink" href="{{ pathto("modindex") }}">{{ _('Global Module Index') }}</a><br>
<span class="linkdescr">{{ _('quick access to all modules') }}</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">{{ _('General Index') }}</a><br>
diff --git a/sphinx/themes/basic/domainindex.html b/sphinx/themes/basic/domainindex.html
index 34800f7e2..745174986 100644
--- a/sphinx/themes/basic/domainindex.html
+++ b/sphinx/themes/basic/domainindex.html
@@ -30,7 +30,7 @@
{%- endfor %}
</div>
- <table class="indextable modindextable" cellspacing="0" cellpadding="2">
+ <table class="indextable modindextable">
{%- for letter, entries in content %}
<tr class="pcap"><td></td><td>&#160;</td><td></td></tr>
<tr class="cap" id="cap-{{ letter }}"><td></td><td>
diff --git a/sphinx/themes/basic/genindex-single.html b/sphinx/themes/basic/genindex-single.html
index 93fb9b332..e1da78ab5 100644
--- a/sphinx/themes/basic/genindex-single.html
+++ b/sphinx/themes/basic/genindex-single.html
@@ -8,7 +8,6 @@
:license: BSD, see LICENSE for details.
#}
{% macro indexentries(firstname, links) %}
- <dt>
{%- if links -%}
<a href="{{ links[0][1] }}">
{%- if links[0][0] %}<strong>{% endif -%}
@@ -25,7 +24,6 @@
{%- else %}
{{ firstname|e }}
{%- endif %}
- </dt>
{% endmacro %}
{%- extends "layout.html" %}
@@ -36,18 +34,18 @@
<table style="width: 100%" class="indextable"><tr>
{%- for column in entries|slice(2) if column %}
- <td style="width: 33%" valign="top"><dl>
+ <td style="width: 33%; vertical-align: top;"><ul>
{%- for entryname, (links, subitems, _) in column %}
- {{ indexentries(entryname, links) }}
+ <li>{{ indexentries(entryname, links) }}
{%- if subitems %}
- <dd><dl>
+ <ul>
{%- for subentryname, subentrylinks in subitems %}
- {{ indexentries(subentryname, subentrylinks) }}
+ <li>{{ indexentries(subentryname, subentrylinks) }}</li>
{%- endfor %}
- </dl></dd>
- {%- endif -%}
+ </ul>
+ {%- endif -%}</li>
{%- endfor %}
- </dl></td>
+ </ul></td>
{%- endfor %}
</tr></table>
diff --git a/sphinx/themes/basic/genindex.html b/sphinx/themes/basic/genindex.html
index c72d980b3..57453c3f5 100644
--- a/sphinx/themes/basic/genindex.html
+++ b/sphinx/themes/basic/genindex.html
@@ -8,7 +8,6 @@
:license: BSD, see LICENSE for details.
#}
{% macro indexentries(firstname, links) %}
- <dt>
{%- if links -%}
<a href="{{ links[0][1] }}">
{%- if links[0][0] %}<strong>{% endif -%}
@@ -25,7 +24,6 @@
{%- else %}
{{ firstname|e }}
{%- endif %}
- </dt>
{% endmacro %}
{%- extends "layout.html" %}
@@ -45,18 +43,18 @@
<h2 id="{{ key }}">{{ key }}</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
{%- for column in entries|slice_index(2) if column %}
- <td style="width: 33%" valign="top"><dl>
+ <td style="width: 33%; vertical-align: top;"><ul>
{%- for entryname, (links, subitems, _) in column %}
- {{ indexentries(entryname, links) }}
+ <li>{{ indexentries(entryname, links) }}
{%- if subitems %}
- <dd><dl>
+ <ul>
{%- for subentryname, subentrylinks in subitems %}
- {{ indexentries(subentryname, subentrylinks) }}
+ <li>{{ indexentries(subentryname, subentrylinks) }}</li>
{%- endfor %}
- </dl></dd>
- {%- endif -%}
+ </ul>
+ {%- endif -%}</li>
{%- endfor %}
- </dl></td>
+ </ul></td>
{%- endfor %}
</tr></table>
{% endfor %}
diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html
index cf41aff4b..2d37d7134 100644
--- a/sphinx/themes/basic/layout.html
+++ b/sphinx/themes/basic/layout.html
@@ -91,7 +91,8 @@
VERSION: '{{ release|e }}',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
- HAS_SOURCE: {{ has_source|lower }}
+ HAS_SOURCE: {{ has_source|lower }},
+ SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
};
</script>
{%- for scriptfile in script_files %}
@@ -139,10 +140,6 @@
{%- if hasdoc('copyright') %}
<link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
{%- endif %}
- <link rel="top" title="{{ docstitle|e }}" href="{{ pathto(master_doc) }}" />
- {%- if parents %}
- <link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}" />
- {%- endif %}
{%- if next %}
<link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
{%- endif %}
diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t
index 54f5e5199..d70003d42 100644
--- a/sphinx/themes/basic/static/basic.css_t
+++ b/sphinx/themes/basic/static/basic.css_t
@@ -122,6 +122,8 @@ ul.keywordmatches li.goodmatch a {
table.contentstable {
width: 90%;
+ margin-left: auto;
+ margin-right: auto;
}
table.contentstable p.biglink {
@@ -149,9 +151,14 @@ table.indextable td {
vertical-align: top;
}
-table.indextable dl, table.indextable dd {
+table.indextable ul {
margin-top: 0;
margin-bottom: 0;
+ list-style-type: none;
+}
+
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
}
table.indextable tr.pcap {
@@ -183,6 +190,13 @@ div.genindex-jumpbox {
padding: 0.4em;
}
+/* -- domain module index --------------------------------------------------- */
+
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
/* -- general body styles --------------------------------------------------- */
div.body p, div.body dd, div.body li, div.body blockquote {
@@ -217,10 +231,6 @@ div.body td {
text-align: left;
}
-.field-list ul {
- padding-left: 1em;
-}
-
.first {
margin-top: 0 !important;
}
@@ -337,10 +347,6 @@ table.docutils td, table.docutils th {
border-bottom: 1px solid #aaa;
}
-table.field-list td, table.field-list th {
- border: 0 !important;
-}
-
table.footnote td, table.footnote th {
border: 0 !important;
}
@@ -377,6 +383,20 @@ div.figure p.caption span.caption-number {
div.figure p.caption span.caption-text {
}
+/* -- field list styles ----------------------------------------------------- */
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
/* -- other body styles ----------------------------------------------------- */
@@ -427,15 +447,6 @@ dl.glossary dt {
font-size: 1.1em;
}
-.field-list ul {
- margin: 0;
- padding-left: 1em;
-}
-
-.field-list p {
- margin: 0;
-}
-
.optional {
font-size: 1.3em;
}
@@ -592,6 +603,16 @@ span.eqno {
float: right;
}
+span.eqno a.headerlink {
+ position: relative;
+ left: 0px;
+ z-index: 1;
+}
+
+div.math:hover a.headerlink {
+ visibility: visible;
+}
+
/* -- printout stylesheet --------------------------------------------------- */
@media print {
diff --git a/sphinx/themes/basic/static/comment-bright.png b/sphinx/themes/basic/static/comment-bright.png
index 551517b8c..15e27edb1 100644
--- a/sphinx/themes/basic/static/comment-bright.png
+++ b/sphinx/themes/basic/static/comment-bright.png
Binary files differ
diff --git a/sphinx/themes/basic/static/comment-close.png b/sphinx/themes/basic/static/comment-close.png
index 09b54be46..4d91bcf57 100644
--- a/sphinx/themes/basic/static/comment-close.png
+++ b/sphinx/themes/basic/static/comment-close.png
Binary files differ
diff --git a/sphinx/themes/basic/static/comment.png b/sphinx/themes/basic/static/comment.png
index 92feb52b8..dfbc0cbd5 100644
--- a/sphinx/themes/basic/static/comment.png
+++ b/sphinx/themes/basic/static/comment.png
Binary files differ
diff --git a/sphinx/themes/basic/static/down-pressed.png b/sphinx/themes/basic/static/down-pressed.png
index 7c30d004b..5756c8cad 100644
--- a/sphinx/themes/basic/static/down-pressed.png
+++ b/sphinx/themes/basic/static/down-pressed.png
Binary files differ
diff --git a/sphinx/themes/basic/static/down.png b/sphinx/themes/basic/static/down.png
index f48098a43..1b3bdad2c 100644
--- a/sphinx/themes/basic/static/down.png
+++ b/sphinx/themes/basic/static/down.png
Binary files differ
diff --git a/sphinx/themes/basic/static/file.png b/sphinx/themes/basic/static/file.png
index 254c60bfb..a858a410e 100644
--- a/sphinx/themes/basic/static/file.png
+++ b/sphinx/themes/basic/static/file.png
Binary files differ
diff --git a/sphinx/themes/basic/static/jquery-1.11.1.js b/sphinx/themes/basic/static/jquery-3.1.0.js
index d4b67f7e6..f2fc27478 100644
--- a/sphinx/themes/basic/static/jquery-1.11.1.js
+++ b/sphinx/themes/basic/static/jquery-3.1.0.js
@@ -1,27 +1,30 @@
+/*eslint-disable no-unused-vars*/
/*!
- * jQuery JavaScript Library v1.11.1
- * http://jquery.com/
+ * jQuery JavaScript Library v3.1.0
+ * https://jquery.com/
*
* Includes Sizzle.js
- * http://sizzlejs.com/
+ * https://sizzlejs.com/
*
- * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
+ * Copyright jQuery Foundation and other contributors
* Released under the MIT license
- * http://jquery.org/license
+ * https://jquery.org/license
*
- * Date: 2014-05-01T17:42Z
+ * Date: 2016-07-07T21:44Z
*/
+( function( global, factory ) {
-(function( global, factory ) {
+ "use strict";
if ( typeof module === "object" && typeof module.exports === "object" ) {
- // For CommonJS and CommonJS-like environments where a proper window is present,
- // execute the factory and get jQuery
- // For environments that do not inherently posses a window with a document
- // (such as Node.js), expose a jQuery-making factory as module.exports
- // This accentuates the need for the creation of a real window
+
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
// e.g. var jQuery = require("jquery")(window);
- // See ticket #14549 for more info
+ // See ticket #14549 for more info.
module.exports = global.document ?
factory( global, true ) :
function( w ) {
@@ -35,23 +38,27 @@
}
// Pass this if window is not defined yet
-}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
-// Can't do this because several apps including ASP.NET trace
-// the stack via arguments.caller.callee and Firefox dies if
-// you try to trace through "use strict" call chains. (#13335)
-// Support: Firefox 18+
-//
+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
+// enough that all such attempts are guarded in a try block.
+"use strict";
-var deletedIds = [];
+var arr = [];
-var slice = deletedIds.slice;
+var document = window.document;
-var concat = deletedIds.concat;
+var getProto = Object.getPrototypeOf;
-var push = deletedIds.push;
+var slice = arr.slice;
-var indexOf = deletedIds.indexOf;
+var concat = arr.concat;
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
var class2type = {};
@@ -59,27 +66,46 @@ var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
+var fnToString = hasOwn.toString;
+
+var ObjectFunctionString = fnToString.call( Object );
+
var support = {};
+ function DOMEval( code, doc ) {
+ doc = doc || document;
+
+ var script = doc.createElement( "script" );
+
+ script.text = code;
+ doc.head.appendChild( script ).parentNode.removeChild( script );
+ }
+/* global Symbol */
+// Defining this global in .eslintrc would create a danger of using the global
+// unguarded in another place, it seems safer to define global only for this module
+
+
+
var
- version = "1.11.1",
+ version = "3.1.0",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
+
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},
- // Support: Android<4.1, IE<9
+ // Support: Android <=4.0 only
// Make sure we trim BOM and NBSP
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
// Matches dashed string for camelizing
rmsPrefix = /^-ms-/,
- rdashAlpha = /-([\da-z])/gi,
+ rdashAlpha = /-([a-z])/g,
// Used by jQuery.camelCase as callback to replace()
fcamelCase = function( all, letter ) {
@@ -87,14 +113,12 @@ var
};
jQuery.fn = jQuery.prototype = {
+
// The current version of jQuery being used
jquery: version,
constructor: jQuery,
- // Start with an empty selector
- selector: "",
-
// The default length of a jQuery object is 0
length: 0,
@@ -123,23 +147,20 @@ jQuery.fn = jQuery.prototype = {
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
- ret.context = this.context;
// Return the newly-formed element set
return ret;
},
// Execute a callback for every element in the matched set.
- // (You can seed the arguments with an array of args, but this is
- // only used internally.)
- each: function( callback, args ) {
- return jQuery.each( this, callback, args );
+ each: function( callback ) {
+ return jQuery.each( this, callback );
},
map: function( callback ) {
- return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return this.pushStack( jQuery.map( this, function( elem, i ) {
return callback.call( elem, i, elem );
- }));
+ } ) );
},
slice: function() {
@@ -157,23 +178,23 @@ jQuery.fn = jQuery.prototype = {
eq: function( i ) {
var len = this.length,
j = +i + ( i < 0 ? len : 0 );
- return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
},
end: function() {
- return this.prevObject || this.constructor(null);
+ return this.prevObject || this.constructor();
},
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: push,
- sort: deletedIds.sort,
- splice: deletedIds.splice
+ sort: arr.sort,
+ splice: arr.splice
};
jQuery.extend = jQuery.fn.extend = function() {
- var src, copyIsArray, copy, name, options, clone,
- target = arguments[0] || {},
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[ 0 ] || {},
i = 1,
length = arguments.length,
deep = false;
@@ -182,25 +203,27 @@ jQuery.extend = jQuery.fn.extend = function() {
if ( typeof target === "boolean" ) {
deep = target;
- // skip the boolean and the target
+ // Skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
- if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
target = {};
}
- // extend jQuery itself if only one argument is passed
+ // Extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
+
// Only deal with non-null/undefined values
- if ( (options = arguments[ i ]) != null ) {
+ if ( ( options = arguments[ i ] ) != null ) {
+
// Extend the base object
for ( name in options ) {
src = target[ name ];
@@ -212,13 +235,15 @@ jQuery.extend = jQuery.fn.extend = function() {
}
// Recurse if we're merging plain objects or arrays
- if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
+ ( copyIsArray = jQuery.isArray( copy ) ) ) ) {
+
if ( copyIsArray ) {
copyIsArray = false;
- clone = src && jQuery.isArray(src) ? src : [];
+ clone = src && jQuery.isArray( src ) ? src : [];
} else {
- clone = src && jQuery.isPlainObject(src) ? src : {};
+ clone = src && jQuery.isPlainObject( src ) ? src : {};
}
// Never move original objects, clone them
@@ -236,7 +261,8 @@ jQuery.extend = jQuery.fn.extend = function() {
return target;
};
-jQuery.extend({
+jQuery.extend( {
+
// Unique for each copy of jQuery on the page
expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
@@ -249,98 +275,81 @@ jQuery.extend({
noop: function() {},
- // See test/unit/core.js for details concerning isFunction.
- // Since version 1.3, DOM methods and functions like alert
- // aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
- return jQuery.type(obj) === "function";
+ return jQuery.type( obj ) === "function";
},
- isArray: Array.isArray || function( obj ) {
- return jQuery.type(obj) === "array";
- },
+ isArray: Array.isArray,
isWindow: function( obj ) {
- /* jshint eqeqeq: false */
- return obj != null && obj == obj.window;
+ return obj != null && obj === obj.window;
},
isNumeric: function( obj ) {
- // parseFloat NaNs numeric-cast false positives (null|true|false|"")
- // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
- // subtraction forces infinities to NaN
- return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
- },
- isEmptyObject: function( obj ) {
- var name;
- for ( name in obj ) {
- return false;
- }
- return true;
+ // As of jQuery 3.0, isNumeric is limited to
+ // strings and numbers (primitives or objects)
+ // that can be coerced to finite numbers (gh-2662)
+ var type = jQuery.type( obj );
+ return ( type === "number" || type === "string" ) &&
+
+ // parseFloat NaNs numeric-cast false positives ("")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ !isNaN( obj - parseFloat( obj ) );
},
isPlainObject: function( obj ) {
- var key;
+ var proto, Ctor;
- // Must be an Object.
- // Because of IE, we also have to check the presence of the constructor property.
- // Make sure that DOM nodes and window objects don't pass through, as well
- if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ // Detect obvious negatives
+ // Use toString instead of jQuery.type to catch host objects
+ if ( !obj || toString.call( obj ) !== "[object Object]" ) {
return false;
}
- try {
- // Not own constructor property must be Object
- if ( obj.constructor &&
- !hasOwn.call(obj, "constructor") &&
- !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
- return false;
- }
- } catch ( e ) {
- // IE8,9 Will throw exceptions on certain host objects #9897
- return false;
- }
+ proto = getProto( obj );
- // Support: IE<9
- // Handle iteration over inherited properties before own properties.
- if ( support.ownLast ) {
- for ( key in obj ) {
- return hasOwn.call( obj, key );
- }
+ // Objects with no prototype (e.g., `Object.create( null )`) are plain
+ if ( !proto ) {
+ return true;
}
- // Own properties are enumerated firstly, so to speed up,
- // if last one is own, then all properties are own.
- for ( key in obj ) {}
+ // Objects with prototype are plain iff they were constructed by a global Object function
+ Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
+ return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
+ },
- return key === undefined || hasOwn.call( obj, key );
+ isEmptyObject: function( obj ) {
+
+ /* eslint-disable no-unused-vars */
+ // See https://github.com/eslint/eslint/issues/6125
+ var name;
+
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
},
type: function( obj ) {
if ( obj == null ) {
return obj + "";
}
+
+ // Support: Android <=2.3 only (functionish RegExp)
return typeof obj === "object" || typeof obj === "function" ?
- class2type[ toString.call(obj) ] || "object" :
+ class2type[ toString.call( obj ) ] || "object" :
typeof obj;
},
// Evaluates a script in a global context
- // Workarounds based on findings by Jim Driscoll
- // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
- globalEval: function( data ) {
- if ( data && jQuery.trim( data ) ) {
- // We use execScript on Internet Explorer
- // We use an anonymous function so that context is window
- // rather than jQuery in Firefox
- ( window.execScript || function( data ) {
- window[ "eval" ].call( window, data );
- } )( data );
- }
+ globalEval: function( code ) {
+ DOMEval( code );
},
// Convert dashed to camelCase; used by the css and data modules
+ // Support: IE <=9 - 11, Edge 12 - 13
// Microsoft forgot to hump their vendor prefix (#9572)
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
@@ -350,49 +359,20 @@ jQuery.extend({
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
},
- // args is for internal usage only
- each: function( obj, callback, args ) {
- var value,
- i = 0,
- length = obj.length,
- isArray = isArraylike( obj );
-
- if ( args ) {
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback.apply( obj[ i ], args );
-
- if ( value === false ) {
- break;
- }
- }
- } else {
- for ( i in obj ) {
- value = callback.apply( obj[ i ], args );
+ each: function( obj, callback ) {
+ var length, i = 0;
- if ( value === false ) {
- break;
- }
+ if ( isArrayLike( obj ) ) {
+ length = obj.length;
+ for ( ; i < length; i++ ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
}
}
-
- // A special, fast, case for the most common use of each
} else {
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback.call( obj[ i ], i, obj[ i ] );
-
- if ( value === false ) {
- break;
- }
- }
- } else {
- for ( i in obj ) {
- value = callback.call( obj[ i ], i, obj[ i ] );
-
- if ( value === false ) {
- break;
- }
+ for ( i in obj ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
}
}
}
@@ -400,7 +380,7 @@ jQuery.extend({
return obj;
},
- // Support: Android<4.1, IE<9
+ // Support: Android <=4.0 only
trim: function( text ) {
return text == null ?
"" :
@@ -412,7 +392,7 @@ jQuery.extend({
var ret = results || [];
if ( arr != null ) {
- if ( isArraylike( Object(arr) ) ) {
+ if ( isArrayLike( Object( arr ) ) ) {
jQuery.merge( ret,
typeof arr === "string" ?
[ arr ] : arr
@@ -426,42 +406,18 @@ jQuery.extend({
},
inArray: function( elem, arr, i ) {
- var len;
-
- if ( arr ) {
- if ( indexOf ) {
- return indexOf.call( arr, elem, i );
- }
-
- len = arr.length;
- i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
-
- for ( ; i < len; i++ ) {
- // Skip accessing in sparse arrays
- if ( i in arr && arr[ i ] === elem ) {
- return i;
- }
- }
- }
-
- return -1;
+ return arr == null ? -1 : indexOf.call( arr, elem, i );
},
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
merge: function( first, second ) {
var len = +second.length,
j = 0,
i = first.length;
- while ( j < len ) {
- first[ i++ ] = second[ j++ ];
- }
-
- // Support: IE<9
- // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
- if ( len !== len ) {
- while ( second[j] !== undefined ) {
- first[ i++ ] = second[ j++ ];
- }
+ for ( ; j < len; j++ ) {
+ first[ i++ ] = second[ j ];
}
first.length = i;
@@ -490,14 +446,13 @@ jQuery.extend({
// arg is for internal usage only
map: function( elems, callback, arg ) {
- var value,
+ var length, value,
i = 0,
- length = elems.length,
- isArray = isArraylike( elems ),
ret = [];
// Go through the array, translating each of the items to their new values
- if ( isArray ) {
+ if ( isArrayLike( elems ) ) {
+ length = elems.length;
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
@@ -527,7 +482,7 @@ jQuery.extend({
// Bind a function to a context, optionally partially applying any
// arguments.
proxy: function( fn, context ) {
- var args, proxy, tmp;
+ var tmp, args, proxy;
if ( typeof context === "string" ) {
tmp = fn[ context ];
@@ -553,45 +508,49 @@ jQuery.extend({
return proxy;
},
- now: function() {
- return +( new Date() );
- },
+ now: Date.now,
// jQuery.support is not used in Core but other projects attach their
// properties to it so it needs to exist.
support: support
-});
+} );
+
+if ( typeof Symbol === "function" ) {
+ jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
+}
// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
+function( i, name ) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
+} );
+
+function isArrayLike( obj ) {
-function isArraylike( obj ) {
- var length = obj.length,
+ // Support: real iOS 8.2 only (not reproducible in simulator)
+ // `in` check used to prevent JIT error (gh-2145)
+ // hasOwn isn't used here due to false negatives
+ // regarding Nodelist length in IE
+ var length = !!obj && "length" in obj && obj.length,
type = jQuery.type( obj );
if ( type === "function" || jQuery.isWindow( obj ) ) {
return false;
}
- if ( obj.nodeType === 1 && length ) {
- return true;
- }
-
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}
var Sizzle =
/*!
- * Sizzle CSS Selector Engine v1.10.19
- * http://sizzlejs.com/
+ * Sizzle CSS Selector Engine v2.3.0
+ * https://sizzlejs.com/
*
- * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Copyright jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2014-04-18
+ * Date: 2016-01-04
*/
(function( window ) {
@@ -618,7 +577,7 @@ var i,
contains,
// Instance-specific data
- expando = "sizzle" + -(new Date()),
+ expando = "sizzle" + 1 * new Date(),
preferredDoc = window.document,
dirruns = 0,
done = 0,
@@ -632,10 +591,6 @@ var i,
return 0;
},
- // General-purpose constants
- strundefined = typeof undefined,
- MAX_NEGATIVE = 1 << 31,
-
// Instance methods
hasOwn = ({}).hasOwnProperty,
arr = [],
@@ -643,12 +598,13 @@ var i,
push_native = arr.push,
push = arr.push,
slice = arr.slice,
- // Use a stripped-down indexOf if we can't use a native one
- indexOf = arr.indexOf || function( elem ) {
+ // Use a stripped-down indexOf as it's faster than native
+ // https://jsperf.com/thor-indexof-vs-for/5
+ indexOf = function( list, elem ) {
var i = 0,
- len = this.length;
+ len = list.length;
for ( ; i < len; i++ ) {
- if ( this[i] === elem ) {
+ if ( list[i] === elem ) {
return i;
}
}
@@ -659,25 +615,21 @@ var i,
// Regular expressions
- // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ // http://www.w3.org/TR/css3-selectors/#whitespace
whitespace = "[\\x20\\t\\r\\n\\f]",
- // http://www.w3.org/TR/css3-syntax/#characters
- characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
- // Loosely modeled on CSS identifier characters
- // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
- // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
- identifier = characterEncoding.replace( "w", "w#" ),
+ // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
- attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
+ attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
// Operator (capture 2)
"*([*^$|!~]?=)" + whitespace +
// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
"*\\]",
- pseudos = ":(" + characterEncoding + ")(?:\\((" +
+ pseudos = ":(" + identifier + ")(?:\\((" +
// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
// 1. quoted (capture 3; capture 4 or capture 5)
"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
@@ -688,6 +640,7 @@ var i,
")\\)|)",
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rwhitespace = new RegExp( whitespace + "+", "g" ),
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
@@ -699,9 +652,9 @@ var i,
ridentifier = new RegExp( "^" + identifier + "$" ),
matchExpr = {
- "ID": new RegExp( "^#(" + characterEncoding + ")" ),
- "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
- "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ID": new RegExp( "^#(" + identifier + ")" ),
+ "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
+ "TAG": new RegExp( "^(" + identifier + "|[*])" ),
"ATTR": new RegExp( "^" + attributes ),
"PSEUDO": new RegExp( "^" + pseudos ),
"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
@@ -723,9 +676,9 @@ var i,
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
rsibling = /[+~]/,
- rescape = /'|\\/g,
- // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ // CSS escapes
+ // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
funescape = function( _, escaped, escapedWhitespace ) {
var high = "0x" + escaped - 0x10000;
@@ -739,7 +692,41 @@ var i,
String.fromCharCode( high + 0x10000 ) :
// Supplemental Plane codepoint (surrogate pair)
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
- };
+ },
+
+ // CSS string/identifier serialization
+ // https://drafts.csswg.org/cssom/#common-serializing-idioms
+ rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,
+ fcssescape = function( ch, asCodePoint ) {
+ if ( asCodePoint ) {
+
+ // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
+ if ( ch === "\0" ) {
+ return "\uFFFD";
+ }
+
+ // Control characters and (dependent upon position) numbers get escaped as code points
+ return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
+ }
+
+ // Other potentially-special ASCII characters get backslash-escaped
+ return "\\" + ch;
+ },
+
+ // Used for iframes
+ // See setDocument()
+ // Removing the function wrapper causes a "Permission Denied"
+ // error in IE
+ unloadHandler = function() {
+ setDocument();
+ },
+
+ disabledAncestor = addCombinator(
+ function( elem ) {
+ return elem.disabled === true;
+ },
+ { dir: "parentNode", next: "legend" }
+ );
// Optimize for push.apply( _, NodeList )
try {
@@ -771,104 +758,128 @@ try {
}
function Sizzle( selector, context, results, seed ) {
- var match, elem, m, nodeType,
- // QSA vars
- i, groups, old, nid, newContext, newSelector;
+ var m, i, elem, nid, match, groups, newSelector,
+ newContext = context && context.ownerDocument,
- if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
- setDocument( context );
- }
+ // nodeType defaults to 9, since context defaults to document
+ nodeType = context ? context.nodeType : 9;
- context = context || document;
results = results || [];
- if ( !selector || typeof selector !== "string" ) {
+ // Return early from calls with invalid selector or context
+ if ( typeof selector !== "string" || !selector ||
+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
return results;
}
- if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
- return [];
- }
+ // Try to shortcut find operations (as opposed to filters) in HTML documents
+ if ( !seed ) {
- if ( documentIsHTML && !seed ) {
-
- // Shortcuts
- if ( (match = rquickExpr.exec( selector )) ) {
- // Speed-up: Sizzle("#ID")
- if ( (m = match[1]) ) {
- if ( nodeType === 9 ) {
- elem = context.getElementById( m );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document (jQuery #6963)
- if ( elem && elem.parentNode ) {
- // Handle the case where IE, Opera, and Webkit return items
- // by name instead of ID
- if ( elem.id === m ) {
- results.push( elem );
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+ context = context || document;
+
+ if ( documentIsHTML ) {
+
+ // If the selector is sufficiently simple, try using a "get*By*" DOM method
+ // (excepting DocumentFragment context, where the methods don't exist)
+ if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
+
+ // ID selector
+ if ( (m = match[1]) ) {
+
+ // Document context
+ if ( nodeType === 9 ) {
+ if ( (elem = context.getElementById( m )) ) {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
return results;
}
+
+ // Element context
} else {
- return results;
- }
- } else {
- // Context is not a document
- if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
- contains( context, elem ) && elem.id === m ) {
- results.push( elem );
- return results;
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( newContext && (elem = newContext.getElementById( m )) &&
+ contains( context, elem ) &&
+ elem.id === m ) {
+
+ results.push( elem );
+ return results;
+ }
}
- }
- // Speed-up: Sizzle("TAG")
- } else if ( match[2] ) {
- push.apply( results, context.getElementsByTagName( selector ) );
- return results;
+ // Type selector
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
- // Speed-up: Sizzle(".CLASS")
- } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
- push.apply( results, context.getElementsByClassName( m ) );
- return results;
+ // Class selector
+ } else if ( (m = match[3]) && support.getElementsByClassName &&
+ context.getElementsByClassName ) {
+
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
}
- }
- // QSA path
- if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
- nid = old = expando;
- newContext = context;
- newSelector = nodeType === 9 && selector;
+ // Take advantage of querySelectorAll
+ if ( support.qsa &&
+ !compilerCache[ selector + " " ] &&
+ (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- groups = tokenize( selector );
+ if ( nodeType !== 1 ) {
+ newContext = context;
+ newSelector = selector;
- if ( (old = context.getAttribute("id")) ) {
- nid = old.replace( rescape, "\\$&" );
- } else {
- context.setAttribute( "id", nid );
- }
- nid = "[id='" + nid + "'] ";
+ // qSA looks outside Element context, which is not what we want
+ // Thanks to Andrew Dupont for this workaround technique
+ // Support: IE <=8
+ // Exclude object elements
+ } else if ( context.nodeName.toLowerCase() !== "object" ) {
- i = groups.length;
- while ( i-- ) {
- groups[i] = nid + toSelector( groups[i] );
+ // Capture the context ID, setting it first if necessary
+ if ( (nid = context.getAttribute( "id" )) ) {
+ nid = nid.replace( rcssescape, fcssescape );
+ } else {
+ context.setAttribute( "id", (nid = expando) );
+ }
+
+ // Prefix every selector in the list
+ groups = tokenize( selector );
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = "#" + nid + " " + toSelector( groups[i] );
+ }
+ newSelector = groups.join( "," );
+
+ // Expand context for sibling selectors
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+ context;
}
- newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
- newSelector = groups.join(",");
- }
- if ( newSelector ) {
- try {
- push.apply( results,
- newContext.querySelectorAll( newSelector )
- );
- return results;
- } catch(qsaError) {
- } finally {
- if ( !old ) {
- context.removeAttribute("id");
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch ( qsaError ) {
+ } finally {
+ if ( nid === expando ) {
+ context.removeAttribute( "id" );
+ }
}
}
}
@@ -881,7 +892,7 @@ function Sizzle( selector, context, results, seed ) {
/**
* Create key-value caches of limited size
- * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * @returns {function(string, object)} Returns the Object data after storing it on itself with
* property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
* deleting the oldest entry
*/
@@ -910,22 +921,22 @@ function markFunction( fn ) {
/**
* Support testing using an element
- * @param {Function} fn Passed the created div and expects a boolean result
+ * @param {Function} fn Passed the created element and returns a boolean result
*/
function assert( fn ) {
- var div = document.createElement("div");
+ var el = document.createElement("fieldset");
try {
- return !!fn( div );
+ return !!fn( el );
} catch (e) {
return false;
} finally {
// Remove from its parent by default
- if ( div.parentNode ) {
- div.parentNode.removeChild( div );
+ if ( el.parentNode ) {
+ el.parentNode.removeChild( el );
}
// release memory in IE
- div = null;
+ el = null;
}
}
@@ -936,7 +947,7 @@ function assert( fn ) {
*/
function addHandle( attrs, handler ) {
var arr = attrs.split("|"),
- i = attrs.length;
+ i = arr.length;
while ( i-- ) {
Expr.attrHandle[ arr[i] ] = handler;
@@ -952,8 +963,7 @@ function addHandle( attrs, handler ) {
function siblingCheck( a, b ) {
var cur = b && a,
diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
- ( ~b.sourceIndex || MAX_NEGATIVE ) -
- ( ~a.sourceIndex || MAX_NEGATIVE );
+ a.sourceIndex - b.sourceIndex;
// Use IE sourceIndex if available on both nodes
if ( diff ) {
@@ -995,6 +1005,34 @@ function createButtonPseudo( type ) {
}
/**
+ * Returns a function to use in pseudos for :enabled/:disabled
+ * @param {Boolean} disabled true for :disabled; false for :enabled
+ */
+function createDisabledPseudo( disabled ) {
+ // Known :disabled false positives:
+ // IE: *[disabled]:not(button, input, select, textarea, optgroup, option, menuitem, fieldset)
+ // not IE: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
+ return function( elem ) {
+
+ // Check form elements and option elements for explicit disabling
+ return "label" in elem && elem.disabled === disabled ||
+ "form" in elem && elem.disabled === disabled ||
+
+ // Check non-disabled form elements for fieldset[disabled] ancestors
+ "form" in elem && elem.disabled === false && (
+ // Support: IE6-11+
+ // Ancestry is covered for us
+ elem.isDisabled === disabled ||
+
+ // Otherwise, assume any non-<option> under fieldset[disabled] is disabled
+ /* jshint -W018 */
+ elem.isDisabled !== !disabled &&
+ ("label" in elem || !disabledAncestor( elem )) !== disabled
+ );
+ };
+}
+
+/**
* Returns a function to use in pseudos for positionals
* @param {Function} fn
*/
@@ -1022,7 +1060,7 @@ function createPositionalPseudo( fn ) {
* @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
*/
function testContext( context ) {
- return context && typeof context.getElementsByTagName !== strundefined && context;
+ return context && typeof context.getElementsByTagName !== "undefined" && context;
}
// Expose support vars for convenience
@@ -1046,36 +1084,31 @@ isXML = Sizzle.isXML = function( elem ) {
* @returns {Object} Returns the current document
*/
setDocument = Sizzle.setDocument = function( node ) {
- var hasCompare,
- doc = node ? node.ownerDocument || node : preferredDoc,
- parent = doc.defaultView;
+ var hasCompare, subWindow,
+ doc = node ? node.ownerDocument || node : preferredDoc;
- // If no document and documentElement is available, return
+ // Return early if doc is invalid or already selected
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
return document;
}
- // Set our document
+ // Update global variables
document = doc;
- docElem = doc.documentElement;
-
- // Support tests
- documentIsHTML = !isXML( doc );
-
- // Support: IE>8
- // If iframe document is assigned to "document" variable and if iframe has been reloaded,
- // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
- // IE6-8 do not support the defaultView property so parent will be undefined
- if ( parent && parent !== parent.top ) {
- // IE11 does not have attachEvent, so all must suffer
- if ( parent.addEventListener ) {
- parent.addEventListener( "unload", function() {
- setDocument();
- }, false );
- } else if ( parent.attachEvent ) {
- parent.attachEvent( "onunload", function() {
- setDocument();
- });
+ docElem = document.documentElement;
+ documentIsHTML = !isXML( document );
+
+ // Support: IE 9-11, Edge
+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
+ if ( preferredDoc !== document &&
+ (subWindow = document.defaultView) && subWindow.top !== subWindow ) {
+
+ // Support: IE 11, Edge
+ if ( subWindow.addEventListener ) {
+ subWindow.addEventListener( "unload", unloadHandler, false );
+
+ // Support: IE 9 - 10 only
+ } else if ( subWindow.attachEvent ) {
+ subWindow.attachEvent( "onunload", unloadHandler );
}
}
@@ -1083,50 +1116,40 @@ setDocument = Sizzle.setDocument = function( node ) {
---------------------------------------------------------------------- */
// Support: IE<8
- // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
- support.attributes = assert(function( div ) {
- div.className = "i";
- return !div.getAttribute("className");
+ // Verify that getAttribute really returns attributes and not properties
+ // (excepting IE8 booleans)
+ support.attributes = assert(function( el ) {
+ el.className = "i";
+ return !el.getAttribute("className");
});
/* getElement(s)By*
---------------------------------------------------------------------- */
// Check if getElementsByTagName("*") returns only elements
- support.getElementsByTagName = assert(function( div ) {
- div.appendChild( doc.createComment("") );
- return !div.getElementsByTagName("*").length;
+ support.getElementsByTagName = assert(function( el ) {
+ el.appendChild( document.createComment("") );
+ return !el.getElementsByTagName("*").length;
});
- // Check if getElementsByClassName can be trusted
- support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
- div.innerHTML = "<div class='a'></div><div class='a i'></div>";
-
- // Support: Safari<4
- // Catch class over-caching
- div.firstChild.className = "i";
- // Support: Opera<10
- // Catch gEBCN failure to find non-leading classes
- return div.getElementsByClassName("i").length === 2;
- });
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test( document.getElementsByClassName );
// Support: IE<10
// Check if getElementById returns elements by name
- // The broken getElementById methods don't pick up programatically-set names,
+ // The broken getElementById methods don't pick up programmatically-set names,
// so use a roundabout getElementsByName test
- support.getById = assert(function( div ) {
- docElem.appendChild( div ).id = expando;
- return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+ support.getById = assert(function( el ) {
+ docElem.appendChild( el ).id = expando;
+ return !document.getElementsByName || !document.getElementsByName( expando ).length;
});
// ID find and filter
if ( support.getById ) {
Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
var m = context.getElementById( id );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- return m && m.parentNode ? [ m ] : [];
+ return m ? [ m ] : [];
}
};
Expr.filter["ID"] = function( id ) {
@@ -1143,7 +1166,8 @@ setDocument = Sizzle.setDocument = function( node ) {
Expr.filter["ID"] = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {
- var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ var node = typeof elem.getAttributeNode !== "undefined" &&
+ elem.getAttributeNode("id");
return node && node.value === attrId;
};
};
@@ -1152,14 +1176,20 @@ setDocument = Sizzle.setDocument = function( node ) {
// Tag
Expr.find["TAG"] = support.getElementsByTagName ?
function( tag, context ) {
- if ( typeof context.getElementsByTagName !== strundefined ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
return context.getElementsByTagName( tag );
+
+ // DocumentFragment nodes don't have gEBTN
+ } else if ( support.qsa ) {
+ return context.querySelectorAll( tag );
}
} :
+
function( tag, context ) {
var elem,
tmp = [],
i = 0,
+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
results = context.getElementsByTagName( tag );
// Filter out possible comments
@@ -1177,7 +1207,7 @@ setDocument = Sizzle.setDocument = function( node ) {
// Class
Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
- if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
return context.getElementsByClassName( className );
}
};
@@ -1194,63 +1224,87 @@ setDocument = Sizzle.setDocument = function( node ) {
// We allow this because of a bug in IE8/9 that throws an error
// whenever `document.activeElement` is accessed on an iframe
// So, we allow :focus to pass through QSA all the time to avoid the IE error
- // See http://bugs.jquery.com/ticket/13378
+ // See https://bugs.jquery.com/ticket/13378
rbuggyQSA = [];
- if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+ if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
// Build QSA regex
// Regex strategy adopted from Diego Perini
- assert(function( div ) {
+ assert(function( el ) {
// Select is set to empty string on purpose
// This is to test IE's treatment of not explicitly
// setting a boolean content attribute,
// since its presence should be enough
- // http://bugs.jquery.com/ticket/12359
- div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
+ // https://bugs.jquery.com/ticket/12359
+ docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
+ "<select id='" + expando + "-\r\\' msallowcapture=''>" +
+ "<option selected=''></option></select>";
// Support: IE8, Opera 11-12.16
// Nothing should be selected when empty strings follow ^= or $= or *=
// The test attribute must be unknown in Opera but "safe" for WinRT
- // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
- if ( div.querySelectorAll("[msallowclip^='']").length ) {
+ // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( el.querySelectorAll("[msallowcapture^='']").length ) {
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
}
// Support: IE8
// Boolean attributes and "value" are not treated correctly
- if ( !div.querySelectorAll("[selected]").length ) {
+ if ( !el.querySelectorAll("[selected]").length ) {
rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
}
+ // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
+ if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push("~=");
+ }
+
// Webkit/Opera - :checked should return selected option elements
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
// IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":checked").length ) {
+ if ( !el.querySelectorAll(":checked").length ) {
rbuggyQSA.push(":checked");
}
+
+ // Support: Safari 8+, iOS 8+
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibling-combinator selector` fails
+ if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push(".#.+[+~]");
+ }
});
- assert(function( div ) {
+ assert(function( el ) {
+ el.innerHTML = "<a href='' disabled='disabled'></a>" +
+ "<select disabled='disabled'><option/></select>";
+
// Support: Windows 8 Native Apps
// The type and name attributes are restricted during .innerHTML assignment
- var input = doc.createElement("input");
+ var input = document.createElement("input");
input.setAttribute( "type", "hidden" );
- div.appendChild( input ).setAttribute( "name", "D" );
+ el.appendChild( input ).setAttribute( "name", "D" );
// Support: IE8
// Enforce case-sensitivity of name attribute
- if ( div.querySelectorAll("[name=d]").length ) {
+ if ( el.querySelectorAll("[name=d]").length ) {
rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
}
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
// IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":enabled").length ) {
+ if ( el.querySelectorAll(":enabled").length !== 2 ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Support: IE9-11+
+ // IE's :disabled selector does not pick up the children of disabled fieldsets
+ docElem.appendChild( el ).disabled = true;
+ if ( el.querySelectorAll(":disabled").length !== 2 ) {
rbuggyQSA.push( ":enabled", ":disabled" );
}
// Opera 10-11 does not throw on post-comma invalid pseudos
- div.querySelectorAll("*,:x");
+ el.querySelectorAll("*,:x");
rbuggyQSA.push(",.*:");
});
}
@@ -1261,14 +1315,14 @@ setDocument = Sizzle.setDocument = function( node ) {
docElem.oMatchesSelector ||
docElem.msMatchesSelector) )) ) {
- assert(function( div ) {
+ assert(function( el ) {
// Check to see if it's possible to do matchesSelector
// on a disconnected node (IE 9)
- support.disconnectedMatch = matches.call( div, "div" );
+ support.disconnectedMatch = matches.call( el, "*" );
// This should fail with an exception
// Gecko does not error, returns false instead
- matches.call( div, "[s!='']:x" );
+ matches.call( el, "[s!='']:x" );
rbuggyMatches.push( "!=", pseudos );
});
}
@@ -1281,7 +1335,7 @@ setDocument = Sizzle.setDocument = function( node ) {
hasCompare = rnative.test( docElem.compareDocumentPosition );
// Element contains another
- // Purposefully does not implement inclusive descendent
+ // Purposefully self-exclusive
// As in, an element does not contain itself
contains = hasCompare || rnative.test( docElem.contains ) ?
function( a, b ) {
@@ -1335,16 +1389,16 @@ setDocument = Sizzle.setDocument = function( node ) {
(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
// Choose the first element that is related to our preferred document
- if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+ if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
return -1;
}
- if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+ if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
return 1;
}
// Maintain original order
return sortInput ?
- ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
0;
}
@@ -1366,12 +1420,12 @@ setDocument = Sizzle.setDocument = function( node ) {
// Parentless nodes are either documents or disconnected
if ( !aup || !bup ) {
- return a === doc ? -1 :
- b === doc ? 1 :
+ return a === document ? -1 :
+ b === document ? 1 :
aup ? -1 :
bup ? 1 :
sortInput ?
- ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
0;
// If the nodes are siblings, we can do a quick check
@@ -1404,7 +1458,7 @@ setDocument = Sizzle.setDocument = function( node ) {
0;
};
- return doc;
+ return document;
};
Sizzle.matches = function( expr, elements ) {
@@ -1421,6 +1475,7 @@ Sizzle.matchesSelector = function( elem, expr ) {
expr = expr.replace( rattributeQuotes, "='$1']" );
if ( support.matchesSelector && documentIsHTML &&
+ !compilerCache[ expr + " " ] &&
( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
@@ -1434,7 +1489,7 @@ Sizzle.matchesSelector = function( elem, expr ) {
elem.document && elem.document.nodeType !== 11 ) {
return ret;
}
- } catch(e) {}
+ } catch (e) {}
}
return Sizzle( expr, document, null, [ elem ] ).length > 0;
@@ -1469,6 +1524,10 @@ Sizzle.attr = function( elem, name ) {
null;
};
+Sizzle.escape = function( sel ) {
+ return (sel + "").replace( rcssescape, fcssescape );
+};
+
Sizzle.error = function( msg ) {
throw new Error( "Syntax error, unrecognized expression: " + msg );
};
@@ -1653,7 +1712,7 @@ Expr = Sizzle.selectors = {
return pattern ||
(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
classCache( className, function( elem ) {
- return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
});
},
@@ -1675,7 +1734,7 @@ Expr = Sizzle.selectors = {
operator === "^=" ? check && result.indexOf( check ) === 0 :
operator === "*=" ? check && result.indexOf( check ) > -1 :
operator === "$=" ? check && result.slice( -check.length ) === check :
- operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
false;
};
@@ -1694,11 +1753,12 @@ Expr = Sizzle.selectors = {
} :
function( elem, context, xml ) {
- var cache, outerCache, node, diff, nodeIndex, start,
+ var cache, uniqueCache, outerCache, node, nodeIndex, start,
dir = simple !== forward ? "nextSibling" : "previousSibling",
parent = elem.parentNode,
name = ofType && elem.nodeName.toLowerCase(),
- useCache = !xml && !ofType;
+ useCache = !xml && !ofType,
+ diff = false;
if ( parent ) {
@@ -1707,7 +1767,10 @@ Expr = Sizzle.selectors = {
while ( dir ) {
node = elem;
while ( (node = node[ dir ]) ) {
- if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ if ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) {
+
return false;
}
}
@@ -1721,11 +1784,21 @@ Expr = Sizzle.selectors = {
// non-xml :nth-child(...) stores cache data on `parent`
if ( forward && useCache ) {
+
// Seek `elem` from a previously-cached index
- outerCache = parent[ expando ] || (parent[ expando ] = {});
- cache = outerCache[ type ] || [];
- nodeIndex = cache[0] === dirruns && cache[1];
- diff = cache[0] === dirruns && cache[2];
+
+ // ...in a gzip-friendly way
+ node = parent;
+ outerCache = node[ expando ] || (node[ expando ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ (outerCache[ node.uniqueID ] = {});
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex && cache[ 2 ];
node = nodeIndex && parent.childNodes[ nodeIndex ];
while ( (node = ++nodeIndex && node && node[ dir ] ||
@@ -1735,29 +1808,55 @@ Expr = Sizzle.selectors = {
// When found, cache indexes on `parent` and break
if ( node.nodeType === 1 && ++diff && node === elem ) {
- outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
break;
}
}
- // Use previously-cached element index if available
- } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
- diff = cache[1];
-
- // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
} else {
- // Use the same loop as above to seek `elem` from the start
- while ( (node = ++nodeIndex && node && node[ dir ] ||
- (diff = nodeIndex = 0) || start.pop()) ) {
+ // Use previously-cached element index if available
+ if ( useCache ) {
+ // ...in a gzip-friendly way
+ node = elem;
+ outerCache = node[ expando ] || (node[ expando ] = {});
- if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
- // Cache the index of each encountered element
- if ( useCache ) {
- (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
- }
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ (outerCache[ node.uniqueID ] = {});
- if ( node === elem ) {
- break;
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex;
+ }
+
+ // xml :nth-child(...)
+ // or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ if ( diff === false ) {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) &&
+ ++diff ) {
+
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ outerCache = node[ expando ] || (node[ expando ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ (outerCache[ node.uniqueID ] = {});
+
+ uniqueCache[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
}
}
}
@@ -1795,7 +1894,7 @@ Expr = Sizzle.selectors = {
matched = fn( seed, argument ),
i = matched.length;
while ( i-- ) {
- idx = indexOf.call( seed, matched[i] );
+ idx = indexOf( seed, matched[i] );
seed[ idx ] = !( matches[ idx ] = matched[i] );
}
}) :
@@ -1834,6 +1933,8 @@ Expr = Sizzle.selectors = {
function( elem, context, xml ) {
input[0] = elem;
matcher( input, null, xml, results );
+ // Don't keep the element (issue #299)
+ input[0] = null;
return !results.pop();
};
}),
@@ -1845,6 +1946,7 @@ Expr = Sizzle.selectors = {
}),
"contains": markFunction(function( text ) {
+ text = text.replace( runescape, funescape );
return function( elem ) {
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
};
@@ -1893,13 +1995,8 @@ Expr = Sizzle.selectors = {
},
// Boolean properties
- "enabled": function( elem ) {
- return elem.disabled === false;
- },
-
- "disabled": function( elem ) {
- return elem.disabled === true;
- },
+ "enabled": createDisabledPseudo( false ),
+ "disabled": createDisabledPseudo( true ),
"checked": function( elem ) {
// In CSS3, :checked should return both checked and selected elements
@@ -2101,7 +2198,9 @@ function toSelector( tokens ) {
function addCombinator( matcher, combinator, base ) {
var dir = combinator.dir,
- checkNonElements = base && dir === "parentNode",
+ skip = combinator.next,
+ key = skip || dir,
+ checkNonElements = base && key === "parentNode",
doneName = done++;
return combinator.first ?
@@ -2116,10 +2215,10 @@ function addCombinator( matcher, combinator, base ) {
// Check against all ancestor/preceding elements
function( elem, context, xml ) {
- var oldCache, outerCache,
+ var oldCache, uniqueCache, outerCache,
newCache = [ dirruns, doneName ];
- // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
if ( xml ) {
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) {
@@ -2132,14 +2231,21 @@ function addCombinator( matcher, combinator, base ) {
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) {
outerCache = elem[ expando ] || (elem[ expando ] = {});
- if ( (oldCache = outerCache[ dir ]) &&
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
+
+ if ( skip && skip === elem.nodeName.toLowerCase() ) {
+ elem = elem[ dir ] || elem;
+ } else if ( (oldCache = uniqueCache[ key ]) &&
oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
// Assign to newCache so results back-propagate to previous elements
return (newCache[ 2 ] = oldCache[ 2 ]);
} else {
// Reuse newcache so results back-propagate to previous elements
- outerCache[ dir ] = newCache;
+ uniqueCache[ key ] = newCache;
// A match means we're done; a fail means we have to keep checking
if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
@@ -2266,7 +2372,7 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS
i = matcherOut.length;
while ( i-- ) {
if ( (elem = matcherOut[i]) &&
- (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+ (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
seed[temp] = !(results[temp] = elem);
}
@@ -2301,13 +2407,16 @@ function matcherFromTokens( tokens ) {
return elem === checkContext;
}, implicitRelative, true ),
matchAnyContext = addCombinator( function( elem ) {
- return indexOf.call( checkContext, elem ) > -1;
+ return indexOf( checkContext, elem ) > -1;
}, implicitRelative, true ),
matchers = [ function( elem, context, xml ) {
- return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
(checkContext = context).nodeType ?
matchContext( elem, context, xml ) :
matchAnyContext( elem, context, xml ) );
+ // Avoid hanging onto element (issue #299)
+ checkContext = null;
+ return ret;
} ];
for ( ; i < len; i++ ) {
@@ -2361,18 +2470,21 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
len = elems.length;
if ( outermost ) {
- outermostContext = context !== document && context;
+ outermostContext = context === document || context || outermost;
}
// Add elements passing elementMatchers directly to results
- // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
// Support: IE<9, Safari
// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
if ( byElement && elem ) {
j = 0;
+ if ( !context && elem.ownerDocument !== document ) {
+ setDocument( elem );
+ xml = !documentIsHTML;
+ }
while ( (matcher = elementMatchers[j++]) ) {
- if ( matcher( elem, context, xml ) ) {
+ if ( matcher( elem, context || document, xml) ) {
results.push( elem );
break;
}
@@ -2396,8 +2508,17 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
}
}
- // Apply set filters to unmatched elements
+ // `i` is now the count of elements visited above, and adding it to `matchedCount`
+ // makes the latter nonnegative.
matchedCount += i;
+
+ // Apply set filters to unmatched elements
+ // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
+ // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
+ // no element matchers and no seed.
+ // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
+ // case, which will result in a "00" `matchedCount` that differs from `i` but is also
+ // numerically zero.
if ( bySet && i !== matchedCount ) {
j = 0;
while ( (matcher = setMatchers[j++]) ) {
@@ -2489,10 +2610,11 @@ select = Sizzle.select = function( selector, context, results, seed ) {
results = results || [];
- // Try to minimize operations if there is no seed and only one group
+ // Try to minimize operations if there is only one selector in the list and no seed
+ // (the latter of which guarantees us context)
if ( match.length === 1 ) {
- // Take a shortcut and set the context if the root selector is an ID
+ // Reduce context if the leading compound selector is an ID
tokens = match[0] = match[0].slice( 0 );
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
support.getById && context.nodeType === 9 && documentIsHTML &&
@@ -2547,7 +2669,7 @@ select = Sizzle.select = function( selector, context, results, seed ) {
context,
!documentIsHTML,
results,
- rsibling.test( selector ) && testContext( context.parentNode ) || context
+ !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
);
return results;
};
@@ -2557,7 +2679,7 @@ select = Sizzle.select = function( selector, context, results, seed ) {
// Sort stability
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
-// Support: Chrome<14
+// Support: Chrome 14-35+
// Always assume duplicates if they aren't passed to the comparison function
support.detectDuplicates = !!hasDuplicate;
@@ -2566,17 +2688,17 @@ setDocument();
// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
// Detached nodes confoundingly follow *each other*
-support.sortDetached = assert(function( div1 ) {
+support.sortDetached = assert(function( el ) {
// Should return 1, but returns 4 (following)
- return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+ return el.compareDocumentPosition( document.createElement("fieldset") ) & 1;
});
// Support: IE<8
// Prevent attribute/property "interpolation"
-// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
-if ( !assert(function( div ) {
- div.innerHTML = "<a href='#'></a>";
- return div.firstChild.getAttribute("href") === "#" ;
+// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( el ) {
+ el.innerHTML = "<a href='#'></a>";
+ return el.firstChild.getAttribute("href") === "#" ;
}) ) {
addHandle( "type|href|height|width", function( elem, name, isXML ) {
if ( !isXML ) {
@@ -2587,10 +2709,10 @@ if ( !assert(function( div ) {
// Support: IE<9
// Use defaultValue in place of getAttribute("value")
-if ( !support.attributes || !assert(function( div ) {
- div.innerHTML = "<input/>";
- div.firstChild.setAttribute( "value", "" );
- return div.firstChild.getAttribute( "value" ) === "";
+if ( !support.attributes || !assert(function( el ) {
+ el.innerHTML = "<input/>";
+ el.firstChild.setAttribute( "value", "" );
+ return el.firstChild.getAttribute( "value" ) === "";
}) ) {
addHandle( "value", function( elem, name, isXML ) {
if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
@@ -2601,8 +2723,8 @@ if ( !support.attributes || !assert(function( div ) {
// Support: IE<9
// Use getAttributeNode to fetch booleans when getAttribute lies
-if ( !assert(function( div ) {
- return div.getAttribute("disabled") == null;
+if ( !assert(function( el ) {
+ return el.getAttribute("disabled") == null;
}) ) {
addHandle( booleans, function( elem, name, isXML ) {
var val;
@@ -2623,17 +2745,50 @@ return Sizzle;
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.pseudos;
-jQuery.unique = Sizzle.uniqueSort;
+
+// Deprecated
+jQuery.expr[ ":" ] = jQuery.expr.pseudos;
+jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;
+jQuery.escapeSelector = Sizzle.escape;
+
+
+var dir = function( elem, dir, until ) {
+ var matched = [],
+ truncate = until !== undefined;
+
+ while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
+ if ( elem.nodeType === 1 ) {
+ if ( truncate && jQuery( elem ).is( until ) ) {
+ break;
+ }
+ matched.push( elem );
+ }
+ }
+ return matched;
+};
+
+
+var siblings = function( n, elem ) {
+ var matched = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ matched.push( n );
+ }
+ }
+
+ return matched;
+};
+
var rneedsContext = jQuery.expr.match.needsContext;
-var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
@@ -2643,16 +2798,15 @@ var risSimple = /^.[^:#\[\.,]*$/;
function winnow( elements, qualifier, not ) {
if ( jQuery.isFunction( qualifier ) ) {
return jQuery.grep( elements, function( elem, i ) {
- /* jshint -W018 */
return !!qualifier.call( elem, i, elem ) !== not;
- });
+ } );
}
if ( qualifier.nodeType ) {
return jQuery.grep( elements, function( elem ) {
return ( elem === qualifier ) !== not;
- });
+ } );
}
@@ -2665,8 +2819,8 @@ function winnow( elements, qualifier, not ) {
}
return jQuery.grep( elements, function( elem ) {
- return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
- });
+ return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1;
+ } );
}
jQuery.filter = function( expr, elems, not ) {
@@ -2680,40 +2834,38 @@ jQuery.filter = function( expr, elems, not ) {
jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
return elem.nodeType === 1;
- }));
+ } ) );
};
-jQuery.fn.extend({
+jQuery.fn.extend( {
find: function( selector ) {
- var i,
- ret = [],
- self = this,
- len = self.length;
+ var i, ret,
+ len = this.length,
+ self = this;
if ( typeof selector !== "string" ) {
- return this.pushStack( jQuery( selector ).filter(function() {
+ return this.pushStack( jQuery( selector ).filter( function() {
for ( i = 0; i < len; i++ ) {
if ( jQuery.contains( self[ i ], this ) ) {
return true;
}
}
- }) );
+ } ) );
}
+ ret = this.pushStack( [] );
+
for ( i = 0; i < len; i++ ) {
jQuery.find( selector, self[ i ], ret );
}
- // Needed because $( selector, context ) becomes $( context ).find( selector )
- ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
- ret.selector = this.selector ? this.selector + " " + selector : selector;
- return ret;
+ return len > 1 ? jQuery.uniqueSort( ret ) : ret;
},
filter: function( selector ) {
- return this.pushStack( winnow(this, selector || [], false) );
+ return this.pushStack( winnow( this, selector || [], false ) );
},
not: function( selector ) {
- return this.pushStack( winnow(this, selector || [], true) );
+ return this.pushStack( winnow( this, selector || [], true ) );
},
is: function( selector ) {
return !!winnow(
@@ -2727,7 +2879,7 @@ jQuery.fn.extend({
false
).length;
}
-});
+} );
// Initialize a jQuery object
@@ -2736,15 +2888,13 @@ jQuery.fn.extend({
// A central reference to the root jQuery(document)
var rootjQuery,
- // Use the correct document accordingly with window argument (sandbox)
- document = window.document,
-
// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
- rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+ // Shortcut simple #id case for speed
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
- init = jQuery.fn.init = function( selector, context ) {
+ init = jQuery.fn.init = function( selector, context, root ) {
var match, elem;
// HANDLE: $(""), $(null), $(undefined), $(false)
@@ -2752,9 +2902,16 @@ var rootjQuery,
return this;
}
+ // Method init() accepts an alternate rootjQuery
+ // so migrate can support jQuery.sub (gh-2101)
+ root = root || rootjQuery;
+
// Handle HTML strings
if ( typeof selector === "string" ) {
- if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ if ( selector[ 0 ] === "<" &&
+ selector[ selector.length - 1 ] === ">" &&
+ selector.length >= 3 ) {
+
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
@@ -2763,23 +2920,24 @@ var rootjQuery,
}
// Match html or make sure no context is specified for #id
- if ( match && (match[1] || !context) ) {
+ if ( match && ( match[ 1 ] || !context ) ) {
// HANDLE: $(html) -> $(array)
- if ( match[1] ) {
- context = context instanceof jQuery ? context[0] : context;
+ if ( match[ 1 ] ) {
+ context = context instanceof jQuery ? context[ 0 ] : context;
- // scripts is true for back-compat
+ // Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge( this, jQuery.parseHTML(
- match[1],
+ match[ 1 ],
context && context.nodeType ? context.ownerDocument || context : document,
true
) );
// HANDLE: $(html, props)
- if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
for ( match in context ) {
+
// Properties of context are called as methods if possible
if ( jQuery.isFunction( this[ match ] ) ) {
this[ match ]( context[ match ] );
@@ -2795,30 +2953,20 @@ var rootjQuery,
// HANDLE: $(#id)
} else {
- elem = document.getElementById( match[2] );
-
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if ( elem.id !== match[2] ) {
- return rootjQuery.find( selector );
- }
+ elem = document.getElementById( match[ 2 ] );
+
+ if ( elem ) {
- // Otherwise, we inject the element directly into the jQuery object
+ // Inject the element directly into the jQuery object
+ this[ 0 ] = elem;
this.length = 1;
- this[0] = elem;
}
-
- this.context = document;
- this.selector = selector;
return this;
}
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
- return ( context || rootjQuery ).find( selector );
+ return ( context || root ).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
@@ -2828,24 +2976,20 @@ var rootjQuery,
// HANDLE: $(DOMElement)
} else if ( selector.nodeType ) {
- this.context = this[0] = selector;
+ this[ 0 ] = selector;
this.length = 1;
return this;
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
- return typeof rootjQuery.ready !== "undefined" ?
- rootjQuery.ready( selector ) :
+ return root.ready !== undefined ?
+ root.ready( selector ) :
+
// Execute immediately if ready is not present
selector( jQuery );
}
- if ( selector.selector !== undefined ) {
- this.selector = selector.selector;
- this.context = selector.context;
- }
-
return jQuery.makeArray( selector, this );
};
@@ -2857,7 +3001,8 @@ rootjQuery = jQuery( document );
var rparentsprev = /^(?:parents|prev(?:Until|All))/,
- // methods guaranteed to produce a unique set when starting from a unique set
+
+ // Methods guaranteed to produce a unique set when starting from a unique set
guaranteedUnique = {
children: true,
contents: true,
@@ -2865,46 +3010,19 @@ var rparentsprev = /^(?:parents|prev(?:Until|All))/,
prev: true
};
-jQuery.extend({
- dir: function( elem, dir, until ) {
- var matched = [],
- cur = elem[ dir ];
-
- while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
- if ( cur.nodeType === 1 ) {
- matched.push( cur );
- }
- cur = cur[dir];
- }
- return matched;
- },
-
- sibling: function( n, elem ) {
- var r = [];
-
- for ( ; n; n = n.nextSibling ) {
- if ( n.nodeType === 1 && n !== elem ) {
- r.push( n );
- }
- }
-
- return r;
- }
-});
-
-jQuery.fn.extend({
+jQuery.fn.extend( {
has: function( target ) {
- var i,
- targets = jQuery( target, this ),
- len = targets.length;
+ var targets = jQuery( target, this ),
+ l = targets.length;
- return this.filter(function() {
- for ( i = 0; i < len; i++ ) {
- if ( jQuery.contains( this, targets[i] ) ) {
+ return this.filter( function() {
+ var i = 0;
+ for ( ; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[ i ] ) ) {
return true;
}
}
- });
+ } );
},
closest: function( selectors, context ) {
@@ -2912,52 +3030,55 @@ jQuery.fn.extend({
i = 0,
l = this.length,
matched = [],
- pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
- jQuery( selectors, context || this.context ) :
- 0;
+ targets = typeof selectors !== "string" && jQuery( selectors );
- for ( ; i < l; i++ ) {
- for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
- // Always skip document fragments
- if ( cur.nodeType < 11 && (pos ?
- pos.index(cur) > -1 :
+ // Positional selectors never match, since there's no _selection_ context
+ if ( !rneedsContext.test( selectors ) ) {
+ for ( ; i < l; i++ ) {
+ for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
- // Don't pass non-elements to Sizzle
- cur.nodeType === 1 &&
- jQuery.find.matchesSelector(cur, selectors)) ) {
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && ( targets ?
+ targets.index( cur ) > -1 :
- matched.push( cur );
- break;
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector( cur, selectors ) ) ) {
+
+ matched.push( cur );
+ break;
+ }
}
}
}
- return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+ return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
},
- // Determine the position of an element within
- // the matched set of elements
+ // Determine the position of an element within the set
index: function( elem ) {
// No argument, return index in parent
if ( !elem ) {
- return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+ return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
- // index in selector
+ // Index in selector
if ( typeof elem === "string" ) {
- return jQuery.inArray( this[0], jQuery( elem ) );
+ return indexOf.call( jQuery( elem ), this[ 0 ] );
}
// Locate the position of the desired element
- return jQuery.inArray(
+ return indexOf.call( this,
+
// If it receives a jQuery object, the first element is used
- elem.jquery ? elem[0] : elem, this );
+ elem.jquery ? elem[ 0 ] : elem
+ );
},
add: function( selector, context ) {
return this.pushStack(
- jQuery.unique(
+ jQuery.uniqueSort(
jQuery.merge( this.get(), jQuery( selector, context ) )
)
);
@@ -2965,29 +3086,26 @@ jQuery.fn.extend({
addBack: function( selector ) {
return this.add( selector == null ?
- this.prevObject : this.prevObject.filter(selector)
+ this.prevObject : this.prevObject.filter( selector )
);
}
-});
+} );
function sibling( cur, dir ) {
- do {
- cur = cur[ dir ];
- } while ( cur && cur.nodeType !== 1 );
-
+ while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
return cur;
}
-jQuery.each({
+jQuery.each( {
parent: function( elem ) {
var parent = elem.parentNode;
return parent && parent.nodeType !== 11 ? parent : null;
},
parents: function( elem ) {
- return jQuery.dir( elem, "parentNode" );
+ return dir( elem, "parentNode" );
},
parentsUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "parentNode", until );
+ return dir( elem, "parentNode", until );
},
next: function( elem ) {
return sibling( elem, "nextSibling" );
@@ -2996,68 +3114,64 @@ jQuery.each({
return sibling( elem, "previousSibling" );
},
nextAll: function( elem ) {
- return jQuery.dir( elem, "nextSibling" );
+ return dir( elem, "nextSibling" );
},
prevAll: function( elem ) {
- return jQuery.dir( elem, "previousSibling" );
+ return dir( elem, "previousSibling" );
},
nextUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "nextSibling", until );
+ return dir( elem, "nextSibling", until );
},
prevUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "previousSibling", until );
+ return dir( elem, "previousSibling", until );
},
siblings: function( elem ) {
- return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ return siblings( ( elem.parentNode || {} ).firstChild, elem );
},
children: function( elem ) {
- return jQuery.sibling( elem.firstChild );
+ return siblings( elem.firstChild );
},
contents: function( elem ) {
- return jQuery.nodeName( elem, "iframe" ) ?
- elem.contentDocument || elem.contentWindow.document :
- jQuery.merge( [], elem.childNodes );
+ return elem.contentDocument || jQuery.merge( [], elem.childNodes );
}
}, function( name, fn ) {
jQuery.fn[ name ] = function( until, selector ) {
- var ret = jQuery.map( this, fn, until );
+ var matched = jQuery.map( this, fn, until );
if ( name.slice( -5 ) !== "Until" ) {
selector = until;
}
if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
+ matched = jQuery.filter( selector, matched );
}
if ( this.length > 1 ) {
+
// Remove duplicates
if ( !guaranteedUnique[ name ] ) {
- ret = jQuery.unique( ret );
+ jQuery.uniqueSort( matched );
}
// Reverse order for parents* and prev-derivatives
if ( rparentsprev.test( name ) ) {
- ret = ret.reverse();
+ matched.reverse();
}
}
- return this.pushStack( ret );
+ return this.pushStack( matched );
};
-});
-var rnotwhite = (/\S+/g);
-
+} );
+var rnotwhite = ( /\S+/g );
-// String to Object options format cache
-var optionsCache = {};
-// Convert String-formatted options into Object-formatted ones and store in cache
+// Convert String-formatted options into Object-formatted ones
function createOptions( options ) {
- var object = optionsCache[ options ] = {};
+ var object = {};
jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
object[ flag ] = true;
- });
+ } );
return object;
}
@@ -3088,156 +3202,186 @@ jQuery.Callbacks = function( options ) {
// Convert options from String-formatted to Object-formatted if needed
// (we check in cache first)
options = typeof options === "string" ?
- ( optionsCache[ options ] || createOptions( options ) ) :
+ createOptions( options ) :
jQuery.extend( {}, options );
var // Flag to know if list is currently firing
firing,
- // Last fire value (for non-forgettable lists)
+
+ // Last fire value for non-forgettable lists
memory,
+
// Flag to know if list was already fired
fired,
- // End of the loop when firing
- firingLength,
- // Index of currently firing callback (modified by remove if needed)
- firingIndex,
- // First callback to fire (used internally by add and fireWith)
- firingStart,
+
+ // Flag to prevent firing
+ locked,
+
// Actual callback list
list = [],
- // Stack of fire calls for repeatable lists
- stack = !options.once && [],
+
+ // Queue of execution data for repeatable lists
+ queue = [],
+
+ // Index of currently firing callback (modified by add/remove as needed)
+ firingIndex = -1,
+
// Fire callbacks
- fire = function( data ) {
- memory = options.memory && data;
- fired = true;
- firingIndex = firingStart || 0;
- firingStart = 0;
- firingLength = list.length;
- firing = true;
- for ( ; list && firingIndex < firingLength; firingIndex++ ) {
- if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
- memory = false; // To prevent further calls using add
- break;
+ fire = function() {
+
+ // Enforce single-firing
+ locked = options.once;
+
+ // Execute callbacks for all pending executions,
+ // respecting firingIndex overrides and runtime changes
+ fired = firing = true;
+ for ( ; queue.length; firingIndex = -1 ) {
+ memory = queue.shift();
+ while ( ++firingIndex < list.length ) {
+
+ // Run callback and check for early termination
+ if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
+ options.stopOnFalse ) {
+
+ // Jump to end and forget the data so .add doesn't re-fire
+ firingIndex = list.length;
+ memory = false;
+ }
}
}
+
+ // Forget the data if we're done with it
+ if ( !options.memory ) {
+ memory = false;
+ }
+
firing = false;
- if ( list ) {
- if ( stack ) {
- if ( stack.length ) {
- fire( stack.shift() );
- }
- } else if ( memory ) {
+
+ // Clean up if we're done firing for good
+ if ( locked ) {
+
+ // Keep an empty list if we have data for future add calls
+ if ( memory ) {
list = [];
+
+ // Otherwise, this object is spent
} else {
- self.disable();
+ list = "";
}
}
},
+
// Actual Callbacks object
self = {
+
// Add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
- // First, we save the current length
- var start = list.length;
- (function add( args ) {
+
+ // If we have memory from a past run, we should fire after adding
+ if ( memory && !firing ) {
+ firingIndex = list.length - 1;
+ queue.push( memory );
+ }
+
+ ( function add( args ) {
jQuery.each( args, function( _, arg ) {
- var type = jQuery.type( arg );
- if ( type === "function" ) {
+ if ( jQuery.isFunction( arg ) ) {
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
- } else if ( arg && arg.length && type !== "string" ) {
+ } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
+
// Inspect recursively
add( arg );
}
- });
- })( arguments );
- // Do we need to add the callbacks to the
- // current firing batch?
- if ( firing ) {
- firingLength = list.length;
- // With memory, if we're not firing then
- // we should call right away
- } else if ( memory ) {
- firingStart = start;
- fire( memory );
+ } );
+ } )( arguments );
+
+ if ( memory && !firing ) {
+ fire();
}
}
return this;
},
+
// Remove a callback from the list
remove: function() {
- if ( list ) {
- jQuery.each( arguments, function( _, arg ) {
- var index;
- while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
- list.splice( index, 1 );
- // Handle firing indexes
- if ( firing ) {
- if ( index <= firingLength ) {
- firingLength--;
- }
- if ( index <= firingIndex ) {
- firingIndex--;
- }
- }
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+
+ // Handle firing indexes
+ if ( index <= firingIndex ) {
+ firingIndex--;
}
- });
- }
+ }
+ } );
return this;
},
+
// Check if a given callback is in the list.
// If no argument is given, return whether or not list has callbacks attached.
has: function( fn ) {
- return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ return fn ?
+ jQuery.inArray( fn, list ) > -1 :
+ list.length > 0;
},
+
// Remove all callbacks from the list
empty: function() {
- list = [];
- firingLength = 0;
+ if ( list ) {
+ list = [];
+ }
return this;
},
- // Have the list do nothing anymore
+
+ // Disable .fire and .add
+ // Abort any current/pending executions
+ // Clear all callbacks and values
disable: function() {
- list = stack = memory = undefined;
+ locked = queue = [];
+ list = memory = "";
return this;
},
- // Is it disabled?
disabled: function() {
return !list;
},
- // Lock the list in its current state
+
+ // Disable .fire
+ // Also disable .add unless we have memory (since it would have no effect)
+ // Abort any pending executions
lock: function() {
- stack = undefined;
- if ( !memory ) {
- self.disable();
+ locked = queue = [];
+ if ( !memory && !firing ) {
+ list = memory = "";
}
return this;
},
- // Is it locked?
locked: function() {
- return !stack;
+ return !!locked;
},
+
// Call all callbacks with the given context and arguments
fireWith: function( context, args ) {
- if ( list && ( !fired || stack ) ) {
+ if ( !locked ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
- if ( firing ) {
- stack.push( args );
- } else {
- fire( args );
+ queue.push( args );
+ if ( !firing ) {
+ fire();
}
}
return this;
},
+
// Call all the callbacks with the given arguments
fire: function() {
self.fireWith( this, arguments );
return this;
},
+
// To know if the callbacks have already been called at least once
fired: function() {
return !!fired;
@@ -3248,14 +3392,58 @@ jQuery.Callbacks = function( options ) {
};
-jQuery.extend({
+function Identity( v ) {
+ return v;
+}
+function Thrower( ex ) {
+ throw ex;
+}
+
+function adoptValue( value, resolve, reject ) {
+ var method;
+
+ try {
+
+ // Check for promise aspect first to privilege synchronous behavior
+ if ( value && jQuery.isFunction( ( method = value.promise ) ) ) {
+ method.call( value ).done( resolve ).fail( reject );
+
+ // Other thenables
+ } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {
+ method.call( value, resolve, reject );
+
+ // Other non-thenables
+ } else {
+
+ // Support: Android 4.0 only
+ // Strict mode functions invoked without .call/.apply get global-object context
+ resolve.call( undefined, value );
+ }
+
+ // For Promises/A+, convert exceptions into rejections
+ // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
+ // Deferred#then to conditionally suppress rejection.
+ } catch ( value ) {
+
+ // Support: Android 4.0 only
+ // Strict mode functions invoked without .call/.apply get global-object context
+ reject.call( undefined, value );
+ }
+}
+
+jQuery.extend( {
Deferred: function( func ) {
var tuples = [
- // action, add listener, listener list, final state
- [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
- [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
- [ "notify", "progress", jQuery.Callbacks("memory") ]
+
+ // action, add listener, callbacks,
+ // ... .then handlers, argument index, [final state]
+ [ "notify", "progress", jQuery.Callbacks( "memory" ),
+ jQuery.Callbacks( "memory" ), 2 ],
+ [ "resolve", "done", jQuery.Callbacks( "once memory" ),
+ jQuery.Callbacks( "once memory" ), 0, "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks( "once memory" ),
+ jQuery.Callbacks( "once memory" ), 1, "rejected" ]
],
state = "pending",
promise = {
@@ -3266,27 +3454,206 @@ jQuery.extend({
deferred.done( arguments ).fail( arguments );
return this;
},
- then: function( /* fnDone, fnFail, fnProgress */ ) {
+ "catch": function( fn ) {
+ return promise.then( null, fn );
+ },
+
+ // Keep pipe for back-compat
+ pipe: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
- return jQuery.Deferred(function( newDefer ) {
+
+ return jQuery.Deferred( function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
- var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
- // deferred[ done | fail | progress ] for forwarding actions to newDefer
- deferred[ tuple[1] ](function() {
+
+ // Map tuples (progress, done, fail) to arguments (done, fail, progress)
+ var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
+
+ // deferred.progress(function() { bind to newDefer or newDefer.notify })
+ // deferred.done(function() { bind to newDefer or newDefer.resolve })
+ // deferred.fail(function() { bind to newDefer or newDefer.reject })
+ deferred[ tuple[ 1 ] ]( function() {
var returned = fn && fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
+ .progress( newDefer.notify )
.done( newDefer.resolve )
- .fail( newDefer.reject )
- .progress( newDefer.notify );
+ .fail( newDefer.reject );
} else {
- newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ newDefer[ tuple[ 0 ] + "With" ](
+ this,
+ fn ? [ returned ] : arguments
+ );
}
- });
- });
+ } );
+ } );
fns = null;
- }).promise();
+ } ).promise();
},
+ then: function( onFulfilled, onRejected, onProgress ) {
+ var maxDepth = 0;
+ function resolve( depth, deferred, handler, special ) {
+ return function() {
+ var that = this,
+ args = arguments,
+ mightThrow = function() {
+ var returned, then;
+
+ // Support: Promises/A+ section 2.3.3.3.3
+ // https://promisesaplus.com/#point-59
+ // Ignore double-resolution attempts
+ if ( depth < maxDepth ) {
+ return;
+ }
+
+ returned = handler.apply( that, args );
+
+ // Support: Promises/A+ section 2.3.1
+ // https://promisesaplus.com/#point-48
+ if ( returned === deferred.promise() ) {
+ throw new TypeError( "Thenable self-resolution" );
+ }
+
+ // Support: Promises/A+ sections 2.3.3.1, 3.5
+ // https://promisesaplus.com/#point-54
+ // https://promisesaplus.com/#point-75
+ // Retrieve `then` only once
+ then = returned &&
+
+ // Support: Promises/A+ section 2.3.4
+ // https://promisesaplus.com/#point-64
+ // Only check objects and functions for thenability
+ ( typeof returned === "object" ||
+ typeof returned === "function" ) &&
+ returned.then;
+
+ // Handle a returned thenable
+ if ( jQuery.isFunction( then ) ) {
+
+ // Special processors (notify) just wait for resolution
+ if ( special ) {
+ then.call(
+ returned,
+ resolve( maxDepth, deferred, Identity, special ),
+ resolve( maxDepth, deferred, Thrower, special )
+ );
+
+ // Normal processors (resolve) also hook into progress
+ } else {
+
+ // ...and disregard older resolution values
+ maxDepth++;
+
+ then.call(
+ returned,
+ resolve( maxDepth, deferred, Identity, special ),
+ resolve( maxDepth, deferred, Thrower, special ),
+ resolve( maxDepth, deferred, Identity,
+ deferred.notifyWith )
+ );
+ }
+
+ // Handle all other returned values
+ } else {
+
+ // Only substitute handlers pass on context
+ // and multiple values (non-spec behavior)
+ if ( handler !== Identity ) {
+ that = undefined;
+ args = [ returned ];
+ }
+
+ // Process the value(s)
+ // Default process is resolve
+ ( special || deferred.resolveWith )( that, args );
+ }
+ },
+
+ // Only normal processors (resolve) catch and reject exceptions
+ process = special ?
+ mightThrow :
+ function() {
+ try {
+ mightThrow();
+ } catch ( e ) {
+
+ if ( jQuery.Deferred.exceptionHook ) {
+ jQuery.Deferred.exceptionHook( e,
+ process.stackTrace );
+ }
+
+ // Support: Promises/A+ section 2.3.3.3.4.1
+ // https://promisesaplus.com/#point-61
+ // Ignore post-resolution exceptions
+ if ( depth + 1 >= maxDepth ) {
+
+ // Only substitute handlers pass on context
+ // and multiple values (non-spec behavior)
+ if ( handler !== Thrower ) {
+ that = undefined;
+ args = [ e ];
+ }
+
+ deferred.rejectWith( that, args );
+ }
+ }
+ };
+
+ // Support: Promises/A+ section 2.3.3.3.1
+ // https://promisesaplus.com/#point-57
+ // Re-resolve promises immediately to dodge false rejection from
+ // subsequent errors
+ if ( depth ) {
+ process();
+ } else {
+
+ // Call an optional hook to record the stack, in case of exception
+ // since it's otherwise lost when execution goes async
+ if ( jQuery.Deferred.getStackHook ) {
+ process.stackTrace = jQuery.Deferred.getStackHook();
+ }
+ window.setTimeout( process );
+ }
+ };
+ }
+
+ return jQuery.Deferred( function( newDefer ) {
+
+ // progress_handlers.add( ... )
+ tuples[ 0 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ jQuery.isFunction( onProgress ) ?
+ onProgress :
+ Identity,
+ newDefer.notifyWith
+ )
+ );
+
+ // fulfilled_handlers.add( ... )
+ tuples[ 1 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ jQuery.isFunction( onFulfilled ) ?
+ onFulfilled :
+ Identity
+ )
+ );
+
+ // rejected_handlers.add( ... )
+ tuples[ 2 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ jQuery.isFunction( onRejected ) ?
+ onRejected :
+ Thrower
+ )
+ );
+ } ).promise();
+ },
+
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
@@ -3295,34 +3662,53 @@ jQuery.extend({
},
deferred = {};
- // Keep pipe for back-compat
- promise.pipe = promise.then;
-
// Add list-specific methods
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ],
- stateString = tuple[ 3 ];
+ stateString = tuple[ 5 ];
- // promise[ done | fail | progress ] = list.add
- promise[ tuple[1] ] = list.add;
+ // promise.progress = list.add
+ // promise.done = list.add
+ // promise.fail = list.add
+ promise[ tuple[ 1 ] ] = list.add;
// Handle state
if ( stateString ) {
- list.add(function() {
- // state = [ resolved | rejected ]
- state = stateString;
+ list.add(
+ function() {
+
+ // state = "resolved" (i.e., fulfilled)
+ // state = "rejected"
+ state = stateString;
+ },
- // [ reject_list | resolve_list ].disable; progress_list.lock
- }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ // rejected_callbacks.disable
+ // fulfilled_callbacks.disable
+ tuples[ 3 - i ][ 2 ].disable,
+
+ // progress_callbacks.lock
+ tuples[ 0 ][ 2 ].lock
+ );
}
- // deferred[ resolve | reject | notify ]
- deferred[ tuple[0] ] = function() {
- deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ // progress_handlers.fire
+ // fulfilled_handlers.fire
+ // rejected_handlers.fire
+ list.add( tuple[ 3 ].fire );
+
+ // deferred.notify = function() { deferred.notifyWith(...) }
+ // deferred.resolve = function() { deferred.resolveWith(...) }
+ // deferred.reject = function() { deferred.rejectWith(...) }
+ deferred[ tuple[ 0 ] ] = function() {
+ deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
return this;
};
- deferred[ tuple[0] + "With" ] = list.fireWith;
- });
+
+ // deferred.notifyWith = list.fireWith
+ // deferred.resolveWith = list.fireWith
+ // deferred.rejectWith = list.fireWith
+ deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
+ } );
// Make the deferred a promise
promise.promise( deferred );
@@ -3337,71 +3723,100 @@ jQuery.extend({
},
// Deferred helper
- when: function( subordinate /* , ..., subordinateN */ ) {
- var i = 0,
- resolveValues = slice.call( arguments ),
- length = resolveValues.length,
+ when: function( singleValue ) {
+ var
- // the count of uncompleted subordinates
- remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+ // count of uncompleted subordinates
+ remaining = arguments.length,
- // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
- deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+ // count of unprocessed arguments
+ i = remaining,
- // Update function for both resolve and progress values
- updateFunc = function( i, contexts, values ) {
- return function( value ) {
- contexts[ i ] = this;
- values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
- if ( values === progressValues ) {
- deferred.notifyWith( contexts, values );
+ // subordinate fulfillment data
+ resolveContexts = Array( i ),
+ resolveValues = slice.call( arguments ),
- } else if ( !(--remaining) ) {
- deferred.resolveWith( contexts, values );
+ // the master Deferred
+ master = jQuery.Deferred(),
+
+ // subordinate callback factory
+ updateFunc = function( i ) {
+ return function( value ) {
+ resolveContexts[ i ] = this;
+ resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( !( --remaining ) ) {
+ master.resolveWith( resolveContexts, resolveValues );
}
};
- },
+ };
- progressValues, progressContexts, resolveContexts;
+ // Single- and empty arguments are adopted like Promise.resolve
+ if ( remaining <= 1 ) {
+ adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject );
- // add listeners to Deferred subordinates; treat others as resolved
- if ( length > 1 ) {
- progressValues = new Array( length );
- progressContexts = new Array( length );
- resolveContexts = new Array( length );
- for ( ; i < length; i++ ) {
- if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
- resolveValues[ i ].promise()
- .done( updateFunc( i, resolveContexts, resolveValues ) )
- .fail( deferred.reject )
- .progress( updateFunc( i, progressContexts, progressValues ) );
- } else {
- --remaining;
- }
+ // Use .then() to unwrap secondary thenables (cf. gh-3000)
+ if ( master.state() === "pending" ||
+ jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
+
+ return master.then();
}
}
- // if we're not waiting on anything, resolve the master
- if ( !remaining ) {
- deferred.resolveWith( resolveContexts, resolveValues );
+ // Multiple arguments are aggregated like Promise.all array elements
+ while ( i-- ) {
+ adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
}
- return deferred.promise();
+ return master.promise();
}
-});
+} );
+
+
+// These usually indicate a programmer mistake during development,
+// warn about them ASAP rather than swallowing them by default.
+var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
+
+jQuery.Deferred.exceptionHook = function( error, stack ) {
+
+ // Support: IE 8 - 9 only
+ // Console exists when dev tools are open, which can happen at any time
+ if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
+ window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
+ }
+};
+
+
+
+
+jQuery.readyException = function( error ) {
+ window.setTimeout( function() {
+ throw error;
+ } );
+};
+
+
// The deferred used on DOM ready
-var readyList;
+var readyList = jQuery.Deferred();
jQuery.fn.ready = function( fn ) {
- // Add the callback
- jQuery.ready.promise().done( fn );
+
+ readyList
+ .then( fn )
+
+ // Wrap jQuery.readyException in a function so that the lookup
+ // happens at the time of error handling instead of callback
+ // registration.
+ .catch( function( error ) {
+ jQuery.readyException( error );
+ } );
return this;
};
-jQuery.extend({
+jQuery.extend( {
+
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
@@ -3426,11 +3841,6 @@ jQuery.extend({
return;
}
- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
- if ( !document.body ) {
- return setTimeout( jQuery.ready );
- }
-
// Remember that the DOM is ready
jQuery.isReady = true;
@@ -3441,486 +3851,360 @@ jQuery.extend({
// If there are functions bound, to execute
readyList.resolveWith( document, [ jQuery ] );
-
- // Trigger any bound ready events
- if ( jQuery.fn.triggerHandler ) {
- jQuery( document ).triggerHandler( "ready" );
- jQuery( document ).off( "ready" );
- }
}
-});
+} );
-/**
- * Clean-up method for dom ready events
- */
-function detach() {
- if ( document.addEventListener ) {
- document.removeEventListener( "DOMContentLoaded", completed, false );
- window.removeEventListener( "load", completed, false );
-
- } else {
- document.detachEvent( "onreadystatechange", completed );
- window.detachEvent( "onload", completed );
- }
-}
+jQuery.ready.then = readyList.then;
-/**
- * The ready event handler and self cleanup method
- */
+// The ready event handler and self cleanup method
function completed() {
- // readyState === "complete" is good enough for us to call the dom ready in oldIE
- if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
- detach();
- jQuery.ready();
- }
+ document.removeEventListener( "DOMContentLoaded", completed );
+ window.removeEventListener( "load", completed );
+ jQuery.ready();
}
-jQuery.ready.promise = function( obj ) {
- if ( !readyList ) {
-
- readyList = jQuery.Deferred();
+// Catch cases where $(document).ready() is called
+// after the browser event has already occurred.
+// Support: IE <=9 - 10 only
+// Older IE sometimes signals "interactive" too soon
+if ( document.readyState === "complete" ||
+ ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
- // Catch cases where $(document).ready() is called after the browser event has already occurred.
- // we once tried to use readyState "interactive" here, but it caused issues like the one
- // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
- if ( document.readyState === "complete" ) {
- // Handle it asynchronously to allow scripts the opportunity to delay ready
- setTimeout( jQuery.ready );
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ window.setTimeout( jQuery.ready );
- // Standards-based browsers support DOMContentLoaded
- } else if ( document.addEventListener ) {
- // Use the handy event callback
- document.addEventListener( "DOMContentLoaded", completed, false );
+} else {
- // A fallback to window.onload, that will always work
- window.addEventListener( "load", completed, false );
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed );
- // If IE event model is used
- } else {
- // Ensure firing before onload, maybe late but safe also for iframes
- document.attachEvent( "onreadystatechange", completed );
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed );
+}
- // A fallback to window.onload, that will always work
- window.attachEvent( "onload", completed );
- // If IE and not a frame
- // continually check to see if the document is ready
- var top = false;
- try {
- top = window.frameElement == null && document.documentElement;
- } catch(e) {}
- if ( top && top.doScroll ) {
- (function doScrollCheck() {
- if ( !jQuery.isReady ) {
-
- try {
- // Use the trick by Diego Perini
- // http://javascript.nwbox.com/IEContentLoaded/
- top.doScroll("left");
- } catch(e) {
- return setTimeout( doScrollCheck, 50 );
- }
-
- // detach all dom ready events
- detach();
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ len = elems.length,
+ bulk = key == null;
- // and execute any waiting functions
- jQuery.ready();
- }
- })();
- }
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ access( elems, fn, i, key[ i ], true, emptyGet, raw );
}
- }
- return readyList.promise( obj );
-};
-
-
-var strundefined = typeof undefined;
-
-
-
-// Support: IE<9
-// Iteration over object's inherited properties before its own
-var i;
-for ( i in jQuery( support ) ) {
- break;
-}
-support.ownLast = i !== "0";
-// Note: most support tests are defined in their respective modules.
-// false until the test is run
-support.inlineBlockNeedsLayout = false;
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
-// Execute ASAP in case we need to set body.style.zoom
-jQuery(function() {
- // Minified: var a,b,c,d
- var val, div, body, container;
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
- body = document.getElementsByTagName( "body" )[ 0 ];
- if ( !body || !body.style ) {
- // Return for frameset docs that don't have a body
- return;
- }
+ if ( bulk ) {
- // Setup
- div = document.createElement( "div" );
- container = document.createElement( "div" );
- container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
- body.appendChild( container ).appendChild( div );
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
- if ( typeof div.style.zoom !== strundefined ) {
- // Support: IE<8
- // Check if natively block-level elements act like inline-block
- // elements when setting their display to 'inline' and giving
- // them layout
- div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
- support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
- if ( val ) {
- // Prevent IE 6 from affecting layout for positioned elements #11048
- // Prevent IE from shrinking the body in IE 7 mode #12869
- // Support: IE<8
- body.style.zoom = 1;
+ if ( fn ) {
+ for ( ; i < len; i++ ) {
+ fn(
+ elems[ i ], key, raw ?
+ value :
+ value.call( elems[ i ], i, fn( elems[ i ], key ) )
+ );
+ }
}
}
- body.removeChild( container );
-});
+ return chainable ?
+ elems :
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ len ? fn( elems[ 0 ], key ) : emptyGet;
+};
+var acceptData = function( owner ) {
+
+ // Accepts only:
+ // - Node
+ // - Node.ELEMENT_NODE
+ // - Node.DOCUMENT_NODE
+ // - Object
+ // - Any
+ return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
+};
-(function() {
- var div = document.createElement( "div" );
- // Execute the test only if not already executed in another module.
- if (support.deleteExpando == null) {
- // Support: IE<9
- support.deleteExpando = true;
- try {
- delete div.test;
- } catch( e ) {
- support.deleteExpando = false;
- }
- }
+function Data() {
+ this.expando = jQuery.expando + Data.uid++;
+}
- // Null elements to avoid leaks in IE.
- div = null;
-})();
+Data.uid = 1;
+Data.prototype = {
-/**
- * Determines whether an object can have data
- */
-jQuery.acceptData = function( elem ) {
- var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
- nodeType = +elem.nodeType || 1;
+ cache: function( owner ) {
- // Do not set data on non-element DOM nodes because it will not be cleared (#8335).
- return nodeType !== 1 && nodeType !== 9 ?
- false :
+ // Check if the owner object already has a cache
+ var value = owner[ this.expando ];
- // Nodes accept data unless otherwise specified; rejection can be conditional
- !noData || noData !== true && elem.getAttribute("classid") === noData;
-};
+ // If not, create one
+ if ( !value ) {
+ value = {};
+ // We can accept data for non-element nodes in modern browsers,
+ // but we should not, see #8335.
+ // Always return an empty object.
+ if ( acceptData( owner ) ) {
-var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
- rmultiDash = /([A-Z])/g;
+ // If it is a node unlikely to be stringify-ed or looped over
+ // use plain assignment
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = value;
-function dataAttr( elem, key, data ) {
- // If nothing was found internally, try to fetch any
- // data from the HTML5 data-* attribute
- if ( data === undefined && elem.nodeType === 1 ) {
-
- var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+ // Otherwise secure it in a non-enumerable property
+ // configurable must be true to allow the property to be
+ // deleted when data is removed
+ } else {
+ Object.defineProperty( owner, this.expando, {
+ value: value,
+ configurable: true
+ } );
+ }
+ }
+ }
- data = elem.getAttribute( name );
+ return value;
+ },
+ set: function( owner, data, value ) {
+ var prop,
+ cache = this.cache( owner );
+ // Handle: [ owner, key, value ] args
+ // Always use camelCase key (gh-2257)
if ( typeof data === "string" ) {
- try {
- data = data === "true" ? true :
- data === "false" ? false :
- data === "null" ? null :
- // Only convert to a number if it doesn't change the string
- +data + "" === data ? +data :
- rbrace.test( data ) ? jQuery.parseJSON( data ) :
- data;
- } catch( e ) {}
-
- // Make sure we set the data so it isn't changed later
- jQuery.data( elem, key, data );
+ cache[ jQuery.camelCase( data ) ] = value;
+ // Handle: [ owner, { properties } ] args
} else {
- data = undefined;
- }
- }
- return data;
-}
-
-// checks a cache object for emptiness
-function isEmptyDataObject( obj ) {
- var name;
- for ( name in obj ) {
-
- // if the public data object is empty, the private is still empty
- if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
- continue;
- }
- if ( name !== "toJSON" ) {
- return false;
+ // Copy the properties one-by-one to the cache object
+ for ( prop in data ) {
+ cache[ jQuery.camelCase( prop ) ] = data[ prop ];
+ }
}
- }
-
- return true;
-}
-
-function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var ret, thisCache,
- internalKey = jQuery.expando,
-
- // We have to handle DOM nodes and JS objects differently because IE6-7
- // can't GC object references properly across the DOM-JS boundary
- isNode = elem.nodeType,
-
- // Only DOM nodes need the global jQuery cache; JS object data is
- // attached directly to the object so GC can occur automatically
- cache = isNode ? jQuery.cache : elem,
+ return cache;
+ },
+ get: function( owner, key ) {
+ return key === undefined ?
+ this.cache( owner ) :
- // Only defining an ID for JS objects if its cache already exists allows
- // the code to shortcut on the same path as a DOM node with no cache
- id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+ // Always use camelCase key (gh-2257)
+ owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];
+ },
+ access: function( owner, key, value ) {
- // Avoid doing any more work than we need to when trying to get data on an
- // object that has no data at all
- if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
- return;
- }
+ // In cases where either:
+ //
+ // 1. No key was specified
+ // 2. A string key was specified, but no value provided
+ //
+ // Take the "read" path and allow the get method to determine
+ // which value to return, respectively either:
+ //
+ // 1. The entire cache object
+ // 2. The data stored at the key
+ //
+ if ( key === undefined ||
+ ( ( key && typeof key === "string" ) && value === undefined ) ) {
- if ( !id ) {
- // Only DOM nodes need a new unique ID for each element since their data
- // ends up in the global cache
- if ( isNode ) {
- id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
- } else {
- id = internalKey;
+ return this.get( owner, key );
}
- }
- if ( !cache[ id ] ) {
- // Avoid exposing jQuery metadata on plain JS objects when the object
- // is serialized using JSON.stringify
- cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
- }
+ // When the key is not a string, or both a key and value
+ // are specified, set or extend (existing objects) with either:
+ //
+ // 1. An object of properties
+ // 2. A key and value
+ //
+ this.set( owner, key, value );
- // An object can be passed to jQuery.data instead of a key/value pair; this gets
- // shallow copied over onto the existing cache
- if ( typeof name === "object" || typeof name === "function" ) {
- if ( pvt ) {
- cache[ id ] = jQuery.extend( cache[ id ], name );
- } else {
- cache[ id ].data = jQuery.extend( cache[ id ].data, name );
- }
- }
-
- thisCache = cache[ id ];
+ // Since the "set" path can have two possible entry points
+ // return the expected data based on which path was taken[*]
+ return value !== undefined ? value : key;
+ },
+ remove: function( owner, key ) {
+ var i,
+ cache = owner[ this.expando ];
- // jQuery data() is stored in a separate object inside the object's internal data
- // cache in order to avoid key collisions between internal data and user-defined
- // data.
- if ( !pvt ) {
- if ( !thisCache.data ) {
- thisCache.data = {};
+ if ( cache === undefined ) {
+ return;
}
- thisCache = thisCache.data;
- }
+ if ( key !== undefined ) {
- if ( data !== undefined ) {
- thisCache[ jQuery.camelCase( name ) ] = data;
- }
+ // Support array or space separated string of keys
+ if ( jQuery.isArray( key ) ) {
- // Check for both converted-to-camel and non-converted data property names
- // If a data property was specified
- if ( typeof name === "string" ) {
+ // If key is an array of keys...
+ // We always set camelCase keys, so remove that.
+ key = key.map( jQuery.camelCase );
+ } else {
+ key = jQuery.camelCase( key );
- // First Try to find as-is property data
- ret = thisCache[ name ];
+ // If a key with the spaces exists, use it.
+ // Otherwise, create an array by matching non-whitespace
+ key = key in cache ?
+ [ key ] :
+ ( key.match( rnotwhite ) || [] );
+ }
- // Test for null|undefined property data
- if ( ret == null ) {
+ i = key.length;
- // Try to find the camelCased property
- ret = thisCache[ jQuery.camelCase( name ) ];
+ while ( i-- ) {
+ delete cache[ key[ i ] ];
+ }
}
- } else {
- ret = thisCache;
- }
-
- return ret;
-}
-
-function internalRemoveData( elem, name, pvt ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache, i,
- isNode = elem.nodeType,
- // See jQuery.data for more information
- cache = isNode ? jQuery.cache : elem,
- id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+ // Remove the expando if there's no more data
+ if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
- // If there is already no cache entry for this object, there is no
- // purpose in continuing
- if ( !cache[ id ] ) {
- return;
+ // Support: Chrome <=35 - 45
+ // Webkit & Blink performance suffers when deleting properties
+ // from DOM nodes, so set to undefined instead
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = undefined;
+ } else {
+ delete owner[ this.expando ];
+ }
+ }
+ },
+ hasData: function( owner ) {
+ var cache = owner[ this.expando ];
+ return cache !== undefined && !jQuery.isEmptyObject( cache );
}
+};
+var dataPriv = new Data();
- if ( name ) {
+var dataUser = new Data();
- thisCache = pvt ? cache[ id ] : cache[ id ].data;
- if ( thisCache ) {
- // Support array or space separated string names for data keys
- if ( !jQuery.isArray( name ) ) {
+// Implementation Summary
+//
+// 1. Enforce API surface and semantic compatibility with 1.9.x branch
+// 2. Improve the module's maintainability by reducing the storage
+// paths to a single mechanism.
+// 3. Use the same single mechanism to support "private" and "user" data.
+// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+// 5. Avoid exposing implementation details on user objects (eg. expando properties)
+// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
- // try the string as a key before any manipulation
- if ( name in thisCache ) {
- name = [ name ];
- } else {
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /[A-Z]/g;
- // split the camel cased version by spaces unless a key with the spaces exists
- name = jQuery.camelCase( name );
- if ( name in thisCache ) {
- name = [ name ];
- } else {
- name = name.split(" ");
- }
- }
- } else {
- // If "name" is an array of keys...
- // When data is initially created, via ("key", "val") signature,
- // keys will be converted to camelCase.
- // Since there is no way to tell _how_ a key was added, remove
- // both plain key and camelCase key. #12786
- // This will only penalize the array argument path.
- name = name.concat( jQuery.map( name, jQuery.camelCase ) );
- }
+function dataAttr( elem, key, data ) {
+ var name;
- i = name.length;
- while ( i-- ) {
- delete thisCache[ name[i] ];
- }
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+ name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
+ data = elem.getAttribute( name );
- // If there is no data left in the cache, we want to continue
- // and let the cache object itself get destroyed
- if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
- return;
- }
- }
- }
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
- // See jQuery.data for more information
- if ( !pvt ) {
- delete cache[ id ].data;
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? JSON.parse( data ) :
+ data;
+ } catch ( e ) {}
- // Don't destroy the parent cache unless the internal data object
- // had been the only thing left in it
- if ( !isEmptyDataObject( cache[ id ] ) ) {
- return;
+ // Make sure we set the data so it isn't changed later
+ dataUser.set( elem, key, data );
+ } else {
+ data = undefined;
}
}
-
- // Destroy the cache
- if ( isNode ) {
- jQuery.cleanData( [ elem ], true );
-
- // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
- /* jshint eqeqeq: false */
- } else if ( support.deleteExpando || cache != cache.window ) {
- /* jshint eqeqeq: true */
- delete cache[ id ];
-
- // When all else fails, null
- } else {
- cache[ id ] = null;
- }
+ return data;
}
-jQuery.extend({
- cache: {},
-
- // The following elements (space-suffixed to avoid Object.prototype collisions)
- // throw uncatchable exceptions if you attempt to set expando properties
- noData: {
- "applet ": true,
- "embed ": true,
- // ...but Flash objects (which have this classid) *can* handle expandos
- "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
- },
-
+jQuery.extend( {
hasData: function( elem ) {
- elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
- return !!elem && !isEmptyDataObject( elem );
+ return dataUser.hasData( elem ) || dataPriv.hasData( elem );
},
data: function( elem, name, data ) {
- return internalData( elem, name, data );
+ return dataUser.access( elem, name, data );
},
removeData: function( elem, name ) {
- return internalRemoveData( elem, name );
+ dataUser.remove( elem, name );
},
- // For internal use only.
+ // TODO: Now that all calls to _data and _removeData have been replaced
+ // with direct calls to dataPriv methods, these can be deprecated.
_data: function( elem, name, data ) {
- return internalData( elem, name, data, true );
+ return dataPriv.access( elem, name, data );
},
_removeData: function( elem, name ) {
- return internalRemoveData( elem, name, true );
+ dataPriv.remove( elem, name );
}
-});
+} );
-jQuery.fn.extend({
+jQuery.fn.extend( {
data: function( key, value ) {
var i, name, data,
- elem = this[0],
+ elem = this[ 0 ],
attrs = elem && elem.attributes;
- // Special expections of .data basically thwart jQuery.access,
- // so implement the relevant behavior ourselves
-
// Gets all values
if ( key === undefined ) {
if ( this.length ) {
- data = jQuery.data( elem );
+ data = dataUser.get( elem );
- if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
i = attrs.length;
while ( i-- ) {
- // Support: IE11+
+ // Support: IE 11 only
// The attrs elements can be null (#14894)
if ( attrs[ i ] ) {
name = attrs[ i ].name;
if ( name.indexOf( "data-" ) === 0 ) {
- name = jQuery.camelCase( name.slice(5) );
+ name = jQuery.camelCase( name.slice( 5 ) );
dataAttr( elem, name, data[ name ] );
}
}
}
- jQuery._data( elem, "parsedAttrs", true );
+ dataPriv.set( elem, "hasDataAttrs", true );
}
}
@@ -3929,43 +4213,68 @@ jQuery.fn.extend({
// Sets multiple values
if ( typeof key === "object" ) {
- return this.each(function() {
- jQuery.data( this, key );
- });
+ return this.each( function() {
+ dataUser.set( this, key );
+ } );
}
- return arguments.length > 1 ?
+ return access( this, function( value ) {
+ var data;
+
+ // The calling jQuery object (element matches) is not empty
+ // (and therefore has an element appears at this[ 0 ]) and the
+ // `value` parameter was not undefined. An empty jQuery object
+ // will result in `undefined` for elem = this[ 0 ] which will
+ // throw an exception if an attempt to read a data cache is made.
+ if ( elem && value === undefined ) {
+
+ // Attempt to get data from the cache
+ // The key will always be camelCased in Data
+ data = dataUser.get( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // Attempt to "discover" the data in
+ // HTML5 custom data-* attrs
+ data = dataAttr( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
- // Sets one value
- this.each(function() {
- jQuery.data( this, key, value );
- }) :
+ // We tried really hard, but the data doesn't exist.
+ return;
+ }
- // Gets one value
- // Try to fetch any internally stored data first
- elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
+ // Set the data...
+ this.each( function() {
+
+ // We always store the camelCased key
+ dataUser.set( this, key, value );
+ } );
+ }, null, value, arguments.length > 1, null, true );
},
removeData: function( key ) {
- return this.each(function() {
- jQuery.removeData( this, key );
- });
+ return this.each( function() {
+ dataUser.remove( this, key );
+ } );
}
-});
+} );
-jQuery.extend({
+jQuery.extend( {
queue: function( elem, type, data ) {
var queue;
if ( elem ) {
type = ( type || "fx" ) + "queue";
- queue = jQuery._data( elem, type );
+ queue = dataPriv.get( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
- if ( !queue || jQuery.isArray(data) ) {
- queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ if ( !queue || jQuery.isArray( data ) ) {
+ queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
} else {
queue.push( data );
}
@@ -3999,7 +4308,7 @@ jQuery.extend({
queue.unshift( "inprogress" );
}
- // clear up the last queue stop function
+ // Clear up the last queue stop function
delete hooks.stop;
fn.call( elem, next, hooks );
}
@@ -4009,19 +4318,18 @@ jQuery.extend({
}
},
- // not intended for public consumption - generates a queueHooks object, or returns the current one
+ // Not public - generate a queueHooks object, or return the current one
_queueHooks: function( elem, type ) {
var key = type + "queueHooks";
- return jQuery._data( elem, key ) || jQuery._data( elem, key, {
- empty: jQuery.Callbacks("once memory").add(function() {
- jQuery._removeData( elem, type + "queue" );
- jQuery._removeData( elem, key );
- })
- });
+ return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
+ empty: jQuery.Callbacks( "once memory" ).add( function() {
+ dataPriv.remove( elem, [ type + "queue", key ] );
+ } )
+ } );
}
-});
+} );
-jQuery.fn.extend({
+jQuery.fn.extend( {
queue: function( type, data ) {
var setter = 2;
@@ -4032,30 +4340,31 @@ jQuery.fn.extend({
}
if ( arguments.length < setter ) {
- return jQuery.queue( this[0], type );
+ return jQuery.queue( this[ 0 ], type );
}
return data === undefined ?
this :
- this.each(function() {
+ this.each( function() {
var queue = jQuery.queue( this, type, data );
- // ensure a hooks for this queue
+ // Ensure a hooks for this queue
jQuery._queueHooks( this, type );
- if ( type === "fx" && queue[0] !== "inprogress" ) {
+ if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
- });
+ } );
},
dequeue: function( type ) {
- return this.each(function() {
+ return this.each( function() {
jQuery.dequeue( this, type );
- });
+ } );
},
clearQueue: function( type ) {
return this.queue( type || "fx", [] );
},
+
// Get a promise resolved when queues of a certain type
// are emptied (fx is the type by default)
promise: function( type, obj ) {
@@ -4077,7 +4386,7 @@ jQuery.fn.extend({
type = type || "fx";
while ( i-- ) {
- tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
if ( tmp && tmp.empty ) {
count++;
tmp.empty.add( resolve );
@@ -4086,171 +4395,400 @@ jQuery.fn.extend({
resolve();
return defer.promise( obj );
}
-});
-var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+} );
+var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
+
+var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
+
var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
-var isHidden = function( elem, el ) {
- // isHidden might be called from jQuery#filter function;
+var isHiddenWithinTree = function( elem, el ) {
+
+ // isHiddenWithinTree might be called from jQuery#filter function;
// in that case, element will be second argument
elem = el || elem;
- return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+
+ // Inline style trumps all
+ return elem.style.display === "none" ||
+ elem.style.display === "" &&
+
+ // Otherwise, check computed style
+ // Support: Firefox <=43 - 45
+ // Disconnected elements can have computed display: none, so first confirm that elem is
+ // in the document.
+ jQuery.contains( elem.ownerDocument, elem ) &&
+
+ jQuery.css( elem, "display" ) === "none";
};
+var swap = function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
-// Multifunctional method to get and set values of a collection
-// The value/s can optionally be executed if it's a function
-var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
- var i = 0,
- length = elems.length,
- bulk = key == null;
+ return ret;
+};
- // Sets many values
- if ( jQuery.type( key ) === "object" ) {
- chainable = true;
- for ( i in key ) {
- jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+
+
+
+function adjustCSS( elem, prop, valueParts, tween ) {
+ var adjusted,
+ scale = 1,
+ maxIterations = 20,
+ currentValue = tween ?
+ function() {
+ return tween.cur();
+ } :
+ function() {
+ return jQuery.css( elem, prop, "" );
+ },
+ initial = currentValue(),
+ unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
+ rcssNum.exec( jQuery.css( elem, prop ) );
+
+ if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
+
+ // Trust units reported by jQuery.css
+ unit = unit || initialInUnit[ 3 ];
+
+ // Make sure we update the tween properties later on
+ valueParts = valueParts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ initialInUnit = +initial || 1;
+
+ do {
+
+ // If previous iteration zeroed out, double until we get *something*.
+ // Use string for doubling so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ initialInUnit = initialInUnit / scale;
+ jQuery.style( elem, prop, initialInUnit + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // Break the loop if scale is unchanged or perfect, or if we've just had enough.
+ } while (
+ scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
+ );
+ }
+
+ if ( valueParts ) {
+ initialInUnit = +initialInUnit || +initial || 0;
+
+ // Apply relative offset (+=/-=) if specified
+ adjusted = valueParts[ 1 ] ?
+ initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+ +valueParts[ 2 ];
+ if ( tween ) {
+ tween.unit = unit;
+ tween.start = initialInUnit;
+ tween.end = adjusted;
}
+ }
+ return adjusted;
+}
- // Sets one value
- } else if ( value !== undefined ) {
- chainable = true;
- if ( !jQuery.isFunction( value ) ) {
- raw = true;
+var defaultDisplayMap = {};
+
+function getDefaultDisplay( elem ) {
+ var temp,
+ doc = elem.ownerDocument,
+ nodeName = elem.nodeName,
+ display = defaultDisplayMap[ nodeName ];
+
+ if ( display ) {
+ return display;
+ }
+
+ temp = doc.body.appendChild( doc.createElement( nodeName ) ),
+ display = jQuery.css( temp, "display" );
+
+ temp.parentNode.removeChild( temp );
+
+ if ( display === "none" ) {
+ display = "block";
+ }
+ defaultDisplayMap[ nodeName ] = display;
+
+ return display;
+}
+
+function showHide( elements, show ) {
+ var display, elem,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ // Determine new display value for elements that need to change
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
}
- if ( bulk ) {
- // Bulk operations run against the entire set
- if ( raw ) {
- fn.call( elems, value );
- fn = null;
+ display = elem.style.display;
+ if ( show ) {
- // ...except when executing function values
- } else {
- bulk = fn;
- fn = function( elem, key, value ) {
- return bulk.call( jQuery( elem ), value );
- };
+ // Since we force visibility upon cascade-hidden elements, an immediate (and slow)
+ // check is required in this first loop unless we have a nonempty display value (either
+ // inline or about-to-be-restored)
+ if ( display === "none" ) {
+ values[ index ] = dataPriv.get( elem, "display" ) || null;
+ if ( !values[ index ] ) {
+ elem.style.display = "";
+ }
}
- }
+ if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
+ values[ index ] = getDefaultDisplay( elem );
+ }
+ } else {
+ if ( display !== "none" ) {
+ values[ index ] = "none";
- if ( fn ) {
- for ( ; i < length; i++ ) {
- fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ // Remember what we're overwriting
+ dataPriv.set( elem, "display", display );
}
}
}
- return chainable ?
- elems :
+ // Set the display of the elements in a second loop to avoid constant reflow
+ for ( index = 0; index < length; index++ ) {
+ if ( values[ index ] != null ) {
+ elements[ index ].style.display = values[ index ];
+ }
+ }
- // Gets
- bulk ?
- fn.call( elems ) :
- length ? fn( elems[0], key ) : emptyGet;
-};
-var rcheckableType = (/^(?:checkbox|radio)$/i);
+ return elements;
+}
+jQuery.fn.extend( {
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+ return this.each( function() {
+ if ( isHiddenWithinTree( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ } );
+ }
+} );
+var rcheckableType = ( /^(?:checkbox|radio)$/i );
-(function() {
- // Minified: var a,b,c
- var input = document.createElement( "input" ),
- div = document.createElement( "div" ),
- fragment = document.createDocumentFragment();
+var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i );
- // Setup
- div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+var rscriptType = ( /^$|\/(?:java|ecma)script/i );
- // IE strips leading whitespace when .innerHTML is used
- support.leadingWhitespace = div.firstChild.nodeType === 3;
- // Make sure that tbody elements aren't automatically inserted
- // IE will insert them into empty tables
- support.tbody = !div.getElementsByTagName( "tbody" ).length;
- // Make sure that link elements get serialized correctly by innerHTML
- // This requires a wrapper element in IE
- support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
+// We have to close these tags to support XHTML (#13200)
+var wrapMap = {
- // Makes sure cloning an html5 element does not cause problems
- // Where outerHTML is undefined, this still works
- support.html5Clone =
- document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";
+ // Support: IE <=9 only
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
- // Check if a disconnected checkbox will retain its checked
- // value of true after appended to the DOM (IE6/7)
- input.type = "checkbox";
- input.checked = true;
- fragment.appendChild( input );
- support.appendChecked = input.checked;
+ // XHTML parsers do not magically insert elements in the
+ // same way that tag soup parsers do. So we cannot shorten
+ // this by omitting <tbody> or other required elements.
+ thead: [ 1, "<table>", "</table>" ],
+ col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
- // Make sure textarea (and checkbox) defaultValue is properly cloned
- // Support: IE6-IE11+
- div.innerHTML = "<textarea>x</textarea>";
- support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+ _default: [ 0, "", "" ]
+};
- // #11217 - WebKit loses check when the name is after the checked attribute
- fragment.appendChild( div );
- div.innerHTML = "<input type='radio' checked='checked' name='t'/>";
+// Support: IE <=9 only
+wrapMap.optgroup = wrapMap.option;
- // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
- // old WebKit doesn't clone checked state correctly in fragments
- support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+
+function getAll( context, tag ) {
+
+ // Support: IE <=9 - 11 only
+ // Use typeof to avoid zero-argument method invocation on host objects (#15151)
+ var ret = typeof context.getElementsByTagName !== "undefined" ?
+ context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== "undefined" ?
+ context.querySelectorAll( tag || "*" ) :
+ [];
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], ret ) :
+ ret;
+}
- // Support: IE<9
- // Opera does not clone events (and typeof div.attachEvent === undefined).
- // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
- support.noCloneEvent = true;
- if ( div.attachEvent ) {
- div.attachEvent( "onclick", function() {
- support.noCloneEvent = false;
- });
- div.cloneNode( true ).click();
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ dataPriv.set(
+ elems[ i ],
+ "globalEval",
+ !refElements || dataPriv.get( refElements[ i ], "globalEval" )
+ );
}
+}
- // Execute the test only if not already executed in another module.
- if (support.deleteExpando == null) {
- // Support: IE<9
- support.deleteExpando = true;
- try {
- delete div.test;
- } catch( e ) {
- support.deleteExpando = false;
+
+var rhtml = /<|&#?\w+;/;
+
+function buildFragment( elems, context, scripts, selection, ignored ) {
+ var elem, tmp, tag, wrap, contains, j,
+ fragment = context.createDocumentFragment(),
+ nodes = [],
+ i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
+
+ // Deserialize a standard representation
+ tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+ tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
+
+ // Descend through wrappers to the right content
+ j = wrap[ 0 ];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Remember the top-level container
+ tmp = fragment.firstChild;
+
+ // Ensure the created nodes are orphaned (#12392)
+ tmp.textContent = "";
+ }
}
}
-})();
+ // Remove wrapper from fragment
+ fragment.textContent = "";
-(function() {
- var i, eventName,
- div = document.createElement( "div" );
+ i = 0;
+ while ( ( elem = nodes[ i++ ] ) ) {
- // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)
- for ( i in { submit: true, change: true, focusin: true }) {
- eventName = "on" + i;
+ // Skip elements already in the context collection (trac-4087)
+ if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
+ if ( ignored ) {
+ ignored.push( elem );
+ }
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
- if ( !(support[ i + "Bubbles" ] = eventName in window) ) {
- // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
- div.setAttribute( eventName, "t" );
- support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false;
+ // Append to fragment
+ tmp = getAll( fragment.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( ( elem = tmp[ j++ ] ) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
}
}
- // Null elements to avoid leaks in IE.
- div = null;
-})();
+ return fragment;
+}
+
+
+( function() {
+ var fragment = document.createDocumentFragment(),
+ div = fragment.appendChild( document.createElement( "div" ) ),
+ input = document.createElement( "input" );
+
+ // Support: Android 4.0 - 4.3 only
+ // Check state lost if the name is set (#11217)
+ // Support: Windows Web Apps (WWA)
+ // `name` and `type` must use .setAttribute for WWA (#14901)
+ input.setAttribute( "type", "radio" );
+ input.setAttribute( "checked", "checked" );
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+
+ // Support: Android <=4.1 only
+ // Older WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE <=11 only
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ div.innerHTML = "<textarea>x</textarea>";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+} )();
+var documentElement = document.documentElement;
+
-var rformElems = /^(?:input|select|textarea)$/i,
+var
rkeyEvent = /^key/,
- rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
- rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
- rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+ rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
function returnTrue() {
return true;
@@ -4260,12 +4798,75 @@ function returnFalse() {
return false;
}
+// Support: IE <=9 only
+// See #13393 for more info
function safeActiveElement() {
try {
return document.activeElement;
} catch ( err ) { }
}
+function on( elem, types, selector, data, fn, one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ on( elem, type, selector, data, types[ type ], one );
+ }
+ return elem;
+ }
+
+ if ( data == null && fn == null ) {
+
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return elem;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return elem.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ } );
+}
+
/*
* Helper functions for managing events -- not part of the public interface.
* Props to Dean Edwards' addEvent library for many of the ideas.
@@ -4275,10 +4876,11 @@ jQuery.event = {
global: {},
add: function( elem, types, handler, data, selector ) {
- var tmp, events, t, handleObjIn,
- special, eventHandle, handleObj,
- handlers, type, namespaces, origType,
- elemData = jQuery._data( elem );
+
+ var handleObjIn, eventHandle, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = dataPriv.get( elem );
// Don't attach events to noData or text/comment nodes (but allow plain objects)
if ( !elemData ) {
@@ -4292,34 +4894,38 @@ jQuery.event = {
selector = handleObjIn.selector;
}
+ // Ensure that invalid selectors throw exceptions at attach time
+ // Evaluate against documentElement in case elem is a non-element node (e.g., document)
+ if ( selector ) {
+ jQuery.find.matchesSelector( documentElement, selector );
+ }
+
// Make sure that the handler has a unique ID, used to find/remove it later
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
// Init the element's event structure and main handler, if this is the first
- if ( !(events = elemData.events) ) {
+ if ( !( events = elemData.events ) ) {
events = elemData.events = {};
}
- if ( !(eventHandle = elemData.handle) ) {
+ if ( !( eventHandle = elemData.handle ) ) {
eventHandle = elemData.handle = function( e ) {
+
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
- return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
- jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
- undefined;
+ return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
+ jQuery.event.dispatch.apply( elem, arguments ) : undefined;
};
- // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
- eventHandle.elem = elem;
}
// Handle multiple events separated by a space
types = ( types || "" ).match( rnotwhite ) || [ "" ];
t = types.length;
while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
// There *must* be a type, no attaching namespace-only handlers
if ( !type ) {
@@ -4336,7 +4942,7 @@ jQuery.event = {
special = jQuery.event.special[ type ] || {};
// handleObj is passed to all event handlers
- handleObj = jQuery.extend({
+ handleObj = jQuery.extend( {
type: type,
origType: origType,
data: data,
@@ -4344,22 +4950,20 @@ jQuery.event = {
guid: handler.guid,
selector: selector,
needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
- namespace: namespaces.join(".")
+ namespace: namespaces.join( "." )
}, handleObjIn );
// Init the event handler queue if we're the first
- if ( !(handlers = events[ type ]) ) {
+ if ( !( handlers = events[ type ] ) ) {
handlers = events[ type ] = [];
handlers.delegateCount = 0;
- // Only use addEventListener/attachEvent if the special events handler returns false
- if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
- // Bind the global event handler to the element
- if ( elem.addEventListener ) {
- elem.addEventListener( type, eventHandle, false );
+ // Only use addEventListener if the special events handler returns false
+ if ( !special.setup ||
+ special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
- } else if ( elem.attachEvent ) {
- elem.attachEvent( "on" + type, eventHandle );
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle );
}
}
}
@@ -4383,19 +4987,17 @@ jQuery.event = {
jQuery.event.global[ type ] = true;
}
- // Nullify elem to prevent memory leaks in IE
- elem = null;
},
// Detach an event or set of events from an element
remove: function( elem, types, handler, selector, mappedTypes ) {
- var j, handleObj, tmp,
- origCount, t, events,
- special, handlers, type,
- namespaces, origType,
- elemData = jQuery.hasData( elem ) && jQuery._data( elem );
- if ( !elemData || !(events = elemData.events) ) {
+ var j, origCount, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
+
+ if ( !elemData || !( events = elemData.events ) ) {
return;
}
@@ -4403,9 +5005,9 @@ jQuery.event = {
types = ( types || "" ).match( rnotwhite ) || [ "" ];
t = types.length;
while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
// Unbind all events (on this namespace, if provided) for the element
if ( !type ) {
@@ -4418,7 +5020,8 @@ jQuery.event = {
special = jQuery.event.special[ type ] || {};
type = ( selector ? special.delegateType : special.bindType ) || type;
handlers = events[ type ] || [];
- tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+ tmp = tmp[ 2 ] &&
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
// Remove matching events
origCount = j = handlers.length;
@@ -4428,7 +5031,8 @@ jQuery.event = {
if ( ( mappedTypes || origType === handleObj.origType ) &&
( !handler || handler.guid === handleObj.guid ) &&
( !tmp || tmp.test( handleObj.namespace ) ) &&
- ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ ( !selector || selector === handleObj.selector ||
+ selector === "**" && handleObj.selector ) ) {
handlers.splice( j, 1 );
if ( handleObj.selector ) {
@@ -4443,7 +5047,9 @@ jQuery.event = {
// Remove generic event handler if we removed something and no more handlers exist
// (avoids potential for endless recursion during removal of special event handlers)
if ( origCount && !handlers.length ) {
- if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ if ( !special.teardown ||
+ special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+
jQuery.removeEvent( elem, type, elemData.handle );
}
@@ -4451,167 +5057,29 @@ jQuery.event = {
}
}
- // Remove the expando if it's no longer used
+ // Remove data and the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
- delete elemData.handle;
-
- // removeData also checks for emptiness and clears the expando if empty
- // so use it instead of delete
- jQuery._removeData( elem, "events" );
+ dataPriv.remove( elem, "handle events" );
}
},
- trigger: function( event, data, elem, onlyHandlers ) {
- var handle, ontype, cur,
- bubbleType, special, tmp, i,
- eventPath = [ elem || document ],
- type = hasOwn.call( event, "type" ) ? event.type : event,
- namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
-
- cur = tmp = elem = elem || document;
-
- // Don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
-
- // focus/blur morphs to focusin/out; ensure we're not firing them right now
- if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
- return;
- }
-
- if ( type.indexOf(".") >= 0 ) {
- // Namespaced trigger; create a regexp to match event type in handle()
- namespaces = type.split(".");
- type = namespaces.shift();
- namespaces.sort();
- }
- ontype = type.indexOf(":") < 0 && "on" + type;
-
- // Caller can pass in a jQuery.Event object, Object, or just an event type string
- event = event[ jQuery.expando ] ?
- event :
- new jQuery.Event( type, typeof event === "object" && event );
-
- // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
- event.isTrigger = onlyHandlers ? 2 : 3;
- event.namespace = namespaces.join(".");
- event.namespace_re = event.namespace ?
- new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
- null;
-
- // Clean up the event in case it is being reused
- event.result = undefined;
- if ( !event.target ) {
- event.target = elem;
- }
-
- // Clone any incoming data and prepend the event, creating the handler arg list
- data = data == null ?
- [ event ] :
- jQuery.makeArray( data, [ event ] );
-
- // Allow special events to draw outside the lines
- special = jQuery.event.special[ type ] || {};
- if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
- return;
- }
-
- // Determine event propagation path in advance, per W3C events spec (#9951)
- // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
- if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
-
- bubbleType = special.delegateType || type;
- if ( !rfocusMorph.test( bubbleType + type ) ) {
- cur = cur.parentNode;
- }
- for ( ; cur; cur = cur.parentNode ) {
- eventPath.push( cur );
- tmp = cur;
- }
-
- // Only add window if we got to document (e.g., not plain obj or detached DOM)
- if ( tmp === (elem.ownerDocument || document) ) {
- eventPath.push( tmp.defaultView || tmp.parentWindow || window );
- }
- }
-
- // Fire handlers on the event path
- i = 0;
- while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
-
- event.type = i > 1 ?
- bubbleType :
- special.bindType || type;
-
- // jQuery handler
- handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
- if ( handle ) {
- handle.apply( cur, data );
- }
-
- // Native handler
- handle = ontype && cur[ ontype ];
- if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
- event.result = handle.apply( cur, data );
- if ( event.result === false ) {
- event.preventDefault();
- }
- }
- }
- event.type = type;
-
- // If nobody prevented the default action, do it now
- if ( !onlyHandlers && !event.isDefaultPrevented() ) {
-
- if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
- jQuery.acceptData( elem ) ) {
-
- // Call a native DOM method on the target with the same name name as the event.
- // Can't use an .isFunction() check here because IE6/7 fails that test.
- // Don't do default actions on window, that's where global variables be (#6170)
- if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
-
- // Don't re-trigger an onFOO event when we call its FOO() method
- tmp = elem[ ontype ];
-
- if ( tmp ) {
- elem[ ontype ] = null;
- }
-
- // Prevent re-triggering of the same event, since we already bubbled it above
- jQuery.event.triggered = type;
- try {
- elem[ type ]();
- } catch ( e ) {
- // IE<9 dies on focus/blur to hidden element (#1486,#12518)
- // only reproducible on winXP IE8 native, not IE9 in IE8 mode
- }
- jQuery.event.triggered = undefined;
-
- if ( tmp ) {
- elem[ ontype ] = tmp;
- }
- }
- }
- }
-
- return event.result;
- },
-
- dispatch: function( event ) {
+ dispatch: function( nativeEvent ) {
// Make a writable jQuery.Event from the native event object
- event = jQuery.event.fix( event );
+ var event = jQuery.event.fix( nativeEvent );
- var i, ret, handleObj, matched, j,
- handlerQueue = [],
- args = slice.call( arguments ),
- handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ var i, j, ret, matched, handleObj, handlerQueue,
+ args = new Array( arguments.length ),
+ handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
special = jQuery.event.special[ event.type ] || {};
// Use the fix-ed jQuery.Event rather than the (read-only) native event
- args[0] = event;
+ args[ 0 ] = event;
+
+ for ( i = 1; i < arguments.length; i++ ) {
+ args[ i ] = arguments[ i ];
+ }
+
event.delegateTarget = this;
// Call the preDispatch hook for the mapped type, and let it bail if desired
@@ -4624,24 +5092,25 @@ jQuery.event = {
// Run delegates first; they may want to stop propagation beneath us
i = 0;
- while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
event.currentTarget = matched.elem;
j = 0;
- while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+ while ( ( handleObj = matched.handlers[ j++ ] ) &&
+ !event.isImmediatePropagationStopped() ) {
- // Triggered event must either 1) have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
- if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+ // Triggered event must either 1) have no namespace, or 2) have namespace(s)
+ // a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
event.handleObj = handleObj;
event.data = handleObj.data;
- ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
- .apply( matched.elem, args );
+ ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
+ handleObj.handler ).apply( matched.elem, args );
if ( ret !== undefined ) {
- if ( (event.result = ret) === false ) {
+ if ( ( event.result = ret ) === false ) {
event.preventDefault();
event.stopPropagation();
}
@@ -4659,23 +5128,25 @@ jQuery.event = {
},
handlers: function( event, handlers ) {
- var sel, handleObj, matches, i,
+ var i, matches, sel, handleObj,
handlerQueue = [],
delegateCount = handlers.delegateCount,
cur = event.target;
+ // Support: IE <=9
// Find delegate handlers
// Black-hole SVG <use> instance trees (#13180)
- // Avoid non-left-click bubbling in Firefox (#3861)
- if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+ //
+ // Support: Firefox <=42
+ // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)
+ if ( delegateCount && cur.nodeType &&
+ ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {
- /* jshint eqeqeq: false */
- for ( ; cur != this; cur = cur.parentNode || this ) {
- /* jshint eqeqeq: true */
+ for ( ; cur !== this; cur = cur.parentNode || this ) {
// Don't check non-elements (#13208)
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
- if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+ if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) {
matches = [];
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
@@ -4685,7 +5156,7 @@ jQuery.event = {
if ( matches[ sel ] === undefined ) {
matches[ sel ] = handleObj.needsContext ?
- jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery( sel, this ).index( cur ) > -1 :
jQuery.find( sel, this, null, [ cur ] ).length;
}
if ( matches[ sel ] ) {
@@ -4693,7 +5164,7 @@ jQuery.event = {
}
}
if ( matches.length ) {
- handlerQueue.push({ elem: cur, handlers: matches });
+ handlerQueue.push( { elem: cur, handlers: matches } );
}
}
}
@@ -4701,125 +5172,59 @@ jQuery.event = {
// Add the remaining (directly-bound) handlers
if ( delegateCount < handlers.length ) {
- handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } );
}
return handlerQueue;
},
- fix: function( event ) {
- if ( event[ jQuery.expando ] ) {
- return event;
- }
-
- // Create a writable copy of the event object and normalize some properties
- var i, prop, copy,
- type = event.type,
- originalEvent = event,
- fixHook = this.fixHooks[ type ];
-
- if ( !fixHook ) {
- this.fixHooks[ type ] = fixHook =
- rmouseEvent.test( type ) ? this.mouseHooks :
- rkeyEvent.test( type ) ? this.keyHooks :
- {};
- }
- copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
-
- event = new jQuery.Event( originalEvent );
-
- i = copy.length;
- while ( i-- ) {
- prop = copy[ i ];
- event[ prop ] = originalEvent[ prop ];
- }
-
- // Support: IE<9
- // Fix target property (#1925)
- if ( !event.target ) {
- event.target = originalEvent.srcElement || document;
- }
-
- // Support: Chrome 23+, Safari?
- // Target should not be a text node (#504, #13143)
- if ( event.target.nodeType === 3 ) {
- event.target = event.target.parentNode;
- }
-
- // Support: IE<9
- // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
- event.metaKey = !!event.metaKey;
-
- return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
- },
-
- // Includes some event props shared by KeyEvent and MouseEvent
- props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+ addProp: function( name, hook ) {
+ Object.defineProperty( jQuery.Event.prototype, name, {
+ enumerable: true,
+ configurable: true,
- fixHooks: {},
-
- keyHooks: {
- props: "char charCode key keyCode".split(" "),
- filter: function( event, original ) {
+ get: jQuery.isFunction( hook ) ?
+ function() {
+ if ( this.originalEvent ) {
+ return hook( this.originalEvent );
+ }
+ } :
+ function() {
+ if ( this.originalEvent ) {
+ return this.originalEvent[ name ];
+ }
+ },
- // Add which for key events
- if ( event.which == null ) {
- event.which = original.charCode != null ? original.charCode : original.keyCode;
+ set: function( value ) {
+ Object.defineProperty( this, name, {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: value
+ } );
}
-
- return event;
- }
+ } );
},
- mouseHooks: {
- props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
- filter: function( event, original ) {
- var body, eventDoc, doc,
- button = original.button,
- fromElement = original.fromElement;
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && original.clientX != null ) {
- eventDoc = event.target.ownerDocument || document;
- doc = eventDoc.documentElement;
- body = eventDoc.body;
-
- event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
- event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
- }
-
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && fromElement ) {
- event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
- }
-
- // Add which for click: 1 === left; 2 === middle; 3 === right
- // Note: button is not normalized, so don't use it
- if ( !event.which && button !== undefined ) {
- event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
- }
-
- return event;
- }
+ fix: function( originalEvent ) {
+ return originalEvent[ jQuery.expando ] ?
+ originalEvent :
+ new jQuery.Event( originalEvent );
},
special: {
load: {
+
// Prevent triggered image.load events from bubbling to window.load
noBubble: true
},
focus: {
+
// Fire native event if possible so blur/focus sequence is correct
trigger: function() {
if ( this !== safeActiveElement() && this.focus ) {
- try {
- this.focus();
- return false;
- } catch ( e ) {
- // Support: IE<9
- // If we error on focus to hidden element (#1486, #12518),
- // let .trigger() run the handlers
- }
+ this.focus();
+ return false;
}
},
delegateType: "focusin"
@@ -4834,9 +5239,10 @@ jQuery.event = {
delegateType: "focusout"
},
click: {
+
// For checkbox, fire native event so checked state will be right
trigger: function() {
- if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+ if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
this.click();
return false;
}
@@ -4858,56 +5264,21 @@ jQuery.event = {
}
}
}
- },
-
- simulate: function( type, elem, event, bubble ) {
- // Piggyback on a donor event to simulate a different one.
- // Fake originalEvent to avoid donor's stopPropagation, but if the
- // simulated event prevents default then we do the same on the donor.
- var e = jQuery.extend(
- new jQuery.Event(),
- event,
- {
- type: type,
- isSimulated: true,
- originalEvent: {}
- }
- );
- if ( bubble ) {
- jQuery.event.trigger( e, null, elem );
- } else {
- jQuery.event.dispatch.call( elem, e );
- }
- if ( e.isDefaultPrevented() ) {
- event.preventDefault();
- }
}
};
-jQuery.removeEvent = document.removeEventListener ?
- function( elem, type, handle ) {
- if ( elem.removeEventListener ) {
- elem.removeEventListener( type, handle, false );
- }
- } :
- function( elem, type, handle ) {
- var name = "on" + type;
+jQuery.removeEvent = function( elem, type, handle ) {
- if ( elem.detachEvent ) {
-
- // #8545, #7054, preventing memory leaks for custom events in IE6-8
- // detachEvent needed property on element, by name of that event, to properly expose it to GC
- if ( typeof elem[ name ] === strundefined ) {
- elem[ name ] = null;
- }
-
- elem.detachEvent( name, handle );
- }
- };
+ // This "if" is needed for plain objects
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle );
+ }
+};
jQuery.Event = function( src, props ) {
+
// Allow instantiation without the 'new' keyword
- if ( !(this instanceof jQuery.Event) ) {
+ if ( !( this instanceof jQuery.Event ) ) {
return new jQuery.Event( src, props );
}
@@ -4920,11 +5291,22 @@ jQuery.Event = function( src, props ) {
// by a handler lower down the tree; reflect the correct value.
this.isDefaultPrevented = src.defaultPrevented ||
src.defaultPrevented === undefined &&
- // Support: IE < 9, Android < 4.0
+
+ // Support: Android <=2.3 only
src.returnValue === false ?
returnTrue :
returnFalse;
+ // Create target properties
+ // Support: Safari <=6 - 7 only
+ // Target should not be a text node (#504, #13143)
+ this.target = ( src.target && src.target.nodeType === 3 ) ?
+ src.target.parentNode :
+ src.target;
+
+ this.currentTarget = src.currentTarget;
+ this.relatedTarget = src.relatedTarget;
+
// Event type
} else {
this.type = src;
@@ -4943,52 +5325,38 @@ jQuery.Event = function( src, props ) {
};
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
-// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
+ constructor: jQuery.Event,
isDefaultPrevented: returnFalse,
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse,
+ isSimulated: false,
preventDefault: function() {
var e = this.originalEvent;
this.isDefaultPrevented = returnTrue;
- if ( !e ) {
- return;
- }
- // If preventDefault exists, run it on the original event
- if ( e.preventDefault ) {
+ if ( e && !this.isSimulated ) {
e.preventDefault();
-
- // Support: IE
- // Otherwise set the returnValue property of the original event to false
- } else {
- e.returnValue = false;
}
},
stopPropagation: function() {
var e = this.originalEvent;
this.isPropagationStopped = returnTrue;
- if ( !e ) {
- return;
- }
- // If stopPropagation exists, run it on the original event
- if ( e.stopPropagation ) {
+
+ if ( e && !this.isSimulated ) {
e.stopPropagation();
}
-
- // Support: IE
- // Set the cancelBubble property of the original event to true
- e.cancelBubble = true;
},
stopImmediatePropagation: function() {
var e = this.originalEvent;
this.isImmediatePropagationStopped = returnTrue;
- if ( e && e.stopImmediatePropagation ) {
+ if ( e && !this.isSimulated ) {
e.stopImmediatePropagation();
}
@@ -4996,8 +5364,64 @@ jQuery.Event.prototype = {
}
};
+// Includes all common event props including KeyEvent and MouseEvent specific props
+jQuery.each( {
+ altKey: true,
+ bubbles: true,
+ cancelable: true,
+ changedTouches: true,
+ ctrlKey: true,
+ detail: true,
+ eventPhase: true,
+ metaKey: true,
+ pageX: true,
+ pageY: true,
+ shiftKey: true,
+ view: true,
+ "char": true,
+ charCode: true,
+ key: true,
+ keyCode: true,
+ button: true,
+ buttons: true,
+ clientX: true,
+ clientY: true,
+ offsetX: true,
+ offsetY: true,
+ pointerId: true,
+ pointerType: true,
+ screenX: true,
+ screenY: true,
+ targetTouches: true,
+ toElement: true,
+ touches: true,
+
+ which: function( event ) {
+ var button = event.button;
+
+ // Add which for key events
+ if ( event.which == null && rkeyEvent.test( event.type ) ) {
+ return event.charCode != null ? event.charCode : event.keyCode;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
+ return ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event.which;
+ }
+}, jQuery.event.addProp );
+
// Create mouseenter/leave events using mouseover/out and event-time checks
-jQuery.each({
+// so that event delegation works in jQuery.
+// Do the same for pointerenter/pointerleave and pointerover/pointerout
+//
+// Support: Safari 7 only
+// Safari sends mouseenter too often; see:
+// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
+// for the description of the bug (it existed in older Chrome versions as well).
+jQuery.each( {
mouseenter: "mouseover",
mouseleave: "mouseout",
pointerenter: "pointerover",
@@ -5013,9 +5437,9 @@ jQuery.each({
related = event.relatedTarget,
handleObj = event.handleObj;
- // For mousenter/leave call the handler if related is outside the target.
+ // For mouseenter/leave call the handler if related is outside the target.
// NB: No relatedTarget if the mouse left/entered the browser window
- if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
event.type = handleObj.origType;
ret = handleObj.handler.apply( this, arguments );
event.type = fix;
@@ -5023,219 +5447,33 @@ jQuery.each({
return ret;
}
};
-});
-
-// IE submit delegation
-if ( !support.submitBubbles ) {
+} );
- jQuery.event.special.submit = {
- setup: function() {
- // Only need this for delegated form submit events
- if ( jQuery.nodeName( this, "form" ) ) {
- return false;
- }
+jQuery.fn.extend( {
- // Lazy-add a submit handler when a descendant form may potentially be submitted
- jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
- // Node name check avoids a VML-related crash in IE (#9807)
- var elem = e.target,
- form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
- if ( form && !jQuery._data( form, "submitBubbles" ) ) {
- jQuery.event.add( form, "submit._submit", function( event ) {
- event._submit_bubble = true;
- });
- jQuery._data( form, "submitBubbles", true );
- }
- });
- // return undefined since we don't need an event listener
- },
-
- postDispatch: function( event ) {
- // If form was submitted by the user, bubble the event up the tree
- if ( event._submit_bubble ) {
- delete event._submit_bubble;
- if ( this.parentNode && !event.isTrigger ) {
- jQuery.event.simulate( "submit", this.parentNode, event, true );
- }
- }
- },
-
- teardown: function() {
- // Only need this for delegated form submit events
- if ( jQuery.nodeName( this, "form" ) ) {
- return false;
- }
-
- // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
- jQuery.event.remove( this, "._submit" );
- }
- };
-}
-
-// IE change delegation and checkbox/radio fix
-if ( !support.changeBubbles ) {
-
- jQuery.event.special.change = {
-
- setup: function() {
-
- if ( rformElems.test( this.nodeName ) ) {
- // IE doesn't fire change on a check/radio until blur; trigger it on click
- // after a propertychange. Eat the blur-change in special.change.handle.
- // This still fires onchange a second time for check/radio after blur.
- if ( this.type === "checkbox" || this.type === "radio" ) {
- jQuery.event.add( this, "propertychange._change", function( event ) {
- if ( event.originalEvent.propertyName === "checked" ) {
- this._just_changed = true;
- }
- });
- jQuery.event.add( this, "click._change", function( event ) {
- if ( this._just_changed && !event.isTrigger ) {
- this._just_changed = false;
- }
- // Allow triggered, simulated change events (#11500)
- jQuery.event.simulate( "change", this, event, true );
- });
- }
- return false;
- }
- // Delegated event; lazy-add a change handler on descendant inputs
- jQuery.event.add( this, "beforeactivate._change", function( e ) {
- var elem = e.target;
-
- if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
- jQuery.event.add( elem, "change._change", function( event ) {
- if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
- jQuery.event.simulate( "change", this.parentNode, event, true );
- }
- });
- jQuery._data( elem, "changeBubbles", true );
- }
- });
- },
-
- handle: function( event ) {
- var elem = event.target;
-
- // Swallow native change events from checkbox/radio, we already triggered them above
- if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
- return event.handleObj.handler.apply( this, arguments );
- }
- },
-
- teardown: function() {
- jQuery.event.remove( this, "._change" );
-
- return !rformElems.test( this.nodeName );
- }
- };
-}
-
-// Create "bubbling" focus and blur events
-if ( !support.focusinBubbles ) {
- jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
- // Attach a single capturing handler on the document while someone wants focusin/focusout
- var handler = function( event ) {
- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
- };
-
- jQuery.event.special[ fix ] = {
- setup: function() {
- var doc = this.ownerDocument || this,
- attaches = jQuery._data( doc, fix );
-
- if ( !attaches ) {
- doc.addEventListener( orig, handler, true );
- }
- jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
- },
- teardown: function() {
- var doc = this.ownerDocument || this,
- attaches = jQuery._data( doc, fix ) - 1;
-
- if ( !attaches ) {
- doc.removeEventListener( orig, handler, true );
- jQuery._removeData( doc, fix );
- } else {
- jQuery._data( doc, fix, attaches );
- }
- }
- };
- });
-}
-
-jQuery.fn.extend({
-
- on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
- var type, origFn;
-
- // Types can be a map of types/handlers
- if ( typeof types === "object" ) {
- // ( types-Object, selector, data )
- if ( typeof selector !== "string" ) {
- // ( types-Object, data )
- data = data || selector;
- selector = undefined;
- }
- for ( type in types ) {
- this.on( type, selector, data, types[ type ], one );
- }
- return this;
- }
-
- if ( data == null && fn == null ) {
- // ( types, fn )
- fn = selector;
- data = selector = undefined;
- } else if ( fn == null ) {
- if ( typeof selector === "string" ) {
- // ( types, selector, fn )
- fn = data;
- data = undefined;
- } else {
- // ( types, data, fn )
- fn = data;
- data = selector;
- selector = undefined;
- }
- }
- if ( fn === false ) {
- fn = returnFalse;
- } else if ( !fn ) {
- return this;
- }
-
- if ( one === 1 ) {
- origFn = fn;
- fn = function( event ) {
- // Can use an empty set, since event contains the info
- jQuery().off( event );
- return origFn.apply( this, arguments );
- };
- // Use same guid so caller can remove using origFn
- fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
- }
- return this.each( function() {
- jQuery.event.add( this, types, fn, data, selector );
- });
+ on: function( types, selector, data, fn ) {
+ return on( this, types, selector, data, fn );
},
one: function( types, selector, data, fn ) {
- return this.on( types, selector, data, fn, 1 );
+ return on( this, types, selector, data, fn, 1 );
},
off: function( types, selector, fn ) {
var handleObj, type;
if ( types && types.preventDefault && types.handleObj ) {
+
// ( event ) dispatched jQuery.Event
handleObj = types.handleObj;
jQuery( types.delegateTarget ).off(
- handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.namespace ?
+ handleObj.origType + "." + handleObj.namespace :
+ handleObj.origType,
handleObj.selector,
handleObj.handler
);
return this;
}
if ( typeof types === "object" ) {
+
// ( types-object [, selector] )
for ( type in types ) {
this.off( type, selector, types[ type ] );
@@ -5243,6 +5481,7 @@ jQuery.fn.extend({
return this;
}
if ( selector === false || typeof selector === "function" ) {
+
// ( types [, fn] )
fn = selector;
selector = undefined;
@@ -5250,263 +5489,238 @@ jQuery.fn.extend({
if ( fn === false ) {
fn = returnFalse;
}
- return this.each(function() {
+ return this.each( function() {
jQuery.event.remove( this, types, fn, selector );
- });
- },
-
- trigger: function( type, data ) {
- return this.each(function() {
- jQuery.event.trigger( type, data, this );
- });
- },
- triggerHandler: function( type, data ) {
- var elem = this[0];
- if ( elem ) {
- return jQuery.event.trigger( type, data, elem, true );
- }
+ } );
}
-});
+} );
-function createSafeFragment( document ) {
- var list = nodeNames.split( "|" ),
- safeFrag = document.createDocumentFragment();
+var
- if ( safeFrag.createElement ) {
- while ( list.length ) {
- safeFrag.createElement(
- list.pop()
- );
- }
- }
- return safeFrag;
-}
+ /* eslint-disable max-len */
-var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
- "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
- rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
- rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
- rleadingWhitespace = /^\s+/,
- rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
- rtagName = /<([\w:]+)/,
- rtbody = /<tbody/i,
- rhtml = /<|&#?\w+;/,
- rnoInnerhtml = /<(?:script|style|link)/i,
- // checked="checked" or checked
- rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
- rscriptType = /^$|\/(?:java|ecma)script/i,
- rscriptTypeMasked = /^true\/(.*)/,
- rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
-
- // We have to close these tags to support XHTML (#13200)
- wrapMap = {
- option: [ 1, "<select multiple='multiple'>", "</select>" ],
- legend: [ 1, "<fieldset>", "</fieldset>" ],
- area: [ 1, "<map>", "</map>" ],
- param: [ 1, "<object>", "</object>" ],
- thead: [ 1, "<table>", "</table>" ],
- tr: [ 2, "<table><tbody>", "</tbody></table>" ],
- col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
- td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
-
- // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
- // unless wrapped in a div with non-breaking characters in front of it.
- _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
- },
- safeFragment = createSafeFragment( document ),
- fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+ // See https://github.com/eslint/eslint/issues/3229
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
+ /* eslint-enable */
-function getAll( context, tag ) {
- var elems, elem,
- i = 0,
- found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) :
- typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) :
- undefined;
+ // Support: IE <=10 - 11, Edge 12 - 13
+ // In IE/Edge using regex groups here causes severe slowdowns.
+ // See https://connect.microsoft.com/IE/feedback/details/1736512/
+ rnoInnerhtml = /<script|<style|<link/i,
- if ( !found ) {
- for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
- if ( !tag || jQuery.nodeName( elem, tag ) ) {
- found.push( elem );
- } else {
- jQuery.merge( found, getAll( elem, tag ) );
- }
- }
- }
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptTypeMasked = /^true\/(.*)/,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
- return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
- jQuery.merge( [ context ], found ) :
- found;
-}
+function manipulationTarget( elem, content ) {
+ if ( jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
-// Used in buildFragment, fixes the defaultChecked property
-function fixDefaultChecked( elem ) {
- if ( rcheckableType.test( elem.type ) ) {
- elem.defaultChecked = elem.checked;
+ return elem.getElementsByTagName( "tbody" )[ 0 ] || elem;
}
-}
-// Support: IE<8
-// Manipulating tables requires a tbody
-function manipulationTarget( elem, content ) {
- return jQuery.nodeName( elem, "table" ) &&
- jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
-
- elem.getElementsByTagName("tbody")[0] ||
- elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
- elem;
+ return elem;
}
// Replace/restore the type attribute of script elements for safe DOM manipulation
function disableScript( elem ) {
- elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
+ elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
return elem;
}
function restoreScript( elem ) {
var match = rscriptTypeMasked.exec( elem.type );
+
if ( match ) {
- elem.type = match[1];
+ elem.type = match[ 1 ];
} else {
- elem.removeAttribute("type");
+ elem.removeAttribute( "type" );
}
- return elem;
-}
-// Mark scripts as having already been evaluated
-function setGlobalEval( elems, refElements ) {
- var elem,
- i = 0;
- for ( ; (elem = elems[i]) != null; i++ ) {
- jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
- }
+ return elem;
}
function cloneCopyEvent( src, dest ) {
+ var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
- if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ if ( dest.nodeType !== 1 ) {
return;
}
- var type, i, l,
- oldData = jQuery._data( src ),
- curData = jQuery._data( dest, oldData ),
- events = oldData.events;
+ // 1. Copy private data: events, handlers, etc.
+ if ( dataPriv.hasData( src ) ) {
+ pdataOld = dataPriv.access( src );
+ pdataCur = dataPriv.set( dest, pdataOld );
+ events = pdataOld.events;
- if ( events ) {
- delete curData.handle;
- curData.events = {};
+ if ( events ) {
+ delete pdataCur.handle;
+ pdataCur.events = {};
- for ( type in events ) {
- for ( i = 0, l = events[ type ].length; i < l; i++ ) {
- jQuery.event.add( dest, type, events[ type ][ i ] );
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
}
}
}
- // make the cloned public data object a copy from the original
- if ( curData.data ) {
- curData.data = jQuery.extend( {}, curData.data );
+ // 2. Copy user data
+ if ( dataUser.hasData( src ) ) {
+ udataOld = dataUser.access( src );
+ udataCur = jQuery.extend( {}, udataOld );
+
+ dataUser.set( dest, udataCur );
}
}
-function fixCloneNodeIssues( src, dest ) {
- var nodeName, e, data;
+// Fix IE bugs, see support tests
+function fixInput( src, dest ) {
+ var nodeName = dest.nodeName.toLowerCase();
- // We do not need to do anything for non-Elements
- if ( dest.nodeType !== 1 ) {
- return;
+ // Fails to persist the checked state of a cloned checkbox or radio button.
+ if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ dest.checked = src.checked;
+
+ // Fails to return the selected option to the default selected state when cloning options
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
}
+}
- nodeName = dest.nodeName.toLowerCase();
+function domManip( collection, args, callback, ignored ) {
- // IE6-8 copies events bound via attachEvent when using cloneNode.
- if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
- data = jQuery._data( dest );
+ // Flatten any nested arrays
+ args = concat.apply( [], args );
- for ( e in data.events ) {
- jQuery.removeEvent( dest, e, data.handle );
- }
+ var fragment, first, scripts, hasScripts, node, doc,
+ i = 0,
+ l = collection.length,
+ iNoClone = l - 1,
+ value = args[ 0 ],
+ isFunction = jQuery.isFunction( value );
- // Event data gets referenced instead of copied if the expando gets copied too
- dest.removeAttribute( jQuery.expando );
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction ||
+ ( l > 1 && typeof value === "string" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return collection.each( function( index ) {
+ var self = collection.eq( index );
+ if ( isFunction ) {
+ args[ 0 ] = value.call( this, index, self.html() );
+ }
+ domManip( self, args, callback, ignored );
+ } );
}
- // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
- if ( nodeName === "script" && dest.text !== src.text ) {
- disableScript( dest ).text = src.text;
- restoreScript( dest );
+ if ( l ) {
+ fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
+ first = fragment.firstChild;
- // IE6-10 improperly clones children of object elements using classid.
- // IE10 throws NoModificationAllowedError if parent is null, #12132.
- } else if ( nodeName === "object" ) {
- if ( dest.parentNode ) {
- dest.outerHTML = src.outerHTML;
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
}
- // This path appears unavoidable for IE9. When cloning an object
- // element in IE9, the outerHTML strategy above is not sufficient.
- // If the src has innerHTML and the destination does not,
- // copy the src.innerHTML into the dest.innerHTML. #10324
- if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
- dest.innerHTML = src.innerHTML;
- }
+ // Require either new content or an interest in ignored elements to invoke the callback
+ if ( first || ignored ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
- } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
- // IE6-8 fails to persist the checked state of a cloned checkbox
- // or radio button. Worse, IE6-7 fail to give the cloned element
- // a checked appearance if the defaultChecked value isn't also set
+ // Use the original fragment for the last item
+ // instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
- dest.defaultChecked = dest.checked = src.checked;
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
- // IE6-7 get confused and end up setting the value of a cloned
- // checkbox/radio button to an empty string instead of "on"
- if ( dest.value !== src.value ) {
- dest.value = src.value;
- }
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
- // IE6-8 fails to return the selected option to the default selected
- // state when cloning options
- } else if ( nodeName === "option" ) {
- dest.defaultSelected = dest.selected = src.defaultSelected;
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
- // IE6-8 fails to set the defaultValue to the correct value when
- // cloning other types of input fields
- } else if ( nodeName === "input" || nodeName === "textarea" ) {
- dest.defaultValue = src.defaultValue;
+ callback.call( collection[ i ], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !dataPriv.access( node, "globalEval" ) &&
+ jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl ) {
+ jQuery._evalUrl( node.src );
+ }
+ } else {
+ DOMEval( node.textContent.replace( rcleanScript, "" ), doc );
+ }
+ }
+ }
+ }
+ }
}
+
+ return collection;
}
-jQuery.extend({
- clone: function( elem, dataAndEvents, deepDataAndEvents ) {
- var destElements, node, clone, i, srcElements,
- inPage = jQuery.contains( elem.ownerDocument, elem );
+function remove( elem, selector, keepData ) {
+ var node,
+ nodes = selector ? jQuery.filter( selector, elem ) : elem,
+ i = 0;
- if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
- clone = elem.cloneNode( true );
+ for ( ; ( node = nodes[ i ] ) != null; i++ ) {
+ if ( !keepData && node.nodeType === 1 ) {
+ jQuery.cleanData( getAll( node ) );
+ }
- // IE<=8 does not properly clone detached, unknown element nodes
- } else {
- fragmentDiv.innerHTML = elem.outerHTML;
- fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ if ( node.parentNode ) {
+ if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
+ setGlobalEval( getAll( node, "script" ) );
+ }
+ node.parentNode.removeChild( node );
}
+ }
+
+ return elem;
+}
- if ( (!support.noCloneEvent || !support.noCloneChecked) &&
- (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+jQuery.extend( {
+ htmlPrefilter: function( html ) {
+ return html.replace( rxhtmlTag, "<$1></$2>" );
+ },
+
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var i, l, srcElements, destElements,
+ clone = elem.cloneNode( true ),
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ // Fix IE cloning issues
+ if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
+ !jQuery.isXMLDoc( elem ) ) {
- // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
destElements = getAll( clone );
srcElements = getAll( elem );
- // Fix all IE cloning issues
- for ( i = 0; (node = srcElements[i]) != null; ++i ) {
- // Ensure that the destination node is not null; Fixes #9587
- if ( destElements[i] ) {
- fixCloneNodeIssues( node, destElements[i] );
- }
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ fixInput( srcElements[ i ], destElements[ i ] );
}
}
@@ -5516,8 +5730,8 @@ jQuery.extend({
srcElements = srcElements || getAll( elem );
destElements = destElements || getAll( clone );
- for ( i = 0; (node = srcElements[i]) != null; i++ ) {
- cloneCopyEvent( node, destElements[i] );
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ cloneCopyEvent( srcElements[ i ], destElements[ i ] );
}
} else {
cloneCopyEvent( elem, clone );
@@ -5530,154 +5744,18 @@ jQuery.extend({
setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
}
- destElements = srcElements = node = null;
-
// Return the cloned set
return clone;
},
- buildFragment: function( elems, context, scripts, selection ) {
- var j, elem, contains,
- tmp, tag, tbody, wrap,
- l = elems.length,
-
- // Ensure a safe fragment
- safe = createSafeFragment( context ),
-
- nodes = [],
+ cleanData: function( elems ) {
+ var data, elem, type,
+ special = jQuery.event.special,
i = 0;
- for ( ; i < l; i++ ) {
- elem = elems[ i ];
-
- if ( elem || elem === 0 ) {
-
- // Add nodes directly
- if ( jQuery.type( elem ) === "object" ) {
- jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
-
- // Convert non-html into a text node
- } else if ( !rhtml.test( elem ) ) {
- nodes.push( context.createTextNode( elem ) );
-
- // Convert html into DOM nodes
- } else {
- tmp = tmp || safe.appendChild( context.createElement("div") );
-
- // Deserialize a standard representation
- tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
- wrap = wrapMap[ tag ] || wrapMap._default;
-
- tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
-
- // Descend through wrappers to the right content
- j = wrap[0];
- while ( j-- ) {
- tmp = tmp.lastChild;
- }
-
- // Manually add leading whitespace removed by IE
- if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
- nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
- }
-
- // Remove IE's autoinserted <tbody> from table fragments
- if ( !support.tbody ) {
-
- // String was a <table>, *may* have spurious <tbody>
- elem = tag === "table" && !rtbody.test( elem ) ?
- tmp.firstChild :
-
- // String was a bare <thead> or <tfoot>
- wrap[1] === "<table>" && !rtbody.test( elem ) ?
- tmp :
- 0;
-
- j = elem && elem.childNodes.length;
- while ( j-- ) {
- if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
- elem.removeChild( tbody );
- }
- }
- }
-
- jQuery.merge( nodes, tmp.childNodes );
-
- // Fix #12392 for WebKit and IE > 9
- tmp.textContent = "";
-
- // Fix #12392 for oldIE
- while ( tmp.firstChild ) {
- tmp.removeChild( tmp.firstChild );
- }
-
- // Remember the top-level container for proper cleanup
- tmp = safe.lastChild;
- }
- }
- }
-
- // Fix #11356: Clear elements from fragment
- if ( tmp ) {
- safe.removeChild( tmp );
- }
-
- // Reset defaultChecked for any radios and checkboxes
- // about to be appended to the DOM in IE 6/7 (#8060)
- if ( !support.appendChecked ) {
- jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
- }
-
- i = 0;
- while ( (elem = nodes[ i++ ]) ) {
-
- // #4087 - If origin and destination elements are the same, and this is
- // that element, do not do anything
- if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
- continue;
- }
-
- contains = jQuery.contains( elem.ownerDocument, elem );
-
- // Append to fragment
- tmp = getAll( safe.appendChild( elem ), "script" );
-
- // Preserve script evaluation history
- if ( contains ) {
- setGlobalEval( tmp );
- }
-
- // Capture executables
- if ( scripts ) {
- j = 0;
- while ( (elem = tmp[ j++ ]) ) {
- if ( rscriptType.test( elem.type || "" ) ) {
- scripts.push( elem );
- }
- }
- }
- }
-
- tmp = null;
-
- return safe;
- },
-
- cleanData: function( elems, /* internal */ acceptData ) {
- var elem, type, id, data,
- i = 0,
- internalKey = jQuery.expando,
- cache = jQuery.cache,
- deleteExpando = support.deleteExpando,
- special = jQuery.event.special;
-
- for ( ; (elem = elems[i]) != null; i++ ) {
- if ( acceptData || jQuery.acceptData( elem ) ) {
-
- id = elem[ internalKey ];
- data = id && cache[ id ];
-
- if ( data ) {
+ for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
+ if ( acceptData( elem ) ) {
+ if ( ( data = elem[ dataPriv.expando ] ) ) {
if ( data.events ) {
for ( type in data.events ) {
if ( special[ type ] ) {
@@ -5690,116 +5768,88 @@ jQuery.extend({
}
}
- // Remove cache only if it was not already removed by jQuery.event.remove
- if ( cache[ id ] ) {
-
- delete cache[ id ];
-
- // IE does not allow us to delete expando properties from nodes,
- // nor does it have a removeAttribute function on Document nodes;
- // we must handle all of these cases
- if ( deleteExpando ) {
- delete elem[ internalKey ];
-
- } else if ( typeof elem.removeAttribute !== strundefined ) {
- elem.removeAttribute( internalKey );
-
- } else {
- elem[ internalKey ] = null;
- }
+ // Support: Chrome <=35 - 45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataPriv.expando ] = undefined;
+ }
+ if ( elem[ dataUser.expando ] ) {
- deletedIds.push( id );
- }
+ // Support: Chrome <=35 - 45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataUser.expando ] = undefined;
}
}
}
}
-});
+} );
+
+jQuery.fn.extend( {
+ detach: function( selector ) {
+ return remove( this, selector, true );
+ },
+
+ remove: function( selector ) {
+ return remove( this, selector );
+ },
-jQuery.fn.extend({
text: function( value ) {
return access( this, function( value ) {
return value === undefined ?
jQuery.text( this ) :
- this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ this.empty().each( function() {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ this.textContent = value;
+ }
+ } );
}, null, value, arguments.length );
},
append: function() {
- return this.domManip( arguments, function( elem ) {
+ return domManip( this, arguments, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
var target = manipulationTarget( this, elem );
target.appendChild( elem );
}
- });
+ } );
},
prepend: function() {
- return this.domManip( arguments, function( elem ) {
+ return domManip( this, arguments, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
var target = manipulationTarget( this, elem );
target.insertBefore( elem, target.firstChild );
}
- });
+ } );
},
before: function() {
- return this.domManip( arguments, function( elem ) {
+ return domManip( this, arguments, function( elem ) {
if ( this.parentNode ) {
this.parentNode.insertBefore( elem, this );
}
- });
+ } );
},
after: function() {
- return this.domManip( arguments, function( elem ) {
+ return domManip( this, arguments, function( elem ) {
if ( this.parentNode ) {
this.parentNode.insertBefore( elem, this.nextSibling );
}
- });
- },
-
- remove: function( selector, keepData /* Internal Use Only */ ) {
- var elem,
- elems = selector ? jQuery.filter( selector, this ) : this,
- i = 0;
-
- for ( ; (elem = elems[i]) != null; i++ ) {
-
- if ( !keepData && elem.nodeType === 1 ) {
- jQuery.cleanData( getAll( elem ) );
- }
-
- if ( elem.parentNode ) {
- if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
- setGlobalEval( getAll( elem, "script" ) );
- }
- elem.parentNode.removeChild( elem );
- }
- }
-
- return this;
+ } );
},
empty: function() {
var elem,
i = 0;
- for ( ; (elem = this[i]) != null; i++ ) {
- // Remove element nodes and prevent memory leaks
+ for ( ; ( elem = this[ i ] ) != null; i++ ) {
if ( elem.nodeType === 1 ) {
- jQuery.cleanData( getAll( elem, false ) );
- }
- // Remove any remaining nodes
- while ( elem.firstChild ) {
- elem.removeChild( elem.firstChild );
- }
+ // Prevent memory leaks
+ jQuery.cleanData( getAll( elem, false ) );
- // If this is a select, ensure that it displays empty (#12336)
- // Support: IE<9
- if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
- elem.options.length = 0;
+ // Remove any remaining nodes
+ elem.textContent = "";
}
}
@@ -5810,9 +5860,9 @@ jQuery.fn.extend({
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
- return this.map(function() {
+ return this.map( function() {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
- });
+ } );
},
html: function( value ) {
@@ -5821,24 +5871,21 @@ jQuery.fn.extend({
i = 0,
l = this.length;
- if ( value === undefined ) {
- return elem.nodeType === 1 ?
- elem.innerHTML.replace( rinlinejQuery, "" ) :
- undefined;
+ if ( value === undefined && elem.nodeType === 1 ) {
+ return elem.innerHTML;
}
// See if we can take a shortcut and just use innerHTML
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
- ( support.htmlSerialize || !rnoshimcache.test( value ) ) &&
- ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
- !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
+ !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
- value = value.replace( rxhtmlTag, "<$1></$2>" );
+ value = jQuery.htmlPrefilter( value );
try {
- for (; i < l; i++ ) {
+ for ( ; i < l; i++ ) {
+ elem = this[ i ] || {};
+
// Remove element nodes and prevent memory leaks
- elem = this[i] || {};
if ( elem.nodeType === 1 ) {
jQuery.cleanData( getAll( elem, false ) );
elem.innerHTML = value;
@@ -5848,7 +5895,7 @@ jQuery.fn.extend({
elem = 0;
// If using innerHTML throws an exception, use the fallback method
- } catch(e) {}
+ } catch ( e ) {}
}
if ( elem ) {
@@ -5858,117 +5905,25 @@ jQuery.fn.extend({
},
replaceWith: function() {
- var arg = arguments[ 0 ];
-
- // Make the changes, replacing each context element with the new content
- this.domManip( arguments, function( elem ) {
- arg = this.parentNode;
-
- jQuery.cleanData( getAll( this ) );
-
- if ( arg ) {
- arg.replaceChild( elem, this );
- }
- });
-
- // Force removal if there was no new content (e.g., from empty arguments)
- return arg && (arg.length || arg.nodeType) ? this : this.remove();
- },
-
- detach: function( selector ) {
- return this.remove( selector, true );
- },
-
- domManip: function( args, callback ) {
+ var ignored = [];
- // Flatten any nested arrays
- args = concat.apply( [], args );
+ // Make the changes, replacing each non-ignored context element with the new content
+ return domManip( this, arguments, function( elem ) {
+ var parent = this.parentNode;
- var first, node, hasScripts,
- scripts, doc, fragment,
- i = 0,
- l = this.length,
- set = this,
- iNoClone = l - 1,
- value = args[0],
- isFunction = jQuery.isFunction( value );
-
- // We can't cloneNode fragments that contain checked, in WebKit
- if ( isFunction ||
- ( l > 1 && typeof value === "string" &&
- !support.checkClone && rchecked.test( value ) ) ) {
- return this.each(function( index ) {
- var self = set.eq( index );
- if ( isFunction ) {
- args[0] = value.call( this, index, self.html() );
+ if ( jQuery.inArray( this, ignored ) < 0 ) {
+ jQuery.cleanData( getAll( this ) );
+ if ( parent ) {
+ parent.replaceChild( elem, this );
}
- self.domManip( args, callback );
- });
- }
-
- if ( l ) {
- fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
- first = fragment.firstChild;
-
- if ( fragment.childNodes.length === 1 ) {
- fragment = first;
}
- if ( first ) {
- scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
- hasScripts = scripts.length;
-
- // Use the original fragment for the last item instead of the first because it can end up
- // being emptied incorrectly in certain situations (#8070).
- for ( ; i < l; i++ ) {
- node = fragment;
-
- if ( i !== iNoClone ) {
- node = jQuery.clone( node, true, true );
-
- // Keep references to cloned scripts for later restoration
- if ( hasScripts ) {
- jQuery.merge( scripts, getAll( node, "script" ) );
- }
- }
-
- callback.call( this[i], node, i );
- }
-
- if ( hasScripts ) {
- doc = scripts[ scripts.length - 1 ].ownerDocument;
-
- // Reenable scripts
- jQuery.map( scripts, restoreScript );
-
- // Evaluate executable scripts on first document insertion
- for ( i = 0; i < hasScripts; i++ ) {
- node = scripts[ i ];
- if ( rscriptType.test( node.type || "" ) &&
- !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
-
- if ( node.src ) {
- // Optional AJAX dependency, but won't run scripts if not present
- if ( jQuery._evalUrl ) {
- jQuery._evalUrl( node.src );
- }
- } else {
- jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
- }
- }
- }
- }
-
- // Fix #11809: Avoid leaking memory
- fragment = first = null;
- }
- }
-
- return this;
+ // Force callback invocation
+ }, ignored );
}
-});
+} );
-jQuery.each({
+jQuery.each( {
appendTo: "append",
prependTo: "prepend",
insertBefore: "before",
@@ -5977,570 +5932,270 @@ jQuery.each({
}, function( name, original ) {
jQuery.fn[ name ] = function( selector ) {
var elems,
- i = 0,
ret = [],
insert = jQuery( selector ),
- last = insert.length - 1;
+ last = insert.length - 1,
+ i = 0;
for ( ; i <= last; i++ ) {
- elems = i === last ? this : this.clone(true);
- jQuery( insert[i] )[ original ]( elems );
+ elems = i === last ? this : this.clone( true );
+ jQuery( insert[ i ] )[ original ]( elems );
- // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // .get() because push.apply(_, arraylike) throws on ancient WebKit
push.apply( ret, elems.get() );
}
return this.pushStack( ret );
};
-});
-
-
-var iframe,
- elemdisplay = {};
-
-/**
- * Retrieve the actual display of a element
- * @param {String} name nodeName of the element
- * @param {Object} doc Document object
- */
-// Called only from within defaultDisplay
-function actualDisplay( name, doc ) {
- var style,
- elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
-
- // getDefaultComputedStyle might be reliably used only on attached element
- display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
-
- // Use of this method is a temporary fix (more like optmization) until something better comes along,
- // since it was removed from specification and supported only in FF
- style.display : jQuery.css( elem[ 0 ], "display" );
-
- // We don't have any data stored on the element,
- // so use "detach" method as fast way to get rid of the element
- elem.detach();
+} );
+var rmargin = ( /^margin/ );
- return display;
-}
-
-/**
- * Try to determine the default display value of an element
- * @param {String} nodeName
- */
-function defaultDisplay( nodeName ) {
- var doc = document,
- display = elemdisplay[ nodeName ];
-
- if ( !display ) {
- display = actualDisplay( nodeName, doc );
-
- // If the simple way fails, read from inside an iframe
- if ( display === "none" || !display ) {
-
- // Use the already-created iframe if possible
- iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
- // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
- doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
+var getStyles = function( elem ) {
- // Support: IE
- doc.write();
- doc.close();
+ // Support: IE <=11 only, Firefox <=30 (#15098, #14150)
+ // IE throws on elements created in popups
+ // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+ var view = elem.ownerDocument.defaultView;
- display = actualDisplay( nodeName, doc );
- iframe.detach();
+ if ( !view || !view.opener ) {
+ view = window;
}
- // Store the correct default display
- elemdisplay[ nodeName ] = display;
- }
-
- return display;
-}
-
+ return view.getComputedStyle( elem );
+ };
-(function() {
- var shrinkWrapBlocksVal;
- support.shrinkWrapBlocks = function() {
- if ( shrinkWrapBlocksVal != null ) {
- return shrinkWrapBlocksVal;
- }
- // Will be changed later if needed.
- shrinkWrapBlocksVal = false;
+( function() {
- // Minified: var b,c,d
- var div, body, container;
+ // Executing both pixelPosition & boxSizingReliable tests require only one layout
+ // so they're executed at the same time to save the second computation.
+ function computeStyleTests() {
- body = document.getElementsByTagName( "body" )[ 0 ];
- if ( !body || !body.style ) {
- // Test fired too early or in an unsupported environment, exit.
+ // This is a singleton, we need to execute it only once
+ if ( !div ) {
return;
}
- // Setup
- div = document.createElement( "div" );
- container = document.createElement( "div" );
- container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
- body.appendChild( container ).appendChild( div );
-
- // Support: IE6
- // Check if elements with layout shrink-wrap their children
- if ( typeof div.style.zoom !== strundefined ) {
- // Reset CSS: box-sizing; display; margin; border
- div.style.cssText =
- // Support: Firefox<29, Android 2.3
- // Vendor-prefix box-sizing
- "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
- "box-sizing:content-box;display:block;margin:0;border:0;" +
- "padding:1px;width:1px;zoom:1";
- div.appendChild( document.createElement( "div" ) ).style.width = "5px";
- shrinkWrapBlocksVal = div.offsetWidth !== 3;
- }
-
- body.removeChild( container );
-
- return shrinkWrapBlocksVal;
- };
-
-})();
-var rmargin = (/^margin/);
-
-var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
-
-
+ div.style.cssText =
+ "box-sizing:border-box;" +
+ "position:relative;display:block;" +
+ "margin:auto;border:1px;padding:1px;" +
+ "top:1%;width:50%";
+ div.innerHTML = "";
+ documentElement.appendChild( container );
-var getStyles, curCSS,
- rposition = /^(top|right|bottom|left)$/;
+ var divStyle = window.getComputedStyle( div );
+ pixelPositionVal = divStyle.top !== "1%";
-if ( window.getComputedStyle ) {
- getStyles = function( elem ) {
- return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
- };
+ // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
+ reliableMarginLeftVal = divStyle.marginLeft === "2px";
+ boxSizingReliableVal = divStyle.width === "4px";
- curCSS = function( elem, name, computed ) {
- var width, minWidth, maxWidth, ret,
- style = elem.style;
+ // Support: Android 4.0 - 4.3 only
+ // Some styles come back with percentage values, even though they shouldn't
+ div.style.marginRight = "50%";
+ pixelMarginRightVal = divStyle.marginRight === "4px";
- computed = computed || getStyles( elem );
+ documentElement.removeChild( container );
- // getPropertyValue is only needed for .css('filter') in IE9, see #12537
- ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
-
- if ( computed ) {
+ // Nullify the div so it wouldn't be stored in the memory and
+ // it will also be a sign that checks already performed
+ div = null;
+ }
- if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
- ret = jQuery.style( elem, name );
- }
+ var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,
+ container = document.createElement( "div" ),
+ div = document.createElement( "div" );
- // A tribute to the "awesome hack by Dean Edwards"
- // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
- // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
- // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
- if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+ // Finish early in limited (non-browser) environments
+ if ( !div.style ) {
+ return;
+ }
- // Remember the original values
- width = style.width;
- minWidth = style.minWidth;
- maxWidth = style.maxWidth;
+ // Support: IE <=9 - 11 only
+ // Style of cloned element affects source element cloned (#8908)
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
- // Put in the new values to get a computed value out
- style.minWidth = style.maxWidth = style.width = ret;
- ret = computed.width;
+ container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
+ "padding:0;margin-top:1px;position:absolute";
+ container.appendChild( div );
- // Revert the changed values
- style.width = width;
- style.minWidth = minWidth;
- style.maxWidth = maxWidth;
- }
+ jQuery.extend( support, {
+ pixelPosition: function() {
+ computeStyleTests();
+ return pixelPositionVal;
+ },
+ boxSizingReliable: function() {
+ computeStyleTests();
+ return boxSizingReliableVal;
+ },
+ pixelMarginRight: function() {
+ computeStyleTests();
+ return pixelMarginRightVal;
+ },
+ reliableMarginLeft: function() {
+ computeStyleTests();
+ return reliableMarginLeftVal;
}
+ } );
+} )();
- // Support: IE
- // IE returns zIndex value as an integer.
- return ret === undefined ?
- ret :
- ret + "";
- };
-} else if ( document.documentElement.currentStyle ) {
- getStyles = function( elem ) {
- return elem.currentStyle;
- };
- curCSS = function( elem, name, computed ) {
- var left, rs, rsLeft, ret,
- style = elem.style;
+function curCSS( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+ style = elem.style;
- computed = computed || getStyles( elem );
- ret = computed ? computed[ name ] : undefined;
+ computed = computed || getStyles( elem );
- // Avoid setting ret to empty string here
- // so we don't default to auto
- if ( ret == null && style && style[ name ] ) {
- ret = style[ name ];
- }
+ // Support: IE <=9 only
+ // getPropertyValue is only needed for .css('filter') (#12537)
+ if ( computed ) {
+ ret = computed.getPropertyValue( name ) || computed[ name ];
- // From the awesome hack by Dean Edwards
- // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
- // If we're not dealing with a regular pixel number
- // but a number that has a weird ending, we need to convert it to pixels
- // but not position css attributes, as those are proportional to the parent element instead
- // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
- if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Android Browser returns percentage for some values,
+ // but width seems to be reliably pixels.
+ // This is against the CSSOM draft spec:
+ // https://drafts.csswg.org/cssom/#resolved-values
+ if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {
// Remember the original values
- left = style.left;
- rs = elem.runtimeStyle;
- rsLeft = rs && rs.left;
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
// Put in the new values to get a computed value out
- if ( rsLeft ) {
- rs.left = elem.currentStyle.left;
- }
- style.left = name === "fontSize" ? "1em" : ret;
- ret = style.pixelLeft + "px";
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
// Revert the changed values
- style.left = left;
- if ( rsLeft ) {
- rs.left = rsLeft;
- }
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
}
+ }
+
+ return ret !== undefined ?
- // Support: IE
+ // Support: IE <=9 - 11 only
// IE returns zIndex value as an integer.
- return ret === undefined ?
- ret :
- ret + "" || "auto";
- };
+ ret + "" :
+ ret;
}
-
-
function addGetHookIf( conditionFn, hookFn ) {
+
// Define the hook, we'll check on the first run if it's really needed.
return {
get: function() {
- var condition = conditionFn();
+ if ( conditionFn() ) {
- if ( condition == null ) {
- // The test was not ready at this point; screw the hook this time
- // but check again when needed next time.
- return;
- }
-
- if ( condition ) {
- // Hook not needed (or it's not possible to use it due to missing dependency),
- // remove it.
- // Since there are no other hooks for marginRight, remove the whole object.
+ // Hook not needed (or it's not possible to use it due
+ // to missing dependency), remove it.
delete this.get;
return;
}
// Hook needed; redefine it so that the support test is not executed again.
-
- return (this.get = hookFn).apply( this, arguments );
+ return ( this.get = hookFn ).apply( this, arguments );
}
};
}
-(function() {
- // Minified: var b,c,d,e,f,g, h,i
- var div, style, a, pixelPositionVal, boxSizingReliableVal,
- reliableHiddenOffsetsVal, reliableMarginRightVal;
-
- // Setup
- div = document.createElement( "div" );
- div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
- a = div.getElementsByTagName( "a" )[ 0 ];
- style = a && a.style;
-
- // Finish early in limited (non-browser) environments
- if ( !style ) {
- return;
- }
-
- style.cssText = "float:left;opacity:.5";
-
- // Support: IE<9
- // Make sure that element opacity exists (as opposed to filter)
- support.opacity = style.opacity === "0.5";
-
- // Verify style float existence
- // (IE uses styleFloat instead of cssFloat)
- support.cssFloat = !!style.cssFloat;
-
- div.style.backgroundClip = "content-box";
- div.cloneNode( true ).style.backgroundClip = "";
- support.clearCloneStyle = div.style.backgroundClip === "content-box";
-
- // Support: Firefox<29, Android 2.3
- // Vendor-prefix box-sizing
- support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" ||
- style.WebkitBoxSizing === "";
-
- jQuery.extend(support, {
- reliableHiddenOffsets: function() {
- if ( reliableHiddenOffsetsVal == null ) {
- computeStyleTests();
- }
- return reliableHiddenOffsetsVal;
- },
-
- boxSizingReliable: function() {
- if ( boxSizingReliableVal == null ) {
- computeStyleTests();
- }
- return boxSizingReliableVal;
- },
-
- pixelPosition: function() {
- if ( pixelPositionVal == null ) {
- computeStyleTests();
- }
- return pixelPositionVal;
- },
-
- // Support: Android 2.3
- reliableMarginRight: function() {
- if ( reliableMarginRightVal == null ) {
- computeStyleTests();
- }
- return reliableMarginRightVal;
- }
- });
-
- function computeStyleTests() {
- // Minified: var b,c,d,j
- var div, body, container, contents;
-
- body = document.getElementsByTagName( "body" )[ 0 ];
- if ( !body || !body.style ) {
- // Test fired too early or in an unsupported environment, exit.
- return;
- }
-
- // Setup
- div = document.createElement( "div" );
- container = document.createElement( "div" );
- container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
- body.appendChild( container ).appendChild( div );
-
- div.style.cssText =
- // Support: Firefox<29, Android 2.3
- // Vendor-prefix box-sizing
- "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
- "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
- "border:1px;padding:1px;width:4px;position:absolute";
-
- // Support: IE<9
- // Assume reasonable values in the absence of getComputedStyle
- pixelPositionVal = boxSizingReliableVal = false;
- reliableMarginRightVal = true;
-
- // Check for getComputedStyle so that this code is not run in IE<9.
- if ( window.getComputedStyle ) {
- pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
- boxSizingReliableVal =
- ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
-
- // Support: Android 2.3
- // Div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container (#3333)
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- contents = div.appendChild( document.createElement( "div" ) );
-
- // Reset CSS: box-sizing; display; margin; border; padding
- contents.style.cssText = div.style.cssText =
- // Support: Firefox<29, Android 2.3
- // Vendor-prefix box-sizing
- "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
- "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
- contents.style.marginRight = contents.style.width = "0";
- div.style.width = "1px";
-
- reliableMarginRightVal =
- !parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight );
- }
-
- // Support: IE8
- // Check if table cells still have offsetWidth/Height when they are set
- // to display:none and there are still other visible table cells in a
- // table row; if so, offsetWidth/Height are not reliable for use when
- // determining if an element has been hidden directly using
- // display:none (it is still safe to use offsets if a parent element is
- // hidden; don safety goggles and see bug #4512 for more information).
- div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
- contents = div.getElementsByTagName( "td" );
- contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
- reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
- if ( reliableHiddenOffsetsVal ) {
- contents[ 0 ].style.display = "";
- contents[ 1 ].style.display = "none";
- reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
- }
-
- body.removeChild( container );
- }
-
-})();
-
-
-// A method for quickly swapping in/out CSS properties to get correct calculations.
-jQuery.swap = function( elem, options, callback, args ) {
- var ret, name,
- old = {};
-
- // Remember the old values, and insert the new ones
- for ( name in options ) {
- old[ name ] = elem.style[ name ];
- elem.style[ name ] = options[ name ];
- }
-
- ret = callback.apply( elem, args || [] );
-
- // Revert the old values
- for ( name in options ) {
- elem.style[ name ] = old[ name ];
- }
-
- return ret;
-};
-
-
var
- ralpha = /alpha\([^)]*\)/i,
- ropacity = /opacity\s*=\s*([^)]*)/,
- // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
- // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ // Swappable if display is none or starts with table
+ // except "table", "table-cell", or "table-caption"
+ // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
- rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
- rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
-
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssNormalTransform = {
letterSpacing: "0",
fontWeight: "400"
},
- cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
-
+ cssPrefixes = [ "Webkit", "Moz", "ms" ],
+ emptyStyle = document.createElement( "div" ).style;
-// return a css property mapped to a potentially vendor prefixed property
-function vendorPropName( style, name ) {
+// Return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( name ) {
- // shortcut for names that are not vendor prefixed
- if ( name in style ) {
+ // Shortcut for names that are not vendor prefixed
+ if ( name in emptyStyle ) {
return name;
}
- // check for vendor prefixed names
- var capName = name.charAt(0).toUpperCase() + name.slice(1),
- origName = name,
+ // Check for vendor prefixed names
+ var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
i = cssPrefixes.length;
while ( i-- ) {
name = cssPrefixes[ i ] + capName;
- if ( name in style ) {
+ if ( name in emptyStyle ) {
return name;
}
}
-
- return origName;
-}
-
-function showHide( elements, show ) {
- var display, elem, hidden,
- values = [],
- index = 0,
- length = elements.length;
-
- for ( ; index < length; index++ ) {
- elem = elements[ index ];
- if ( !elem.style ) {
- continue;
- }
-
- values[ index ] = jQuery._data( elem, "olddisplay" );
- display = elem.style.display;
- if ( show ) {
- // Reset the inline display of this element to learn if it is
- // being hidden by cascaded rules or not
- if ( !values[ index ] && display === "none" ) {
- elem.style.display = "";
- }
-
- // Set elements which have been overridden with display: none
- // in a stylesheet to whatever the default browser style is
- // for such an element
- if ( elem.style.display === "" && isHidden( elem ) ) {
- values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
- }
- } else {
- hidden = isHidden( elem );
-
- if ( display && display !== "none" || !hidden ) {
- jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
- }
- }
- }
-
- // Set the display of most of the elements in a second loop
- // to avoid the constant reflow
- for ( index = 0; index < length; index++ ) {
- elem = elements[ index ];
- if ( !elem.style ) {
- continue;
- }
- if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
- elem.style.display = show ? values[ index ] || "" : "none";
- }
- }
-
- return elements;
}
function setPositiveNumber( elem, value, subtract ) {
- var matches = rnumsplit.exec( value );
+
+ // Any relative (+/-) values have already been
+ // normalized at this point
+ var matches = rcssNum.exec( value );
return matches ?
+
// Guard against undefined "subtract", e.g., when used as in cssHooks
- Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
value;
}
function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
var i = extra === ( isBorderBox ? "border" : "content" ) ?
+
// If we already have the right measurement, avoid augmentation
4 :
+
// Otherwise initialize for horizontal or vertical properties
name === "width" ? 1 : 0,
val = 0;
for ( ; i < 4; i += 2 ) {
- // both box models exclude margin, so add it if we want it
+
+ // Both box models exclude margin, so add it if we want it
if ( extra === "margin" ) {
val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
}
if ( isBorderBox ) {
+
// border-box includes padding, so remove it if we want content
if ( extra === "content" ) {
val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
}
- // at this point, extra isn't border nor margin, so remove border
+ // At this point, extra isn't border nor margin, so remove border
if ( extra !== "margin" ) {
val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
} else {
- // at this point, extra isn't content, so add padding
+
+ // At this point, extra isn't content, so add padding
val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
- // at this point, extra isn't content nor padding, so add border
+ // At this point, extra isn't content nor padding, so add border
if ( extra !== "padding" ) {
val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
@@ -6553,15 +6208,23 @@ function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
function getWidthOrHeight( elem, name, extra ) {
// Start with offset property, which is equivalent to the border-box value
- var valueIsBorderBox = true,
- val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ var val,
+ valueIsBorderBox = true,
styles = getStyles( elem ),
- isBorderBox = support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+ isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
- // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // Support: IE <=11 only
+ // Running getBoundingClientRect on a disconnected node
+ // in IE throws an error.
+ if ( elem.getClientRects().length ) {
+ val = elem.getBoundingClientRect()[ name ];
+ }
+
+ // Some non-html elements return undefined for offsetWidth, so check for null/undefined
// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
if ( val <= 0 || val == null ) {
+
// Fall back to computed then uncomputed css if necessary
val = curCSS( elem, name, styles );
if ( val < 0 || val == null ) {
@@ -6569,19 +6232,20 @@ function getWidthOrHeight( elem, name, extra ) {
}
// Computed unit is not pixels. Stop here and return.
- if ( rnumnonpx.test(val) ) {
+ if ( rnumnonpx.test( val ) ) {
return val;
}
- // we need the check for style in case a browser which returns unreliable values
+ // Check for style in case a browser which returns unreliable values
// for getComputedStyle silently falls back to the reliable elem.style
- valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );
+ valueIsBorderBox = isBorderBox &&
+ ( support.boxSizingReliable() || val === elem.style[ name ] );
// Normalize "", auto, and prepare for extra
val = parseFloat( val ) || 0;
}
- // use the active box-sizing model to add/subtract irrelevant styles
+ // Use the active box-sizing model to add/subtract irrelevant styles
return ( val +
augmentWidthOrHeight(
elem,
@@ -6593,13 +6257,15 @@ function getWidthOrHeight( elem, name, extra ) {
) + "px";
}
-jQuery.extend({
+jQuery.extend( {
+
// Add in style property hooks for overriding the default
// behavior of getting and setting a style property
cssHooks: {
opacity: {
get: function( elem, computed ) {
if ( computed ) {
+
// We should always get a number back from opacity
var ret = curCSS( elem, "opacity" );
return ret === "" ? "1" : ret;
@@ -6610,6 +6276,7 @@ jQuery.extend({
// Don't automatically add "px" to these possibly-unitless properties
cssNumber: {
+ "animationIterationCount": true,
"columnCount": true,
"fillOpacity": true,
"flexGrow": true,
@@ -6627,12 +6294,12 @@ jQuery.extend({
// Add in properties whose names you wish to fix before
// setting or getting the value
cssProps: {
- // normalize float css property
- "float": support.cssFloat ? "cssFloat" : "styleFloat"
+ "float": "cssFloat"
},
// Get and set the style property on a DOM Node
style: function( elem, name, value, extra ) {
+
// Don't set styles on text and comment nodes
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
return;
@@ -6643,52 +6310,52 @@ jQuery.extend({
origName = jQuery.camelCase( name ),
style = elem.style;
- name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+ name = jQuery.cssProps[ origName ] ||
+ ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
- // gets hook for the prefixed version
- // followed by the unprefixed version
+ // Gets hook for the prefixed version, then unprefixed version
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// Check if we're setting a value
if ( value !== undefined ) {
type = typeof value;
- // convert relative number strings (+= or -=) to relative numbers. #7345
- if ( type === "string" && (ret = rrelNum.exec( value )) ) {
- value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Convert "+=" or "-=" to relative numbers (#7345)
+ if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
+ value = adjustCSS( elem, name, ret );
+
// Fixes bug #9237
type = "number";
}
- // Make sure that null and NaN values aren't set. See: #7116
+ // Make sure that null and NaN values aren't set (#7116)
if ( value == null || value !== value ) {
return;
}
- // If a number was passed in, add 'px' to the (except for certain CSS properties)
- if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
- value += "px";
+ // If a number was passed in, add the unit (except for certain CSS properties)
+ if ( type === "number" ) {
+ value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
}
- // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
- // but it would mean to define eight (for every problematic property) identical functions
- if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ // background-* props affect original clone's values
+ if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
style[ name ] = "inherit";
}
// If a hook was provided, use that value, otherwise just set the specified value
- if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+ if ( !hooks || !( "set" in hooks ) ||
+ ( value = hooks.set( elem, value, extra ) ) !== undefined ) {
- // Support: IE
- // Swallow errors from 'invalid' CSS values (#5509)
- try {
- style[ name ] = value;
- } catch(e) {}
+ style[ name ] = value;
}
} else {
+
// If a hook was provided get the non-computed value from there
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ if ( hooks && "get" in hooks &&
+ ( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
+
return ret;
}
@@ -6698,14 +6365,14 @@ jQuery.extend({
},
css: function( elem, name, extra, styles ) {
- var num, val, hooks,
+ var val, num, hooks,
origName = jQuery.camelCase( name );
// Make sure that we're working with the right name
- name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+ name = jQuery.cssProps[ origName ] ||
+ ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
- // gets hook for the prefixed version
- // followed by the unprefixed version
+ // Try prefixed name followed by the unprefixed name
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// If a hook was provided get the computed value from there
@@ -6718,106 +6385,82 @@ jQuery.extend({
val = curCSS( elem, name, styles );
}
- //convert "normal" to computed value
+ // Convert "normal" to computed value
if ( val === "normal" && name in cssNormalTransform ) {
val = cssNormalTransform[ name ];
}
- // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ // Make numeric if forced or a qualifier was provided and val looks numeric
if ( extra === "" || extra ) {
num = parseFloat( val );
- return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ return extra === true || isFinite( num ) ? num || 0 : val;
}
return val;
}
-});
+} );
-jQuery.each([ "height", "width" ], function( i, name ) {
+jQuery.each( [ "height", "width" ], function( i, name ) {
jQuery.cssHooks[ name ] = {
get: function( elem, computed, extra ) {
if ( computed ) {
- // certain elements can have dimension info if we invisibly show them
- // however, it must have a current display style that would benefit from this
- return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
- jQuery.swap( elem, cssShow, function() {
- return getWidthOrHeight( elem, name, extra );
- }) :
- getWidthOrHeight( elem, name, extra );
+
+ // Certain elements can have dimension info if we invisibly show them
+ // but it must have a current display style that would benefit
+ return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
+
+ // Support: Safari 8+
+ // Table columns in Safari have non-zero offsetWidth & zero
+ // getBoundingClientRect().width unless display is changed.
+ // Support: IE <=11 only
+ // Running getBoundingClientRect on a disconnected node
+ // in IE throws an error.
+ ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
+ swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ } ) :
+ getWidthOrHeight( elem, name, extra );
}
},
set: function( elem, value, extra ) {
- var styles = extra && getStyles( elem );
- return setPositiveNumber( elem, value, extra ?
- augmentWidthOrHeight(
+ var matches,
+ styles = extra && getStyles( elem ),
+ subtract = extra && augmentWidthOrHeight(
elem,
name,
extra,
- support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
styles
- ) : 0
- );
- }
- };
-});
+ );
-if ( !support.opacity ) {
- jQuery.cssHooks.opacity = {
- get: function( elem, computed ) {
- // IE uses filters for opacity
- return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
- ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
- computed ? "1" : "";
- },
+ // Convert to pixels if value adjustment is needed
+ if ( subtract && ( matches = rcssNum.exec( value ) ) &&
+ ( matches[ 3 ] || "px" ) !== "px" ) {
- set: function( elem, value ) {
- var style = elem.style,
- currentStyle = elem.currentStyle,
- opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
- filter = currentStyle && currentStyle.filter || style.filter || "";
-
- // IE has trouble with opacity if it does not have layout
- // Force it by setting the zoom level
- style.zoom = 1;
-
- // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
- // if value === "", then remove inline opacity #12685
- if ( ( value >= 1 || value === "" ) &&
- jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
- style.removeAttribute ) {
-
- // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
- // if "filter:" is present at all, clearType is disabled, we want to avoid this
- // style.removeAttribute is IE Only, but so apparently is this code path...
- style.removeAttribute( "filter" );
-
- // if there is no filter style applied in a css rule or unset inline opacity, we are done
- if ( value === "" || currentStyle && !currentStyle.filter ) {
- return;
- }
+ elem.style[ name ] = value;
+ value = jQuery.css( elem, name );
}
- // otherwise, set new filter values
- style.filter = ralpha.test( filter ) ?
- filter.replace( ralpha, opacity ) :
- filter + " " + opacity;
+ return setPositiveNumber( elem, value, subtract );
}
};
-}
+} );
-jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
function( elem, computed ) {
if ( computed ) {
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- // Work around by temporarily setting element display to inline-block
- return jQuery.swap( elem, { "display": "inline-block" },
- curCSS, [ elem, "marginRight" ] );
+ return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
+ elem.getBoundingClientRect().left -
+ swap( elem, { marginLeft: 0 }, function() {
+ return elem.getBoundingClientRect().left;
+ } )
+ ) + "px";
}
}
);
// These hooks are used by animate to expand properties
-jQuery.each({
+jQuery.each( {
margin: "",
padding: "",
border: "Width"
@@ -6827,8 +6470,8 @@ jQuery.each({
var i = 0,
expanded = {},
- // assumes a single number if not a string
- parts = typeof value === "string" ? value.split(" ") : [ value ];
+ // Assumes a single number if not a string
+ parts = typeof value === "string" ? value.split( " " ) : [ value ];
for ( ; i < 4; i++ ) {
expanded[ prefix + cssExpand[ i ] + suffix ] =
@@ -6842,9 +6485,9 @@ jQuery.each({
if ( !rmargin.test( prefix ) ) {
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
}
-});
+} );
-jQuery.fn.extend({
+jQuery.fn.extend( {
css: function( name, value ) {
return access( this, function( elem, name, value ) {
var styles, len,
@@ -6866,27 +6509,8 @@ jQuery.fn.extend({
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
}, name, value, arguments.length > 1 );
- },
- show: function() {
- return showHide( this, true );
- },
- hide: function() {
- return showHide( this );
- },
- toggle: function( state ) {
- if ( typeof state === "boolean" ) {
- return state ? this.show() : this.hide();
- }
-
- return this.each(function() {
- if ( isHidden( this ) ) {
- jQuery( this ).show();
- } else {
- jQuery( this ).hide();
- }
- });
}
-});
+} );
function Tween( elem, options, prop, end, easing ) {
@@ -6899,7 +6523,7 @@ Tween.prototype = {
init: function( elem, options, prop, end, easing, unit ) {
this.elem = elem;
this.prop = prop;
- this.easing = easing || "swing";
+ this.easing = easing || jQuery.easing._default;
this.options = options;
this.start = this.now = this.cur();
this.end = end;
@@ -6945,25 +6569,32 @@ Tween.propHooks = {
get: function( tween ) {
var result;
- if ( tween.elem[ tween.prop ] != null &&
- (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ // Use a property on the element directly when it is not a DOM element,
+ // or when there is no matching style property that exists.
+ if ( tween.elem.nodeType !== 1 ||
+ tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
return tween.elem[ tween.prop ];
}
- // passing an empty string as a 3rd parameter to .css will automatically
- // attempt a parseFloat and fallback to a string if the parse fails
- // so, simple values such as "10px" are parsed to Float.
- // complex values such as "rotate(1rad)" are returned as is.
+ // Passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails.
+ // Simple values such as "10px" are parsed to Float;
+ // complex values such as "rotate(1rad)" are returned as-is.
result = jQuery.css( tween.elem, tween.prop, "" );
+
// Empty strings, null, undefined and "auto" are converted to 0.
return !result || result === "auto" ? 0 : result;
},
set: function( tween ) {
- // use step hook for back compat - use cssHook if its there - use .style if its
- // available and use plain properties where available
+
+ // Use step hook for back compat.
+ // Use cssHook if its there.
+ // Use .style if available and use plain properties where available.
if ( jQuery.fx.step[ tween.prop ] ) {
jQuery.fx.step[ tween.prop ]( tween );
- } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ } else if ( tween.elem.nodeType === 1 &&
+ ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||
+ jQuery.cssHooks[ tween.prop ] ) ) {
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
} else {
tween.elem[ tween.prop ] = tween.now;
@@ -6972,9 +6603,8 @@ Tween.propHooks = {
}
};
-// Support: IE <=9
+// Support: IE <=9 only
// Panic based approach to setting things on disconnected nodes
-
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
set: function( tween ) {
if ( tween.elem.nodeType && tween.elem.parentNode ) {
@@ -6989,12 +6619,13 @@ jQuery.easing = {
},
swing: function( p ) {
return 0.5 - Math.cos( p * Math.PI ) / 2;
- }
+ },
+ _default: "swing"
};
jQuery.fx = Tween.prototype.init;
-// Back Compat <1.8 extension point
+// Back compat <1.8 extension point
jQuery.fx.step = {};
@@ -7003,78 +6634,33 @@ jQuery.fx.step = {};
var
fxNow, timerId,
rfxtypes = /^(?:toggle|show|hide)$/,
- rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
- rrun = /queueHooks$/,
- animationPrefilters = [ defaultPrefilter ],
- tweeners = {
- "*": [ function( prop, value ) {
- var tween = this.createTween( prop, value ),
- target = tween.cur(),
- parts = rfxnum.exec( value ),
- unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
-
- // Starting value computation is required for potential unit mismatches
- start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
- rfxnum.exec( jQuery.css( tween.elem, prop ) ),
- scale = 1,
- maxIterations = 20;
+ rrun = /queueHooks$/;
- if ( start && start[ 3 ] !== unit ) {
- // Trust units reported by jQuery.css
- unit = unit || start[ 3 ];
-
- // Make sure we update the tween properties later on
- parts = parts || [];
-
- // Iteratively approximate from a nonzero starting point
- start = +target || 1;
-
- do {
- // If previous iteration zeroed out, double until we get *something*
- // Use a string for doubling factor so we don't accidentally see scale as unchanged below
- scale = scale || ".5";
-
- // Adjust and apply
- start = start / scale;
- jQuery.style( tween.elem, prop, start + unit );
-
- // Update scale, tolerating zero or NaN from tween.cur()
- // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
- } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
- }
-
- // Update tween properties
- if ( parts ) {
- start = tween.start = +start || +target || 0;
- tween.unit = unit;
- // If a +=/-= token was provided, we're doing a relative animation
- tween.end = parts[ 1 ] ?
- start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
- +parts[ 2 ];
- }
-
- return tween;
- } ]
- };
+function raf() {
+ if ( timerId ) {
+ window.requestAnimationFrame( raf );
+ jQuery.fx.tick();
+ }
+}
// Animations created synchronously will run synchronously
function createFxNow() {
- setTimeout(function() {
+ window.setTimeout( function() {
fxNow = undefined;
- });
+ } );
return ( fxNow = jQuery.now() );
}
// Generate parameters to create a standard animation
function genFx( type, includeWidth ) {
var which,
- attrs = { height: type },
- i = 0;
+ i = 0,
+ attrs = { height: type };
- // if we include width, step value is 1 to do all cssExpand values,
- // if we don't include width, step value is 2 to skip over Left and Right
+ // If we include width, step value is 1 to do all cssExpand values,
+ // otherwise step value is 2 to skip over Left and Right
includeWidth = includeWidth ? 1 : 0;
- for ( ; i < 4 ; i += 2 - includeWidth ) {
+ for ( ; i < 4; i += 2 - includeWidth ) {
which = cssExpand[ i ];
attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
}
@@ -7088,28 +6674,28 @@ function genFx( type, includeWidth ) {
function createTween( value, prop, animation ) {
var tween,
- collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
index = 0,
length = collection.length;
for ( ; index < length; index++ ) {
- if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+ if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
- // we're done with this property
+ // We're done with this property
return tween;
}
}
}
function defaultPrefilter( elem, props, opts ) {
- /* jshint validthis: true */
- var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+ var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
+ isBox = "width" in props || "height" in props,
anim = this,
orig = {},
style = elem.style,
- hidden = elem.nodeType && isHidden( elem ),
- dataShow = jQuery._data( elem, "fxshow" );
+ hidden = elem.nodeType && isHiddenWithinTree( elem ),
+ dataShow = dataPriv.get( elem, "fxshow" );
- // handle queue: false promises
+ // Queue-skipping animations hijack the fx hooks
if ( !opts.queue ) {
hooks = jQuery._queueHooks( elem, "fx" );
if ( hooks.unqueued == null ) {
@@ -7123,122 +6709,151 @@ function defaultPrefilter( elem, props, opts ) {
}
hooks.unqueued++;
- anim.always(function() {
- // doing this makes sure that the complete handler will be called
- // before this completes
- anim.always(function() {
+ anim.always( function() {
+
+ // Ensure the complete handler is called before this completes
+ anim.always( function() {
hooks.unqueued--;
if ( !jQuery.queue( elem, "fx" ).length ) {
hooks.empty.fire();
}
- });
- });
- }
-
- // height/width overflow pass
- if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
- // Make sure that nothing sneaks out
- // Record all 3 overflow attributes because IE does not
- // change the overflow attribute when overflowX and
- // overflowY are set to the same value
- opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
-
- // Set display property to inline-block for height/width
- // animations on inline elements that are having width/height animated
- display = jQuery.css( elem, "display" );
-
- // Test default display if display is currently "none"
- checkDisplay = display === "none" ?
- jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
-
- if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
-
- // inline-level elements accept inline-block;
- // block-level elements need to be inline with layout
- if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
- style.display = "inline-block";
- } else {
- style.zoom = 1;
- }
- }
+ } );
+ } );
}
- if ( opts.overflow ) {
- style.overflow = "hidden";
- if ( !support.shrinkWrapBlocks() ) {
- anim.always(function() {
- style.overflow = opts.overflow[ 0 ];
- style.overflowX = opts.overflow[ 1 ];
- style.overflowY = opts.overflow[ 2 ];
- });
- }
- }
-
- // show/hide pass
+ // Detect show/hide animations
for ( prop in props ) {
value = props[ prop ];
- if ( rfxtypes.exec( value ) ) {
+ if ( rfxtypes.test( value ) ) {
delete props[ prop ];
toggle = toggle || value === "toggle";
if ( value === ( hidden ? "hide" : "show" ) ) {
- // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+ // Pretend to be hidden if this is a "show" and
+ // there is still data from a stopped show/hide
if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
hidden = true;
+
+ // Ignore all other no-op show/hide data
} else {
continue;
}
}
orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
-
- // Any non-fx value stops us from restoring the original display value
- } else {
- display = undefined;
}
}
- if ( !jQuery.isEmptyObject( orig ) ) {
- if ( dataShow ) {
- if ( "hidden" in dataShow ) {
- hidden = dataShow.hidden;
- }
- } else {
- dataShow = jQuery._data( elem, "fxshow", {} );
- }
+ // Bail out if this is a no-op like .hide().hide()
+ propTween = !jQuery.isEmptyObject( props );
+ if ( !propTween && jQuery.isEmptyObject( orig ) ) {
+ return;
+ }
+
+ // Restrict "overflow" and "display" styles during box animations
+ if ( isBox && elem.nodeType === 1 ) {
+
+ // Support: IE <=9 - 11, Edge 12 - 13
+ // Record all 3 overflow attributes because IE does not infer the shorthand
+ // from identically-valued overflowX and overflowY
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
- // store state if its toggle - enables .stop().toggle() to "reverse"
- if ( toggle ) {
- dataShow.hidden = !hidden;
+ // Identify a display type, preferring old show/hide data over the CSS cascade
+ restoreDisplay = dataShow && dataShow.display;
+ if ( restoreDisplay == null ) {
+ restoreDisplay = dataPriv.get( elem, "display" );
}
- if ( hidden ) {
- jQuery( elem ).show();
- } else {
- anim.done(function() {
- jQuery( elem ).hide();
- });
+ display = jQuery.css( elem, "display" );
+ if ( display === "none" ) {
+ if ( restoreDisplay ) {
+ display = restoreDisplay;
+ } else {
+
+ // Get nonempty value(s) by temporarily forcing visibility
+ showHide( [ elem ], true );
+ restoreDisplay = elem.style.display || restoreDisplay;
+ display = jQuery.css( elem, "display" );
+ showHide( [ elem ] );
+ }
}
- anim.done(function() {
- var prop;
- jQuery._removeData( elem, "fxshow" );
- for ( prop in orig ) {
- jQuery.style( elem, prop, orig[ prop ] );
+
+ // Animate inline elements as inline-block
+ if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
+ if ( jQuery.css( elem, "float" ) === "none" ) {
+
+ // Restore the original display value at the end of pure show/hide animations
+ if ( !propTween ) {
+ anim.done( function() {
+ style.display = restoreDisplay;
+ } );
+ if ( restoreDisplay == null ) {
+ display = style.display;
+ restoreDisplay = display === "none" ? "" : display;
+ }
+ }
+ style.display = "inline-block";
}
- });
- for ( prop in orig ) {
- tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
-
- if ( !( prop in dataShow ) ) {
- dataShow[ prop ] = tween.start;
- if ( hidden ) {
- tween.end = tween.start;
- tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ anim.always( function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ } );
+ }
+
+ // Implement show/hide animations
+ propTween = false;
+ for ( prop in orig ) {
+
+ // General show/hide setup for this element animation
+ if ( !propTween ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
}
+ } else {
+ dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
}
+
+ // Store hidden/visible for toggle so `.stop().toggle()` "reverses"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+
+ // Show elements before animating them
+ if ( hidden ) {
+ showHide( [ elem ], true );
+ }
+
+ /* eslint-disable no-loop-func */
+
+ anim.done( function() {
+
+ /* eslint-enable no-loop-func */
+
+ // The final step of a "hide" animation is actually hiding the element
+ if ( !hidden ) {
+ showHide( [ elem ] );
+ }
+ dataPriv.remove( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ } );
}
- // If this is a noop like .hide().hide(), restore an overwritten display value
- } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
- style.display = display;
+ // Per-property setup
+ propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = propTween.start;
+ if ( hidden ) {
+ propTween.end = propTween.start;
+ propTween.start = 0;
+ }
+ }
}
}
@@ -7265,8 +6880,8 @@ function propFilter( props, specialEasing ) {
value = hooks.expand( value );
delete props[ name ];
- // not quite $.extend, this wont overwrite keys already present.
- // also - reusing 'index' from above because we have the correct "name"
+ // Not quite $.extend, this won't overwrite existing keys.
+ // Reusing 'index' because we have the correct "name"
for ( index in value ) {
if ( !( index in props ) ) {
props[ index ] = value[ index ];
@@ -7283,28 +6898,31 @@ function Animation( elem, properties, options ) {
var result,
stopped,
index = 0,
- length = animationPrefilters.length,
+ length = Animation.prefilters.length,
deferred = jQuery.Deferred().always( function() {
- // don't match elem in the :animated selector
+
+ // Don't match elem in the :animated selector
delete tick.elem;
- }),
+ } ),
tick = function() {
if ( stopped ) {
return false;
}
var currentTime = fxNow || createFxNow(),
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
- // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+
+ // Support: Android 2.3 only
+ // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
temp = remaining / animation.duration || 0,
percent = 1 - temp,
index = 0,
length = animation.tweens.length;
- for ( ; index < length ; index++ ) {
+ for ( ; index < length; index++ ) {
animation.tweens[ index ].run( percent );
}
- deferred.notifyWith( elem, [ animation, percent, remaining ]);
+ deferred.notifyWith( elem, [ animation, percent, remaining ] );
if ( percent < 1 && length ) {
return remaining;
@@ -7313,10 +6931,13 @@ function Animation( elem, properties, options ) {
return false;
}
},
- animation = deferred.promise({
+ animation = deferred.promise( {
elem: elem,
props: jQuery.extend( {}, properties ),
- opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ opts: jQuery.extend( true, {
+ specialEasing: {},
+ easing: jQuery.easing._default
+ }, options ),
originalProperties: properties,
originalOptions: options,
startTime: fxNow || createFxNow(),
@@ -7330,34 +6951,39 @@ function Animation( elem, properties, options ) {
},
stop: function( gotoEnd ) {
var index = 0,
- // if we are going to the end, we want to run all the tweens
+
+ // If we are going to the end, we want to run all the tweens
// otherwise we skip this part
length = gotoEnd ? animation.tweens.length : 0;
if ( stopped ) {
return this;
}
stopped = true;
- for ( ; index < length ; index++ ) {
+ for ( ; index < length; index++ ) {
animation.tweens[ index ].run( 1 );
}
- // resolve when we played the last frame
- // otherwise, reject
+ // Resolve when we played the last frame; otherwise, reject
if ( gotoEnd ) {
+ deferred.notifyWith( elem, [ animation, 1, 0 ] );
deferred.resolveWith( elem, [ animation, gotoEnd ] );
} else {
deferred.rejectWith( elem, [ animation, gotoEnd ] );
}
return this;
}
- }),
+ } ),
props = animation.props;
propFilter( props, animation.opts.specialEasing );
- for ( ; index < length ; index++ ) {
- result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ for ( ; index < length; index++ ) {
+ result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
if ( result ) {
+ if ( jQuery.isFunction( result.stop ) ) {
+ jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
+ jQuery.proxy( result.stop, result );
+ }
return result;
}
}
@@ -7373,7 +6999,7 @@ function Animation( elem, properties, options ) {
elem: elem,
anim: animation,
queue: animation.opts.queue
- })
+ } )
);
// attach callbacks from options
@@ -7384,33 +7010,44 @@ function Animation( elem, properties, options ) {
}
jQuery.Animation = jQuery.extend( Animation, {
+
+ tweeners: {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value );
+ adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
+ return tween;
+ } ]
+ },
+
tweener: function( props, callback ) {
if ( jQuery.isFunction( props ) ) {
callback = props;
props = [ "*" ];
} else {
- props = props.split(" ");
+ props = props.match( rnotwhite );
}
var prop,
index = 0,
length = props.length;
- for ( ; index < length ; index++ ) {
+ for ( ; index < length; index++ ) {
prop = props[ index ];
- tweeners[ prop ] = tweeners[ prop ] || [];
- tweeners[ prop ].unshift( callback );
+ Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
+ Animation.tweeners[ prop ].unshift( callback );
}
},
+ prefilters: [ defaultPrefilter ],
+
prefilter: function( callback, prepend ) {
if ( prepend ) {
- animationPrefilters.unshift( callback );
+ Animation.prefilters.unshift( callback );
} else {
- animationPrefilters.push( callback );
+ Animation.prefilters.push( callback );
}
}
-});
+} );
jQuery.speed = function( speed, easing, fn ) {
var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
@@ -7420,10 +7057,17 @@ jQuery.speed = function( speed, easing, fn ) {
easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
};
- opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
- opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+ // Go to the end state if fx are off or if document is hidden
+ if ( jQuery.fx.off || document.hidden ) {
+ opt.duration = 0;
- // normalize opt.queue - true/undefined/null -> "fx"
+ } else {
+ opt.duration = typeof opt.duration === "number" ?
+ opt.duration : opt.duration in jQuery.fx.speeds ?
+ jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+ }
+
+ // Normalize opt.queue - true/undefined/null -> "fx"
if ( opt.queue == null || opt.queue === true ) {
opt.queue = "fx";
}
@@ -7444,24 +7088,25 @@ jQuery.speed = function( speed, easing, fn ) {
return opt;
};
-jQuery.fn.extend({
+jQuery.fn.extend( {
fadeTo: function( speed, to, easing, callback ) {
- // show any hidden elements after setting opacity to 0
- return this.filter( isHidden ).css( "opacity", 0 ).show()
+ // Show any hidden elements after setting opacity to 0
+ return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
- // animate to the value specified
- .end().animate({ opacity: to }, speed, easing, callback );
+ // Animate to the value specified
+ .end().animate( { opacity: to }, speed, easing, callback );
},
animate: function( prop, speed, easing, callback ) {
var empty = jQuery.isEmptyObject( prop ),
optall = jQuery.speed( speed, easing, callback ),
doAnimation = function() {
+
// Operate on a copy of prop so per-property easing won't be lost
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
// Empty animations, or finishing resolves immediately
- if ( empty || jQuery._data( this, "finish" ) ) {
+ if ( empty || dataPriv.get( this, "finish" ) ) {
anim.stop( true );
}
};
@@ -7487,11 +7132,11 @@ jQuery.fn.extend({
this.queue( type || "fx", [] );
}
- return this.each(function() {
+ return this.each( function() {
var dequeue = true,
index = type != null && type + "queueHooks",
timers = jQuery.timers,
- data = jQuery._data( this );
+ data = dataPriv.get( this );
if ( index ) {
if ( data[ index ] && data[ index ].stop ) {
@@ -7506,44 +7151,46 @@ jQuery.fn.extend({
}
for ( index = timers.length; index--; ) {
- if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ if ( timers[ index ].elem === this &&
+ ( type == null || timers[ index ].queue === type ) ) {
+
timers[ index ].anim.stop( gotoEnd );
dequeue = false;
timers.splice( index, 1 );
}
}
- // start the next in the queue if the last step wasn't forced
- // timers currently will call their complete callbacks, which will dequeue
- // but only if they were gotoEnd
+ // Start the next in the queue if the last step wasn't forced.
+ // Timers currently will call their complete callbacks, which
+ // will dequeue but only if they were gotoEnd.
if ( dequeue || !gotoEnd ) {
jQuery.dequeue( this, type );
}
- });
+ } );
},
finish: function( type ) {
if ( type !== false ) {
type = type || "fx";
}
- return this.each(function() {
+ return this.each( function() {
var index,
- data = jQuery._data( this ),
+ data = dataPriv.get( this ),
queue = data[ type + "queue" ],
hooks = data[ type + "queueHooks" ],
timers = jQuery.timers,
length = queue ? queue.length : 0;
- // enable finishing flag on private data
+ // Enable finishing flag on private data
data.finish = true;
- // empty the queue first
+ // Empty the queue first
jQuery.queue( this, type, [] );
if ( hooks && hooks.stop ) {
hooks.stop.call( this, true );
}
- // look for any active animations, and finish them
+ // Look for any active animations, and finish them
for ( index = timers.length; index--; ) {
if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
timers[ index ].anim.stop( true );
@@ -7551,33 +7198,33 @@ jQuery.fn.extend({
}
}
- // look for any animations in the old queue and finish them
+ // Look for any animations in the old queue and finish them
for ( index = 0; index < length; index++ ) {
if ( queue[ index ] && queue[ index ].finish ) {
queue[ index ].finish.call( this );
}
}
- // turn off finishing flag
+ // Turn off finishing flag
delete data.finish;
- });
+ } );
}
-});
+} );
-jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
var cssFn = jQuery.fn[ name ];
jQuery.fn[ name ] = function( speed, easing, callback ) {
return speed == null || typeof speed === "boolean" ?
cssFn.apply( this, arguments ) :
this.animate( genFx( name, true ), speed, easing, callback );
};
-});
+} );
// Generate shortcuts for custom animations
-jQuery.each({
- slideDown: genFx("show"),
- slideUp: genFx("hide"),
- slideToggle: genFx("toggle"),
+jQuery.each( {
+ slideDown: genFx( "show" ),
+ slideUp: genFx( "hide" ),
+ slideToggle: genFx( "toggle" ),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" },
fadeToggle: { opacity: "toggle" }
@@ -7585,18 +7232,19 @@ jQuery.each({
jQuery.fn[ name ] = function( speed, easing, callback ) {
return this.animate( props, speed, easing, callback );
};
-});
+} );
jQuery.timers = [];
jQuery.fx.tick = function() {
var timer,
- timers = jQuery.timers,
- i = 0;
+ i = 0,
+ timers = jQuery.timers;
fxNow = jQuery.now();
for ( ; i < timers.length; i++ ) {
timer = timers[ i ];
+
// Checks the timer has not already been removed
if ( !timer() && timers[ i ] === timer ) {
timers.splice( i--, 1 );
@@ -7619,375 +7267,139 @@ jQuery.fx.timer = function( timer ) {
};
jQuery.fx.interval = 13;
-
jQuery.fx.start = function() {
if ( !timerId ) {
- timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ timerId = window.requestAnimationFrame ?
+ window.requestAnimationFrame( raf ) :
+ window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
}
};
jQuery.fx.stop = function() {
- clearInterval( timerId );
+ if ( window.cancelAnimationFrame ) {
+ window.cancelAnimationFrame( timerId );
+ } else {
+ window.clearInterval( timerId );
+ }
+
timerId = null;
};
jQuery.fx.speeds = {
slow: 600,
fast: 200,
+
// Default speed
_default: 400
};
// Based off of the plugin by Clint Helfers, with permission.
-// http://blindsignals.com/index.php/2009/07/jquery-delay/
+// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
jQuery.fn.delay = function( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
return this.queue( type, function( next, hooks ) {
- var timeout = setTimeout( next, time );
+ var timeout = window.setTimeout( next, time );
hooks.stop = function() {
- clearTimeout( timeout );
+ window.clearTimeout( timeout );
};
- });
+ } );
};
-(function() {
- // Minified: var a,b,c,d,e
- var input, div, select, a, opt;
-
- // Setup
- div = document.createElement( "div" );
- div.setAttribute( "className", "t" );
- div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
- a = div.getElementsByTagName("a")[ 0 ];
-
- // First batch of tests.
- select = document.createElement("select");
- opt = select.appendChild( document.createElement("option") );
- input = div.getElementsByTagName("input")[ 0 ];
-
- a.style.cssText = "top:1px";
-
- // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
- support.getSetAttribute = div.className !== "t";
-
- // Get the style information from getAttribute
- // (IE uses .cssText instead)
- support.style = /top/.test( a.getAttribute("style") );
+( function() {
+ var input = document.createElement( "input" ),
+ select = document.createElement( "select" ),
+ opt = select.appendChild( document.createElement( "option" ) );
- // Make sure that URLs aren't manipulated
- // (IE normalizes it by default)
- support.hrefNormalized = a.getAttribute("href") === "/a";
+ input.type = "checkbox";
- // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
- support.checkOn = !!input.value;
+ // Support: Android <=4.3 only
+ // Default value for a checkbox should be "on"
+ support.checkOn = input.value !== "";
- // Make sure that a selected-by-default option has a working selected property.
- // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ // Support: IE <=11 only
+ // Must access selectedIndex to make default options select
support.optSelected = opt.selected;
- // Tests for enctype support on a form (#6743)
- support.enctype = !!document.createElement("form").enctype;
-
- // Make sure that the options inside disabled selects aren't marked as disabled
- // (WebKit marks them as disabled)
- select.disabled = true;
- support.optDisabled = !opt.disabled;
-
- // Support: IE8 only
- // Check if we can trust getAttribute("value")
+ // Support: IE <=11 only
+ // An input loses its value after becoming a radio
input = document.createElement( "input" );
- input.setAttribute( "value", "" );
- support.input = input.getAttribute( "value" ) === "";
-
- // Check if an input maintains its value after becoming a radio
input.value = "t";
- input.setAttribute( "type", "radio" );
+ input.type = "radio";
support.radioValue = input.value === "t";
-})();
-
+} )();
-var rreturn = /\r/g;
-jQuery.fn.extend({
- val: function( value ) {
- var hooks, ret, isFunction,
- elem = this[0];
+var boolHook,
+ attrHandle = jQuery.expr.attrHandle;
- if ( !arguments.length ) {
- if ( elem ) {
- hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
-
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
- return ret;
- }
-
- ret = elem.value;
-
- return typeof ret === "string" ?
- // handle most common string cases
- ret.replace(rreturn, "") :
- // handle cases where value is null/undef or number
- ret == null ? "" : ret;
- }
-
- return;
- }
-
- isFunction = jQuery.isFunction( value );
-
- return this.each(function( i ) {
- var val;
-
- if ( this.nodeType !== 1 ) {
- return;
- }
-
- if ( isFunction ) {
- val = value.call( this, i, jQuery( this ).val() );
- } else {
- val = value;
- }
-
- // Treat null/undefined as ""; convert numbers to string
- if ( val == null ) {
- val = "";
- } else if ( typeof val === "number" ) {
- val += "";
- } else if ( jQuery.isArray( val ) ) {
- val = jQuery.map( val, function( value ) {
- return value == null ? "" : value + "";
- });
- }
-
- hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
-
- // If set returns undefined, fall back to normal setting
- if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
- this.value = val;
- }
- });
- }
-});
-
-jQuery.extend({
- valHooks: {
- option: {
- get: function( elem ) {
- var val = jQuery.find.attr( elem, "value" );
- return val != null ?
- val :
- // Support: IE10-11+
- // option.text throws exceptions (#14686, #14858)
- jQuery.trim( jQuery.text( elem ) );
- }
- },
- select: {
- get: function( elem ) {
- var value, option,
- options = elem.options,
- index = elem.selectedIndex,
- one = elem.type === "select-one" || index < 0,
- values = one ? null : [],
- max = one ? index + 1 : options.length,
- i = index < 0 ?
- max :
- one ? index : 0;
-
- // Loop through all the selected options
- for ( ; i < max; i++ ) {
- option = options[ i ];
-
- // oldIE doesn't update selected after form reset (#2551)
- if ( ( option.selected || i === index ) &&
- // Don't return options that are disabled or in a disabled optgroup
- ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
- ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
-
- // Get the specific value for the option
- value = jQuery( option ).val();
-
- // We don't need an array for one selects
- if ( one ) {
- return value;
- }
-
- // Multi-Selects return an array
- values.push( value );
- }
- }
-
- return values;
- },
-
- set: function( elem, value ) {
- var optionSet, option,
- options = elem.options,
- values = jQuery.makeArray( value ),
- i = options.length;
-
- while ( i-- ) {
- option = options[ i ];
-
- if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {
-
- // Support: IE6
- // When new option element is added to select box we need to
- // force reflow of newly added node in order to workaround delay
- // of initialization properties
- try {
- option.selected = optionSet = true;
-
- } catch ( _ ) {
-
- // Will be executed only in IE6
- option.scrollHeight;
- }
-
- } else {
- option.selected = false;
- }
- }
-
- // Force browsers to behave consistently when non-matching value is set
- if ( !optionSet ) {
- elem.selectedIndex = -1;
- }
-
- return options;
- }
- }
- }
-});
-
-// Radios and checkboxes getter/setter
-jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- set: function( elem, value ) {
- if ( jQuery.isArray( value ) ) {
- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
- }
- }
- };
- if ( !support.checkOn ) {
- jQuery.valHooks[ this ].get = function( elem ) {
- // Support: Webkit
- // "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- };
- }
-});
-
-
-
-
-var nodeHook, boolHook,
- attrHandle = jQuery.expr.attrHandle,
- ruseDefault = /^(?:checked|selected)$/i,
- getSetAttribute = support.getSetAttribute,
- getSetInput = support.input;
-
-jQuery.fn.extend({
+jQuery.fn.extend( {
attr: function( name, value ) {
return access( this, jQuery.attr, name, value, arguments.length > 1 );
},
removeAttr: function( name ) {
- return this.each(function() {
+ return this.each( function() {
jQuery.removeAttr( this, name );
- });
+ } );
}
-});
+} );
-jQuery.extend({
+jQuery.extend( {
attr: function( elem, name, value ) {
- var hooks, ret,
+ var ret, hooks,
nType = elem.nodeType;
- // don't get/set attributes on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ // Don't get/set attributes on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
return;
}
// Fallback to prop when attributes are not supported
- if ( typeof elem.getAttribute === strundefined ) {
+ if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
- // All attributes are lowercase
+ // Attribute hooks are determined by the lowercase version
// Grab necessary hook if one is defined
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
- name = name.toLowerCase();
- hooks = jQuery.attrHooks[ name ] ||
- ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+ hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
}
if ( value !== undefined ) {
-
if ( value === null ) {
jQuery.removeAttr( elem, name );
+ return;
+ }
- } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
return ret;
-
- } else {
- elem.setAttribute( name, value + "" );
- return value;
}
- } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
- ret = jQuery.find.attr( elem, name );
-
- // Non-existent attributes return null, we normalize to undefined
- return ret == null ?
- undefined :
- ret;
+ elem.setAttribute( name, value + "" );
+ return value;
}
- },
-
- removeAttr: function( elem, value ) {
- var name, propName,
- i = 0,
- attrNames = value && value.match( rnotwhite );
- if ( attrNames && elem.nodeType === 1 ) {
- while ( (name = attrNames[i++]) ) {
- propName = jQuery.propFix[ name ] || name;
-
- // Boolean attributes get special treatment (#10870)
- if ( jQuery.expr.match.bool.test( name ) ) {
- // Set corresponding property to false
- if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
- elem[ propName ] = false;
- // Support: IE<9
- // Also clear defaultChecked/defaultSelected (if appropriate)
- } else {
- elem[ jQuery.camelCase( "default-" + name ) ] =
- elem[ propName ] = false;
- }
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
- // See #9699 for explanation of this approach (setting first, then removal)
- } else {
- jQuery.attr( elem, name, "" );
- }
+ ret = jQuery.find.attr( elem, name );
- elem.removeAttribute( getSetAttribute ? name : propName );
- }
- }
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ? undefined : ret;
},
attrHooks: {
type: {
set: function( elem, value ) {
- if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
- // Setting the type on a radio button after the value resets the value in IE6-9
- // Reset value to default in case type is set after value during creation
+ if ( !support.radioValue && value === "radio" &&
+ jQuery.nodeName( elem, "input" ) ) {
var val = elem.value;
elem.setAttribute( "type", value );
if ( val ) {
@@ -7997,264 +7409,163 @@ jQuery.extend({
}
}
}
+ },
+
+ removeAttr: function( elem, value ) {
+ var name,
+ i = 0,
+ attrNames = value && value.match( rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( ( name = attrNames[ i++ ] ) ) {
+ elem.removeAttribute( name );
+ }
+ }
}
-});
+} );
-// Hook for boolean attributes
+// Hooks for boolean attributes
boolHook = {
set: function( elem, value, name ) {
if ( value === false ) {
+
// Remove boolean attributes when set to false
jQuery.removeAttr( elem, name );
- } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
- // IE<8 needs the *property* name
- elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
-
- // Use defaultChecked and defaultSelected for oldIE
} else {
- elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ elem.setAttribute( name, name );
}
-
return name;
}
};
-// Retrieve booleans specially
jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
-
var getter = attrHandle[ name ] || jQuery.find.attr;
- attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
- function( elem, name, isXML ) {
- var ret, handle;
- if ( !isXML ) {
- // Avoid an infinite loop by temporarily removing this function from the getter
- handle = attrHandle[ name ];
- attrHandle[ name ] = ret;
- ret = getter( elem, name, isXML ) != null ?
- name.toLowerCase() :
- null;
- attrHandle[ name ] = handle;
- }
- return ret;
- } :
- function( elem, name, isXML ) {
- if ( !isXML ) {
- return elem[ jQuery.camelCase( "default-" + name ) ] ?
- name.toLowerCase() :
- null;
- }
- };
-});
-
-// fix oldIE attroperties
-if ( !getSetInput || !getSetAttribute ) {
- jQuery.attrHooks.value = {
- set: function( elem, value, name ) {
- if ( jQuery.nodeName( elem, "input" ) ) {
- // Does not return so that setAttribute is also used
- elem.defaultValue = value;
- } else {
- // Use nodeHook if defined (#1954); otherwise setAttribute is fine
- return nodeHook && nodeHook.set( elem, value, name );
- }
- }
- };
-}
-
-// IE6/7 do not support getting/setting some attributes with get/setAttribute
-if ( !getSetAttribute ) {
-
- // Use this for any attribute in IE6/7
- // This fixes almost every IE6/7 issue
- nodeHook = {
- set: function( elem, value, name ) {
- // Set the existing or create a new attribute node
- var ret = elem.getAttributeNode( name );
- if ( !ret ) {
- elem.setAttributeNode(
- (ret = elem.ownerDocument.createAttribute( name ))
- );
- }
-
- ret.value = value += "";
-
- // Break association with cloned elements by also using setAttribute (#9646)
- if ( name === "value" || value === elem.getAttribute( name ) ) {
- return value;
- }
- }
- };
-
- // Some attributes are constructed with empty-string values when not defined
- attrHandle.id = attrHandle.name = attrHandle.coords =
- function( elem, name, isXML ) {
- var ret;
- if ( !isXML ) {
- return (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
- ret.value :
- null;
- }
- };
-
- // Fixing value retrieval on a button requires this module
- jQuery.valHooks.button = {
- get: function( elem, name ) {
- var ret = elem.getAttributeNode( name );
- if ( ret && ret.specified ) {
- return ret.value;
- }
- },
- set: nodeHook.set
- };
-
- // Set contenteditable to false on removals(#10429)
- // Setting to empty string throws an error as an invalid value
- jQuery.attrHooks.contenteditable = {
- set: function( elem, value, name ) {
- nodeHook.set( elem, value === "" ? false : value, name );
- }
- };
+ attrHandle[ name ] = function( elem, name, isXML ) {
+ var ret, handle,
+ lowercaseName = name.toLowerCase();
- // Set width and height to auto instead of 0 on empty string( Bug #8150 )
- // This is for removals
- jQuery.each([ "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = {
- set: function( elem, value ) {
- if ( value === "" ) {
- elem.setAttribute( name, "auto" );
- return value;
- }
- }
- };
- });
-}
+ if ( !isXML ) {
-if ( !support.style ) {
- jQuery.attrHooks.style = {
- get: function( elem ) {
- // Return undefined in the case of empty string
- // Note: IE uppercases css property names, but if we were to .toLowerCase()
- // .cssText, that would destroy case senstitivity in URL's, like in "background"
- return elem.style.cssText || undefined;
- },
- set: function( elem, value ) {
- return ( elem.style.cssText = value + "" );
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ lowercaseName ];
+ attrHandle[ lowercaseName ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ lowercaseName :
+ null;
+ attrHandle[ lowercaseName ] = handle;
}
+ return ret;
};
-}
+} );
-var rfocusable = /^(?:input|select|textarea|button|object)$/i,
+var rfocusable = /^(?:input|select|textarea|button)$/i,
rclickable = /^(?:a|area)$/i;
-jQuery.fn.extend({
+jQuery.fn.extend( {
prop: function( name, value ) {
return access( this, jQuery.prop, name, value, arguments.length > 1 );
},
removeProp: function( name ) {
- name = jQuery.propFix[ name ] || name;
- return this.each(function() {
- // try/catch handles cases where IE balks (such as removing a property on window)
- try {
- this[ name ] = undefined;
- delete this[ name ];
- } catch( e ) {}
- });
+ return this.each( function() {
+ delete this[ jQuery.propFix[ name ] || name ];
+ } );
}
-});
-
-jQuery.extend({
- propFix: {
- "for": "htmlFor",
- "class": "className"
- },
+} );
+jQuery.extend( {
prop: function( elem, name, value ) {
- var ret, hooks, notxml,
+ var ret, hooks,
nType = elem.nodeType;
- // don't get/set properties on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ // Don't get/set properties on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
return;
}
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
- if ( notxml ) {
// Fix name and attach hooks
name = jQuery.propFix[ name ] || name;
hooks = jQuery.propHooks[ name ];
}
if ( value !== undefined ) {
- return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
- ret :
- ( elem[ name ] = value );
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+ return ret;
+ }
- } else {
- return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
- ret :
- elem[ name ];
+ return ( elem[ name ] = value );
}
+
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
+
+ return elem[ name ];
},
propHooks: {
tabIndex: {
get: function( elem ) {
- // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
- // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+
+ // Support: IE <=9 - 11 only
+ // elem.tabIndex doesn't always return the
+ // correct value when it hasn't been explicitly set
+ // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
// Use proper attribute retrieval(#12072)
var tabindex = jQuery.find.attr( elem, "tabindex" );
return tabindex ?
parseInt( tabindex, 10 ) :
- rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
- 0 :
- -1;
+ rfocusable.test( elem.nodeName ) ||
+ rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ -1;
}
}
- }
-});
+ },
-// Some attributes require a special call on IE
-// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
-if ( !support.hrefNormalized ) {
- // href/src property should get the full normalized URL (#10299/#12915)
- jQuery.each([ "href", "src" ], function( i, name ) {
- jQuery.propHooks[ name ] = {
- get: function( elem ) {
- return elem.getAttribute( name, 4 );
- }
- };
- });
-}
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ }
+} );
-// Support: Safari, IE9+
-// mis-reports the default selected property of an option
-// Accessing the parent's selectedIndex property fixes it
+// Support: IE <=11 only
+// Accessing the selectedIndex property
+// forces the browser to respect setting selected
+// on the option
+// The getter ensures a default option is selected
+// when in an optgroup
if ( !support.optSelected ) {
jQuery.propHooks.selected = {
get: function( elem ) {
var parent = elem.parentNode;
-
+ if ( parent && parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ return null;
+ },
+ set: function( elem ) {
+ var parent = elem.parentNode;
if ( parent ) {
parent.selectedIndex;
- // Make sure that it also works with optgroups, see #5701
if ( parent.parentNode ) {
parent.parentNode.selectedIndex;
}
}
- return null;
}
};
}
-jQuery.each([
+jQuery.each( [
"tabIndex",
"readOnly",
"maxLength",
@@ -8267,54 +7578,48 @@ jQuery.each([
"contentEditable"
], function() {
jQuery.propFix[ this.toLowerCase() ] = this;
-});
-
-// IE6/7 call enctype encoding
-if ( !support.enctype ) {
- jQuery.propFix.enctype = "encoding";
-}
+} );
var rclass = /[\t\r\n\f]/g;
-jQuery.fn.extend({
+function getClass( elem ) {
+ return elem.getAttribute && elem.getAttribute( "class" ) || "";
+}
+
+jQuery.fn.extend( {
addClass: function( value ) {
- var classes, elem, cur, clazz, j, finalValue,
- i = 0,
- len = this.length,
- proceed = typeof value === "string" && value;
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).addClass( value.call( this, j, this.className ) );
- });
+ return this.each( function( j ) {
+ jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
+ } );
}
- if ( proceed ) {
- // The disjunction here is for better compressibility (see removeClass)
- classes = ( value || "" ).match( rnotwhite ) || [];
+ if ( typeof value === "string" && value ) {
+ classes = value.match( rnotwhite ) || [];
- for ( ; i < len; i++ ) {
- elem = this[ i ];
- cur = elem.nodeType === 1 && ( elem.className ?
- ( " " + elem.className + " " ).replace( rclass, " " ) :
- " "
- );
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+ cur = elem.nodeType === 1 &&
+ ( " " + curValue + " " ).replace( rclass, " " );
if ( cur ) {
j = 0;
- while ( (clazz = classes[j++]) ) {
+ while ( ( clazz = classes[ j++ ] ) ) {
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
cur += clazz + " ";
}
}
- // only assign if different to avoid unneeded rendering.
+ // Only assign if different to avoid unneeded rendering.
finalValue = jQuery.trim( cur );
- if ( elem.className !== finalValue ) {
- elem.className = finalValue;
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
}
}
}
@@ -8324,40 +7629,43 @@ jQuery.fn.extend({
},
removeClass: function( value ) {
- var classes, elem, cur, clazz, j, finalValue,
- i = 0,
- len = this.length,
- proceed = arguments.length === 0 || typeof value === "string" && value;
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).removeClass( value.call( this, j, this.className ) );
- });
+ return this.each( function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
+ } );
}
- if ( proceed ) {
- classes = ( value || "" ).match( rnotwhite ) || [];
- for ( ; i < len; i++ ) {
- elem = this[ i ];
+ if ( !arguments.length ) {
+ return this.attr( "class", "" );
+ }
+
+ if ( typeof value === "string" && value ) {
+ classes = value.match( rnotwhite ) || [];
+
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+
// This expression is here for better compressibility (see addClass)
- cur = elem.nodeType === 1 && ( elem.className ?
- ( " " + elem.className + " " ).replace( rclass, " " ) :
- ""
- );
+ cur = elem.nodeType === 1 &&
+ ( " " + curValue + " " ).replace( rclass, " " );
if ( cur ) {
j = 0;
- while ( (clazz = classes[j++]) ) {
+ while ( ( clazz = classes[ j++ ] ) ) {
+
// Remove *all* instances
- while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
cur = cur.replace( " " + clazz + " ", " " );
}
}
- // only assign if different to avoid unneeded rendering.
- finalValue = value ? jQuery.trim( cur ) : "";
- if ( elem.className !== finalValue ) {
- elem.className = finalValue;
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = jQuery.trim( cur );
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
}
}
}
@@ -8374,21 +7682,27 @@ jQuery.fn.extend({
}
if ( jQuery.isFunction( value ) ) {
- return this.each(function( i ) {
- jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
- });
+ return this.each( function( i ) {
+ jQuery( this ).toggleClass(
+ value.call( this, i, getClass( this ), stateVal ),
+ stateVal
+ );
+ } );
}
- return this.each(function() {
+ return this.each( function() {
+ var className, i, self, classNames;
+
if ( type === "string" ) {
- // toggle individual class names
- var className,
- i = 0,
- self = jQuery( this ),
- classNames = value.match( rnotwhite ) || [];
-
- while ( (className = classNames[ i++ ]) ) {
- // check each className given, space separated list
+
+ // Toggle individual class names
+ i = 0;
+ self = jQuery( this );
+ classNames = value.match( rnotwhite ) || [];
+
+ while ( ( className = classNames[ i++ ] ) ) {
+
+ // Check each className given, space separated list
if ( self.hasClass( className ) ) {
self.removeClass( className );
} else {
@@ -8397,34 +7711,224 @@ jQuery.fn.extend({
}
// Toggle whole class name
- } else if ( type === strundefined || type === "boolean" ) {
- if ( this.className ) {
- // store className if set
- jQuery._data( this, "__className__", this.className );
+ } else if ( value === undefined || type === "boolean" ) {
+ className = getClass( this );
+ if ( className ) {
+
+ // Store className if set
+ dataPriv.set( this, "__className__", className );
}
- // If the element has a class name or if we're passed "false",
+ // If the element has a class name or if we're passed `false`,
// then remove the whole classname (if there was one, the above saved it).
// Otherwise bring back whatever was previously saved (if anything),
// falling back to the empty string if nothing was stored.
- this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ if ( this.setAttribute ) {
+ this.setAttribute( "class",
+ className || value === false ?
+ "" :
+ dataPriv.get( this, "__className__" ) || ""
+ );
+ }
}
- });
+ } );
},
hasClass: function( selector ) {
- var className = " " + selector + " ",
- i = 0,
- l = this.length;
- for ( ; i < l; i++ ) {
- if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ var className, elem,
+ i = 0;
+
+ className = " " + selector + " ";
+ while ( ( elem = this[ i++ ] ) ) {
+ if ( elem.nodeType === 1 &&
+ ( " " + getClass( elem ) + " " ).replace( rclass, " " )
+ .indexOf( className ) > -1
+ ) {
return true;
}
}
return false;
}
-});
+} );
+
+
+
+
+var rreturn = /\r/g,
+ rspaces = /[\x20\t\r\n\f]+/g;
+
+jQuery.fn.extend( {
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[ 0 ];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] ||
+ jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks &&
+ "get" in hooks &&
+ ( ret = hooks.get( elem, "value" ) ) !== undefined
+ ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+
+ // Handle most common string cases
+ ret.replace( rreturn, "" ) :
+
+ // Handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each( function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+
+ } else if ( typeof val === "number" ) {
+ val += "";
+
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map( val, function( value ) {
+ return value == null ? "" : value + "";
+ } );
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ } );
+ }
+} );
+
+jQuery.extend( {
+ valHooks: {
+ option: {
+ get: function( elem ) {
+
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+
+ // Support: IE <=10 - 11 only
+ // option.text throws exceptions (#14686, #14858)
+ // Strip and collapse whitespace
+ // https://html.spec.whatwg.org/#strip-and-collapse-whitespace
+ jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " );
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one",
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // Support: IE <=9 only
+ // IE8-9 doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+
+ // Don't return options that are disabled or in a disabled optgroup
+ !option.disabled &&
+ ( !option.parentNode.disabled ||
+ !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+
+ /* eslint-disable no-cond-assign */
+
+ if ( option.selected =
+ jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
+ ) {
+ optionSet = true;
+ }
+
+ /* eslint-enable no-cond-assign */
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ }
+} );
+
+// Radios and checkboxes getter/setter
+jQuery.each( [ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ return elem.getAttribute( "value" ) === null ? "on" : elem.value;
+ };
+ }
+} );
@@ -8432,9 +7936,182 @@ jQuery.fn.extend({
// Return jQuery for attributes-only inclusion
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;
+
+jQuery.extend( jQuery.event, {
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+
+ var i, cur, tmp, bubbleType, ontype, handle, special,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf( "." ) > -1 ) {
+
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split( "." );
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf( ":" ) < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join( "." );
+ event.rnamespace = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === ( elem.ownerDocument || document ) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
+ dataPriv.get( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( ( !special._default ||
+ special._default.apply( eventPath.pop(), data ) === false ) &&
+ acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name as the event.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ // Piggyback on a donor event to simulate a different one
+ // Used only for `focus(in | out)` events
+ simulate: function( type, elem, event ) {
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true
+ }
+ );
+
+ jQuery.event.trigger( e, null, elem );
+ }
+
+} );
+
+jQuery.fn.extend( {
+
+ trigger: function( type, data ) {
+ return this.each( function() {
+ jQuery.event.trigger( type, data, this );
+ } );
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[ 0 ];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+} );
+
+
+jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
- "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+ "change select submit keydown keypress keyup contextmenu" ).split( " " ),
+ function( i, name ) {
// Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
@@ -8442,100 +8119,85 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
this.on( name, null, data, fn ) :
this.trigger( name );
};
-});
+} );
-jQuery.fn.extend({
+jQuery.fn.extend( {
hover: function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
- },
-
- bind: function( types, data, fn ) {
- return this.on( types, null, data, fn );
- },
- unbind: function( types, fn ) {
- return this.off( types, null, fn );
- },
-
- delegate: function( selector, types, data, fn ) {
- return this.on( types, selector, data, fn );
- },
- undelegate: function( selector, types, fn ) {
- // ( namespace ) or ( selector, types [, fn] )
- return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
}
-});
+} );
-var nonce = jQuery.now();
-var rquery = (/\?/);
+support.focusin = "onfocusin" in window;
-var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
+// Support: Firefox <=44
+// Firefox doesn't have focus(in | out) events
+// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
+//
+// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
+// focus(in | out) events fire after focus & blur events,
+// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
+// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
+if ( !support.focusin ) {
+ jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-jQuery.parseJSON = function( data ) {
- // Attempt to parse using the native JSON parser first
- if ( window.JSON && window.JSON.parse ) {
- // Support: Android 2.3
- // Workaround failure to string-cast null input
- return window.JSON.parse( data + "" );
- }
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
+ };
- var requireNonComma,
- depth = null,
- str = jQuery.trim( data + "" );
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ var doc = this.ownerDocument || this,
+ attaches = dataPriv.access( doc, fix );
- // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
- // after removing valid tokens
- return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this,
+ attaches = dataPriv.access( doc, fix ) - 1;
- // Force termination if we see a misplaced comma
- if ( requireNonComma && comma ) {
- depth = 0;
- }
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ dataPriv.remove( doc, fix );
- // Perform no more replacements after returning to outermost depth
- if ( depth === 0 ) {
- return token;
- }
+ } else {
+ dataPriv.access( doc, fix, attaches );
+ }
+ }
+ };
+ } );
+}
+var location = window.location;
- // Commas must not follow "[", "{", or ","
- requireNonComma = open || comma;
+var nonce = jQuery.now();
- // Determine new depth
- // array/object open ("[" or "{"): depth += true - false (increment)
- // array/object close ("]" or "}"): depth += false - true (decrement)
- // other cases ("," or primitive): depth += true - true (numeric cast)
- depth += !close - !open;
+var rquery = ( /\?/ );
- // Remove this token
- return "";
- }) ) ?
- ( Function( "return " + str ) )() :
- jQuery.error( "Invalid JSON: " + data );
-};
// Cross-browser xml parsing
jQuery.parseXML = function( data ) {
- var xml, tmp;
+ var xml;
if ( !data || typeof data !== "string" ) {
return null;
}
+
+ // Support: IE 9 - 11 only
+ // IE throws on parseFromString with invalid input.
try {
- if ( window.DOMParser ) { // Standard
- tmp = new DOMParser();
- xml = tmp.parseFromString( data, "text/xml" );
- } else { // IE
- xml = new ActiveXObject( "Microsoft.XMLDOM" );
- xml.async = "false";
- xml.loadXML( data );
- }
- } catch( e ) {
+ xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
+ } catch ( e ) {
xml = undefined;
}
- if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+
+ if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
@@ -8543,18 +8205,130 @@ jQuery.parseXML = function( data ) {
var
- // Document location
- ajaxLocParts,
- ajaxLocation,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams(
+ prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
+ v,
+ traditional,
+ add
+ );
+ }
+ } );
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, valueOrFunction ) {
+
+ // If value is a function, invoke it and use its return value
+ var value = jQuery.isFunction( valueOrFunction ) ?
+ valueOrFunction() :
+ valueOrFunction;
+
+ s[ s.length ] = encodeURIComponent( key ) + "=" +
+ encodeURIComponent( value == null ? "" : value );
+ };
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ } );
+
+ } else {
+
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" );
+};
+
+jQuery.fn.extend( {
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map( function() {
+
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ } )
+ .filter( function() {
+ var type = this.type;
+
+ // Use .is( ":disabled" ) so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !rcheckableType.test( type ) );
+ } )
+ .map( function( i, elem ) {
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ) {
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ } ) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ } ).get();
+ }
+} );
+
+var
+ r20 = /%20/g,
rhash = /#.*$/,
rts = /([?&])_=[^&]*/,
- rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+
// #7653, #8125, #8152: local protocol detection
rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
rnoContent = /^(?:GET|HEAD)$/,
rprotocol = /^\/\//,
- rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
/* Prefilters
* 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
@@ -8575,22 +8349,11 @@ var
transports = {},
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
- allTypes = "*/".concat("*");
+ allTypes = "*/".concat( "*" ),
-// #8138, IE may throw an exception when accessing
-// a field from window.location if document.domain has been set
-try {
- ajaxLocation = location.href;
-} catch( e ) {
- // Use the href attribute of an A element
- // since IE will modify it given document.location
- ajaxLocation = document.createElement( "a" );
- ajaxLocation.href = "";
- ajaxLocation = ajaxLocation.href;
-}
-
-// Segment location into parts
-ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+ // Anchor tag for parsing the document origin
+ originAnchor = document.createElement( "a" );
+ originAnchor.href = location.href;
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {
@@ -8608,16 +8371,18 @@ function addToPrefiltersOrTransports( structure ) {
dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
if ( jQuery.isFunction( func ) ) {
+
// For each dataType in the dataTypeExpression
- while ( (dataType = dataTypes[i++]) ) {
+ while ( ( dataType = dataTypes[ i++ ] ) ) {
+
// Prepend if requested
- if ( dataType.charAt( 0 ) === "+" ) {
+ if ( dataType[ 0 ] === "+" ) {
dataType = dataType.slice( 1 ) || "*";
- (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+ ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
// Otherwise append
} else {
- (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ ( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
}
}
}
@@ -8635,14 +8400,16 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX
inspected[ dataType ] = true;
jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
- if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ if ( typeof dataTypeOrTransport === "string" &&
+ !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+
options.dataTypes.unshift( dataTypeOrTransport );
inspect( dataTypeOrTransport );
return false;
} else if ( seekingTransport ) {
return !( selected = dataTypeOrTransport );
}
- });
+ } );
return selected;
}
@@ -8653,12 +8420,12 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX
// that takes "flat" options (not to be deep extended)
// Fixes #9887
function ajaxExtend( target, src ) {
- var deep, key,
+ var key, deep,
flatOptions = jQuery.ajaxSettings.flatOptions || {};
for ( key in src ) {
if ( src[ key ] !== undefined ) {
- ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
}
}
if ( deep ) {
@@ -8673,7 +8440,8 @@ function ajaxExtend( target, src ) {
* - returns the corresponding response
*/
function ajaxHandleResponses( s, jqXHR, responses ) {
- var firstDataType, ct, finalDataType, type,
+
+ var ct, type, finalDataType, firstDataType,
contents = s.contents,
dataTypes = s.dataTypes;
@@ -8681,7 +8449,7 @@ function ajaxHandleResponses( s, jqXHR, responses ) {
while ( dataTypes[ 0 ] === "*" ) {
dataTypes.shift();
if ( ct === undefined ) {
- ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
}
}
@@ -8699,9 +8467,10 @@ function ajaxHandleResponses( s, jqXHR, responses ) {
if ( dataTypes[ 0 ] in responses ) {
finalDataType = dataTypes[ 0 ];
} else {
+
// Try convertible dataTypes
for ( type in responses ) {
- if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
finalDataType = type;
break;
}
@@ -8709,6 +8478,7 @@ function ajaxHandleResponses( s, jqXHR, responses ) {
firstDataType = type;
}
}
+
// Or just use first one
finalDataType = finalDataType || firstDataType;
}
@@ -8730,6 +8500,7 @@ function ajaxHandleResponses( s, jqXHR, responses ) {
function ajaxConvert( s, response, jqXHR, isSuccess ) {
var conv2, current, conv, tmp, prev,
converters = {},
+
// Work with a copy of dataTypes in case we need to modify it for conversion
dataTypes = s.dataTypes.slice();
@@ -8782,6 +8553,7 @@ function ajaxConvert( s, response, jqXHR, isSuccess ) {
conv = converters[ prev + " " + tmp[ 0 ] ] ||
converters[ "* " + tmp[ 0 ] ];
if ( conv ) {
+
// Condense equivalence converters
if ( conv === true ) {
conv = converters[ conv2 ];
@@ -8801,13 +8573,16 @@ function ajaxConvert( s, response, jqXHR, isSuccess ) {
if ( conv !== true ) {
// Unless errors are allowed to bubble, catch and return them
- if ( conv && s[ "throws" ] ) {
+ if ( conv && s.throws ) {
response = conv( response );
} else {
try {
response = conv( response );
} catch ( e ) {
- return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ return {
+ state: "parsererror",
+ error: conv ? e : "No conversion from " + prev + " to " + current
+ };
}
}
}
@@ -8818,7 +8593,7 @@ function ajaxConvert( s, response, jqXHR, isSuccess ) {
return { state: "success", data: response };
}
-jQuery.extend({
+jQuery.extend( {
// Counter for holding the number of active queries
active: 0,
@@ -8828,13 +8603,14 @@ jQuery.extend({
etag: {},
ajaxSettings: {
- url: ajaxLocation,
+ url: location.href,
type: "GET",
- isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ isLocal: rlocalProtocol.test( location.protocol ),
global: true,
processData: true,
async: true,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+
/*
timeout: 0,
data: null,
@@ -8856,9 +8632,9 @@ jQuery.extend({
},
contents: {
- xml: /xml/,
- html: /html/,
- json: /json/
+ xml: /\bxml\b/,
+ html: /\bhtml/,
+ json: /\bjson\b/
},
responseFields: {
@@ -8878,7 +8654,7 @@ jQuery.extend({
"text html": true,
// Evaluate text as a json expression
- "text json": jQuery.parseJSON,
+ "text json": JSON.parse,
// Parse text as xml
"text xml": jQuery.parseXML
@@ -8922,43 +8698,59 @@ jQuery.extend({
// Force options to be an object
options = options || {};
- var // Cross-domain detection vars
- parts,
- // Loop variable
- i,
+ var transport,
+
// URL without anti-cache param
cacheURL,
- // Response headers as string
+
+ // Response headers
responseHeadersString,
+ responseHeaders,
+
// timeout handle
timeoutTimer,
+ // Url cleanup var
+ urlAnchor,
+
+ // Request state (becomes false upon send and true upon completion)
+ completed,
+
// To know if global events are to be dispatched
fireGlobals,
- transport,
- // Response headers
- responseHeaders,
+ // Loop variable
+ i,
+
+ // uncached part of the url
+ uncached,
+
// Create the final options object
s = jQuery.ajaxSetup( {}, options ),
+
// Callbacks context
callbackContext = s.context || s,
+
// Context for global events is callbackContext if it is a DOM node or jQuery collection
- globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
- jQuery( callbackContext ) :
- jQuery.event,
+ globalEventContext = s.context &&
+ ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+
// Deferreds
deferred = jQuery.Deferred(),
- completeDeferred = jQuery.Callbacks("once memory"),
+ completeDeferred = jQuery.Callbacks( "once memory" ),
+
// Status-dependent callbacks
statusCode = s.statusCode || {},
+
// Headers (they are sent all at once)
requestHeaders = {},
requestHeadersNames = {},
- // The jqXHR state
- state = 0,
+
// Default abort message
strAbort = "canceled",
+
// Fake xhr
jqXHR = {
readyState: 0,
@@ -8966,11 +8758,11 @@ jQuery.extend({
// Builds headers hashtable if needed
getResponseHeader: function( key ) {
var match;
- if ( state === 2 ) {
+ if ( completed ) {
if ( !responseHeaders ) {
responseHeaders = {};
- while ( (match = rheaders.exec( responseHeadersString )) ) {
- responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
}
}
match = responseHeaders[ key.toLowerCase() ];
@@ -8980,14 +8772,14 @@ jQuery.extend({
// Raw string
getAllResponseHeaders: function() {
- return state === 2 ? responseHeadersString : null;
+ return completed ? responseHeadersString : null;
},
// Caches the header
setRequestHeader: function( name, value ) {
- var lname = name.toLowerCase();
- if ( !state ) {
- name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ if ( completed == null ) {
+ name = requestHeadersNames[ name.toLowerCase() ] =
+ requestHeadersNames[ name.toLowerCase() ] || name;
requestHeaders[ name ] = value;
}
return this;
@@ -8995,7 +8787,7 @@ jQuery.extend({
// Overrides response content-type header
overrideMimeType: function( type ) {
- if ( !state ) {
+ if ( completed == null ) {
s.mimeType = type;
}
return this;
@@ -9005,14 +8797,16 @@ jQuery.extend({
statusCode: function( map ) {
var code;
if ( map ) {
- if ( state < 2 ) {
+ if ( completed ) {
+
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ } else {
+
+ // Lazy-add the new callbacks in a way that preserves old ones
for ( code in map ) {
- // Lazy-add the new callback in a way that preserves old ones
statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
}
- } else {
- // Execute the appropriate callbacks
- jqXHR.always( map[ jqXHR.status ] );
}
}
return this;
@@ -9030,30 +8824,41 @@ jQuery.extend({
};
// Attach deferreds
- deferred.promise( jqXHR ).complete = completeDeferred.add;
- jqXHR.success = jqXHR.done;
- jqXHR.error = jqXHR.fail;
+ deferred.promise( jqXHR );
- // Remove hash character (#7531: and string promotion)
- // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // Add protocol if not provided (prefilters might expect it)
// Handle falsy url in the settings object (#10093: consistency with old signature)
// We also use the url parameter if available
- s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+ s.url = ( ( url || s.url || location.href ) + "" )
+ .replace( rprotocol, location.protocol + "//" );
// Alias method option to type as per ticket #12004
s.type = options.method || options.type || s.method || s.type;
// Extract dataTypes list
- s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
+ s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
- // A cross-domain request is in order when we have a protocol:host:port mismatch
+ // A cross-domain request is in order when the origin doesn't match the current origin.
if ( s.crossDomain == null ) {
- parts = rurl.exec( s.url.toLowerCase() );
- s.crossDomain = !!( parts &&
- ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
- ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
- ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
- );
+ urlAnchor = document.createElement( "a" );
+
+ // Support: IE <=8 - 11, Edge 12 - 13
+ // IE throws exception on accessing the href property if url is malformed,
+ // e.g. http://example.com:80x/
+ try {
+ urlAnchor.href = s.url;
+
+ // Support: IE <=8 - 11 only
+ // Anchor's host property isn't correctly set when s.url is relative
+ urlAnchor.href = urlAnchor.href;
+ s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
+ urlAnchor.protocol + "//" + urlAnchor.host;
+ } catch ( e ) {
+
+ // If there is an error parsing the URL, assume it is crossDomain,
+ // it can be rejected by the transport if it is invalid
+ s.crossDomain = true;
+ }
}
// Convert data if not already a string
@@ -9065,16 +8870,17 @@ jQuery.extend({
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
// If request was aborted inside a prefilter, stop there
- if ( state === 2 ) {
+ if ( completed ) {
return jqXHR;
}
// We can fire global events as of now if asked to
- fireGlobals = s.global;
+ // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+ fireGlobals = jQuery.event && s.global;
// Watch for a new set of requests
if ( fireGlobals && jQuery.active++ === 0 ) {
- jQuery.event.trigger("ajaxStart");
+ jQuery.event.trigger( "ajaxStart" );
}
// Uppercase the type
@@ -9085,28 +8891,36 @@ jQuery.extend({
// Save the URL in case we're toying with the If-Modified-Since
// and/or If-None-Match header later on
- cacheURL = s.url;
+ // Remove hash to simplify url manipulation
+ cacheURL = s.url.replace( rhash, "" );
// More options handling for requests with no content
if ( !s.hasContent ) {
+ // Remember the hash so we can put it back
+ uncached = s.url.slice( cacheURL.length );
+
// If data is available, append data to url
if ( s.data ) {
- cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
+
// #9682: remove data so that it's not used in an eventual retry
delete s.data;
}
- // Add anti-cache in url if needed
+ // Add anti-cache in uncached url if needed
if ( s.cache === false ) {
- s.url = rts.test( cacheURL ) ?
+ cacheURL = cacheURL.replace( rts, "" );
+ uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached;
+ }
- // If there is already a '_' parameter, set its value
- cacheURL.replace( rts, "$1_=" + nonce++ ) :
+ // Put hash and anti-cache on the URL that will be requested (gh-1732)
+ s.url = cacheURL + uncached;
- // Otherwise add one to the end
- cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
- }
+ // Change '%20' to '+' if this is encoded form body content (gh-2658)
+ } else if ( s.data && s.processData &&
+ ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
+ s.data = s.data.replace( r20, "+" );
}
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
@@ -9127,8 +8941,9 @@ jQuery.extend({
// Set the Accepts header for the server, depending on the dataType
jqXHR.setRequestHeader(
"Accept",
- s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
- s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
+ s.accepts[ s.dataTypes[ 0 ] ] +
+ ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
s.accepts[ "*" ]
);
@@ -9138,18 +8953,20 @@ jQuery.extend({
}
// Allow custom headers/mimetypes and early abort
- if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ if ( s.beforeSend &&
+ ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
+
// Abort if not done already and return
return jqXHR.abort();
}
- // aborting is no longer a cancellation
+ // Aborting is no longer a cancellation
strAbort = "abort";
// Install callbacks on deferreds
- for ( i in { success: 1, error: 1, complete: 1 } ) {
- jqXHR[ i ]( s[ i ] );
- }
+ completeDeferred.add( s.complete );
+ jqXHR.done( s.success );
+ jqXHR.fail( s.error );
// Get transport
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
@@ -9164,24 +8981,31 @@ jQuery.extend({
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
}
+
+ // If request was aborted inside ajaxSend, stop there
+ if ( completed ) {
+ return jqXHR;
+ }
+
// Timeout
if ( s.async && s.timeout > 0 ) {
- timeoutTimer = setTimeout(function() {
- jqXHR.abort("timeout");
+ timeoutTimer = window.setTimeout( function() {
+ jqXHR.abort( "timeout" );
}, s.timeout );
}
try {
- state = 1;
+ completed = false;
transport.send( requestHeaders, done );
} catch ( e ) {
- // Propagate exception as error if not done
- if ( state < 2 ) {
- done( -1, e );
- // Simply rethrow otherwise
- } else {
+
+ // Rethrow post-completion exceptions
+ if ( completed ) {
throw e;
}
+
+ // Propagate others as results
+ done( -1, e );
}
}
@@ -9190,17 +9014,16 @@ jQuery.extend({
var isSuccess, success, error, response, modified,
statusText = nativeStatusText;
- // Called once
- if ( state === 2 ) {
+ // Ignore repeat invocations
+ if ( completed ) {
return;
}
- // State is "done" now
- state = 2;
+ completed = true;
// Clear timeout if it exists
if ( timeoutTimer ) {
- clearTimeout( timeoutTimer );
+ window.clearTimeout( timeoutTimer );
}
// Dereference transport for early garbage collection
@@ -9229,11 +9052,11 @@ jQuery.extend({
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
- modified = jqXHR.getResponseHeader("Last-Modified");
+ modified = jqXHR.getResponseHeader( "Last-Modified" );
if ( modified ) {
jQuery.lastModified[ cacheURL ] = modified;
}
- modified = jqXHR.getResponseHeader("etag");
+ modified = jqXHR.getResponseHeader( "etag" );
if ( modified ) {
jQuery.etag[ cacheURL ] = modified;
}
@@ -9255,8 +9078,8 @@ jQuery.extend({
isSuccess = !error;
}
} else {
- // We extract error from statusText
- // then normalize statusText and status for non-aborts
+
+ // Extract error from statusText and normalize for non-aborts
error = statusText;
if ( status || !statusText ) {
statusText = "error";
@@ -9291,9 +9114,10 @@ jQuery.extend({
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+
// Handle the global AJAX counter
if ( !( --jQuery.active ) ) {
- jQuery.event.trigger("ajaxStop");
+ jQuery.event.trigger( "ajaxStop" );
}
}
}
@@ -9308,72 +9132,70 @@ jQuery.extend({
getScript: function( url, callback ) {
return jQuery.get( url, undefined, callback, "script" );
}
-});
+} );
jQuery.each( [ "get", "post" ], function( i, method ) {
jQuery[ method ] = function( url, data, callback, type ) {
- // shift arguments if data argument was omitted
+
+ // Shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = undefined;
}
- return jQuery.ajax({
+ // The url can be an options object (which then must have .url)
+ return jQuery.ajax( jQuery.extend( {
url: url,
type: method,
dataType: type,
data: data,
success: callback
- });
+ }, jQuery.isPlainObject( url ) && url ) );
};
-});
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
- jQuery.fn[ type ] = function( fn ) {
- return this.on( type, fn );
- };
-});
+} );
jQuery._evalUrl = function( url ) {
- return jQuery.ajax({
+ return jQuery.ajax( {
url: url,
+
+ // Make this explicit, since user can override this through ajaxSetup (#11264)
type: "GET",
dataType: "script",
+ cache: true,
async: false,
global: false,
"throws": true
- });
+ } );
};
-jQuery.fn.extend({
+jQuery.fn.extend( {
wrapAll: function( html ) {
- if ( jQuery.isFunction( html ) ) {
- return this.each(function(i) {
- jQuery(this).wrapAll( html.call(this, i) );
- });
- }
+ var wrap;
+
+ if ( this[ 0 ] ) {
+ if ( jQuery.isFunction( html ) ) {
+ html = html.call( this[ 0 ] );
+ }
- if ( this[0] ) {
// The elements to wrap the target around
- var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+ wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
- if ( this[0].parentNode ) {
- wrap.insertBefore( this[0] );
+ if ( this[ 0 ].parentNode ) {
+ wrap.insertBefore( this[ 0 ] );
}
- wrap.map(function() {
+ wrap.map( function() {
var elem = this;
- while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
- elem = elem.firstChild;
+ while ( elem.firstElementChild ) {
+ elem = elem.firstElementChild;
}
return elem;
- }).append( this );
+ } ).append( this );
}
return this;
@@ -9381,12 +9203,12 @@ jQuery.fn.extend({
wrapInner: function( html ) {
if ( jQuery.isFunction( html ) ) {
- return this.each(function(i) {
- jQuery(this).wrapInner( html.call(this, i) );
- });
+ return this.each( function( i ) {
+ jQuery( this ).wrapInner( html.call( this, i ) );
+ } );
}
- return this.each(function() {
+ return this.each( function() {
var self = jQuery( this ),
contents = self.contents();
@@ -9396,342 +9218,214 @@ jQuery.fn.extend({
} else {
self.append( html );
}
- });
+ } );
},
wrap: function( html ) {
var isFunction = jQuery.isFunction( html );
- return this.each(function(i) {
- jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
- });
+ return this.each( function( i ) {
+ jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );
+ } );
},
- unwrap: function() {
- return this.parent().each(function() {
- if ( !jQuery.nodeName( this, "body" ) ) {
- jQuery( this ).replaceWith( this.childNodes );
- }
- }).end();
+ unwrap: function( selector ) {
+ this.parent( selector ).not( "body" ).each( function() {
+ jQuery( this ).replaceWith( this.childNodes );
+ } );
+ return this;
}
-});
+} );
-jQuery.expr.filters.hidden = function( elem ) {
- // Support: Opera <= 12.12
- // Opera reports offsetWidths and offsetHeights less than zero on some elements
- return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
- (!support.reliableHiddenOffsets() &&
- ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+jQuery.expr.pseudos.hidden = function( elem ) {
+ return !jQuery.expr.pseudos.visible( elem );
};
-
-jQuery.expr.filters.visible = function( elem ) {
- return !jQuery.expr.filters.hidden( elem );
+jQuery.expr.pseudos.visible = function( elem ) {
+ return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};
-var r20 = /%20/g,
- rbracket = /\[\]$/,
- rCRLF = /\r?\n/g,
- rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
- rsubmittable = /^(?:input|select|textarea|keygen)/i;
-
-function buildParams( prefix, obj, traditional, add ) {
- var name;
-
- if ( jQuery.isArray( obj ) ) {
- // Serialize array item.
- jQuery.each( obj, function( i, v ) {
- if ( traditional || rbracket.test( prefix ) ) {
- // Treat each array item as a scalar.
- add( prefix, v );
-
- } else {
- // Item is non-scalar (array or object), encode its numeric index.
- buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
- }
- });
-
- } else if ( !traditional && jQuery.type( obj ) === "object" ) {
- // Serialize object item.
- for ( name in obj ) {
- buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
- }
-
- } else {
- // Serialize scalar item.
- add( prefix, obj );
- }
-}
-
-// Serialize an array of form elements or a set of
-// key/values into a query string
-jQuery.param = function( a, traditional ) {
- var prefix,
- s = [],
- add = function( key, value ) {
- // If value is a function, invoke it and return its value
- value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
- s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
- };
-
- // Set traditional to true for jQuery <= 1.3.2 behavior.
- if ( traditional === undefined ) {
- traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
- }
-
- // If an array was passed in, assume that it is an array of form elements.
- if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
- // Serialize the form elements
- jQuery.each( a, function() {
- add( this.name, this.value );
- });
-
- } else {
- // If traditional, encode the "old" way (the way 1.3.2 or older
- // did it), otherwise encode params recursively.
- for ( prefix in a ) {
- buildParams( prefix, a[ prefix ], traditional, add );
- }
- }
-
- // Return the resulting serialization
- return s.join( "&" ).replace( r20, "+" );
+jQuery.ajaxSettings.xhr = function() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch ( e ) {}
};
-jQuery.fn.extend({
- serialize: function() {
- return jQuery.param( this.serializeArray() );
- },
- serializeArray: function() {
- return this.map(function() {
- // Can add propHook for "elements" to filter or add form elements
- var elements = jQuery.prop( this, "elements" );
- return elements ? jQuery.makeArray( elements ) : this;
- })
- .filter(function() {
- var type = this.type;
- // Use .is(":disabled") so that fieldset[disabled] works
- return this.name && !jQuery( this ).is( ":disabled" ) &&
- rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
- ( this.checked || !rcheckableType.test( type ) );
- })
- .map(function( i, elem ) {
- var val = jQuery( this ).val();
-
- return val == null ?
- null :
- jQuery.isArray( val ) ?
- jQuery.map( val, function( val ) {
- return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }) :
- { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }).get();
- }
-});
-
-
-// Create the request object
-// (This is still attached to ajaxSettings for backward compatibility)
-jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
- // Support: IE6+
- function() {
+var xhrSuccessStatus = {
- // XHR cannot access local files, always use ActiveX for that case
- return !this.isLocal &&
+ // File protocol always yields status code 0, assume 200
+ 0: 200,
- // Support: IE7-8
- // oldIE XHR does not support non-RFC2616 methods (#13240)
- // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
- // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
- // Although this check for six methods instead of eight
- // since IE also does not support "trace" and "connect"
- /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
-
- createStandardXHR() || createActiveXHR();
- } :
- // For all other browsers, use the standard XMLHttpRequest object
- createStandardXHR;
-
-var xhrId = 0,
- xhrCallbacks = {},
+ // Support: IE <=9 only
+ // #1450: sometimes IE returns 1223 when it should be 204
+ 1223: 204
+ },
xhrSupported = jQuery.ajaxSettings.xhr();
-// Support: IE<10
-// Open requests must be manually aborted on unload (#5280)
-if ( window.ActiveXObject ) {
- jQuery( window ).on( "unload", function() {
- for ( var key in xhrCallbacks ) {
- xhrCallbacks[ key ]( undefined, true );
- }
- });
-}
-
-// Determine support properties
support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
-xhrSupported = support.ajax = !!xhrSupported;
+support.ajax = xhrSupported = !!xhrSupported;
-// Create transport if the browser can provide an xhr
-if ( xhrSupported ) {
+jQuery.ajaxTransport( function( options ) {
+ var callback, errorCallback;
- jQuery.ajaxTransport(function( options ) {
- // Cross domain only allowed if supported through XMLHttpRequest
- if ( !options.crossDomain || support.cors ) {
-
- var callback;
-
- return {
- send: function( headers, complete ) {
- var i,
- xhr = options.xhr(),
- id = ++xhrId;
-
- // Open the socket
- xhr.open( options.type, options.url, options.async, options.username, options.password );
-
- // Apply custom fields if provided
- if ( options.xhrFields ) {
- for ( i in options.xhrFields ) {
- xhr[ i ] = options.xhrFields[ i ];
- }
- }
-
- // Override mime type if needed
- if ( options.mimeType && xhr.overrideMimeType ) {
- xhr.overrideMimeType( options.mimeType );
- }
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( support.cors || xhrSupported && !options.crossDomain ) {
+ return {
+ send: function( headers, complete ) {
+ var i,
+ xhr = options.xhr();
+
+ xhr.open(
+ options.type,
+ options.url,
+ options.async,
+ options.username,
+ options.password
+ );
- // X-Requested-With header
- // For cross-domain requests, seeing as conditions for a preflight are
- // akin to a jigsaw puzzle, we simply never set it to be sure.
- // (it can always be set on a per-request basis or even using ajaxSetup)
- // For same-domain requests, won't change header if already provided.
- if ( !options.crossDomain && !headers["X-Requested-With"] ) {
- headers["X-Requested-With"] = "XMLHttpRequest";
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
}
+ }
- // Set headers
- for ( i in headers ) {
- // Support: IE<9
- // IE's ActiveXObject throws a 'Type Mismatch' exception when setting
- // request header to a null-value.
- //
- // To keep consistent with other XHR implementations, cast the value
- // to string and ignore `undefined`.
- if ( headers[ i ] !== undefined ) {
- xhr.setRequestHeader( i, headers[ i ] + "" );
- }
- }
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
- // Do send the request
- // This may raise an exception which is actually
- // handled in jQuery.ajax (so no try/catch here)
- xhr.send( ( options.hasContent && options.data ) || null );
-
- // Listener
- callback = function( _, isAbort ) {
- var status, statusText, responses;
-
- // Was never called and is aborted or complete
- if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
- // Clean up
- delete xhrCallbacks[ id ];
- callback = undefined;
- xhr.onreadystatechange = jQuery.noop;
-
- // Abort manually if needed
- if ( isAbort ) {
- if ( xhr.readyState !== 4 ) {
- xhr.abort();
- }
- } else {
- responses = {};
- status = xhr.status;
-
- // Support: IE<10
- // Accessing binary-data responseText throws an exception
- // (#11426)
- if ( typeof xhr.responseText === "string" ) {
- responses.text = xhr.responseText;
- }
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
+ headers[ "X-Requested-With" ] = "XMLHttpRequest";
+ }
- // Firefox throws an exception when accessing
- // statusText for faulty cross-domain requests
- try {
- statusText = xhr.statusText;
- } catch( e ) {
- // We normalize with Webkit giving an empty statusText
- statusText = "";
- }
+ // Set headers
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
- // Filter status for non standard behaviors
+ // Callback
+ callback = function( type ) {
+ return function() {
+ if ( callback ) {
+ callback = errorCallback = xhr.onload =
+ xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;
+
+ if ( type === "abort" ) {
+ xhr.abort();
+ } else if ( type === "error" ) {
+
+ // Support: IE <=9 only
+ // On a manual native abort, IE9 throws
+ // errors on any property access that is not readyState
+ if ( typeof xhr.status !== "number" ) {
+ complete( 0, "error" );
+ } else {
+ complete(
- // If the request is local and we have data: assume a success
- // (success with no data won't get notified, that's the best we
- // can do given current implementations)
- if ( !status && options.isLocal && !options.crossDomain ) {
- status = responses.text ? 200 : 404;
- // IE - #1450: sometimes returns 1223 when it should be 204
- } else if ( status === 1223 ) {
- status = 204;
+ // File: protocol always yields status 0; see #8605, #14207
+ xhr.status,
+ xhr.statusText
+ );
}
+ } else {
+ complete(
+ xhrSuccessStatus[ xhr.status ] || xhr.status,
+ xhr.statusText,
+
+ // Support: IE <=9 only
+ // IE9 has no XHR2 but throws on binary (trac-11426)
+ // For XHR2 non-text, let the caller handle it (gh-2498)
+ ( xhr.responseType || "text" ) !== "text" ||
+ typeof xhr.responseText !== "string" ?
+ { binary: xhr.response } :
+ { text: xhr.responseText },
+ xhr.getAllResponseHeaders()
+ );
}
}
+ };
+ };
+
+ // Listen to events
+ xhr.onload = callback();
+ errorCallback = xhr.onerror = callback( "error" );
- // Call complete if needed
- if ( responses ) {
- complete( status, statusText, responses, xhr.getAllResponseHeaders() );
+ // Support: IE 9 only
+ // Use onreadystatechange to replace onabort
+ // to handle uncaught aborts
+ if ( xhr.onabort !== undefined ) {
+ xhr.onabort = errorCallback;
+ } else {
+ xhr.onreadystatechange = function() {
+
+ // Check readyState before timeout as it changes
+ if ( xhr.readyState === 4 ) {
+
+ // Allow onerror to be called first,
+ // but that will not handle a native abort
+ // Also, save errorCallback to a variable
+ // as xhr.onerror cannot be accessed
+ window.setTimeout( function() {
+ if ( callback ) {
+ errorCallback();
+ }
+ } );
}
};
+ }
- if ( !options.async ) {
- // if we're in sync mode we fire the callback
- callback();
- } else if ( xhr.readyState === 4 ) {
- // (IE6 & IE7) if it's in cache and has been
- // retrieved directly we need to fire the callback
- setTimeout( callback );
- } else {
- // Add to the list of active xhr callbacks
- xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
- }
- },
+ // Create the abort callback
+ callback = callback( "abort" );
- abort: function() {
+ try {
+
+ // Do send the request (this may raise an exception)
+ xhr.send( options.hasContent && options.data || null );
+ } catch ( e ) {
+
+ // #14683: Only rethrow if this hasn't been notified as an error yet
if ( callback ) {
- callback( undefined, true );
+ throw e;
}
}
- };
- }
- });
-}
+ },
-// Functions to create xhrs
-function createStandardXHR() {
- try {
- return new window.XMLHttpRequest();
- } catch( e ) {}
-}
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+} );
-function createActiveXHR() {
- try {
- return new window.ActiveXObject( "Microsoft.XMLHTTP" );
- } catch( e ) {}
-}
+// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
+jQuery.ajaxPrefilter( function( s ) {
+ if ( s.crossDomain ) {
+ s.contents.script = false;
+ }
+} );
// Install script dataType
-jQuery.ajaxSetup({
+jQuery.ajaxSetup( {
accepts: {
- script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ script: "text/javascript, application/javascript, " +
+ "application/ecmascript, application/x-ecmascript"
},
contents: {
- script: /(?:java|ecma)script/
+ script: /\b(?:java|ecma)script\b/
},
converters: {
"text script": function( text ) {
@@ -9739,78 +9433,51 @@ jQuery.ajaxSetup({
return text;
}
}
-});
+} );
-// Handle cache's special case and global
+// Handle cache's special case and crossDomain
jQuery.ajaxPrefilter( "script", function( s ) {
if ( s.cache === undefined ) {
s.cache = false;
}
if ( s.crossDomain ) {
s.type = "GET";
- s.global = false;
}
-});
+} );
// Bind script tag hack transport
-jQuery.ajaxTransport( "script", function(s) {
+jQuery.ajaxTransport( "script", function( s ) {
// This transport only deals with cross domain requests
if ( s.crossDomain ) {
-
- var script,
- head = document.head || jQuery("head")[0] || document.documentElement;
-
+ var script, callback;
return {
-
- send: function( _, callback ) {
-
- script = document.createElement("script");
-
- script.async = true;
-
- if ( s.scriptCharset ) {
- script.charset = s.scriptCharset;
- }
-
- script.src = s.url;
-
- // Attach handlers for all browsers
- script.onload = script.onreadystatechange = function( _, isAbort ) {
-
- if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
-
- // Handle memory leak in IE
- script.onload = script.onreadystatechange = null;
-
- // Remove the script
- if ( script.parentNode ) {
- script.parentNode.removeChild( script );
- }
-
- // Dereference the script
- script = null;
-
- // Callback if not abort
- if ( !isAbort ) {
- callback( 200, "success" );
+ send: function( _, complete ) {
+ script = jQuery( "<script>" ).prop( {
+ charset: s.scriptCharset,
+ src: s.url
+ } ).on(
+ "load error",
+ callback = function( evt ) {
+ script.remove();
+ callback = null;
+ if ( evt ) {
+ complete( evt.type === "error" ? 404 : 200, evt.type );
}
}
- };
+ );
- // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
// Use native DOM manipulation to avoid our domManip AJAX trickery
- head.insertBefore( script, head.firstChild );
+ document.head.appendChild( script[ 0 ] );
},
-
abort: function() {
- if ( script ) {
- script.onload( undefined, true );
+ if ( callback ) {
+ callback();
}
}
};
}
-});
+} );
@@ -9819,14 +9486,14 @@ var oldCallbacks = [],
rjsonp = /(=)\?(?=&|$)|\?\?/;
// Default jsonp settings
-jQuery.ajaxSetup({
+jQuery.ajaxSetup( {
jsonp: "callback",
jsonpCallback: function() {
var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
this[ callback ] = true;
return callback;
}
-});
+} );
// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
@@ -9834,7 +9501,10 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
var callbackName, overwritten, responseContainer,
jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
"url" :
- typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ typeof s.data === "string" &&
+ ( s.contentType || "" )
+ .indexOf( "application/x-www-form-urlencoded" ) === 0 &&
+ rjsonp.test( s.data ) && "data"
);
// Handle iff the expected data type is "jsonp" or we have a parameter to set
@@ -9853,14 +9523,14 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
}
// Use data converter to retrieve json after script execution
- s.converters["script json"] = function() {
+ s.converters[ "script json" ] = function() {
if ( !responseContainer ) {
jQuery.error( callbackName + " was not called" );
}
return responseContainer[ 0 ];
};
- // force json dataType
+ // Force json dataType
s.dataTypes[ 0 ] = "json";
// Install callback
@@ -9870,16 +9540,24 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
};
// Clean-up function (fires after converters)
- jqXHR.always(function() {
- // Restore preexisting value
- window[ callbackName ] = overwritten;
+ jqXHR.always( function() {
+
+ // If previous value didn't exist - remove it
+ if ( overwritten === undefined ) {
+ jQuery( window ).removeProp( callbackName );
+
+ // Otherwise restore preexisting value
+ } else {
+ window[ callbackName ] = overwritten;
+ }
// Save back as free
if ( s[ callbackName ] ) {
- // make sure that re-using the options doesn't screw things around
+
+ // Make sure that re-using the options doesn't screw things around
s.jsonpCallback = originalSettings.jsonpCallback;
- // save the callback name for future use
+ // Save the callback name for future use
oldCallbacks.push( callbackName );
}
@@ -9889,38 +9567,70 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
}
responseContainer = overwritten = undefined;
- });
+ } );
// Delegate to script
return "script";
}
-});
+} );
-// data: string of html
-// context (optional): If specified, the fragment will be created in this context, defaults to document
+// Support: Safari 8 only
+// In Safari 8 documents created via document.implementation.createHTMLDocument
+// collapse sibling forms: the second one becomes a child of the first one.
+// Because of that, this security measure has to be disabled in Safari 8.
+// https://bugs.webkit.org/show_bug.cgi?id=137337
+support.createHTMLDocument = ( function() {
+ var body = document.implementation.createHTMLDocument( "" ).body;
+ body.innerHTML = "<form></form><form></form>";
+ return body.childNodes.length === 2;
+} )();
+
+
+// Argument "data" should be string of html
+// context (optional): If specified, the fragment will be created in this context,
+// defaults to document
// keepScripts (optional): If true, will include scripts passed in the html string
jQuery.parseHTML = function( data, context, keepScripts ) {
- if ( !data || typeof data !== "string" ) {
- return null;
+ if ( typeof data !== "string" ) {
+ return [];
}
if ( typeof context === "boolean" ) {
keepScripts = context;
context = false;
}
- context = context || document;
- var parsed = rsingleTag.exec( data ),
- scripts = !keepScripts && [];
+ var base, parsed, scripts;
+
+ if ( !context ) {
+
+ // Stop scripts or inline event handlers from being executed immediately
+ // by using document.implementation
+ if ( support.createHTMLDocument ) {
+ context = document.implementation.createHTMLDocument( "" );
+
+ // Set the base href for the created document
+ // so any parsed elements with URLs
+ // are based on the document's URL (gh-2965)
+ base = context.createElement( "base" );
+ base.href = document.location.href;
+ context.head.appendChild( base );
+ } else {
+ context = document;
+ }
+ }
+
+ parsed = rsingleTag.exec( data );
+ scripts = !keepScripts && [];
// Single tag
if ( parsed ) {
- return [ context.createElement( parsed[1] ) ];
+ return [ context.createElement( parsed[ 1 ] ) ];
}
- parsed = jQuery.buildFragment( [ data ], context, scripts );
+ parsed = buildFragment( [ data ], context, scripts );
if ( scripts && scripts.length ) {
jQuery( scripts ).remove();
@@ -9930,23 +9640,16 @@ jQuery.parseHTML = function( data, context, keepScripts ) {
};
-// Keep a copy of the old load method
-var _load = jQuery.fn.load;
-
/**
* Load a url into a page
*/
jQuery.fn.load = function( url, params, callback ) {
- if ( typeof url !== "string" && _load ) {
- return _load.apply( this, arguments );
- }
-
- var selector, response, type,
+ var selector, type, response,
self = this,
- off = url.indexOf(" ");
+ off = url.indexOf( " " );
- if ( off >= 0 ) {
- selector = jQuery.trim( url.slice( off, url.length ) );
+ if ( off > -1 ) {
+ selector = jQuery.trim( url.slice( off ) );
url = url.slice( 0, off );
}
@@ -9964,14 +9667,16 @@ jQuery.fn.load = function( url, params, callback ) {
// If we have elements to modify, make the request
if ( self.length > 0 ) {
- jQuery.ajax({
+ jQuery.ajax( {
url: url,
- // if "type" variable is undefined, then "GET" method will be used
- type: type,
+ // If "type" variable is undefined, then "GET" method will be used.
+ // Make value of this field explicit since
+ // user can override it through ajaxSetup method
+ type: type || "GET",
dataType: "html",
data: params
- }).done(function( responseText ) {
+ } ).done( function( responseText ) {
// Save response for use in complete callback
response = arguments;
@@ -9980,14 +9685,19 @@ jQuery.fn.load = function( url, params, callback ) {
// If a selector was specified, locate the right elements in a dummy div
// Exclude scripts to avoid IE 'Permission Denied' errors
- jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+ jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
// Otherwise use the full result
responseText );
- }).complete( callback && function( jqXHR, status ) {
- self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
- });
+ // If the request succeeds, this function gets "data", "status", "jqXHR"
+ // but they are ignored because response was set above.
+ // If it fails, this function gets "jqXHR", "status", "error"
+ } ).always( callback && function( jqXHR, status ) {
+ self.each( function() {
+ callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
+ } );
+ } );
}
return this;
@@ -9996,27 +9706,37 @@ jQuery.fn.load = function( url, params, callback ) {
-jQuery.expr.filters.animated = function( elem ) {
- return jQuery.grep(jQuery.timers, function( fn ) {
- return elem === fn.elem;
- }).length;
-};
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [
+ "ajaxStart",
+ "ajaxStop",
+ "ajaxComplete",
+ "ajaxError",
+ "ajaxSuccess",
+ "ajaxSend"
+], function( i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+} );
+jQuery.expr.pseudos.animated = function( elem ) {
+ return jQuery.grep( jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ } ).length;
+};
+
+
-var docElem = window.document.documentElement;
/**
* Gets a window from an element
*/
function getWindow( elem ) {
- return jQuery.isWindow( elem ) ?
- elem :
- elem.nodeType === 9 ?
- elem.defaultView || elem.parentWindow :
- false;
+ return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
}
jQuery.offset = {
@@ -10026,7 +9746,7 @@ jQuery.offset = {
curElem = jQuery( elem ),
props = {};
- // set position first, in-case top/left are set even on static elem
+ // Set position first, in-case top/left are set even on static elem
if ( position === "static" ) {
elem.style.position = "relative";
}
@@ -10035,20 +9755,24 @@ jQuery.offset = {
curCSSTop = jQuery.css( elem, "top" );
curCSSLeft = jQuery.css( elem, "left" );
calculatePosition = ( position === "absolute" || position === "fixed" ) &&
- jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
+ ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
- // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ // Need to be able to calculate position if either
+ // top or left is auto and position is either absolute or fixed
if ( calculatePosition ) {
curPosition = curElem.position();
curTop = curPosition.top;
curLeft = curPosition.left;
+
} else {
curTop = parseFloat( curCSSTop ) || 0;
curLeft = parseFloat( curCSSLeft ) || 0;
}
if ( jQuery.isFunction( options ) ) {
- options = options.call( elem, i, curOffset );
+
+ // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
+ options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
}
if ( options.top != null ) {
@@ -10060,48 +9784,55 @@ jQuery.offset = {
if ( "using" in options ) {
options.using.call( elem, props );
+
} else {
curElem.css( props );
}
}
};
-jQuery.fn.extend({
+jQuery.fn.extend( {
offset: function( options ) {
+
+ // Preserve chaining for setter
if ( arguments.length ) {
return options === undefined ?
this :
- this.each(function( i ) {
+ this.each( function( i ) {
jQuery.offset.setOffset( this, options, i );
- });
+ } );
}
- var docElem, win,
- box = { top: 0, left: 0 },
- elem = this[ 0 ],
- doc = elem && elem.ownerDocument;
+ var docElem, win, rect, doc,
+ elem = this[ 0 ];
- if ( !doc ) {
+ if ( !elem ) {
return;
}
- docElem = doc.documentElement;
-
- // Make sure it's not a disconnected DOM node
- if ( !jQuery.contains( docElem, elem ) ) {
- return box;
+ // Support: IE <=11 only
+ // Running getBoundingClientRect on a
+ // disconnected node in IE throws an error
+ if ( !elem.getClientRects().length ) {
+ return { top: 0, left: 0 };
}
- // If we don't have gBCR, just use 0,0 rather than error
- // BlackBerry 5, iOS 3 (original iPhone)
- if ( typeof elem.getBoundingClientRect !== strundefined ) {
- box = elem.getBoundingClientRect();
+ rect = elem.getBoundingClientRect();
+
+ // Make sure element is not hidden (display: none)
+ if ( rect.width || rect.height ) {
+ doc = elem.ownerDocument;
+ win = getWindow( doc );
+ docElem = doc.documentElement;
+
+ return {
+ top: rect.top + win.pageYOffset - docElem.clientTop,
+ left: rect.left + win.pageXOffset - docElem.clientLeft
+ };
}
- win = getWindow( doc );
- return {
- top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
- left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
- };
+
+ // Return zeros for disconnected and hidden elements (gh-2310)
+ return rect;
},
position: function() {
@@ -10110,14 +9841,18 @@ jQuery.fn.extend({
}
var offsetParent, offset,
- parentOffset = { top: 0, left: 0 },
- elem = this[ 0 ];
+ elem = this[ 0 ],
+ parentOffset = { top: 0, left: 0 };
- // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
+ // Fixed elements are offset from window (parentOffset = {top:0, left: 0},
+ // because it is its only offset parent
if ( jQuery.css( elem, "position" ) === "fixed" ) {
- // we assume that getBoundingClientRect is available when computed position is fixed
+
+ // Assume getBoundingClientRect is there when computed position is fixed
offset = elem.getBoundingClientRect();
+
} else {
+
// Get *real* offsetParent
offsetParent = this.offsetParent();
@@ -10128,81 +9863,95 @@ jQuery.fn.extend({
}
// Add offsetParent borders
- parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
- parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ parentOffset = {
+ top: parentOffset.top + jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ),
+ left: parentOffset.left + jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true )
+ };
}
// Subtract parent offsets and element margins
- // note: when an element has margin: auto the offsetLeft and marginLeft
- // are the same in Safari causing offset.left to incorrectly be 0
return {
- top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
- left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
};
},
+ // This method will return documentElement in the following cases:
+ // 1) For the element inside the iframe without offsetParent, this method will return
+ // documentElement of the parent window
+ // 2) For the hidden or detached element
+ // 3) For body or html element, i.e. in case of the html node - it will return itself
+ //
+ // but those exceptions were never presented as a real life use-cases
+ // and might be considered as more preferable results.
+ //
+ // This logic, however, is not guaranteed and can change at any point in the future
offsetParent: function() {
- return this.map(function() {
- var offsetParent = this.offsetParent || docElem;
+ return this.map( function() {
+ var offsetParent = this.offsetParent;
- while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
+ while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
offsetParent = offsetParent.offsetParent;
}
- return offsetParent || docElem;
- });
+
+ return offsetParent || documentElement;
+ } );
}
-});
+} );
// Create scrollLeft and scrollTop methods
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
- var top = /Y/.test( prop );
+ var top = "pageYOffset" === prop;
jQuery.fn[ method ] = function( val ) {
return access( this, function( elem, method, val ) {
var win = getWindow( elem );
if ( val === undefined ) {
- return win ? (prop in win) ? win[ prop ] :
- win.document.documentElement[ method ] :
- elem[ method ];
+ return win ? win[ prop ] : elem[ method ];
}
if ( win ) {
win.scrollTo(
- !top ? val : jQuery( win ).scrollLeft(),
- top ? val : jQuery( win ).scrollTop()
+ !top ? val : win.pageXOffset,
+ top ? val : win.pageYOffset
);
} else {
elem[ method ] = val;
}
- }, method, val, arguments.length, null );
+ }, method, val, arguments.length );
};
-});
+} );
+// Support: Safari <=7 - 9.1, Chrome <=37 - 49
// Add the top/left cssHooks using jQuery.fn.position
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
-// getComputedStyle returns percent when specified for top/left/bottom/right
-// rather than make the css module depend on the offset module, we just check for it here
+// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
+// getComputedStyle returns percent when specified for top/left/bottom/right;
+// rather than make the css module depend on the offset module, just check for it here
jQuery.each( [ "top", "left" ], function( i, prop ) {
jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
function( elem, computed ) {
if ( computed ) {
computed = curCSS( elem, prop );
- // if curCSS returns percentage, fallback to offset
+
+ // If curCSS returns percentage, fallback to offset
return rnumnonpx.test( computed ) ?
jQuery( elem ).position()[ prop ] + "px" :
computed;
}
}
);
-});
+} );
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
- jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
- // margin is only for outerHeight, outerWidth
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
+ function( defaultExtra, funcName ) {
+
+ // Margin is only for outerHeight, outerWidth
jQuery.fn[ funcName ] = function( margin, value ) {
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
@@ -10211,18 +9960,19 @@ jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
var doc;
if ( jQuery.isWindow( elem ) ) {
- // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
- // isn't a whole lot we can do. See pull request at this URL for discussion:
- // https://github.com/jquery/jquery/pull/764
- return elem.document.documentElement[ "client" + name ];
+
+ // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
+ return funcName.indexOf( "outer" ) === 0 ?
+ elem[ "inner" + name ] :
+ elem.document.documentElement[ "client" + name ];
}
// Get document width or height
if ( elem.nodeType === 9 ) {
doc = elem.documentElement;
- // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
- // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
+ // whichever is greatest
return Math.max(
elem.body[ "scroll" + name ], doc[ "scroll" + name ],
elem.body[ "offset" + name ], doc[ "offset" + name ],
@@ -10231,23 +9981,40 @@ jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
}
return value === undefined ?
+
// Get width or height on the element, requesting but not forcing parseFloat
jQuery.css( elem, type, extra ) :
// Set width or height on the element
jQuery.style( elem, type, value, extra );
- }, type, chainable ? margin : undefined, chainable, null );
+ }, type, chainable ? margin : undefined, chainable );
};
- });
-});
+ } );
+} );
-// The number of elements contained in the matched element set
-jQuery.fn.size = function() {
- return this.length;
-};
+jQuery.fn.extend( {
-jQuery.fn.andSelf = jQuery.fn.addBack;
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ?
+ this.off( selector, "**" ) :
+ this.off( types, selector || "**", fn );
+ }
+} );
+
+jQuery.parseJSON = JSON.parse;
@@ -10268,13 +10035,15 @@ jQuery.fn.andSelf = jQuery.fn.addBack;
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
- });
+ } );
}
+
var
+
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
@@ -10293,16 +10062,13 @@ jQuery.noConflict = function( deep ) {
return jQuery;
};
-// Expose jQuery and $ identifiers, even in
-// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// Expose jQuery and $ identifiers, even in AMD
+// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
// and CommonJS for browser emulators (#13566)
-if ( typeof noGlobal === strundefined ) {
+if ( !noGlobal ) {
window.jQuery = window.$ = jQuery;
}
-
-
return jQuery;
-
-}));
+} );
diff --git a/sphinx/themes/basic/static/jquery.js b/sphinx/themes/basic/static/jquery.js
index ab28a2472..f6a6a99e6 100644
--- a/sphinx/themes/basic/static/jquery.js
+++ b/sphinx/themes/basic/static/jquery.js
@@ -1,4 +1,4 @@
-/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
-!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
-if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==cb()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===cb()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ab:bb):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:bb,isPropagationStopped:bb,isImmediatePropagationStopped:bb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ab,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ab,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ab,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=bb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=bb),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function db(a){var b=eb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var eb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fb=/ jQuery\d+="(?:null|\d+)"/g,gb=new RegExp("<(?:"+eb+")[\\s/>]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/<tbody/i,lb=/<|&#?\w+;/,mb=/<(?:script|style|link)/i,nb=/checked\s*(?:[^=]|=\s*.checked.)/i,ob=/^$|\/(?:java|ecma)script/i,pb=/^true\/(.*)/,qb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,rb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?"<table>"!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")
-},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$b=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_b||(_b=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_b),_b=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});
+/*! jQuery v3.1.0 | (c) jQuery Foundation | jquery.org/license */
+!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.1.0",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null!=a?a<0?this[a+this.length]:this[a]:f.call(this)},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=r.isArray(d)))?(e?(e=!1,f=c&&r.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"label"in b&&b.disabled===a||"form"in b&&b.disabled===a||"form"in b&&b.disabled===!1&&(b.isDisabled===a||b.isDisabled!==!a&&("label"in b||!ea(b))!==a)}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e)}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(_,aa),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=V.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(_,aa),$.test(j[0].type)&&qa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&sa(j),!a)return G.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||$.test(a)&&qa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext,B=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,C=/^.[^:#\[\.,]*$/;function D(a,b,c){if(r.isFunction(b))return r.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return r.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(C.test(b))return r.filter(b,a,c);b=r.filter(b,a)}return r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType})}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(D(this,a||[],!1))},not:function(a){return this.pushStack(D(this,a||[],!0))},is:function(a){return!!D(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var E,F=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,G=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||E,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:F.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),B.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};G.prototype=r.fn,E=r(d);var H=/^(?:parents|prev(?:Until|All))/,I={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function J(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return J(a,"nextSibling")},prev:function(a){return J(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return a.contentDocument||r.merge([],a.childNodes)}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(I[a]||r.uniqueSort(e),H.test(a)&&e.reverse()),this.pushStack(e)}});var K=/\S+/g;function L(a){var b={};return r.each(a.match(K)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?L(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function M(a){return a}function N(a){throw a}function O(a,b,c){var d;try{a&&r.isFunction(d=a.promise)?d.call(a).done(b).fail(c):a&&r.isFunction(d=a.then)?d.call(a,b,c):b.call(void 0,a)}catch(a){c.call(void 0,a)}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,M,e),g(f,c,N,e)):(f++,j.call(a,g(f,c,M,e),g(f,c,N,e),g(f,c,M,c.notifyWith))):(d!==M&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==N&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:M,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:M)),c[2][3].add(g(0,a,r.isFunction(d)?d:N))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(O(a,g.done(h(c)).resolve,g.reject),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)O(e[c],h(c),g.reject);return g.promise()}});var P=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&P.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var Q=r.Deferred();r.fn.ready=function(a){return Q.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,holdReady:function(a){a?r.readyWait++:r.ready(!0)},ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||Q.resolveWith(d,[r]))}}),r.ready.then=Q.then;function R(){d.removeEventListener("DOMContentLoaded",R),a.removeEventListener("load",R),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",R),a.addEventListener("load",R));var S=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)S(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,
+r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},T=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function U(){this.expando=r.expando+U.uid++}U.uid=1,U.prototype={cache:function(a){var b=a[this.expando];return b||(b={},T(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){r.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(K)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var V=new U,W=new U,X=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Y=/[A-Z]/g;function Z(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Y,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c||"false"!==c&&("null"===c?null:+c+""===c?+c:X.test(c)?JSON.parse(c):c)}catch(e){}W.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return W.hasData(a)||V.hasData(a)},data:function(a,b,c){return W.access(a,b,c)},removeData:function(a,b){W.remove(a,b)},_data:function(a,b,c){return V.access(a,b,c)},_removeData:function(a,b){V.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=W.get(f),1===f.nodeType&&!V.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),Z(f,d,e[d])));V.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){W.set(this,a)}):S(this,function(b){var c;if(f&&void 0===b){if(c=W.get(f,a),void 0!==c)return c;if(c=Z(f,a),void 0!==c)return c}else this.each(function(){W.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){W.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=V.get(a,b),c&&(!d||r.isArray(c)?d=V.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return V.get(a,c)||V.access(a,c,{empty:r.Callbacks("once memory").add(function(){V.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=V.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var $=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,_=new RegExp("^(?:([+-])=|)("+$+")([a-z%]*)$","i"),aa=["Top","Right","Bottom","Left"],ba=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ca=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function da(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&_.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ea={};function fa(a){var b,c=a.ownerDocument,d=a.nodeName,e=ea[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ea[d]=e,e)}function ga(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=V.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&ba(d)&&(e[f]=fa(d))):"none"!==c&&(e[f]="none",V.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ga(this,!0)},hide:function(){return ga(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){ba(this)?r(this).show():r(this).hide()})}});var ha=/^(?:checkbox|radio)$/i,ia=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,ja=/^$|\/(?:java|ecma)script/i,ka={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ka.optgroup=ka.option,ka.tbody=ka.tfoot=ka.colgroup=ka.caption=ka.thead,ka.th=ka.td;function la(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&r.nodeName(a,b)?r.merge([a],c):c}function ma(a,b){for(var c=0,d=a.length;c<d;c++)V.set(a[c],"globalEval",!b||V.get(b[c],"globalEval"))}var na=/<|&#?\w+;/;function oa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(na.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ia.exec(f)||["",""])[1].toLowerCase(),i=ka[h]||ka._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=la(l.appendChild(f),"script"),j&&ma(g),c){k=0;while(f=g[k++])ja.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var pa=d.documentElement,qa=/^key/,ra=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,sa=/^([^.]*)(?:\.(.+)|)/;function ta(){return!0}function ua(){return!1}function va(){try{return d.activeElement}catch(a){}}function wa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)wa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ua;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(pa,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(K)||[""],j=b.length;while(j--)h=sa.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=V.hasData(a)&&V.get(a);if(q&&(i=q.events)){b=(b||"").match(K)||[""],j=b.length;while(j--)if(h=sa.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&V.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(V.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;c<h;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?r(e,this).index(i)>-1:r.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==va()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===va()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&r.nodeName(this,"input"))return this.click(),!1},_default:function(a){return r.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ta:ua,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:ua,isPropagationStopped:ua,isImmediatePropagationStopped:ua,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ta,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ta,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ta,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&qa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ra.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return wa(this,a,b,c,d)},one:function(a,b,c,d){return wa(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=ua),this.each(function(){r.event.remove(this,a,c,b)})}});var xa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,ya=/<script|<style|<link/i,za=/checked\s*(?:[^=]|=\s*.checked.)/i,Aa=/^true\/(.*)/,Ba=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ca(a,b){return r.nodeName(a,"table")&&r.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a:a}function Da(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ea(a){var b=Aa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(V.hasData(a)&&(f=V.access(a),g=V.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}W.hasData(a)&&(h=W.access(a),i=r.extend({},h),W.set(b,i))}}function Ga(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ha.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ha(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&za.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(m&&(e=oa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(la(e,"script"),Da),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,la(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ea),l=0;l<i;l++)j=h[l],ja.test(j.type||"")&&!V.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Ba,""),k))}return a}function Ia(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(la(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&ma(la(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(xa,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=la(h),f=la(a),d=0,e=f.length;d<e;d++)Ga(f[d],g[d]);if(b)if(c)for(f=f||la(a),g=g||la(h),d=0,e=f.length;d<e;d++)Fa(f[d],g[d]);else Fa(a,h);return g=la(h,"script"),g.length>0&&ma(g,!i&&la(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(T(c)){if(b=c[V.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[V.expando]=void 0}c[W.expando]&&(c[W.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return S(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(la(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return S(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!ya.test(a)&&!ka[(ia.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(la(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(la(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var Ja=/^margin/,Ka=new RegExp("^("+$+")(?!px)[a-z%]+$","i"),La=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",pa.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,pa.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Ma(a,b,c){var d,e,f,g,h=a.style;return c=c||La(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ka.test(g)&&Ja.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Na(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Oa=/^(none|table(?!-c[ea]).+)/,Pa={position:"absolute",visibility:"hidden",display:"block"},Qa={letterSpacing:"0",fontWeight:"400"},Ra=["Webkit","Moz","ms"],Sa=d.createElement("div").style;function Ta(a){if(a in Sa)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ra.length;while(c--)if(a=Ra[c]+b,a in Sa)return a}function Ua(a,b,c){var d=_.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Va(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+aa[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+aa[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+aa[f]+"Width",!0,e))):(g+=r.css(a,"padding"+aa[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+aa[f]+"Width",!0,e)));return g}function Wa(a,b,c){var d,e=!0,f=La(a),g="border-box"===r.css(a,"boxSizing",!1,f);if(a.getClientRects().length&&(d=a.getBoundingClientRect()[b]),d<=0||null==d){if(d=Ma(a,b,f),(d<0||null==d)&&(d=a.style[b]),Ka.test(d))return d;e=g&&(o.boxSizingReliable()||d===a.style[b]),d=parseFloat(d)||0}return d+Va(a,b,c||(g?"border":"content"),e,f)+"px"}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Ma(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=a.style;return b=r.cssProps[h]||(r.cssProps[h]=Ta(h)||h),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=_.exec(c))&&e[1]&&(c=da(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b);return b=r.cssProps[h]||(r.cssProps[h]=Ta(h)||h),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Ma(a,b,d)),"normal"===e&&b in Qa&&(e=Qa[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Oa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?Wa(a,b,d):ca(a,Pa,function(){return Wa(a,b,d)})},set:function(a,c,d){var e,f=d&&La(a),g=d&&Va(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=_.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ua(a,c,g)}}}),r.cssHooks.marginLeft=Na(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Ma(a,"marginLeft"))||a.getBoundingClientRect().left-ca(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+aa[d]+b]=f[d]||f[d-2]||f[0];return e}},Ja.test(a)||(r.cssHooks[a+b].set=Ua)}),r.fn.extend({css:function(a,b){return S(this,function(a,b,c){var d,e,f={},g=0;if(r.isArray(b)){for(d=La(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function Xa(a,b,c,d,e){return new Xa.prototype.init(a,b,c,d,e)}r.Tween=Xa,Xa.prototype={constructor:Xa,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=Xa.propHooks[this.prop];return a&&a.get?a.get(this):Xa.propHooks._default.get(this)},run:function(a){var b,c=Xa.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Xa.propHooks._default.set(this),this}},Xa.prototype.init.prototype=Xa.prototype,Xa.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},Xa.propHooks.scrollTop=Xa.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=Xa.prototype.init,r.fx.step={};var Ya,Za,$a=/^(?:toggle|show|hide)$/,_a=/queueHooks$/;function ab(){Za&&(a.requestAnimationFrame(ab),r.fx.tick())}function bb(){return a.setTimeout(function(){Ya=void 0}),Ya=r.now()}function cb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=aa[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function db(a,b,c){for(var d,e=(gb.tweeners[b]||[]).concat(gb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function eb(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&ba(a),q=V.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],$a.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=V.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ga([a],!0),j=a.style.display||j,k=r.css(a,"display"),ga([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=V.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ga([a],!0),m.done(function(){p||ga([a]),V.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=db(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function fb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],r.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function gb(a,b,c){var d,e,f=0,g=gb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Ya||bb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:Ya||bb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(fb(k,j.opts.specialEasing);f<g;f++)if(d=gb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,db,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}r.Animation=r.extend(gb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return da(c.elem,a,_.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(K);for(var c,d=0,e=a.length;d<e;d++)c=a[d],gb.tweeners[c]=gb.tweeners[c]||[],gb.tweeners[c].unshift(b)},prefilters:[eb],prefilter:function(a,b){b?gb.prefilters.unshift(a):gb.prefilters.push(a)}}),r.speed=function(a,b,c){var e=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off||d.hidden?e.duration=0:e.duration="number"==typeof e.duration?e.duration:e.duration in r.fx.speeds?r.fx.speeds[e.duration]:r.fx.speeds._default,null!=e.queue&&e.queue!==!0||(e.queue="fx"),e.old=e.complete,e.complete=function(){r.isFunction(e.old)&&e.old.call(this),e.queue&&r.dequeue(this,e.queue)},e},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(ba).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=gb(this,r.extend({},a),f);(e||V.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=V.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&_a.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=V.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(cb(b,!0),a,d,e)}}),r.each({slideDown:cb("show"),slideUp:cb("hide"),slideToggle:cb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(Ya=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),Ya=void 0},r.fx.timer=function(a){r.timers.push(a),a()?r.fx.start():r.timers.pop()},r.fx.interval=13,r.fx.start=function(){Za||(Za=a.requestAnimationFrame?a.requestAnimationFrame(ab):a.setInterval(r.fx.tick,r.fx.interval))},r.fx.stop=function(){a.cancelAnimationFrame?a.cancelAnimationFrame(Za):a.clearInterval(Za),Za=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var hb,ib=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return S(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?hb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&r.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(K);
+if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),hb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=ib[b]||r.find.attr;ib[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=ib[g],ib[g]=e,e=null!=c(a,b,d)?g:null,ib[g]=f),e}});var jb=/^(?:input|select|textarea|button)$/i,kb=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return S(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):jb.test(a.nodeName)||kb.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});var lb=/[\t\r\n\f]/g;function mb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,mb(this)))});if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=r.trim(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,mb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(K)||[];while(c=this[i++])if(e=mb(c),d=1===c.nodeType&&(" "+e+" ").replace(lb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=r.trim(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,mb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(K)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=mb(this),b&&V.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":V.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+mb(c)+" ").replace(lb," ").indexOf(b)>-1)return!0;return!1}});var nb=/\r/g,ob=/[\x20\t\r\n\f]+/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":r.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(nb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:r.trim(r.text(a)).replace(ob," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type,g=f?null:[],h=f?e+1:d.length,i=e<0?h:f?e:0;i<h;i++)if(c=d[i],(c.selected||i===e)&&!c.disabled&&(!c.parentNode.disabled||!r.nodeName(c.parentNode,"optgroup"))){if(b=r(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(r.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var pb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!pb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,pb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(V.get(h,"events")||{})[b.type]&&V.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&T(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!T(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=V.access(d,b);e||d.addEventListener(a,c,!0),V.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=V.access(d,b)-1;e?V.access(d,b,e):(d.removeEventListener(a,c,!0),V.remove(d,b))}}});var qb=a.location,rb=r.now(),sb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var tb=/\[\]$/,ub=/\r?\n/g,vb=/^(?:submit|button|image|reset|file)$/i,wb=/^(?:input|select|textarea|keygen)/i;function xb(a,b,c,d){var e;if(r.isArray(b))r.each(b,function(b,e){c||tb.test(a)?d(a,e):xb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)xb(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(r.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)xb(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&wb.test(this.nodeName)&&!vb.test(a)&&(this.checked||!ha.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:r.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(ub,"\r\n")}}):{name:b.name,value:c.replace(ub,"\r\n")}}).get()}});var yb=/%20/g,zb=/#.*$/,Ab=/([?&])_=[^&]*/,Bb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Cb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Db=/^(?:GET|HEAD)$/,Eb=/^\/\//,Fb={},Gb={},Hb="*/".concat("*"),Ib=d.createElement("a");Ib.href=qb.href;function Jb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(K)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Kb(a,b,c,d){var e={},f=a===Gb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Lb(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Mb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Nb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:qb.href,type:"GET",isLocal:Cb.test(qb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Hb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Lb(Lb(a,r.ajaxSettings),b):Lb(r.ajaxSettings,a)},ajaxPrefilter:Jb(Fb),ajaxTransport:Jb(Gb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Bb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||qb.href)+"").replace(Eb,qb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(K)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Ib.protocol+"//"+Ib.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Kb(Fb,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Db.test(o.type),f=o.url.replace(zb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(yb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(sb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Ab,""),n=(sb.test(f)?"&":"?")+"_="+rb++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Hb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Kb(Gb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Mb(o,y,d)),v=Nb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Ob={0:200,1223:204},Pb=r.ajaxSettings.xhr();o.cors=!!Pb&&"withCredentials"in Pb,o.ajax=Pb=!!Pb,r.ajaxTransport(function(b){var c,d;if(o.cors||Pb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Ob[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Qb=[],Rb=/(=)\?(?=&|$)|\?\?/;r.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Qb.pop()||r.expando+"_"+rb++;return this[a]=!0,a}}),r.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Rb.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Rb.test(b.data)&&"data");if(h||"jsonp"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Rb,"$1"+e):b.jsonp!==!1&&(b.url+=(sb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||r.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Qb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),"script"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=B.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=oa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=r.trim(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&r.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?r("<div>").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length};function Sb(a){return r.isWindow(a)?a:9===a.nodeType&&a.defaultView}r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),d.width||d.height?(e=f.ownerDocument,c=Sb(e),b=e.documentElement,{top:d.top+c.pageYOffset-b.clientTop,left:d.left+c.pageXOffset-b.clientLeft}):d):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),r.nodeName(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||pa})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return S(this,function(a,d,e){var f=Sb(a);return void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Na(o.pixelPosition,function(a,c){if(c)return c=Ma(a,b),Ka.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return S(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.parseJSON=JSON.parse,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var Tb=a.jQuery,Ub=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Ub),b&&a.jQuery===r&&(a.jQuery=Tb),r},b||(a.jQuery=a.$=r),r});
diff --git a/sphinx/themes/basic/static/minus.png b/sphinx/themes/basic/static/minus.png
index 0f22b16b0..d96755fda 100644
--- a/sphinx/themes/basic/static/minus.png
+++ b/sphinx/themes/basic/static/minus.png
Binary files differ
diff --git a/sphinx/themes/basic/static/plus.png b/sphinx/themes/basic/static/plus.png
index 0cfe084cf..7107cec93 100644
--- a/sphinx/themes/basic/static/plus.png
+++ b/sphinx/themes/basic/static/plus.png
Binary files differ
diff --git a/sphinx/themes/basic/static/searchtools.js_t b/sphinx/themes/basic/static/searchtools.js_t
index 45ff1e4de..f521c3794 100644
--- a/sphinx/themes/basic/static/searchtools.js_t
+++ b/sphinx/themes/basic/static/searchtools.js_t
@@ -159,6 +159,10 @@ var Search = {
}
// stem the word
var word = stemmer.stemWord(tmp[i].toLowerCase());
+ // prevent stemmer from cutting word smaller than two chars
+ if(word.length < 3 && tmp[i].length >= 3) {
+ word = tmp[i];
+ }
var toAppend;
// select the correct list
if (word[0] == '-') {
@@ -256,7 +260,8 @@ var Search = {
displayNextItem();
});
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
- $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
+ var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX;
+ $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].endsWith(suffix) ? '' : suffix),
dataType: "text",
complete: function(jqxhr, textstatus) {
var data = jqxhr.responseText;
@@ -295,6 +300,7 @@ var Search = {
*/
performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames;
+ var docnames = this._index.docnames;
var objects = this._index.objects;
var objnames = this._index.objnames;
var titles = this._index.titles;
@@ -348,7 +354,7 @@ var Search = {
} else {
score += Scorer.objPrioDefault;
}
- results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
+ results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
}
}
}
@@ -360,6 +366,7 @@ var Search = {
* search for full-text terms in the index
*/
performTermsSearch : function(searchterms, excluded, terms, titleterms) {
+ var docnames = this._index.docnames;
var filenames = this._index.filenames;
var titles = this._index.titles;
@@ -434,7 +441,7 @@ var Search = {
// select one (max) score for the file.
// for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
- results.push([filenames[file], titles[file], '', null, score]);
+ results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
}
}
return results;
diff --git a/sphinx/themes/basic/static/up-pressed.png b/sphinx/themes/basic/static/up-pressed.png
index 99e721096..acee3b68e 100644
--- a/sphinx/themes/basic/static/up-pressed.png
+++ b/sphinx/themes/basic/static/up-pressed.png
Binary files differ
diff --git a/sphinx/themes/basic/static/up.png b/sphinx/themes/basic/static/up.png
index 26de002e8..2a940a7da 100644
--- a/sphinx/themes/basic/static/up.png
+++ b/sphinx/themes/basic/static/up.png
Binary files differ
diff --git a/sphinx/themes/bizstyle/static/background_b01.png b/sphinx/themes/bizstyle/static/background_b01.png
index d262745b4..353f26dde 100644
--- a/sphinx/themes/bizstyle/static/background_b01.png
+++ b/sphinx/themes/bizstyle/static/background_b01.png
Binary files differ
diff --git a/sphinx/themes/classic/layout.html b/sphinx/themes/classic/layout.html
index 934d62c0d..9e7222cf3 100644
--- a/sphinx/themes/classic/layout.html
+++ b/sphinx/themes/classic/layout.html
@@ -1,8 +1,8 @@
{#
- default/layout.html
+ classic/layout.html
~~~~~~~~~~~~~~~~~~~
- Sphinx layout template for the default theme.
+ Sphinx layout template for the classic theme.
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
diff --git a/sphinx/themes/classic/static/classic.css_t b/sphinx/themes/classic/static/classic.css_t
index 93673b01f..a705fcbf9 100644
--- a/sphinx/themes/classic/static/classic.css_t
+++ b/sphinx/themes/classic/static/classic.css_t
@@ -1,8 +1,8 @@
/*
- * default.css_t
+ * classic.css_t
* ~~~~~~~~~~~~~
*
- * Sphinx stylesheet -- default theme.
+ * Sphinx stylesheet -- classic theme.
*
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
diff --git a/sphinx/themes/epub/layout.html b/sphinx/themes/epub/layout.html
index 541fcdba5..051d789c3 100644
--- a/sphinx/themes/epub/layout.html
+++ b/sphinx/themes/epub/layout.html
@@ -15,14 +15,7 @@
{# add only basic navigation links #}
{% block sidebar1 %}{% endblock %}
{% block sidebar2 %}{% endblock %}
+{% block relbar1 %}{% endblock %}
{% block relbar2 %}{% endblock %}
{% block linktags %}{% endblock %}
-
-{# redefine relbar1 and footer to only call super if options are true #}
-{%- block relbar1 %}
-{% if theme_relbar1|tobool %}{{ super() }}{% endif %}
-{%- endblock %}
-{%- block footer %}
-{% if theme_footer|tobool %}{{ super() }}{% endif %}
-{%- endblock %}
-
+{% block footer %}{% endblock %}
diff --git a/sphinx/themes/epub/static/epub.css_t b/sphinx/themes/epub/static/epub.css_t
new file mode 100644
index 000000000..ab8610072
--- /dev/null
+++ b/sphinx/themes/epub/static/epub.css_t
@@ -0,0 +1,591 @@
+/*
+ * epub.css_t
+ * ~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- epub theme.
+ *
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+{% if theme_writing_mode is defined %}
+body{
+ writing-mode: {{ theme_writing_mode }};
+ line-break: normal;
+ -epub-writing-mode: {{ theme_writing_mode }};
+ -webkit-writing-mode: {{ theme_writing_mode }};
+ -epub-line-break: normal;
+ -webkit-line-break: normal;
+}
+{% endif %}
+
+div.clearer {
+ clear: both;
+}
+
+a:link, a:visited {
+ color: #3333ff;
+ text-decoration: underline;
+}
+
+img {
+ border: 0;
+ max-width: 100%;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+ width: 100%;
+ font-family: sans-serif;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+}
+
+div.sphinxsidebar ul {
+ list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 100%;
+}
+
+img {
+ border: 0;
+ max-width: 100%;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 130%;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable ul {
+ margin-top: 0;
+ margin-bottom: 0;
+ list-style-type: none;
+}
+
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+/* -- domain module index --------------------------------------------------- */
+
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+a.headerlink {
+ visibility: hidden;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+.align-left {
+ text-align: left;
+}
+
+.align-center {
+ text-align: center;
+}
+
+.align-right {
+ text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar {
+ margin: 0 0 0.5em 1em;
+ border: 1px solid #ddb;
+ padding: 7px 7px 0 7px;
+ background-color: #ffe;
+ width: 40%;
+ float: right;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+div.topic {
+ border: 1px solid #ccc;
+ padding: 7px 7px 0 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 110%;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+ border: 0;
+ border-collapse: collapse;
+}
+
+table caption span.caption-number {
+ font-style: italic;
+}
+
+table caption span.caption-text {
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 5px;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+table.footnote td, table.footnote th {
+ border: 0 !important;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px;
+}
+
+table.citation td {
+ border-bottom: none;
+}
+
+/* -- figures --------------------------------------------------------------- */
+
+div.figure p.caption span.caption-number {
+ font-style: italic;
+}
+
+div.figure p.caption span.caption-text {
+}
+
+/* -- field list styles ----------------------------------------------------- */
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+/* -- other body styles ----------------------------------------------------- */
+
+ol.arabic {
+ list-style: decimal;
+}
+
+ol.loweralpha {
+ list-style: lower-alpha;
+}
+
+ol.upperalpha {
+ list-style: upper-alpha;
+}
+
+ol.lowerroman {
+ list-style: lower-roman;
+}
+
+ol.upperroman {
+ list-style: upper-roman;
+}
+
+dl {
+ margin-bottom: 15px;
+}
+
+dd p {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+dt:target, .highlighted {
+ background-color: #ddd;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 110%;
+}
+
+.optional {
+ font-size: 130%;
+}
+
+.sig-paren {
+ font-size: larger;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+.footnote:target {
+ background-color: #dddddd;
+}
+
+.line-block {
+ display: block;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.line-block .line-block {
+ margin-top: 0;
+ margin-bottom: 0;
+ margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+ font-style: italic;
+}
+
+.accelerator {
+ text-decoration: underline;
+}
+
+.classifier {
+ font-style: oblique;
+}
+
+abbr, acronym {
+ border-bottom: dotted 1px;
+ cursor: help;
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+ font-family: monospace;
+ overflow: auto;
+ overflow-y: hidden;
+}
+
+td.linenos pre {
+ padding: 5px 0px;
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ margin-left: 0.5em;
+}
+
+table.highlighttable td {
+ padding: 0 0.5em 0 0.5em;
+}
+
+code {
+ font-family: monospace;
+}
+
+div.code-block-caption span.caption-number {
+ padding: 0.1em 0.3em;
+ font-style: italic;
+}
+
+div.code-block-caption span.caption-text {
+}
+
+div.literal-block-wrapper {
+ padding: 1em 1em 0;
+}
+
+div.literal-block-wrapper div.highlight {
+ margin: 0;
+}
+
+code.descname {
+ background-color: transparent;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+code.descclassname {
+ background-color: transparent;
+}
+
+code.xref, a code {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
+ background-color: transparent;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+ vertical-align: middle;
+}
+
+div.body div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+/* -- special divs --------------------------------------------------------- */
+
+div.quotebar {
+ background-color: #e3eff1;
+ max-width: 250px;
+ float: right;
+ font-family: sans-serif;
+ padding: 7px 7px;
+ border: 1px solid #ccc;
+}
+div.footer {
+ background-color: #e3eff1;
+ padding: 3px 8px 3px 0;
+ clear: both;
+ font-family: sans-serif;
+ font-size: 80%;
+ text-align: right;
+}
+
+div.footer a {
+ text-decoration: underline;
+}
+
+/* -- link-target ----------------------------------------------------------- */
+
+.link-target {
+ font-size: 80%;
+}
+
+table .link-target {
+ /* Do not show links in tables, there is not enough space */
+ display: none;
+}
+
+/* -- font-face ------------------------------------------------------------- */
+
+/*
+@font-face {
+ font-family: "LiberationNarrow";
+ font-style: normal;
+ font-weight: normal;
+ src: url("res:///Data/fonts/LiberationNarrow-Regular.otf")
+ format("opentype");
+}
+@font-face {
+ font-family: "LiberationNarrow";
+ font-style: oblique, italic;
+ font-weight: normal;
+ src: url("res:///Data/fonts/LiberationNarrow-Italic.otf")
+ format("opentype");
+}
+@font-face {
+ font-family: "LiberationNarrow";
+ font-style: normal;
+ font-weight: bold;
+ src: url("res:///Data/fonts/LiberationNarrow-Bold.otf")
+ format("opentype");
+}
+@font-face {
+ font-family: "LiberationNarrow";
+ font-style: oblique, italic;
+ font-weight: bold;
+ src: url("res:///Data/fonts/LiberationNarrow-BoldItalic.otf")
+ format("opentype");
+}
+*/
diff --git a/sphinx/themes/haiku/static/alert_info_32.png b/sphinx/themes/haiku/static/alert_info_32.png
index 05b4fe898..ea4d1baf7 100644
--- a/sphinx/themes/haiku/static/alert_info_32.png
+++ b/sphinx/themes/haiku/static/alert_info_32.png
Binary files differ
diff --git a/sphinx/themes/haiku/static/alert_warning_32.png b/sphinx/themes/haiku/static/alert_warning_32.png
index f13611cde..a687c3dca 100644
--- a/sphinx/themes/haiku/static/alert_warning_32.png
+++ b/sphinx/themes/haiku/static/alert_warning_32.png
Binary files differ
diff --git a/sphinx/themes/haiku/static/bg-page.png b/sphinx/themes/haiku/static/bg-page.png
index 0103ee1a7..fe0a6dc89 100644
--- a/sphinx/themes/haiku/static/bg-page.png
+++ b/sphinx/themes/haiku/static/bg-page.png
Binary files differ
diff --git a/sphinx/themes/haiku/static/bullet_orange.png b/sphinx/themes/haiku/static/bullet_orange.png
index ad5d02f34..1cb8097ce 100644
--- a/sphinx/themes/haiku/static/bullet_orange.png
+++ b/sphinx/themes/haiku/static/bullet_orange.png
Binary files differ
diff --git a/sphinx/themes/nonav/layout.html b/sphinx/themes/nonav/layout.html
new file mode 100644
index 000000000..256c2d5b2
--- /dev/null
+++ b/sphinx/themes/nonav/layout.html
@@ -0,0 +1,23 @@
+{#
+ nonav/layout.html
+ ~~~~~~~~~~~~~~~~
+
+ Sphinx layout template for the any help system theme.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{%- extends "basic/layout.html" %}
+
+{%- block doctype -%}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+{%- endblock -%}
+{# add only basic navigation links #}
+{% block sidebar1 %}{% endblock %}
+{% block sidebar2 %}{% endblock %}
+{% block relbar1 %}{% endblock %}
+{% block relbar2 %}{% endblock %}
+{% block linktags %}{% endblock %}
+{% block footer %}{% endblock %}
+
diff --git a/sphinx/themes/epub/static/epub.css b/sphinx/themes/nonav/static/nonav.css
index 84db952c4..cbaee7ced 100644
--- a/sphinx/themes/epub/static/epub.css
+++ b/sphinx/themes/nonav/static/nonav.css
@@ -1,8 +1,8 @@
/*
- * epub.css_t
+ * nonav.css
* ~~~~~~~~~~
*
- * Sphinx stylesheet -- epub theme.
+ * Sphinx stylesheet -- nonav theme.
*
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
@@ -150,9 +150,14 @@ table.indextable td {
vertical-align: top;
}
-table.indextable dl, table.indextable dd {
+table.indextable ul {
margin-top: 0;
margin-bottom: 0;
+ list-style-type: none;
+}
+
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
}
table.indextable tr.pcap {
@@ -170,6 +175,13 @@ img.toggler {
cursor: pointer;
}
+/* -- domain module index --------------------------------------------------- */
+
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
/* -- general body styles --------------------------------------------------- */
a.headerlink {
@@ -184,10 +196,6 @@ div.body td {
text-align: left;
}
-.field-list ul {
- padding-left: 100%;
-}
-
.first {
margin-top: 0 !important;
}
@@ -286,10 +294,6 @@ table.docutils td, table.docutils th {
border-bottom: 1px solid #aaa;
}
-table.field-list td, table.field-list th {
- border: 0 !important;
-}
-
table.footnote td, table.footnote th {
border: 0 !important;
}
@@ -317,6 +321,21 @@ div.figure p.caption span.caption-number {
div.figure p.caption span.caption-text {
}
+/* -- field list styles ----------------------------------------------------- */
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
@@ -366,15 +385,6 @@ dl.glossary dt {
font-size: 110%;
}
-.field-list ul {
- margin: 0;
- padding-left: 1em;
-}
-
-.field-list p {
- margin: 0;
-}
-
.optional {
font-size: 130%;
}
diff --git a/sphinx/themes/nonav/theme.conf b/sphinx/themes/nonav/theme.conf
new file mode 100644
index 000000000..d4799c75a
--- /dev/null
+++ b/sphinx/themes/nonav/theme.conf
@@ -0,0 +1,8 @@
+[theme]
+inherit = basic
+stylesheet = nonav.css
+pygments_style = none
+
+[options]
+relbar1 = true
+footer = true
diff --git a/sphinx/themes/pyramid/static/dialog-note.png b/sphinx/themes/pyramid/static/dialog-note.png
index 708682114..5a6336d11 100644
--- a/sphinx/themes/pyramid/static/dialog-note.png
+++ b/sphinx/themes/pyramid/static/dialog-note.png
Binary files differ
diff --git a/sphinx/themes/pyramid/static/dialog-seealso.png b/sphinx/themes/pyramid/static/dialog-seealso.png
index a27a0fcba..97553a8b7 100644
--- a/sphinx/themes/pyramid/static/dialog-seealso.png
+++ b/sphinx/themes/pyramid/static/dialog-seealso.png
Binary files differ
diff --git a/sphinx/themes/pyramid/static/dialog-todo.png b/sphinx/themes/pyramid/static/dialog-todo.png
index 9caa91e8a..cfbc28088 100644
--- a/sphinx/themes/pyramid/static/dialog-todo.png
+++ b/sphinx/themes/pyramid/static/dialog-todo.png
Binary files differ
diff --git a/sphinx/themes/pyramid/static/dialog-topic.png b/sphinx/themes/pyramid/static/dialog-topic.png
index 2ac57475c..a75afeaaf 100644
--- a/sphinx/themes/pyramid/static/dialog-topic.png
+++ b/sphinx/themes/pyramid/static/dialog-topic.png
Binary files differ
diff --git a/sphinx/themes/pyramid/static/dialog-warning.png b/sphinx/themes/pyramid/static/dialog-warning.png
index 4f598b12b..8bb7d8d35 100644
--- a/sphinx/themes/pyramid/static/dialog-warning.png
+++ b/sphinx/themes/pyramid/static/dialog-warning.png
Binary files differ
diff --git a/sphinx/themes/pyramid/static/headerbg.png b/sphinx/themes/pyramid/static/headerbg.png
index 0596f2020..e1051af48 100644
--- a/sphinx/themes/pyramid/static/headerbg.png
+++ b/sphinx/themes/pyramid/static/headerbg.png
Binary files differ
diff --git a/sphinx/themes/pyramid/static/middlebg.png b/sphinx/themes/pyramid/static/middlebg.png
index b3a89f4e5..5ee55db25 100644
--- a/sphinx/themes/pyramid/static/middlebg.png
+++ b/sphinx/themes/pyramid/static/middlebg.png
Binary files differ
diff --git a/sphinx/themes/scrolls/static/darkmetal.png b/sphinx/themes/scrolls/static/darkmetal.png
index 3ed486d5c..49c82f301 100644
--- a/sphinx/themes/scrolls/static/darkmetal.png
+++ b/sphinx/themes/scrolls/static/darkmetal.png
Binary files differ
diff --git a/sphinx/themes/scrolls/static/headerbg.png b/sphinx/themes/scrolls/static/headerbg.png
index 0c5b3657c..ef15cc09c 100644
--- a/sphinx/themes/scrolls/static/headerbg.png
+++ b/sphinx/themes/scrolls/static/headerbg.png
Binary files differ
diff --git a/sphinx/themes/scrolls/static/logo.png b/sphinx/themes/scrolls/static/logo.png
index 3dc573e0f..354aded6b 100644
--- a/sphinx/themes/scrolls/static/logo.png
+++ b/sphinx/themes/scrolls/static/logo.png
Binary files differ
diff --git a/sphinx/themes/scrolls/static/metal.png b/sphinx/themes/scrolls/static/metal.png
index e51010b5f..c29cd9eca 100644
--- a/sphinx/themes/scrolls/static/metal.png
+++ b/sphinx/themes/scrolls/static/metal.png
Binary files differ
diff --git a/sphinx/themes/scrolls/static/navigation.png b/sphinx/themes/scrolls/static/navigation.png
index 5be5b3183..89c447a29 100644
--- a/sphinx/themes/scrolls/static/navigation.png
+++ b/sphinx/themes/scrolls/static/navigation.png
Binary files differ
diff --git a/sphinx/themes/scrolls/static/scrolls.css_t b/sphinx/themes/scrolls/static/scrolls.css_t
index 12bb7755e..af10144a1 100644
--- a/sphinx/themes/scrolls/static/scrolls.css_t
+++ b/sphinx/themes/scrolls/static/scrolls.css_t
@@ -299,14 +299,21 @@ table.genindextable td {
width: 50%;
}
-table.indextable dl dd {
+table.indextable ul {
+ margin-top: 0;
+ margin-bottom: 0;
+ list-style-type: none;
font-size: 11px;
}
-table.indextable dl dd a {
+table.indextable ul a {
color: #000;
}
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
+}
+
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
@@ -319,6 +326,11 @@ table.modindextable {
border: none;
}
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
table.modindextable img.toggler {
margin-right: 10px;
}
diff --git a/sphinx/themes/scrolls/static/watermark.png b/sphinx/themes/scrolls/static/watermark.png
index 903a96edb..d71dc4bbe 100644
--- a/sphinx/themes/scrolls/static/watermark.png
+++ b/sphinx/themes/scrolls/static/watermark.png
Binary files differ
diff --git a/sphinx/themes/scrolls/static/watermark_blur.png b/sphinx/themes/scrolls/static/watermark_blur.png
index 022690062..9fc0b6d31 100644
--- a/sphinx/themes/scrolls/static/watermark_blur.png
+++ b/sphinx/themes/scrolls/static/watermark_blur.png
Binary files differ
diff --git a/sphinx/themes/sphinxdoc/static/contents.png b/sphinx/themes/sphinxdoc/static/contents.png
index 7fb82154a..6c59aa1f9 100644
--- a/sphinx/themes/sphinxdoc/static/contents.png
+++ b/sphinx/themes/sphinxdoc/static/contents.png
Binary files differ
diff --git a/sphinx/themes/sphinxdoc/static/navigation.png b/sphinx/themes/sphinxdoc/static/navigation.png
index 1081dc143..fda6cd29e 100644
--- a/sphinx/themes/sphinxdoc/static/navigation.png
+++ b/sphinx/themes/sphinxdoc/static/navigation.png
Binary files differ
diff --git a/sphinx/themes/traditional/static/traditional.css_t b/sphinx/themes/traditional/static/traditional.css_t
index 1e1127eda..306b5b51d 100644
--- a/sphinx/themes/traditional/static/traditional.css_t
+++ b/sphinx/themes/traditional/static/traditional.css_t
@@ -390,9 +390,14 @@ table.indextable td {
vertical-align: top;
}
-table.indextable dl, table.indextable dd {
+table.indextable ul {
margin-top: 0;
margin-bottom: 0;
+ list-style-type: none;
+}
+
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
}
table.indextable tr.pcap {
@@ -410,6 +415,13 @@ img.toggler {
cursor: pointer;
}
+/* :::: DOMAIN MODULE INDEX STYLES :::: */
+
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
/* :::: GLOBAL STYLES :::: */
p.subhead {
diff --git a/sphinx/theming.py b/sphinx/theming.py
index 539184115..42e4448db 100644
--- a/sphinx/theming.py
+++ b/sphinx/theming.py
@@ -133,9 +133,8 @@ class Theme(object):
dirname = path.dirname(name)
if not path.isdir(path.join(self.themedir, dirname)):
os.makedirs(path.join(self.themedir, dirname))
- fp = open(path.join(self.themedir, name), 'wb')
- fp.write(tinfo.read(name))
- fp.close()
+ with open(path.join(self.themedir, name), 'wb') as fp:
+ fp.write(tinfo.read(name))
self.themeconf = configparser.RawConfigParser()
self.themeconf.read(path.join(self.themedir, THEMECONF))
diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py
new file mode 100644
index 000000000..79ac99c9f
--- /dev/null
+++ b/sphinx/transforms/__init__.py
@@ -0,0 +1,223 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.transforms
+ ~~~~~~~~~~~~~~~~~
+
+ Docutils transforms used by Sphinx when reading documents.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from docutils import nodes
+from docutils.transforms import Transform
+from docutils.transforms.parts import ContentsFilter
+
+from sphinx import addnodes
+from sphinx.locale import _
+from sphinx.util.i18n import format_date
+from sphinx.util.nodes import apply_source_workaround
+
+default_substitutions = set([
+ 'version',
+ 'release',
+ 'today',
+])
+
+
+class DefaultSubstitutions(Transform):
+ """
+ Replace some substitutions if they aren't defined in the document.
+ """
+ # run before the default Substitutions
+ default_priority = 210
+
+ def apply(self):
+ env = self.document.settings.env
+ config = self.document.settings.env.config
+ # only handle those not otherwise defined in the document
+ to_handle = default_substitutions - set(self.document.substitution_defs)
+ for ref in self.document.traverse(nodes.substitution_reference):
+ refname = ref['refname']
+ if refname in to_handle:
+ text = config[refname]
+ if refname == 'today' and not text:
+ # special handling: can also specify a strftime format
+ text = format_date(config.today_fmt or _('%b %d, %Y'),
+ language=config.language, warn=env.warn)
+ ref.replace_self(nodes.Text(text, text))
+
+
+class MoveModuleTargets(Transform):
+ """
+ Move module targets that are the first thing in a section to the section
+ title.
+
+ XXX Python specific
+ """
+ default_priority = 210
+
+ def apply(self):
+ for node in self.document.traverse(nodes.target):
+ if not node['ids']:
+ continue
+ if ('ismod' in node and
+ node.parent.__class__ is nodes.section and
+ # index 0 is the section title node
+ node.parent.index(node) == 1):
+ node.parent['ids'][0:0] = node['ids']
+ node.parent.remove(node)
+
+
+class HandleCodeBlocks(Transform):
+ """
+ Several code block related transformations.
+ """
+ default_priority = 210
+
+ def apply(self):
+ # move doctest blocks out of blockquotes
+ for node in self.document.traverse(nodes.block_quote):
+ if all(isinstance(child, nodes.doctest_block) for child
+ in node.children):
+ node.replace_self(node.children)
+ # combine successive doctest blocks
+ # for node in self.document.traverse(nodes.doctest_block):
+ # if node not in node.parent.children:
+ # continue
+ # parindex = node.parent.index(node)
+ # while len(node.parent) > parindex+1 and \
+ # isinstance(node.parent[parindex+1], nodes.doctest_block):
+ # node[0] = nodes.Text(node[0] + '\n\n' +
+ # node.parent[parindex+1][0])
+ # del node.parent[parindex+1]
+
+
+class AutoNumbering(Transform):
+ """
+ Register IDs of tables, figures and literal_blocks to assign numbers.
+ """
+ default_priority = 210
+
+ def apply(self):
+ domain = self.document.settings.env.domains['std']
+
+ for node in self.document.traverse(nodes.Element):
+ if domain.is_enumerable_node(node) and domain.get_numfig_title(node) is not None:
+ self.document.note_implicit_target(node)
+
+
+class SortIds(Transform):
+ """
+ Sort secion IDs so that the "id[0-9]+" one comes last.
+ """
+ default_priority = 261
+
+ def apply(self):
+ for node in self.document.traverse(nodes.section):
+ if len(node['ids']) > 1 and node['ids'][0].startswith('id'):
+ node['ids'] = node['ids'][1:] + [node['ids'][0]]
+
+
+class CitationReferences(Transform):
+ """
+ Replace citation references by pending_xref nodes before the default
+ docutils transform tries to resolve them.
+ """
+ default_priority = 619
+
+ def apply(self):
+ for citnode in self.document.traverse(nodes.citation_reference):
+ cittext = citnode.astext()
+ refnode = addnodes.pending_xref(cittext, refdomain='std', reftype='citation',
+ reftarget=cittext, refwarn=True,
+ ids=citnode["ids"])
+ refnode.source = citnode.source or citnode.parent.source
+ refnode.line = citnode.line or citnode.parent.line
+ refnode += nodes.Text('[' + cittext + ']')
+ citnode.parent.replace(citnode, refnode)
+
+
+TRANSLATABLE_NODES = {
+ 'literal-block': nodes.literal_block,
+ 'doctest-block': nodes.doctest_block,
+ 'raw': nodes.raw,
+ 'index': addnodes.index,
+ 'image': nodes.image,
+}
+
+
+class ApplySourceWorkaround(Transform):
+ """
+ update source and rawsource attributes
+ """
+ default_priority = 10
+
+ def apply(self):
+ for n in self.document.traverse():
+ if isinstance(n, nodes.TextElement):
+ apply_source_workaround(n)
+
+
+class AutoIndexUpgrader(Transform):
+ """
+ Detect old style; 4 column based indices and automatically upgrade to new style.
+ """
+ default_priority = 210
+
+ def apply(self):
+ env = self.document.settings.env
+ for node in self.document.traverse(addnodes.index):
+ if 'entries' in node and any(len(entry) == 4 for entry in node['entries']):
+ msg = ('4 column based index found. '
+ 'It might be a bug of extensions you use: %r' % node['entries'])
+ env.warn_node(msg, node)
+ for i, entry in enumerate(node['entries']):
+ if len(entry) == 4:
+ node['entries'][i] = entry + (None,)
+
+
+class ExtraTranslatableNodes(Transform):
+ """
+ make nodes translatable
+ """
+ default_priority = 10
+
+ def apply(self):
+ targets = self.document.settings.env.config.gettext_additional_targets
+ target_nodes = [v for k, v in TRANSLATABLE_NODES.items() if k in targets]
+ if not target_nodes:
+ return
+
+ def is_translatable_node(node):
+ return isinstance(node, tuple(target_nodes))
+
+ for node in self.document.traverse(is_translatable_node):
+ node['translatable'] = True
+
+
+class FilterSystemMessages(Transform):
+ """Filter system messages from a doctree."""
+ default_priority = 999
+
+ def apply(self):
+ env = self.document.settings.env
+ filterlevel = env.config.keep_warnings and 2 or 5
+ for node in self.document.traverse(nodes.system_message):
+ if node['level'] < filterlevel:
+ env.app.debug('%s [filtered system message]', node.astext())
+ node.parent.remove(node)
+
+
+class SphinxContentsFilter(ContentsFilter):
+ """
+ Used with BuildEnvironment.add_toc_from() to discard cross-file links
+ within table-of-contents link nodes.
+ """
+ def visit_pending_xref(self, node):
+ text = node.astext()
+ self.parent.append(nodes.literal(text, text))
+ raise nodes.SkipNode
+
+ def visit_image(self, node):
+ raise nodes.SkipNode
diff --git a/sphinx/transforms/compact_bullet_list.py b/sphinx/transforms/compact_bullet_list.py
new file mode 100644
index 000000000..61b23f382
--- /dev/null
+++ b/sphinx/transforms/compact_bullet_list.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.transforms.compact_bullet_list
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Docutils transforms used by Sphinx when reading documents.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from docutils import nodes
+from docutils.transforms import Transform
+
+from sphinx import addnodes
+
+
+class RefOnlyListChecker(nodes.GenericNodeVisitor):
+ """Raise `nodes.NodeFound` if non-simple list item is encountered.
+
+ Here 'simple' means a list item containing only a paragraph with a
+ single reference in it.
+ """
+
+ def default_visit(self, node):
+ raise nodes.NodeFound
+
+ def visit_bullet_list(self, node):
+ pass
+
+ def visit_list_item(self, node):
+ children = []
+ for child in node.children:
+ if not isinstance(child, nodes.Invisible):
+ children.append(child)
+ if len(children) != 1:
+ raise nodes.NodeFound
+ if not isinstance(children[0], nodes.paragraph):
+ raise nodes.NodeFound
+ para = children[0]
+ if len(para) != 1:
+ raise nodes.NodeFound
+ if not isinstance(para[0], addnodes.pending_xref):
+ raise nodes.NodeFound
+ raise nodes.SkipChildren
+
+ def invisible_visit(self, node):
+ """Invisible nodes should be ignored."""
+ pass
+
+
+class RefOnlyBulletListTransform(Transform):
+ """Change refonly bullet lists to use compact_paragraphs.
+
+ Specifically implemented for 'Indices and Tables' section, which looks
+ odd when html_compact_lists is false.
+ """
+ default_priority = 100
+
+ def apply(self):
+ env = self.document.settings.env
+ if env.config.html_compact_lists:
+ return
+
+ def check_refonly_list(node):
+ """Check for list with only references in it."""
+ visitor = RefOnlyListChecker(self.document)
+ try:
+ node.walk(visitor)
+ except nodes.NodeFound:
+ return False
+ else:
+ return True
+
+ for node in self.document.traverse(nodes.bullet_list):
+ if check_refonly_list(node):
+ for item in node.traverse(nodes.list_item):
+ para = item[0]
+ ref = para[0]
+ compact_para = addnodes.compact_paragraph()
+ compact_para += ref
+ item.replace(para, compact_para)
diff --git a/sphinx/transforms.py b/sphinx/transforms/i18n.py
index cb4a5779b..38c5aef25 100644
--- a/sphinx/transforms.py
+++ b/sphinx/transforms/i18n.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""
- sphinx.transforms
- ~~~~~~~~~~~~~~~~~
+ sphinx.transforms.i18n
+ ~~~~~~~~~~~~~~~~~~~~~~
Docutils transforms used by Sphinx when reading documents.
@@ -15,198 +15,19 @@ from docutils import nodes
from docutils.io import StringInput
from docutils.utils import relative_path
from docutils.transforms import Transform
-from docutils.transforms.parts import ContentsFilter
from sphinx import addnodes
-from sphinx.locale import _, init as init_locale
from sphinx.util import split_index_msg
+from sphinx.util.i18n import find_catalog
from sphinx.util.nodes import (
- traverse_translatable_index, extract_messages, LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
- apply_source_workaround,
+ LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
+ extract_messages, is_pending_meta, traverse_translatable_index,
)
-from sphinx.util.i18n import find_catalog, format_date
from sphinx.util.pycompat import indent
+from sphinx.locale import init as init_locale
from sphinx.domains.std import make_glossary_term, split_term_classifiers
-default_substitutions = set([
- 'version',
- 'release',
- 'today',
-])
-
-
-class DefaultSubstitutions(Transform):
- """
- Replace some substitutions if they aren't defined in the document.
- """
- # run before the default Substitutions
- default_priority = 210
-
- def apply(self):
- env = self.document.settings.env
- config = self.document.settings.env.config
- # only handle those not otherwise defined in the document
- to_handle = default_substitutions - set(self.document.substitution_defs)
- for ref in self.document.traverse(nodes.substitution_reference):
- refname = ref['refname']
- if refname in to_handle:
- text = config[refname]
- if refname == 'today' and not text:
- # special handling: can also specify a strftime format
- text = format_date(config.today_fmt or _('%b %d, %Y'),
- language=config.language, warn=env.warn)
- ref.replace_self(nodes.Text(text, text))
-
-
-class MoveModuleTargets(Transform):
- """
- Move module targets that are the first thing in a section to the section
- title.
-
- XXX Python specific
- """
- default_priority = 210
-
- def apply(self):
- for node in self.document.traverse(nodes.target):
- if not node['ids']:
- continue
- if ('ismod' in node and
- node.parent.__class__ is nodes.section and
- # index 0 is the section title node
- node.parent.index(node) == 1):
- node.parent['ids'][0:0] = node['ids']
- node.parent.remove(node)
-
-
-class HandleCodeBlocks(Transform):
- """
- Several code block related transformations.
- """
- default_priority = 210
-
- def apply(self):
- # move doctest blocks out of blockquotes
- for node in self.document.traverse(nodes.block_quote):
- if all(isinstance(child, nodes.doctest_block) for child
- in node.children):
- node.replace_self(node.children)
- # combine successive doctest blocks
- # for node in self.document.traverse(nodes.doctest_block):
- # if node not in node.parent.children:
- # continue
- # parindex = node.parent.index(node)
- # while len(node.parent) > parindex+1 and \
- # isinstance(node.parent[parindex+1], nodes.doctest_block):
- # node[0] = nodes.Text(node[0] + '\n\n' +
- # node.parent[parindex+1][0])
- # del node.parent[parindex+1]
-
-
-class AutoNumbering(Transform):
- """
- Register IDs of tables, figures and literal_blocks to assign numbers.
- """
- default_priority = 210
-
- def apply(self):
- domain = self.document.settings.env.domains['std']
-
- for node in self.document.traverse(nodes.Element):
- if domain.is_enumerable_node(node) and domain.get_numfig_title(node) is not None:
- self.document.note_implicit_target(node)
-
-
-class SortIds(Transform):
- """
- Sort secion IDs so that the "id[0-9]+" one comes last.
- """
- default_priority = 261
-
- def apply(self):
- for node in self.document.traverse(nodes.section):
- if len(node['ids']) > 1 and node['ids'][0].startswith('id'):
- node['ids'] = node['ids'][1:] + [node['ids'][0]]
-
-
-class CitationReferences(Transform):
- """
- Replace citation references by pending_xref nodes before the default
- docutils transform tries to resolve them.
- """
- default_priority = 619
-
- def apply(self):
- for citnode in self.document.traverse(nodes.citation_reference):
- cittext = citnode.astext()
- refnode = addnodes.pending_xref(cittext, reftype='citation',
- reftarget=cittext, refwarn=True,
- ids=citnode["ids"])
- refnode.source = citnode.source or citnode.parent.source
- refnode.line = citnode.line or citnode.parent.line
- refnode += nodes.Text('[' + cittext + ']')
- citnode.parent.replace(citnode, refnode)
-
-
-TRANSLATABLE_NODES = {
- 'literal-block': nodes.literal_block,
- 'doctest-block': nodes.doctest_block,
- 'raw': nodes.raw,
- 'index': addnodes.index,
- 'image': nodes.image,
-}
-
-
-class ApplySourceWorkaround(Transform):
- """
- update source and rawsource attributes
- """
- default_priority = 10
-
- def apply(self):
- for n in self.document.traverse():
- if isinstance(n, nodes.TextElement):
- apply_source_workaround(n)
-
-
-class AutoIndexUpgrader(Transform):
- """
- Detect old style; 4 column based indices and automatically upgrade to new style.
- """
- default_priority = 210
-
- def apply(self):
- env = self.document.settings.env
- for node in self.document.traverse(addnodes.index):
- if 'entries' in node and any(len(entry) == 4 for entry in node['entries']):
- msg = ('4 column based index found. '
- 'It might be a bug of extensions you use: %r' % node['entries'])
- env.warn_node(msg, node)
- for i, entry in enumerate(node['entries']):
- if len(entry) == 4:
- node['entries'][i] = entry + (None,)
-
-
-class ExtraTranslatableNodes(Transform):
- """
- make nodes translatable
- """
- default_priority = 10
-
- def apply(self):
- targets = self.document.settings.env.config.gettext_additional_targets
- target_nodes = [v for k, v in TRANSLATABLE_NODES.items() if k in targets]
- if not target_nodes:
- return
-
- def is_translatable_node(node):
- return isinstance(node, tuple(target_nodes))
-
- for node in self.document.traverse(is_translatable_node):
- node['translatable'] = True
-
-
def publish_msgstr(app, source, source_path, source_line, config, settings):
"""Publish msgstr (single line) into docutils document
@@ -238,6 +59,17 @@ def publish_msgstr(app, source, source_path, source_line, config, settings):
return doc
+class PreserveTranslatableMessages(Transform):
+ """
+ Preserve original translatable messages befor translation
+ """
+ default_priority = 10 # this MUST be invoked before Locale transform
+
+ def apply(self):
+ for node in self.document.traverse(addnodes.translatable):
+ node.preserve_original_messages()
+
+
class Locale(Transform):
"""
Replace translatable nodes with their translated doctree.
@@ -384,6 +216,16 @@ class Locale(Transform):
if not msgstr or msgstr == msg: # as-of-yet untranslated
continue
+ # update translatable nodes
+ if isinstance(node, addnodes.translatable):
+ node.apply_translated_message(msg, msgstr)
+ continue
+
+ # update meta nodes
+ if is_pending_meta(node):
+ node.details['nodes'][0]['content'] = msgstr
+ continue
+
# Avoid "Literal block expected; none found." warnings.
# If msgstr ends with '::' then it cause warning message at
# parser.parse() processing.
@@ -574,17 +416,3 @@ class RemoveTranslatableInline(Transform):
if 'translatable' in inline:
inline.parent.remove(inline)
inline.parent += inline.children
-
-
-class SphinxContentsFilter(ContentsFilter):
- """
- Used with BuildEnvironment.add_toc_from() to discard cross-file links
- within table-of-contents link nodes.
- """
- def visit_pending_xref(self, node):
- text = node.astext()
- self.parent.append(nodes.literal(text, text))
- raise nodes.SkipNode
-
- def visit_image(self, node):
- raise nodes.SkipNode
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index 9c5365aa7..7ac5c62f7 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import absolute_import
import os
import re
@@ -18,20 +19,17 @@ import posixpath
import traceback
import unicodedata
from os import path
-from codecs import open, BOM_UTF8
+from codecs import BOM_UTF8
from collections import deque
from six import iteritems, text_type, binary_type
from six.moves import range
from six.moves.urllib.parse import urlsplit, urlunsplit, quote_plus, parse_qsl, urlencode
-import docutils
from docutils.utils import relative_path
-import jinja2
-
-import sphinx
from sphinx.errors import PycodeError, SphinxParallelError, ExtensionError
from sphinx.util.console import strip_colors
+from sphinx.util.fileutil import copy_asset_file
from sphinx.util.osutil import fs_encoding
# import other utilities; partly for backwards compatibility, so don't
@@ -148,7 +146,7 @@ class FilenameUniqDict(dict):
def copy_static_entry(source, targetdir, builder, context={},
exclude_matchers=(), level=0):
- """Copy a HTML builder static_path entry from source to targetdir.
+ """[DEPRECATED] Copy a HTML builder static_path entry from source to targetdir.
Handles all possible cases of files, directories and subdirectories.
"""
@@ -158,16 +156,7 @@ def copy_static_entry(source, targetdir, builder, context={},
if matcher(relpath):
return
if path.isfile(source):
- target = path.join(targetdir, path.basename(source))
- if source.lower().endswith('_t') and builder.templates:
- # templated!
- fsrc = open(source, 'r', encoding='utf-8')
- fdst = open(target[:-2], 'w', encoding='utf-8')
- fdst.write(builder.templates.render_string(fsrc.read(), context))
- fsrc.close()
- fdst.close()
- else:
- copyfile(source, target)
+ copy_asset_file(source, targetdir, context, builder.templates)
elif path.isdir(source):
if not path.isdir(targetdir):
os.mkdir(targetdir)
@@ -182,37 +171,6 @@ def copy_static_entry(source, targetdir, builder, context={},
exclude_matchers=exclude_matchers)
-def copy_extra_entry(source, targetdir, exclude_matchers=()):
- """Copy a HTML builder extra_path entry from source to targetdir.
-
- Handles all possible cases of files, directories and subdirectories.
- """
- def excluded(path):
- relpath = relative_path(os.path.dirname(source), path)
- return any(matcher(relpath) for matcher in exclude_matchers)
-
- def copy_extra_file(source_, targetdir_):
- if not excluded(source_):
- target = path.join(targetdir_, os.path.basename(source_))
- copyfile(source_, target)
-
- if os.path.isfile(source):
- copy_extra_file(source, targetdir)
- return
-
- for root, dirs, files in os.walk(source):
- reltargetdir = os.path.join(targetdir, relative_path(source, root))
- for dir in dirs[:]:
- if excluded(os.path.join(root, dir)):
- dirs.remove(dir)
- else:
- target = os.path.join(reltargetdir, dir)
- if not path.exists(target):
- os.mkdir(target)
- for file in files:
- copy_extra_file(os.path.join(root, file), reltargetdir)
-
-
_DEBUG_HEADER = '''\
# Sphinx version: %s
# Python version: %s (%s)
@@ -226,6 +184,9 @@ _DEBUG_HEADER = '''\
def save_traceback(app):
"""Save the current exception's traceback in a temporary file."""
+ import sphinx
+ import jinja2
+ import docutils
import platform
exc = sys.exc_info()[1]
if isinstance(exc, SphinxParallelError):
diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py
index 5329cb668..0af65cbe3 100644
--- a/sphinx/util/compat.py
+++ b/sphinx/util/compat.py
@@ -8,6 +8,8 @@
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import absolute_import
+
import warnings
from docutils import nodes
diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py
index f4eb703ce..d5cb4038f 100644
--- a/sphinx/util/docfields.py
+++ b/sphinx/util/docfields.py
@@ -9,6 +9,7 @@
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import absolute_import
from docutils import nodes
@@ -62,6 +63,10 @@ class Field(object):
refnode += contnode or innernode(target, target)
return refnode
+ def make_xrefs(self, rolename, domain, target,
+ innernode=addnodes.literal_emphasis, contnode=None):
+ return [self.make_xref(rolename, domain, target, innernode, contnode)]
+
def make_entry(self, fieldarg, content):
return (fieldarg, content)
@@ -70,14 +75,15 @@ class Field(object):
fieldname = nodes.field_name('', self.label)
if fieldarg:
fieldname += nodes.Text(' ')
- fieldname += self.make_xref(self.rolename, domain,
- fieldarg, nodes.Text)
+ fieldname.extend(self.make_xrefs(self.rolename, domain,
+ fieldarg, nodes.Text))
+
if len(content) == 1 and (
isinstance(content[0], nodes.Text) or
(isinstance(content[0], nodes.inline) and len(content[0]) == 1 and
isinstance(content[0][0], nodes.Text))):
- content = [self.make_xref(self.bodyrolename, domain,
- content[0].astext(), contnode=content[0])]
+ content = self.make_xrefs(self.bodyrolename, domain,
+ content[0].astext(), contnode=content[0])
fieldbody = nodes.field_body('', nodes.paragraph('', '', *content))
return nodes.field('', fieldname, fieldbody)
@@ -108,14 +114,16 @@ class GroupedField(Field):
listnode = self.list_type()
for fieldarg, content in items:
par = nodes.paragraph()
- par += self.make_xref(self.rolename, domain, fieldarg,
- addnodes.literal_strong)
+ par.extend(self.make_xrefs(self.rolename, domain, fieldarg,
+ addnodes.literal_strong))
par += nodes.Text(' -- ')
par += content
listnode += nodes.list_item('', par)
+
if len(items) == 1 and self.can_collapse:
fieldbody = nodes.field_body('', listnode[0][0])
return nodes.field('', fieldname, fieldbody)
+
fieldbody = nodes.field_body('', listnode)
return nodes.field('', fieldname, fieldbody)
@@ -150,8 +158,8 @@ class TypedField(GroupedField):
def make_field(self, types, domain, items):
def handle_item(fieldarg, content):
par = nodes.paragraph()
- par += self.make_xref(self.rolename, domain, fieldarg,
- addnodes.literal_strong)
+ par.extend(self.make_xrefs(self.rolename, domain, fieldarg,
+ addnodes.literal_strong))
if fieldarg in types:
par += nodes.Text(' (')
# NOTE: using .pop() here to prevent a single type node to be
@@ -160,8 +168,8 @@ class TypedField(GroupedField):
fieldtype = types.pop(fieldarg)
if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text):
typename = u''.join(n.astext() for n in fieldtype)
- par += self.make_xref(self.typerolename, domain, typename,
- addnodes.literal_emphasis)
+ par.extend(self.make_xrefs(self.typerolename, domain, typename,
+ addnodes.literal_emphasis))
else:
par += fieldtype
par += nodes.Text(')')
diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py
new file mode 100644
index 000000000..be9e2edad
--- /dev/null
+++ b/sphinx/util/docutils.py
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.util.docutils
+ ~~~~~~~~~~~~~~~~~~~~
+
+ Utility functions for docutils.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+from __future__ import absolute_import
+
+from copy import copy
+from contextlib import contextmanager
+from docutils.parsers.rst import directives, roles
+
+
+@contextmanager
+def docutils_namespace():
+ """Create namespace for reST parsers."""
+ try:
+ _directives = copy(directives._directives)
+ _roles = copy(roles._roles)
+
+ yield
+ finally:
+ directives._directives = _directives
+ roles._roles = _roles
+
+
+class ElementLookupError(Exception):
+ pass
+
+
+class sphinx_domains(object):
+ """Monkey-patch directive and role dispatch, so that domain-specific
+ markup takes precedence.
+ """
+ def __init__(self, env):
+ self.env = env
+ self.directive_func = None
+ self.roles_func = None
+
+ def __enter__(self):
+ self.enable()
+
+ def __exit__(self, type, value, traceback):
+ self.disable()
+
+ def enable(self):
+ self.directive_func = directives.directive
+ self.role_func = roles.role
+
+ directives.directive = self.lookup_directive
+ roles.role = self.lookup_role
+
+ def disable(self):
+ directives.directive = self.directive_func
+ roles.role = self.role_func
+
+ def lookup_domain_element(self, type, name):
+ """Lookup a markup element (directive or role), given its name which can
+ be a full name (with domain).
+ """
+ name = name.lower()
+ # explicit domain given?
+ if ':' in name:
+ domain_name, name = name.split(':', 1)
+ if domain_name in self.env.domains:
+ domain = self.env.domains[domain_name]
+ element = getattr(domain, type)(name)
+ if element is not None:
+ return element, []
+ # else look in the default domain
+ else:
+ def_domain = self.env.temp_data.get('default_domain')
+ if def_domain is not None:
+ element = getattr(def_domain, type)(name)
+ if element is not None:
+ return element, []
+
+ # always look in the std domain
+ element = getattr(self.env.domains['std'], type)(name)
+ if element is not None:
+ return element, []
+
+ raise ElementLookupError
+
+ def lookup_directive(self, name, lang_module, document):
+ try:
+ return self.lookup_domain_element('directive', name)
+ except ElementLookupError:
+ return self.directive_func(name, lang_module, document)
+
+ def lookup_role(self, name, lang_module, lineno, reporter):
+ try:
+ return self.lookup_domain_element('role', name)
+ except ElementLookupError:
+ return self.role_func(name, lang_module, lineno, reporter)
diff --git a/sphinx/util/fileutil.py b/sphinx/util/fileutil.py
new file mode 100644
index 000000000..4375b7e61
--- /dev/null
+++ b/sphinx/util/fileutil.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.util.fileutil
+ ~~~~~~~~~~~~~~~~~~~~
+
+ File utility functions for Sphinx.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+from __future__ import absolute_import
+
+import os
+import codecs
+import posixpath
+from docutils.utils import relative_path
+from sphinx.util.osutil import copyfile, ensuredir, walk
+
+
+def copy_asset_file(source, destination, context=None, renderer=None):
+ """Copy an asset file to destination.
+
+ On copying, it expands the template variables if context argument is given and
+ the asset is a template file.
+
+ :param source: The path to source file
+ :param destination: The path to destination file or directory
+ :param context: The template variables. If not given, template files are simply copied
+ :param renderer: The template engine. If not given, SphinxRenderer is used by default
+ """
+ if not os.path.exists(source):
+ return
+
+ if os.path.exists(destination) and os.path.isdir(destination):
+ # Use source filename if destination points a directory
+ destination = os.path.join(destination, os.path.basename(source))
+
+ if source.lower().endswith('_t') and context:
+ if renderer is None:
+ from sphinx.util.template import SphinxRenderer
+ renderer = SphinxRenderer()
+
+ with codecs.open(source, 'r', encoding='utf-8') as fsrc:
+ with codecs.open(destination[:-2], 'w', encoding='utf-8') as fdst:
+ fdst.write(renderer.render_string(fsrc.read(), context))
+ else:
+ copyfile(source, destination)
+
+
+def copy_asset(source, destination, excluded=lambda path: False, context=None, renderer=None):
+ """Copy asset files to destination recursively.
+
+ On copying, it expands the template variables if context argument is given and
+ the asset is a template file.
+
+ :param source: The path to source file or directory
+ :param destination: The path to destination directory
+ :param excluded: The matcher to determine the given path should be copied or not
+ :param context: The template variables. If not given, template files are simply copied
+ :param renderer: The template engine. If not given, SphinxRenderer is used by default
+ """
+ if not os.path.exists(source):
+ return
+
+ ensuredir(destination)
+ if os.path.isfile(source):
+ copy_asset_file(source, destination, context, renderer)
+ return
+
+ for root, dirs, files in walk(source):
+ reldir = relative_path(source, root)
+ for dir in dirs[:]:
+ if excluded(posixpath.join(reldir, dir)):
+ dirs.remove(dir)
+ else:
+ ensuredir(posixpath.join(destination, reldir, dir))
+
+ for filename in files:
+ if not excluded(posixpath.join(reldir, filename)):
+ copy_asset_file(posixpath.join(root, filename),
+ posixpath.join(destination, reldir),
+ context, renderer)
diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py
index 5b396820c..112353d47 100644
--- a/sphinx/util/i18n.py
+++ b/sphinx/util/i18n.py
@@ -230,10 +230,16 @@ def get_image_filename_for_language(filename, env):
return filename
filename_format = env.config.figure_language_filename
- root, ext = path.splitext(filename)
+ d = dict()
+ d['root'], d['ext'] = path.splitext(filename)
+ dirname = path.dirname(d['root'])
+ if dirname and not dirname.endswith(path.sep):
+ dirname += path.sep
+ d['path'] = dirname
+ d['basename'] = path.basename(d['root'])
+ d['language'] = env.config.language
try:
- return filename_format.format(root=root, ext=ext,
- language=env.config.language)
+ return filename_format.format(**d)
except KeyError as exc:
raise SphinxError('Invalid figure_language_filename: %r' % exc)
diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py
index 81ffe25c8..147d43592 100644
--- a/sphinx/util/inspect.py
+++ b/sphinx/util/inspect.py
@@ -60,7 +60,7 @@ if PY3:
raise TypeError('%r is not a Python function' % func)
return inspect.getfullargspec(func)
-else: # 2.6, 2.7
+else: # 2.7
from functools import partial
def getargspec(func):
@@ -94,6 +94,18 @@ else: # 2.6, 2.7
pass
return inspect.ArgSpec(args, varargs, varkw, func_defaults)
+try:
+ import enum
+except ImportError:
+ enum = None
+
+
+def isenumattribute(x):
+ """Check if the object is attribute of enum."""
+ if enum is None:
+ return False
+ return isinstance(x, enum.Enum)
+
def isdescriptor(x):
"""Check if the object is some kind of descriptor."""
diff --git a/sphinx/util/matching.py b/sphinx/util/matching.py
index 91fda6378..fc7750be9 100644
--- a/sphinx/util/matching.py
+++ b/sphinx/util/matching.py
@@ -62,6 +62,27 @@ def compile_matchers(patterns):
return [re.compile(_translate_pattern(pat)).match for pat in patterns]
+class Matcher(object):
+ """A pattern matcher for Multiple shell-style glob patterns.
+
+ Note: this modifies the patterns to work with copy_asset().
+ For example, "**/index.rst" matches with "index.rst"
+ """
+
+ def __init__(self, patterns):
+ expanded = [pat[3:] for pat in patterns if pat.startswith('**/')]
+ self.patterns = compile_matchers(patterns + expanded)
+
+ def __call__(self, string):
+ return self.match(string)
+
+ def match(self, string):
+ return any(pat(string) for pat in self.patterns)
+
+
+DOTFILES = Matcher(['**/.*'])
+
+
_pat_cache = {}
diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py
index e4a2fd73b..fe3b0f2f9 100644
--- a/sphinx/util/nodes.py
+++ b/sphinx/util/nodes.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import absolute_import
import re
@@ -85,7 +86,18 @@ IGNORED_NODES = (
)
+def is_pending_meta(node):
+ if (isinstance(node, nodes.pending) and
+ isinstance(node.details.get('nodes', [None])[0], addnodes.meta)):
+ return True
+ else:
+ return False
+
+
def is_translatable(node):
+ if isinstance(node, addnodes.translatable):
+ return True
+
if isinstance(node, nodes.TextElement):
if not node.source:
return False # built-in message
@@ -103,6 +115,11 @@ def is_translatable(node):
if isinstance(node, nodes.image) and node.get('translatable'):
return True
+ if isinstance(node, addnodes.meta):
+ return True
+ if is_pending_meta(node):
+ return True
+
return False
@@ -114,11 +131,18 @@ LITERAL_TYPE_NODES = (
IMAGE_TYPE_NODES = (
nodes.image,
)
+META_TYPE_NODES = (
+ addnodes.meta,
+)
def extract_messages(doctree):
"""Extract translatable messages from a document tree."""
for node in doctree.traverse(is_translatable):
+ if isinstance(node, addnodes.translatable):
+ for msg in node.extract_original_messages():
+ yield node, msg
+ continue
if isinstance(node, LITERAL_TYPE_NODES):
msg = node.rawsource
if not msg:
@@ -127,6 +151,10 @@ def extract_messages(doctree):
msg = '.. image:: %s' % node['uri']
if node.get('alt'):
msg += '\n :alt: %s' % node['alt']
+ elif isinstance(node, META_TYPE_NODES):
+ msg = node.rawcontent
+ elif is_pending_meta(node):
+ msg = node.details['nodes'][0].rawcontent
else:
msg = node.rawsource.replace('\n', ' ').strip()
@@ -293,6 +321,27 @@ def set_role_source_info(inliner, lineno, node):
node.source, node.line = inliner.reporter.get_source_and_line(lineno)
+def process_only_nodes(doctree, tags, warn_node=None):
+ # A comment on the comment() nodes being inserted: replacing by [] would
+ # result in a "Losing ids" exception if there is a target node before
+ # the only node, so we make sure docutils can transfer the id to
+ # something, even if it's just a comment and will lose the id anyway...
+ for node in doctree.traverse(addnodes.only):
+ try:
+ ret = tags.eval_condition(node['expr'])
+ except Exception as err:
+ if warn_node is None:
+ raise err
+ warn_node('exception while evaluating only '
+ 'directive expression: %s' % err, node)
+ node.replace_self(node.children or nodes.comment())
+ else:
+ if ret:
+ node.replace_self(node.children or nodes.comment())
+ else:
+ node.replace_self(nodes.comment())
+
+
# monkey-patch Element.copy to copy the rawsource and line
def _new_copy(self):
diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py
index b416a8c1f..b8fffb220 100644
--- a/sphinx/util/osutil.py
+++ b/sphinx/util/osutil.py
@@ -17,8 +17,10 @@ import time
import errno
import locale
import shutil
+import filecmp
from os import path
import contextlib
+from io import BytesIO, StringIO
from six import PY2, text_type
@@ -78,8 +80,8 @@ def ensuredir(path):
raise
-# This function is same as os.walk of Python2.6, 2.7, 3.2, 3.3 except a
-# customization that check UnicodeError.
+# This function is same as os.walk of Python2.7 except a customization
+# that check UnicodeError.
# The customization obstacle to replace the function with the os.walk.
def walk(top, topdown=True, followlinks=False):
"""Backport of os.walk from 2.6, where the *followlinks* argument was
@@ -141,13 +143,16 @@ def copytimes(source, dest):
def copyfile(source, dest):
- """Copy a file and its modification times, if possible."""
- shutil.copyfile(source, dest)
- try:
- # don't do full copystat because the source may be read-only
- copytimes(source, dest)
- except OSError:
- pass
+ """Copy a file and its modification times, if possible.
+
+ Note: ``copyfile`` skips copying if the file has not been changed"""
+ if not path.exists(dest) or not filecmp.cmp(source, dest):
+ shutil.copyfile(source, dest)
+ try:
+ # don't do full copystat because the source may be read-only
+ copytimes(source, dest)
+ except OSError:
+ pass
no_fn_re = re.compile(r'[^a-zA-Z0-9_-]')
@@ -215,6 +220,73 @@ def cd(target_dir):
os.chdir(cwd)
+class FileAvoidWrite(object):
+ """File-like object that buffers output and only writes if content changed.
+
+ Use this class like when writing to a file to avoid touching the original
+ file if the content hasn't changed. This is useful in scenarios where file
+ mtime is used to invalidate caches or trigger new behavior.
+
+ When writing to this file handle, all writes are buffered until the object
+ is closed.
+
+ Objects can be used as context managers.
+ """
+ def __init__(self, path):
+ self._path = path
+ self._io = None
+
+ def write(self, data):
+ if not self._io:
+ if isinstance(data, text_type):
+ self._io = StringIO()
+ else:
+ self._io = BytesIO()
+
+ self._io.write(data)
+
+ def close(self):
+ """Stop accepting writes and write file, if needed."""
+ if not self._io:
+ raise Exception('FileAvoidWrite does not support empty files.')
+
+ buf = self.getvalue()
+ self._io.close()
+
+ r_mode = 'r'
+ w_mode = 'w'
+ if isinstance(self._io, BytesIO):
+ r_mode = 'rb'
+ w_mode = 'wb'
+
+ old_content = None
+
+ try:
+ with open(self._path, r_mode) as old_f:
+ old_content = old_f.read()
+ if old_content == buf:
+ return
+ except IOError:
+ pass
+
+ with open(self._path, w_mode) as f:
+ f.write(buf)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.close()
+
+ def __getattr__(self, name):
+ # Proxy to _io instance.
+ if not self._io:
+ raise Exception('Must write to FileAvoidWrite before other '
+ 'methods can be used')
+
+ return getattr(self._io, name)
+
+
def rmtree(path):
if os.path.isdir(path):
shutil.rmtree(path)
diff --git a/sphinx/util/png.py b/sphinx/util/png.py
index e28445a42..476d45ccd 100644
--- a/sphinx/util/png.py
+++ b/sphinx/util/png.py
@@ -23,18 +23,14 @@ IEND_CHUNK = b'\x00\x00\x00\x00IEND\xAE\x42\x60\x82'
def read_png_depth(filename):
"""Read the special tEXt chunk indicating the depth from a PNG file."""
- result = None
- f = open(filename, 'rb')
- try:
+ with open(filename, 'rb') as f:
f.seek(- (LEN_IEND + LEN_DEPTH), 2)
depthchunk = f.read(LEN_DEPTH)
if not depthchunk.startswith(DEPTH_CHUNK_LEN + DEPTH_CHUNK_START):
# either not a PNG file or not containing the depth chunk
return None
- result = struct.unpack('!i', depthchunk[14:18])[0]
- finally:
- f.close()
- return result
+ else:
+ return struct.unpack('!i', depthchunk[14:18])[0]
def write_png_depth(filename, depth):
@@ -43,8 +39,7 @@ def write_png_depth(filename, depth):
The chunk is placed immediately before the special IEND chunk.
"""
data = struct.pack('!i', depth)
- f = open(filename, 'r+b')
- try:
+ with open(filename, 'r+b') as f:
# seek to the beginning of the IEND chunk
f.seek(-LEN_IEND, 2)
# overwrite it with the depth chunk
@@ -54,5 +49,3 @@ def write_png_depth(filename, depth):
f.write(struct.pack('!I', crc))
# replace the IEND chunk
f.write(IEND_CHUNK)
- finally:
- f.close()
diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py
index 4503c34e1..e3b17ef62 100644
--- a/sphinx/util/pycompat.py
+++ b/sphinx/util/pycompat.py
@@ -55,7 +55,7 @@ if PY3:
return text_type(tree)
from html import escape as htmlescape # noqa: >= Python 3.2
- class UnicodeMixin:
+ class UnicodeMixin(object):
"""Mixin class to handle defining the proper __str__/__unicode__
methods in Python 2 or 3."""
@@ -105,11 +105,8 @@ def execfile_(filepath, _globals, open=open):
from sphinx.util.osutil import fs_encoding
# get config source -- 'b' is a no-op under 2.x, while 'U' is
# ignored under 3.x (but 3.x compile() accepts \r\n newlines)
- f = open(filepath, 'rbU')
- try:
+ with open(filepath, 'rbU') as f:
source = f.read()
- finally:
- f.close()
# py26 accept only LF eol instead of CRLF
if sys.version_info[:2] == (2, 6):
diff --git a/sphinx/util/requests.py b/sphinx/util/requests.py
new file mode 100644
index 000000000..36ac1e0e7
--- /dev/null
+++ b/sphinx/util/requests.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.util.requests
+ ~~~~~~~~~~~~~~~~~~~~
+
+ Simple requests package loader
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from __future__ import absolute_import
+
+import requests
+import warnings
+import pkg_resources
+from requests.packages.urllib3.exceptions import SSLError
+
+# try to load requests[security]
+try:
+ pkg_resources.require(['requests[security]'])
+except pkg_resources.DistributionNotFound:
+ import ssl
+ if not getattr(ssl, 'HAS_SNI', False):
+ # don't complain on each url processed about the SSL issue
+ requests.packages.urllib3.disable_warnings(
+ requests.packages.urllib3.exceptions.InsecurePlatformWarning)
+ warnings.warn(
+ 'Some links may return broken results due to being unable to '
+ 'check the Server Name Indication (SNI) in the returned SSL cert '
+ 'against the hostname in the url requested. Recommended to '
+ 'install "requests[security]" as a dependency or upgrade to '
+ 'a python version with SNI support (Python 3 and Python 2.7.9+).'
+ )
+except pkg_resources.UnknownExtra:
+ warnings.warn(
+ 'Some links may return broken results due to being unable to '
+ 'check the Server Name Indication (SNI) in the returned SSL cert '
+ 'against the hostname in the url requested. Recommended to '
+ 'install requests-2.4.1+.'
+ )
+
+useragent_header = [('User-Agent',
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0')]
+
+
+def is_ssl_error(exc):
+ if isinstance(exc, SSLError):
+ return True
+ else:
+ args = getattr(exc, 'args', [])
+ if args and isinstance(args[0], SSLError):
+ return True
+ else:
+ return False
diff --git a/sphinx/util/template.py b/sphinx/util/template.py
new file mode 100644
index 000000000..7cb897e7d
--- /dev/null
+++ b/sphinx/util/template.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.util.template
+ ~~~~~~~~~~~~~~~~~~~~
+
+ Templates utility functions for Sphinx.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import os
+from jinja2.sandbox import SandboxedEnvironment
+
+from sphinx import package_dir
+from sphinx.jinja2glue import SphinxFileSystemLoader
+
+
+class BaseRenderer(object):
+ def __init__(self, loader=None):
+ self.env = SandboxedEnvironment(loader=loader)
+ self.env.filters['repr'] = repr
+
+ def render(self, template_name, context):
+ return self.env.get_template(template_name).render(context)
+
+ def render_string(self, source, context):
+ return self.env.from_string(source).render(context)
+
+
+class FileRenderer(BaseRenderer):
+ def __init__(self, search_path):
+ loader = SphinxFileSystemLoader(search_path)
+ super(FileRenderer, self).__init__(loader)
+
+ @classmethod
+ def render_from_file(cls, filename, context):
+ dirname = os.path.dirname(filename)
+ basename = os.path.basename(filename)
+ return cls(dirname).render(basename, context)
+
+
+class SphinxRenderer(FileRenderer):
+ def __init__(self):
+ super(SphinxRenderer, self).__init__(os.path.join(package_dir, 'templates'))
+
+ @classmethod
+ def render_from_file(cls, filename, context):
+ return FileRenderer.render_from_file(filename, context)
+
+
+class LaTeXRenderer(SphinxRenderer):
+ def __init__(self):
+ super(LaTeXRenderer, self).__init__()
+
+ # use JSP/eRuby like tagging instead because curly bracket; the default
+ # tagging of jinja2 is not good for LaTeX sources.
+ self.env.variable_start_string = '<%='
+ self.env.variable_end_string = '%>'
+ self.env.block_start_string = '<%'
+ self.env.block_end_string = '%>'
diff --git a/sphinx/websupport/__init__.py b/sphinx/websupport/__init__.py
index 606d549a6..69914da95 100644
--- a/sphinx/websupport/__init__.py
+++ b/sphinx/websupport/__init__.py
@@ -130,11 +130,8 @@ class WebSupport(object):
"""Load and return the "global context" pickle."""
if not self._globalcontext:
infilename = path.join(self.datadir, 'globalcontext.pickle')
- f = open(infilename, 'rb')
- try:
+ with open(infilename, 'rb') as f:
self._globalcontext = pickle.load(f)
- finally:
- f.close()
return self._globalcontext
def get_document(self, docname, username='', moderator=False):
@@ -185,14 +182,11 @@ class WebSupport(object):
infilename = docpath + '.fpickle'
try:
- f = open(infilename, 'rb')
+ with open(infilename, 'rb') as f:
+ document = pickle.load(f)
except IOError:
raise errors.DocumentNotFoundError(
'The document "%s" could not be found' % docname)
- try:
- document = pickle.load(f)
- finally:
- f.close()
comment_opts = self._make_comment_options(username, moderator)
comment_meta = self._make_metadata(
diff --git a/sphinx/websupport/search/__init__.py b/sphinx/websupport/search/__init__.py
index 844a3b468..80b5a3535 100644
--- a/sphinx/websupport/search/__init__.py
+++ b/sphinx/websupport/search/__init__.py
@@ -34,19 +34,20 @@ class BaseSearch(object):
"""
pass
- def feed(self, pagename, title, doctree):
+ def feed(self, pagename, filename, title, doctree):
"""Called by the builder to add a doctree to the index. Converts the
`doctree` to text and passes it to :meth:`add_document`. You probably
won't want to override this unless you need access to the `doctree`.
Override :meth:`add_document` instead.
:param pagename: the name of the page to be indexed
+ :param filename: the name of the original source file
:param title: the title of the page to be indexed
:param doctree: is the docutils doctree representation of the page
"""
- self.add_document(pagename, title, doctree.astext())
+ self.add_document(pagename, filename, title, doctree.astext())
- def add_document(self, pagename, title, text):
+ def add_document(self, pagename, filename, title, text):
"""Called by :meth:`feed` to add a document to the search index.
This method should should do everything necessary to add a single
document to the search index.
@@ -59,6 +60,7 @@ class BaseSearch(object):
query.
:param pagename: the name of the page being indexed
+ :param filename: the name of the original source file
:param title: the page's title
:param text: the full text of the page
"""
diff --git a/sphinx/websupport/search/nullsearch.py b/sphinx/websupport/search/nullsearch.py
index 9e990b1cf..4d0db9553 100644
--- a/sphinx/websupport/search/nullsearch.py
+++ b/sphinx/websupport/search/nullsearch.py
@@ -17,7 +17,7 @@ class NullSearch(BaseSearch):
"""A search adapter that does nothing. Used when no search adapter
is specified.
"""
- def feed(self, pagename, title, doctree):
+ def feed(self, pagename, filename, title, doctree):
pass
def query(self, q):
diff --git a/sphinx/websupport/search/whooshsearch.py b/sphinx/websupport/search/whooshsearch.py
index 4b0769f50..f31dc4d52 100644
--- a/sphinx/websupport/search/whooshsearch.py
+++ b/sphinx/websupport/search/whooshsearch.py
@@ -44,7 +44,7 @@ class WhooshSearch(BaseSearch):
def finish_indexing(self):
self.index_writer.commit()
- def add_document(self, pagename, title, text):
+ def add_document(self, pagename, filename, title, text):
self.index_writer.add_document(path=text_type(pagename),
title=title,
text=text)
diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py
index 6a30d4c3a..ba2b758d8 100644
--- a/sphinx/writers/html.py
+++ b/sphinx/writers/html.py
@@ -104,9 +104,19 @@ class HTMLTranslator(BaseTranslator):
self.body.append('<!--[%s]-->' % node['ids'][0])
def depart_desc_signature(self, node):
- self.add_permalink_ref(node, _('Permalink to this definition'))
+ if not node.get('is_multiline'):
+ self.add_permalink_ref(node, _('Permalink to this definition'))
self.body.append('</dt>\n')
+ def visit_desc_signature_line(self, node):
+ pass
+
+ def depart_desc_signature_line(self, node):
+ if node.get('add_permalink'):
+ # the permalink info is on the parent desc_signature node
+ self.add_permalink_ref(node.parent, _('Permalink to this definition'))
+ self.body.append('<br />')
+
def visit_desc_addname(self, node):
self.body.append(self.starttag(node, 'code', '', CLASS='descclassname'))
@@ -213,6 +223,8 @@ class HTMLTranslator(BaseTranslator):
atts['class'] += ' image-reference'
if 'reftitle' in node:
atts['title'] = node['reftitle']
+ if 'target' in node:
+ atts['target'] = node['target']
self.body.append(self.starttag(node, 'a', '', **atts))
if node.get('secnumber'):
@@ -295,13 +307,34 @@ class HTMLTranslator(BaseTranslator):
format = u'<a class="headerlink" href="#%s" title="%s">%s</a>'
self.body.append(format % (node['ids'][0], title, self.permalink_text))
- # overwritten to avoid emitting empty <ul></ul>
+ def generate_targets_for_listing(self, node):
+ """Generate hyperlink targets for listings.
+
+ Original visit_bullet_list(), visit_definition_list() and visit_enumerated_list()
+ generates hyperlink targets inside listing tags (<ul>, <ol> and <dl>) if multiple
+ IDs are assigned to listings. That is invalid DOM structure.
+ (This is a bug of docutils <= 0.12)
+
+ This exports hyperlink targets before listings to make valid DOM structure.
+ """
+ for id in node['ids'][1:]:
+ self.body.append('<span id="%s"></span>' % id)
+ node['ids'].remove(id)
+
+ # overwritten
def visit_bullet_list(self, node):
if len(node) == 1 and node[0].tagname == 'toctree':
+ # avoid emitting empty <ul></ul>
raise nodes.SkipNode
+ self.generate_targets_for_listing(node)
BaseTranslator.visit_bullet_list(self, node)
# overwritten
+ def visit_enumerated_list(self, node):
+ self.generate_targets_for_listing(node)
+ BaseTranslator.visit_enumerated_list(self, node)
+
+ # overwritten
def visit_title(self, node):
BaseTranslator.visit_title(self, node)
self.add_secnumber(node)
@@ -446,7 +479,7 @@ class HTMLTranslator(BaseTranslator):
pass
def visit_download_reference(self, node):
- if node.hasattr('filename'):
+ if self.builder.download_support and node.hasattr('filename'):
self.body.append(
'<a class="reference download internal" href="%s" download="">' %
posixpath.join(self.builder.dlpath, node['filename']))
@@ -646,6 +679,7 @@ class HTMLTranslator(BaseTranslator):
# overwritten to do not add '</dt>' in 'visit_definition' state.
def visit_definition(self, node):
+ self.generate_targets_for_listing(node)
self.body.append(self.starttag(node, 'dd', ''))
self.set_first_last(node)
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 08afb1b86..60483ded5 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -28,42 +28,10 @@ from sphinx.locale import admonitionlabels, _
from sphinx.util import split_into
from sphinx.util.i18n import format_date
from sphinx.util.nodes import clean_astext, traverse_parent
+from sphinx.util.template import LaTeXRenderer
from sphinx.util.texescape import tex_escape_map, tex_replace_map
from sphinx.util.smartypants import educate_quotes_latex
-HEADER = r'''%% Generated by Sphinx.
-\def\sphinxdocclass{%(docclass)s}
-\newif\ifsphinxKeepOldNames %(keepoldnames)s
-\documentclass[%(papersize)s,%(pointsize)s%(classoptions)s]{%(wrapperclass)s}
-\usepackage{iftex}
-%(passoptionstopackages)s
-%(inputenc)s
-%(utf8extra)s
-%(cmappkg)s
-%(fontenc)s
-%(amsmath)s
-%(babel)s
-%(fontpkg)s
-%(fncychap)s
-%(longtable)s
-\usepackage{sphinx}
-\usepackage{multirow}
-\usepackage{eqparbox}
-%(usepackages)s
-%(contentsname)s
-%(numfig_format)s
-%(pageautorefname)s
-%(tocdepth)s
-%(preamble)s
-
-\title{%(title)s}
-\date{%(date)s}
-\release{%(release)s}
-\author{%(author)s}
-\newcommand{\sphinxlogo}{%(logo)s}
-\renewcommand{\releasename}{%(releasename)s}
-%(makeindex)s
-'''
BEGIN_DOC = r'''
\begin{document}
@@ -72,13 +40,88 @@ BEGIN_DOC = r'''
%(tableofcontents)s
'''
-FOOTER = r'''
-\renewcommand{\indexname}{%(indexname)s}
-%(printindex)s
-\end{document}
-'''
+DEFAULT_TEMPLATE = 'latex/content.tex_t'
URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:')
+SECNUMDEPTH = 3
+
+DEFAULT_SETTINGS = {
+ 'latex_engine': 'pdflatex',
+ 'papersize': 'letterpaper',
+ 'pointsize': '10pt',
+ 'pxunit': '49336sp',
+ 'classoptions': '',
+ 'extraclassoptions': '',
+ 'maxlistdepth': '',
+ 'sphinxpkgoptions': '',
+ 'sphinxsetup': '',
+ 'passoptionstopackages': '',
+ 'geometry': ('\\usepackage[margin=1in,marginparwidth=0.5in]'
+ '{geometry}'),
+ 'inputenc': '',
+ 'utf8extra': '',
+ 'cmappkg': '\\usepackage{cmap}',
+ 'fontenc': '\\usepackage[T1]{fontenc}',
+ 'amsmath': '\\usepackage{amsmath,amssymb,amstext}',
+ 'multilingual': '',
+ 'babel': '\\usepackage{babel}',
+ 'polyglossia': '',
+ 'fontpkg': '\\usepackage{times}',
+ 'fncychap': '\\usepackage[Bjarne]{fncychap}',
+ 'longtable': '\\usepackage{longtable}',
+ 'hyperref': ('% Include hyperref last.\n'
+ '\\usepackage{hyperref}\n'
+ '% Fix anchor placement for figures with captions.\n'
+ '\\usepackage{hypcap}% it must be loaded after hyperref.\n'
+ '% Set up styles of URL: it should be placed after hyperref.\n'
+ '\\urlstyle{same}'),
+ 'usepackages': '',
+ 'numfig_format': '',
+ 'contentsname': '',
+ 'preamble': '',
+ 'title': '',
+ 'date': '',
+ 'release': '',
+ 'author': '',
+ 'logo': '',
+ 'releasename': 'Release',
+ 'makeindex': '\\makeindex',
+ 'shorthandoff': '',
+ 'maketitle': '\\maketitle',
+ 'tableofcontents': '\\sphinxtableofcontents',
+ 'atendofbody': '',
+ 'printindex': '\\printindex',
+ 'transition': '\n\n\\bigskip\\hrule{}\\bigskip\n\n',
+ 'figure_align': 'htbp',
+ 'tocdepth': '',
+ 'secnumdepth': '',
+ 'pageautorefname': '',
+}
+
+ADDITIONAL_SETTINGS = {
+ 'pdflatex': {
+ 'inputenc': '\\usepackage[utf8]{inputenc}',
+ 'utf8extra': ('\\ifdefined\\DeclareUnicodeCharacter\n'
+ ' \\DeclareUnicodeCharacter{00A0}{\\nobreakspace}\n'
+ '\\fi'),
+ },
+ 'xelatex': {
+ 'latex_engine': 'xelatex',
+ 'polyglossia': '\\usepackage{polyglossia}',
+ 'fontenc': '\\usepackage{fontspec}',
+ 'fontpkg': '',
+ 'utf8extra': ('\\catcode`^^^^00a0\\active\\protected\\def^^^^00a0'
+ '{\\leavevmode\\nobreak\\ }'),
+ },
+ 'lualatex': {
+ 'latex_engine': 'lualatex',
+ 'utf8extra': ('\\catcode`^^^^00a0\\active\\protected\\def^^^^00a0'
+ '{\\leavevmode\\nobreak\\ }'),
+ },
+ 'platex': {
+ 'latex_engine': 'platex',
+ },
+}
class collected_footnote(nodes.footnote):
@@ -128,7 +171,7 @@ class ExtBabel(Babel):
if shortlang in ('de', 'ngerman', 'sl', 'slovene', 'pt', 'portuges',
'es', 'spanish', 'nl', 'dutch', 'pl', 'polish', 'it',
'italian'):
- return '\\shorthandoff{"}'
+ return '\\if\\catcode`\\"\\active\\shorthandoff{"}\\fi'
elif shortlang in ('tr', 'turkish'):
return '\\shorthandoff{=}'
return ''
@@ -181,15 +224,11 @@ class ShowUrlsTransform(object):
if node.astext() != uri:
index = node.parent.index(node)
if show_urls == 'footnote':
- if list(traverse_parent(node, nodes.topic)):
- # should not expand references in topics
- pass
- else:
- footnote_nodes = self.create_footnote(uri)
- for i, fn in enumerate(footnote_nodes):
- node.parent.insert(index + i + 1, fn)
-
- self.expanded = True
+ footnote_nodes = self.create_footnote(uri)
+ for i, fn in enumerate(footnote_nodes):
+ node.parent.insert(index + i + 1, fn)
+
+ self.expanded = True
else: # all other true values (b/w compat)
textnode = nodes.Text(" (%s)" % uri)
node.parent.insert(index + 1, textnode)
@@ -270,53 +309,29 @@ def escape_abbr(text):
return re.sub('\.(?=\s|$)', '.\\@', text)
+def rstdim_to_latexdim(width_str):
+ """Convert `width_str` with rst length to LaTeX length."""
+ match = re.match('^(\d*\.?\d*)\s*(\S*)$', width_str)
+ if not match:
+ raise ValueError
+ res = width_str
+ amount, unit = match.groups()[:2]
+ float(amount) # validate amount is float
+ if unit in ('', "px"):
+ res = "%s\\sphinxpxdimen" % amount
+ elif unit == 'pt':
+ res = '%sbp' % amount # convert to 'bp'
+ elif unit == "%":
+ res = "%.3f\\linewidth" % (float(amount) / 100.0)
+ return res
+
+
class LaTeXTranslator(nodes.NodeVisitor):
sectionnames = ["part", "chapter", "section", "subsection",
"subsubsection", "paragraph", "subparagraph"]
ignore_missing_images = False
- default_elements = {
- 'papersize': 'letterpaper',
- 'pointsize': '10pt',
- 'classoptions': '',
- 'extraclassoptions': '',
- 'passoptionstopackages': '',
- 'inputenc': ('\\ifPDFTeX\n'
- ' \\usepackage[utf8]{inputenc}\n'
- '\\fi'),
- 'utf8extra': ('\\ifdefined\\DeclareUnicodeCharacter\n'
- ' \\DeclareUnicodeCharacter{00A0}{\\nobreakspace}\n'
- '\\fi'),
- 'cmappkg': '\\usepackage{cmap}',
- 'fontenc': '\\usepackage[T1]{fontenc}',
- 'amsmath': '\\usepackage{amsmath,amssymb,amstext}',
- 'babel': '\\usepackage{babel}',
- 'fontpkg': '\\usepackage{times}',
- 'fncychap': '\\usepackage[Bjarne]{fncychap}',
- 'longtable': '\\usepackage{longtable}',
- 'usepackages': '',
- 'numfig_format': '',
- 'contentsname': '',
- 'preamble': '',
- 'title': '',
- 'date': '',
- 'release': '',
- 'author': '',
- 'logo': '',
- 'releasename': 'Release',
- 'makeindex': '\\makeindex',
- 'shorthandoff': '',
- 'maketitle': '\\maketitle',
- 'tableofcontents': '\\tableofcontents',
- 'footer': '',
- 'printindex': '\\printindex',
- 'transition': '\n\n\\bigskip\\hrule{}\\bigskip\n\n',
- 'figure_align': 'htbp',
- 'tocdepth': '',
- 'pageautorefname': '',
- }
-
# sphinx specific document classes
docclasses = ('howto', 'manual')
@@ -351,34 +366,22 @@ class LaTeXTranslator(nodes.NodeVisitor):
if document.settings.docclass == 'howto':
self.top_sectionlevel = 2
else:
- if builder.config.latex_use_parts:
- self.top_sectionlevel = 0
- else:
- self.top_sectionlevel = 1
+ self.top_sectionlevel = 1
# sort out some elements
- papersize = builder.config.latex_paper_size + 'paper'
- if papersize == 'paper': # e.g. command line "-D latex_paper_size="
- papersize = 'letterpaper'
-
- self.elements = self.default_elements.copy()
+ self.elements = DEFAULT_SETTINGS.copy()
+ self.elements.update(ADDITIONAL_SETTINGS.get(builder.config.latex_engine, {}))
self.elements.update({
'wrapperclass': self.format_docclass(document.settings.docclass),
- 'papersize': papersize,
- 'pointsize': builder.config.latex_font_size,
# if empty, the title is set to the first section title
'title': document.settings.title,
'release': builder.config.release,
'author': document.settings.author,
'releasename': _('Release'),
- 'preamble': builder.config.latex_preamble,
'indexname': _('Index'),
})
- # set-up boolean for sphinx.sty
- if builder.config.latex_keep_old_macro_names:
- self.elements['keepoldnames'] = '\\sphinxKeepOldNamestrue'
- else:
- self.elements['keepoldnames'] = '\\sphinxKeepOldNamesfalse'
+ if not builder.config.latex_keep_old_macro_names:
+ self.elements['sphinxpkgoptions'] = 'dontkeepoldnames'
if document.settings.docclass == 'howto':
docclass = builder.config.latex_docclass.get('howto', 'article')
else:
@@ -393,28 +396,46 @@ class LaTeXTranslator(nodes.NodeVisitor):
# no need for \\noindent here, used in flushright
self.elements['logo'] = '\\sphinxincludegraphics{%s}\\par' % \
path.basename(builder.config.latex_logo)
- # setup babel
- self.babel = ExtBabel(builder.config.language)
- self.elements['classoptions'] += ',' + self.babel.get_language()
+
if builder.config.language:
- if not self.babel.is_supported_language():
- self.builder.warn('no Babel option known for language %r' %
- builder.config.language)
- self.elements['shorthandoff'] = self.babel.get_shorthandoff()
+ # use Sonny style if any language specified
self.elements['fncychap'] = '\\usepackage[Sonny]{fncychap}'
- # Times fonts don't work with Cyrillic languages
- if self.babel.uses_cyrillic():
- self.elements['fontpkg'] = ''
-
- # pTeX (Japanese TeX) for support
- if builder.config.language == 'ja':
- # use dvipdfmx as default class option in Japanese
- self.elements['classoptions'] = ',dvipdfmx'
- # disable babel which has not publishing quality in Japanese
- self.elements['babel'] = ''
- # disable fncychap in Japanese documents
- self.elements['fncychap'] = ''
+ self.babel = ExtBabel(builder.config.language)
+ if builder.config.language and not self.babel.is_supported_language():
+ # emit warning if specified language is invalid
+ # (only emitting, nothing changed to processing)
+ self.builder.warn('no Babel option known for language %r' %
+ builder.config.language)
+
+ # simply use babel.get_language() always, as get_language() returns
+ # 'english' even if language is invalid or empty
+ self.elements['classoptions'] += ',' + self.babel.get_language()
+
+ # set up multilingual module...
+ if self.elements['polyglossia']:
+ self.elements['babel'] = '' # disable babel
+ self.elements['multilingual'] = '%s\n\\setmainlanguage{%s}' % \
+ (self.elements['polyglossia'], self.babel.get_language())
+ elif self.elements['babel']:
+ self.elements['multilingual'] = self.elements['babel']
+ if builder.config.language:
+ self.elements['shorthandoff'] = self.babel.get_shorthandoff()
+
+ # Times fonts don't work with Cyrillic languages
+ if self.babel.uses_cyrillic():
+ self.elements['fontpkg'] = ''
+
+ # pTeX (Japanese TeX) for support
+ if builder.config.language == 'ja':
+ # use dvipdfmx as default class option in Japanese
+ self.elements['classoptions'] = ',dvipdfmx'
+ # disable babel which has not publishing quality in Japanese
+ self.elements['babel'] = ''
+ self.elements['multilingual'] = ''
+ # disable fncychap in Japanese documents
+ self.elements['fncychap'] = ''
+
if getattr(builder, 'usepackages', None):
def declare_package(packagename, options=None):
if options:
@@ -423,11 +444,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
return '\\usepackage{%s}' % (packagename,)
usepackages = (declare_package(*p) for p in builder.usepackages)
self.elements['usepackages'] += "\n".join(usepackages)
- # allow the user to override them all
- self.elements.update(builder.config.latex_elements)
- if self.elements['extraclassoptions']:
- self.elements['classoptions'] += ',' + \
- self.elements['extraclassoptions']
if document.get('tocdepth'):
# redece tocdepth if `part` or `chapter` is used for top_sectionlevel
# tocdepth = -1: show only parts
@@ -435,11 +451,34 @@ class LaTeXTranslator(nodes.NodeVisitor):
# tocdepth = 1: show parts, chapters and sections
# tocdepth = 2: show parts, chapters, sections and subsections
# ...
- self.elements['tocdepth'] = ('\\setcounter{tocdepth}{%d}' %
- (document['tocdepth'] + self.top_sectionlevel - 2))
+ tocdepth = document['tocdepth'] + self.top_sectionlevel - 2
+ maxdepth = len(self.sectionnames) - self.top_sectionlevel
+ if tocdepth > maxdepth:
+ self.builder.warn('too large :maxdepth:, ignored.')
+ tocdepth = maxdepth
+
+ self.elements['tocdepth'] = '\\setcounter{tocdepth}{%d}' % tocdepth
+ if tocdepth >= SECNUMDEPTH:
+ # Increase secnumdepth if tocdepth is depther than default SECNUMDEPTH
+ self.elements['secnumdepth'] = '\\setcounter{secnumdepth}{%d}' % tocdepth
if getattr(document.settings, 'contentsname', None):
self.elements['contentsname'] = \
self.babel_renewcommand('\\contentsname', document.settings.contentsname)
+ # allow the user to override them all
+ self.check_latex_elements()
+ self.elements.update(builder.config.latex_elements)
+ if self.elements['maxlistdepth']:
+ self.elements['sphinxpkgoptions'] += (',maxlistdepth=%s' %
+ self.elements['maxlistdepth'])
+ if self.elements['sphinxpkgoptions']:
+ self.elements['sphinxpkgoptions'] = ('[%s]' %
+ self.elements['sphinxpkgoptions'])
+ if self.elements['sphinxsetup']:
+ self.elements['sphinxsetup'] = ('\\sphinxsetup{%s}' %
+ self.elements['sphinxsetup'])
+ if self.elements['extraclassoptions']:
+ self.elements['classoptions'] += ',' + \
+ self.elements['extraclassoptions']
self.elements['pageautorefname'] = \
self.babel_defmacro('\\pageautorefname', self.encode(_('page')))
self.elements['numfig_format'] = self.generate_numfig_format(builder)
@@ -483,6 +522,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
def pop_hyperlink_ids(self, figtype):
return self.next_hyperlink_ids.pop(figtype, set())
+ def check_latex_elements(self):
+ for key in self.builder.config.latex_elements:
+ if key not in self.elements:
+ msg = _("Unknown configure key: latex_elements[%r] is ignored.")
+ self.builder.warn(msg % key)
+
def restrict_footnote(self, node):
if self.footnote_restricted is False:
self.footnote_restricted = node
@@ -504,12 +549,16 @@ class LaTeXTranslator(nodes.NodeVisitor):
return docclass
def astext(self):
- return (HEADER % self.elements +
- self.highlighter.get_stylesheet() +
- u''.join(self.body) +
- '\n' + self.elements['footer'] + '\n' +
- self.generate_indices() +
- FOOTER % self.elements)
+ self.elements.update({
+ 'body': u''.join(self.body),
+ 'indices': self.generate_indices()
+ })
+
+ template_path = path.join(self.builder.srcdir, '_templates', 'latex.tex_t')
+ if path.exists(template_path):
+ return LaTeXRenderer().render(template_path, self.elements)
+ else:
+ return LaTeXRenderer().render(DEFAULT_TEMPLATE, self.elements)
def hypertarget(self, id, withdoc=True, anchor=True):
if withdoc:
@@ -583,16 +632,16 @@ class LaTeXTranslator(nodes.NodeVisitor):
if len(codeblock) == 1:
pass # FIXME
else:
- ret.append('\\SetupFloatingEnvironment{literal-block}{name=%s}\n' %
- escape_abbr(text_type(codeblock[0]).translate(tex_escape_map)))
- if table[1]:
+ definition = escape_abbr(text_type(codeblock[0]).translate(tex_escape_map))
+ ret.append(self.babel_renewcommand('\\literalblockname', definition))
+ if codeblock[1]:
pass # FIXME
return ''.join(ret)
def generate_indices(self):
def generate(content, collapsed):
- ret.append('\\begin{theindex}\n')
+ ret.append('\\begin{sphinxtheindex}\n')
ret.append('\\def\\bigletter#1{{\\Large\\sffamily#1}'
'\\nopagebreak\\vspace{1mm}}\n')
for i, (letter, entries) in enumerate(content):
@@ -603,13 +652,13 @@ class LaTeXTranslator(nodes.NodeVisitor):
for entry in entries:
if not entry[3]:
continue
- ret.append('\\item {\\texttt{%s}}' % self.encode(entry[0]))
+ ret.append('\\item {\\sphinxstyleindexentry{%s}}' % self.encode(entry[0]))
if entry[4]:
# add "extra" info
- ret.append(' \\emph{(%s)}' % self.encode(entry[4]))
- ret.append(', \\pageref{%s:%s}\n' %
+ ret.append('\\sphinxstyleindexextra{%s}' % self.encode(entry[4]))
+ ret.append('\\sphinxstyleindexpageref{%s:%s}\n' %
(entry[2], self.idescape(entry[3])))
- ret.append('\\end{theindex}\n')
+ ret.append('\\end{sphinxtheindex}\n')
ret = []
# latex_domain_indices can be False/True or a list of index names
@@ -657,14 +706,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
for bi in self.bibitems:
if len(widest_label) < len(bi[0]):
widest_label = bi[0]
- self.body.append(u'\n\\begin{thebibliography}{%s}\n' % widest_label)
+ self.body.append(u'\n\\begin{sphinxthebibliography}{%s}\n' % widest_label)
for bi in self.bibitems:
target = self.hypertarget(bi[2] + ':' + bi[3],
withdoc=False)
self.body.append(u'\\bibitem[%s]{%s}{%s %s}\n' %
(self.encode(bi[0]), self.idescape(bi[0]),
target, bi[1]))
- self.body.append(u'\\end{thebibliography}\n')
+ self.body.append(u'\\end{sphinxthebibliography}\n')
self.bibitems = []
def visit_start_of_file(self, node):
@@ -795,9 +844,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.context[-1] += self.hypertarget(id, anchor=False)
self.next_section_ids.clear()
- elif isinstance(parent, (nodes.topic, nodes.sidebar)):
- self.body.append(r'\textbf{')
- self.context.append('}\n\n\medskip\n\n')
+ elif isinstance(parent, nodes.topic):
+ self.body.append(r'\sphinxstyletopictitle{')
+ self.context.append('}\n')
+ elif isinstance(parent, nodes.sidebar):
+ self.body.append(r'\sphinxstylesidebartitle{')
+ self.context.append('}\n')
elif isinstance(parent, nodes.Admonition):
self.body.append('{')
self.context.append('}\n')
@@ -809,7 +861,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
'encountered title node not in section, topic, table, '
'admonition or sidebar',
(self.curfilestack[-1], node.line or ''))
- self.body.append('\\textbf{')
+ self.body.append('\\sphinxstyleothertitle{')
self.context.append('}\n')
self.in_title = 1
@@ -823,8 +875,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_subtitle(self, node):
if isinstance(node.parent, nodes.sidebar):
- self.body.append('~\\\\\n\\textbf{')
- self.context.append('}\n\\smallskip\n')
+ self.body.append('\\sphinxstylesidebarsubtitle{')
+ self.context.append('}\n')
else:
self.context.append('')
@@ -839,12 +891,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_desc(self, node):
self.body.append('\n\\end{fulllineitems}\n\n')
- def visit_desc_signature(self, node):
- if node.parent['objtype'] != 'describe' and node['ids']:
- hyper = self.hypertarget(node['ids'][0])
- else:
- hyper = ''
- self.body.append(hyper)
+ def _visit_signature_line(self, node):
for child in node:
if isinstance(child, addnodes.desc_parameterlist):
self.body.append(r'\pysiglinewithargsret{')
@@ -852,9 +899,28 @@ class LaTeXTranslator(nodes.NodeVisitor):
else:
self.body.append(r'\pysigline{')
- def depart_desc_signature(self, node):
+ def _depart_signature_line(self, node):
self.body.append('}')
+ def visit_desc_signature(self, node):
+ if node.parent['objtype'] != 'describe' and node['ids']:
+ hyper = self.hypertarget(node['ids'][0])
+ else:
+ hyper = ''
+ self.body.append(hyper)
+ if not node.get('is_multiline'):
+ self._visit_signature_line(node)
+
+ def depart_desc_signature(self, node):
+ if not node.get('is_multiline'):
+ self._depart_signature_line(node)
+
+ def visit_desc_signature_line(self, node):
+ self._visit_signature_line(node)
+
+ def depart_desc_signature_line(self, node):
+ self._depart_signature_line(node)
+
def visit_desc_addname(self, node):
self.body.append(r'\sphinxcode{')
self.literal_whitespace += 1
@@ -950,12 +1016,17 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_collected_footnote(self, node):
self.in_footnote += 1
if 'footnotetext' in node:
- self.body.append('\\footnotetext[%s]{\sphinxAtStartFootnote%%\n' % node['number'])
+ self.body.append('%%\n\\begin{footnotetext}[%s]'
+ '\\sphinxAtStartFootnote\n' % node['number'])
else:
- self.body.append('\\footnote[%s]{\sphinxAtStartFootnote%%\n' % node['number'])
+ self.body.append('%%\n\\begin{footnote}[%s]'
+ '\\sphinxAtStartFootnote\n' % node['number'])
def depart_collected_footnote(self, node):
- self.body.append('}')
+ if 'footnotetext' in node:
+ self.body.append('%\n\\end{footnotetext}')
+ else:
+ self.body.append('%\n\\end{footnote}')
self.in_footnote -= 1
def visit_label(self, node):
@@ -1014,9 +1085,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append(self.table.colspec)
else:
if self.table.has_problematic:
- colwidth = 0.95 / self.table.colcount
- colspec = ('p{%.3f\\linewidth}|' % colwidth) * \
- self.table.colcount
+ colspec = ('*{%d}{p{\\dimexpr(\\linewidth-\\arrayrulewidth)/%d'
+ '-2\\tabcolsep-\\arrayrulewidth\\relax}|}' %
+ (self.table.colcount, self.table.colcount))
self.body.append('{|' + colspec + '}\n')
elif self.table.longtable:
self.body.append('{|' + ('l|' * self.table.colcount) + '}\n')
@@ -1161,7 +1232,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
if len(node) == 1 and isinstance(node[0], nodes.paragraph) and node.astext() == '':
pass
else:
- self.body.append('\\textsf{\\relax ')
+ self.body.append('\\sphinxstylethead{\\relax ')
context += '\\unskip}\\relax '
while self.remember_multirow.get(self.table.col + 1, 0):
self.table.col += 1
@@ -1336,28 +1407,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_hlistcol(self, node):
pass
- def latex_image_length(self, width_str, figure=False):
- """Convert `width_str` with rst length to LaTeX length.
-
- This function is copied from docutils' latex writer
-
- The last parameter, ``figure`` is only for compatibility with 1.4.4.
- It will be removed at Sphinx-1.5.
- """
- match = re.match('(\d*\.?\d*)\s*(\S*)', width_str)
- if not match:
- # fallback
- return width_str
- res = width_str
- amount, unit = match.groups()[:2]
- if figure and unit in ('', 'pt'):
- res = '%sbp' % amount # convert to 'bp'
- elif not unit or unit == "px":
- # pixels: let LaTeX alone
- return None
- elif unit == "%":
- res = "%.3f\\linewidth" % (float(amount) / 100.0)
- return res
+ def latex_image_length(self, width_str):
+ try:
+ return rstdim_to_latexdim(width_str)
+ except ValueError:
+ self.builder.warn('dimension unit %s is invalid. Ignored.' % width_str)
def is_inline(self, node):
"""Check whether a node represents an inline element."""
@@ -1369,11 +1423,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
post = []
include_graphics_options = []
is_inline = self.is_inline(node)
- if 'scale' in attrs:
- # Could also be done with ``scale`` option to
- # ``\includegraphics``; doing it this way for consistency.
- pre.append('\\scalebox{%f}{' % (attrs['scale'] / 100.0,))
- post.append('}')
if 'width' in attrs:
w = self.latex_image_length(attrs['width'])
if w:
@@ -1382,6 +1431,17 @@ class LaTeXTranslator(nodes.NodeVisitor):
h = self.latex_image_length(attrs['height'])
if h:
include_graphics_options.append('height=%s' % h)
+ if 'scale' in attrs:
+ if include_graphics_options:
+ # unfortunately passing "height=1cm,scale=2.0" to \includegraphics
+ # does not result in a height of 2cm. We must scale afterwards.
+ pre.append('\\scalebox{%f}{' % (attrs['scale'] / 100.0,))
+ post.append('}')
+ else:
+ # if no "width" nor "height", \sphinxincludegraphics will fit
+ # to the available text width if oversized after rescaling.
+ include_graphics_options.append('scale=%s'
+ % (float(attrs['scale']) / 100.0))
if 'align' in attrs:
align_prepost = {
# By default latex aligns the top of an image.
@@ -1446,22 +1506,23 @@ class LaTeXTranslator(nodes.NodeVisitor):
if self.table:
# TODO: support align option
if 'width' in node:
- length = self.latex_image_length(node['width'], figure=True)
- self.body.append('\\begin{sphinxfigure-in-table}[%s]\n\\centering\n' % length)
+ length = self.latex_image_length(node['width'])
+ if length:
+ self.body.append('\\begin{sphinxfigure-in-table}[%s]\n'
+ '\\centering\n' % length)
else:
self.body.append('\\begin{sphinxfigure-in-table}\n\\centering\n')
if any(isinstance(child, nodes.caption) for child in node):
self.body.append('\\capstart')
self.context.append(ids + '\\end{sphinxfigure-in-table}\\relax\n')
elif node.get('align', '') in ('left', 'right'):
+ length = None
if 'width' in node:
- length = self.latex_image_length(node['width'], figure=True)
+ length = self.latex_image_length(node['width'])
elif 'width' in node[0]:
- length = self.latex_image_length(node[0]['width'], figure=True)
- else:
- length = '0pt'
+ length = self.latex_image_length(node[0]['width'])
self.body.append('\\begin{wrapfigure}{%s}{%s}\n\\centering' %
- (node['align'] == 'right' and 'r' or 'l', length))
+ (node['align'] == 'right' and 'r' or 'l', length or '0pt'))
self.context.append(ids + '\\end{wrapfigure}\n')
elif self.in_minipage:
if ('align' not in node.attributes or
@@ -1493,8 +1554,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_caption(self, node):
self.in_caption += 1
+ self.restrict_footnote(node)
if self.in_container_literal_block:
- self.body.append('\\sphinxSetupCaptionForVerbatim{literal-block}{')
+ self.body.append('\\sphinxSetupCaptionForVerbatim{')
elif self.in_minipage and isinstance(node.parent, nodes.figure):
self.body.append('\\captionof{figure}{')
elif self.table and node.parent.tagname == 'figure':
@@ -1505,6 +1567,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_caption(self, node):
self.body.append('}')
self.in_caption -= 1
+ self.unrestrict_footnote(node)
def visit_legend(self, node):
self.body.append('{\\small ')
@@ -1513,19 +1576,19 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('}')
def visit_admonition(self, node):
- self.body.append('\n\\begin{notice}{note}')
+ self.body.append('\n\\begin{sphinxadmonition}{note}')
def depart_admonition(self, node):
- self.body.append('\\end{notice}\n')
+ self.body.append('\\end{sphinxadmonition}\n')
def _make_visit_admonition(name):
def visit_admonition(self, node):
- self.body.append(u'\n\\begin{notice}{%s}{%s:}' %
+ self.body.append(u'\n\\begin{sphinxadmonition}{%s}{%s:}' %
(name, admonitionlabels[name]))
return visit_admonition
def _depart_named_admonition(self, node):
- self.body.append('\\end{notice}\n')
+ self.body.append('\\end{sphinxadmonition}\n')
visit_attention = _make_visit_admonition('attention')
depart_attention = _depart_named_admonition
@@ -1718,10 +1781,17 @@ class LaTeXTranslator(nodes.NodeVisitor):
else:
id = node.get('refuri', '')[1:].replace('#', ':')
- ref = '\\ref{%s}' % self.idescape(id)
title = node.get('title', '%s')
title = text_type(title).translate(tex_escape_map).replace('\\%s', '%s')
- hyperref = '\\hyperref[%s]{%s}' % (self.idescape(id), escape_abbr(title) % ref)
+ if '\\{name\\}' in title or '\\{number\\}' in title:
+ # new style format (cf. "Fig.%{number}")
+ title = title.replace('\\{name\\}', '{name}').replace('\\{number\\}', '{number}')
+ text = escape_abbr(title).format(name='\\nameref{%s}' % self.idescape(id),
+ number='\\ref{%s}' % self.idescape(id))
+ else:
+ # old style format (cf. "Fig.%{number}")
+ text = escape_abbr(title) % ('\\ref{%s}' % self.idescape(id))
+ hyperref = '\\hyperref[%s]{%s}' % (self.idescape(id), text)
self.body.append(hyperref)
raise nodes.SkipNode
@@ -1739,36 +1809,36 @@ class LaTeXTranslator(nodes.NodeVisitor):
pass
def visit_emphasis(self, node):
- self.body.append(r'\emph{')
+ self.body.append(r'\sphinxstyleemphasis{')
def depart_emphasis(self, node):
self.body.append('}')
def visit_literal_emphasis(self, node):
- self.body.append(r'\emph{\texttt{')
+ self.body.append(r'\sphinxstyleliteralemphasis{')
self.no_contractions += 1
def depart_literal_emphasis(self, node):
- self.body.append('}}')
+ self.body.append('}')
self.no_contractions -= 1
def visit_strong(self, node):
- self.body.append(r'\textbf{')
+ self.body.append(r'\sphinxstylestrong{')
def depart_strong(self, node):
self.body.append('}')
def visit_literal_strong(self, node):
- self.body.append(r'\textbf{\texttt{')
+ self.body.append(r'\sphinxstyleliteralstrong{')
self.no_contractions += 1
def depart_literal_strong(self, node):
- self.body.append('}}')
+ self.body.append('}')
self.no_contractions -= 1
def visit_abbreviation(self, node):
abbr = node.astext()
- self.body.append(r'\textsc{')
+ self.body.append(r'\sphinxstyleabbreviation{')
# spell out the explanation once
if node.hasattr('explanation') and abbr not in self.handled_abbrs:
self.context.append('} (%s)' % self.encode(node['explanation']))
@@ -1812,7 +1882,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_literal(self, node):
self.no_contractions += 1
if self.in_title:
- self.body.append(r'\texttt{')
+ self.body.append(r'\sphinxstyleliteralintitle{')
else:
self.body.append(r'\sphinxcode{')
@@ -1829,13 +1899,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
# if a footnote has been inserted once, it shouldn't be repeated
# by the next reference
if used:
- if self.table or self.in_term or self.in_title:
- self.body.append('\\protect\\footnotemark[%s]' % num)
- else:
- self.body.append('\\footnotemark[%s]' % num)
+ self.body.append('\\sphinxfootnotemark[%s]' % num)
elif self.footnote_restricted:
self.footnotestack[-1][num][1] = True
- self.body.append('\\protect\\footnotemark[%s]' % num)
+ self.body.append('\\sphinxfootnotemark[%s]' % num)
self.pending_footnotes.append(footnode)
else:
self.footnotestack[-1][num][1] = True
@@ -1846,10 +1913,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
pass
def visit_literal_block(self, node):
- if self.in_footnote:
- raise UnsupportedError('%s:%s: literal blocks in footnotes are '
- 'not supported by LaTeX' %
- (self.curfilestack[-1], node.line))
if node.rawsource != node.astext():
# most probably a parsed-literal block -- don't highlight
self.body.append('\\begin{alltt}\n')
@@ -1861,7 +1924,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
# suppress with anchor=False \phantomsection insertion
ids += self.hypertarget(node['ids'][0], anchor=False)
# LaTeX code will insert \phantomsection prior to \label
- if ids:
+ if ids and not self.in_footnote:
self.body.append('\n\\def\\sphinxLiteralBlockLabel{' + ids + '}')
code = node.astext()
lang = self.hlsettingstack[-1][0]
@@ -1886,18 +1949,28 @@ class LaTeXTranslator(nodes.NodeVisitor):
**highlight_args)
# workaround for Unicode issue
hlcode = hlcode.replace(u'€', u'@texteuro[]')
- # must use original Verbatim environment and "tabular" environment
- if self.table:
+ if self.in_footnote:
+ self.body.append('\n\\sphinxSetupCodeBlockInFootnote')
hlcode = hlcode.replace('\\begin{Verbatim}',
- '\\begin{OriginalVerbatim}')
+ '\\begin{sphinxVerbatim}')
+ # if in table raise verbatim flag to avoid "tabulary" environment
+ # and opt for sphinxVerbatimintable to handle caption & long lines
+ elif self.table:
self.table.has_problematic = True
self.table.has_verbatim = True
+ hlcode = hlcode.replace('\\begin{Verbatim}',
+ '\\begin{sphinxVerbatimintable}')
+ else:
+ hlcode = hlcode.replace('\\begin{Verbatim}',
+ '\\begin{sphinxVerbatim}')
# get consistent trailer
hlcode = hlcode.rstrip()[:-14] # strip \end{Verbatim}
- self.body.append('\n' + hlcode + '\\end{%sVerbatim}\n' %
- (self.table and 'Original' or ''))
+ self.body.append('\n' + hlcode + '\\end{sphinxVerbatim')
+ if self.table and not self.in_footnote:
+ self.body.append('intable')
+ self.body.append('}\n')
if ids:
- self.body.append('\\let\\sphinxLiteralBlockLabel\empty\n')
+ self.body.append('\\let\\sphinxLiteralBlockLabel\\empty\n')
raise nodes.SkipNode
def depart_literal_block(self, node):
diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py
index 223ed78fd..b9c9bd646 100644
--- a/sphinx/writers/manpage.py
+++ b/sphinx/writers/manpage.py
@@ -138,6 +138,12 @@ class ManualPageTranslator(BaseTranslator):
def depart_desc_signature(self, node):
self.depart_term(node)
+ def visit_desc_signature_line(self, node):
+ pass
+
+ def depart_desc_signature_line(self, node):
+ self.body.append(' ')
+
def visit_desc_addname(self, node):
pass
diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py
index 2463920ef..7032208ea 100644
--- a/sphinx/writers/text.py
+++ b/sphinx/writers/text.py
@@ -281,8 +281,11 @@ class TextTranslator(nodes.NodeVisitor):
char = '^'
text = ''.join(x[1] for x in self.states.pop() if x[0] == -1)
self.stateindent.pop()
- self.states[-1].append(
- (0, ['', text, '%s' % (char * column_width(text)), '']))
+ title = ['', text, '%s' % (char * column_width(text)), '']
+ if len(self.states) == 2 and len(self.states[-1]) == 0:
+ # remove an empty line before title if it is first section title in the document
+ title.pop(0)
+ self.states[-1].append((0, title))
def visit_subtitle(self, node):
pass
@@ -309,6 +312,12 @@ class TextTranslator(nodes.NodeVisitor):
# XXX: wrap signatures in a way that makes sense
self.end_state(wrap=False, end=None)
+ def visit_desc_signature_line(self, node):
+ pass
+
+ def depart_desc_signature_line(self, node):
+ self.add_text('\n')
+
def visit_desc_name(self, node):
pass
diff --git a/test-reqs.txt b/test-reqs.txt
index 32a7599af..b53adbfe5 100644
--- a/test-reqs.txt
+++ b/test-reqs.txt
@@ -13,3 +13,6 @@ whoosh>=2.0
alabaster
sphinx_rtd_theme
imagesize
+requests
+html5lib
+enum34
diff --git a/tests/coverage.py b/tests/coverage.py
index f9341d8ba..cd36e218a 100755
--- a/tests/coverage.py
+++ b/tests/coverage.py
@@ -472,10 +472,9 @@ class coverage:
def save(self):
if self.usecache and self.cache:
self.canonicalize_filenames()
- cache = open(self.cache, 'wb')
import marshal
- marshal.dump(self.cexecuted, cache)
- cache.close()
+ with open(self.cache, 'wb') as cache:
+ marshal.dump(self.cexecuted, cache)
# restore(). Restore coverage data from the coverage cache (if it exists).
@@ -488,10 +487,9 @@ class coverage:
def restore_file(self, file_name):
try:
- cache = open(file_name, 'rb')
import marshal
- cexecuted = marshal.load(cache)
- cache.close()
+ with open(file_name, 'rb') as cache:
+ cexecuted = marshal.load(cache)
if isinstance(cexecuted, dict):
return cexecuted
else:
@@ -614,8 +612,8 @@ class coverage:
)
filename = filename[:-1]
if not source:
- sourcef = open(filename, 'rU')
- source = sourcef.read()
+ with open(filename, 'rU') as sourcef:
+ source = sourcef.read()
try:
lines, excluded_lines, line_map = self.find_executable_statements(
source, exclude=self.exclude_re
@@ -625,8 +623,6 @@ class coverage:
"Couldn't parse '%s' as Python source: '%s' at line %d" %
(filename, synerr.msg, synerr.lineno)
)
- if sourcef:
- sourcef.close()
result = filename, lines, excluded_lines, line_map
self.analysis_cache[morf] = result
return result
diff --git a/tests/root/Makefile b/tests/root/Makefile
index 7954bc7cb..7d5162fe7 100644
--- a/tests/root/Makefile
+++ b/tests/root/Makefile
@@ -17,7 +17,7 @@ help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " pickle to make pickle files (usable by e.g. sphinx-web)"
- @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " htmlhelp to make HTML files and an HTML help project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " changes to make an overview over all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
diff --git a/tests/root/autodoc_missing_imports.py b/tests/root/autodoc_missing_imports.py
index 7a7173452..0901ce8e2 100644
--- a/tests/root/autodoc_missing_imports.py
+++ b/tests/root/autodoc_missing_imports.py
@@ -5,5 +5,14 @@ import missing_package1.missing_module1
from missing_package2 import missing_module2
from missing_package3.missing_module3 import missing_name
+@missing_name
+def decoratedFunction():
+ """decoratedFunction docstring"""
+ return None
+
class TestAutodoc(object):
"""TestAutodoc docstring."""
+ @missing_name
+ def decoratedMethod(self):
+ """TestAutodoc::decoratedMethod docstring"""
+ return None
diff --git a/tests/root/img.foo.png b/tests/root/img.foo.png
index 4c8f89929..a97e86d66 100644
--- a/tests/root/img.foo.png
+++ b/tests/root/img.foo.png
Binary files differ
diff --git a/tests/root/img.png b/tests/root/img.png
index 4c8f89929..a97e86d66 100644
--- a/tests/root/img.png
+++ b/tests/root/img.png
Binary files differ
diff --git a/tests/root/objects.txt b/tests/root/objects.txt
index cd711070f..1fc23567a 100644
--- a/tests/root/objects.txt
+++ b/tests/root/objects.txt
@@ -93,7 +93,7 @@ Referring to :func:`nothing <>`.
* expression
:returns: a new :class:`Time` instance
:rtype: Time
- :raises ValueError: if the values are out of range
+ :raises Error: if the values are out of range
:ivar int hour: like *hour*
:ivar minute: like *minute*
:vartype minute: int
@@ -172,9 +172,13 @@ Others
.. option:: +p
+.. option:: --plugin.option
+
+.. option:: create-auth-token
+
.. option:: arg
-Link to :option:`perl +p` and :option:`arg`
+Link to :option:`perl +p`, :option:`--plugin.option`, :option:`create-auth-token` and :option:`arg`
.. program:: hg
diff --git a/tests/root/pep_0420/a/b/c/__init__.py b/tests/root/pep_0420/a/b/c/__init__.py
new file mode 100644
index 000000000..619273942
--- /dev/null
+++ b/tests/root/pep_0420/a/b/c/__init__.py
@@ -0,0 +1 @@
+"Package C" \ No newline at end of file
diff --git a/tests/root/pep_0420/a/b/c/d.py b/tests/root/pep_0420/a/b/c/d.py
new file mode 100644
index 000000000..6b0b45d90
--- /dev/null
+++ b/tests/root/pep_0420/a/b/c/d.py
@@ -0,0 +1 @@
+"Module d" \ No newline at end of file
diff --git a/tests/root/pep_0420/a/b/x/y.py b/tests/root/pep_0420/a/b/x/y.py
new file mode 100644
index 000000000..8b49b2079
--- /dev/null
+++ b/tests/root/pep_0420/a/b/x/y.py
@@ -0,0 +1 @@
+"Module y" \ No newline at end of file
diff --git a/tests/root/rimg.png b/tests/root/rimg.png
index 1081dc143..fda6cd29e 100644
--- a/tests/root/rimg.png
+++ b/tests/root/rimg.png
Binary files differ
diff --git a/tests/root/subdir/img.png b/tests/root/subdir/img.png
index 4c8f89929..a97e86d66 100644
--- a/tests/root/subdir/img.png
+++ b/tests/root/subdir/img.png
Binary files differ
diff --git a/tests/root/subdir/simg.png b/tests/root/subdir/simg.png
index 4c8f89929..a97e86d66 100644
--- a/tests/root/subdir/simg.png
+++ b/tests/root/subdir/simg.png
Binary files differ
diff --git a/tests/root/testtheme/static/staticimg.png b/tests/root/testtheme/static/staticimg.png
index 1081dc143..fda6cd29e 100644
--- a/tests/root/testtheme/static/staticimg.png
+++ b/tests/root/testtheme/static/staticimg.png
Binary files differ
diff --git a/tests/roots/test-add_enumerable_node/rimg.png b/tests/roots/test-add_enumerable_node/rimg.png
index 1081dc143..fda6cd29e 100644
--- a/tests/roots/test-add_enumerable_node/rimg.png
+++ b/tests/roots/test-add_enumerable_node/rimg.png
Binary files differ
diff --git a/tests/roots/test-config/conf.py b/tests/roots/test-config/conf.py
index b6075e5cb..1e583d1e0 100644
--- a/tests/roots/test-config/conf.py
+++ b/tests/roots/test-config/conf.py
@@ -1,4 +1,4 @@
-from sphinx.config import string_classes
+from sphinx.config import string_classes, ENUM
value1 = 123 # wrong type
value2 = 123 # lambda with wrong type
@@ -45,3 +45,4 @@ def setup(app):
app.add_config_value('value14', None, False, string_classes)
app.add_config_value('value15', u'unicode', False)
app.add_config_value('value16', u'unicode', False)
+ app.add_config_value('value17', 'default', False, ENUM('default', 'one', 'two'))
diff --git a/tests/roots/test-directive-code/lineno_match.rst b/tests/roots/test-directive-code/lineno_match.rst
index 1015c8df7..42987609a 100644
--- a/tests/roots/test-directive-code/lineno_match.rst
+++ b/tests/roots/test-directive-code/lineno_match.rst
@@ -16,5 +16,11 @@ Literal Includes with Line Numbers Matching
:start-after: pass
:lineno-match:
+.. literalinclude:: literal.inc
+ :language: python
+ :start-at: class Bar:
+ :end-at: pass
+ :lineno-match:
+
.. literalinclude:: empty.inc
:lineno-match:
diff --git a/tests/roots/test-ext-autodoc/autodoc_dummy_module.py b/tests/roots/test-ext-autodoc/autodoc_dummy_module.py
new file mode 100644
index 000000000..c05d96e0d
--- /dev/null
+++ b/tests/roots/test-ext-autodoc/autodoc_dummy_module.py
@@ -0,0 +1,6 @@
+from dummy import *
+
+
+def test():
+ """Dummy function using dummy.*"""
+ dummy_function()
diff --git a/tests/roots/test-ext-autodoc/conf.py b/tests/roots/test-ext-autodoc/conf.py
new file mode 100644
index 000000000..01e6dcc75
--- /dev/null
+++ b/tests/roots/test-ext-autodoc/conf.py
@@ -0,0 +1,12 @@
+import sys, os
+
+sys.path.insert(0, os.path.abspath('.'))
+
+extensions = ['sphinx.ext.autodoc']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+autodoc_mock_imports = [
+ 'dummy'
+]
diff --git a/tests/roots/test-ext-autodoc/contents.rst b/tests/roots/test-ext-autodoc/contents.rst
new file mode 100644
index 000000000..b808eafda
--- /dev/null
+++ b/tests/roots/test-ext-autodoc/contents.rst
@@ -0,0 +1,3 @@
+
+.. automodule:: autodoc_dummy_module
+ :members:
diff --git a/tests/roots/test-ext-graphviz/index.rst b/tests/roots/test-ext-graphviz/index.rst
index b778307e3..ab86e2a5a 100644
--- a/tests/roots/test-ext-graphviz/index.rst
+++ b/tests/roots/test-ext-graphviz/index.rst
@@ -19,3 +19,9 @@ Hello |graph| graphviz world
.. graphviz:: graph.dot
+
+.. digraph:: bar
+ :align: right
+ :caption: on right
+
+ foo -> bar
diff --git a/tests/roots/test-ext-inheritance_diagram/index.rst b/tests/roots/test-ext-inheritance_diagram/index.rst
index 876996ca8..777192bd7 100644
--- a/tests/roots/test-ext-inheritance_diagram/index.rst
+++ b/tests/roots/test-ext-inheritance_diagram/index.rst
@@ -3,3 +3,6 @@ test-ext-inheritance_diagram
============================
.. inheritance-diagram:: test.Foo
+
+.. inheritance-diagram:: test.Foo
+ :caption: Test Foo!
diff --git a/tests/roots/test-ext-math/index.rst b/tests/roots/test-ext-math/index.rst
index 02f50c20a..9d16824f6 100644
--- a/tests/roots/test-ext-math/index.rst
+++ b/tests/roots/test-ext-math/index.rst
@@ -1,6 +1,10 @@
Test Math
=========
+.. toctree::
+
+ math
+
.. math:: a^2+b^2=c^2
Inline :math:`E=mc^2`
diff --git a/tests/roots/test-ext-todo/bar.rst b/tests/roots/test-ext-todo/bar.rst
new file mode 100644
index 000000000..6804a68c1
--- /dev/null
+++ b/tests/roots/test-ext-todo/bar.rst
@@ -0,0 +1,4 @@
+bar
+===
+
+.. todo:: todo in bar
diff --git a/tests/roots/test-ext-todo/conf.py b/tests/roots/test-ext-todo/conf.py
new file mode 100644
index 000000000..c67a86c5a
--- /dev/null
+++ b/tests/roots/test-ext-todo/conf.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+
+extensions = ['sphinx.ext.todo']
+master_doc = 'index'
diff --git a/tests/roots/test-ext-todo/foo.rst b/tests/roots/test-ext-todo/foo.rst
new file mode 100644
index 000000000..269199977
--- /dev/null
+++ b/tests/roots/test-ext-todo/foo.rst
@@ -0,0 +1,4 @@
+foo
+===
+
+.. todo:: todo in foo
diff --git a/tests/roots/test-ext-todo/index.rst b/tests/roots/test-ext-todo/index.rst
new file mode 100644
index 000000000..6b95f73fd
--- /dev/null
+++ b/tests/roots/test-ext-todo/index.rst
@@ -0,0 +1,9 @@
+test for sphinx.ext.todo
+========================
+
+.. toctree::
+
+ foo
+ bar
+
+.. todolist::
diff --git a/tests/roots/test-footnotes/index.rst b/tests/roots/test-footnotes/index.rst
index 3a8bc25c5..a714f9e22 100644
--- a/tests/roots/test-footnotes/index.rst
+++ b/tests/roots/test-footnotes/index.rst
@@ -76,15 +76,17 @@ Footnote in term [#]_
.. [#] Foot note in table
-.. list-table:: footnote [#]_ in caption of longtable
+.. list-table:: footnote [#]_ in caption [#]_ of longtable
:widths: 1 1
:header-rows: 1
* - name
- desc
- * - a
- - b
- * - a
+ * - This is a reference to the code-block in the footnote:
+ :ref:`codeblockinfootnote`
+ - This is one more footnote with some code in it [#]_.
+ * - This is a reference to the other code block:
+ :ref:`codeblockinanotherfootnote`
- b
* - a
- b
@@ -148,3 +150,21 @@ Footnote in term [#]_
- b
.. [#] Foot note in longtable
+
+.. [#] Second footnote in caption of longtable
+
+ .. code-block:: python
+ :caption: I am in a footnote
+ :name: codeblockinfootnote
+
+ def foo(x,y):
+ return x+y
+
+.. [#] Third footnote in longtable
+
+ .. code-block:: python
+ :caption: I am also in a footnote
+ :name: codeblockinanotherfootnote
+
+ def bar(x,y):
+ return x+y
diff --git a/tests/roots/test-footnotes/rimg.png b/tests/roots/test-footnotes/rimg.png
index 1081dc143..fda6cd29e 100644
--- a/tests/roots/test-footnotes/rimg.png
+++ b/tests/roots/test-footnotes/rimg.png
Binary files differ
diff --git a/tests/roots/test-html_extra_path/conf.py b/tests/roots/test-html_assets/conf.py
index 53ee62197..a17e417a3 100644
--- a/tests/roots/test-html_extra_path/conf.py
+++ b/tests/roots/test-html_assets/conf.py
@@ -1,6 +1,9 @@
# -*- coding: utf-8 -*-
master_doc = 'index'
+project = 'Sphinx'
+version = '1.4.4'
+html_static_path = ['static', 'subdir']
html_extra_path = ['extra', 'subdir']
exclude_patterns = ['**/_build', '**/.htpasswd']
diff --git a/tests/roots/test-html_extra_path/extra/.htpasswd b/tests/roots/test-html_assets/extra/.htaccess
index e69de29bb..e69de29bb 100644
--- a/tests/roots/test-html_extra_path/extra/.htpasswd
+++ b/tests/roots/test-html_assets/extra/.htaccess
diff --git a/tests/roots/test-html_extra_path/extra/API.html_t b/tests/roots/test-html_assets/extra/.htpasswd
index e69de29bb..e69de29bb 100644
--- a/tests/roots/test-html_extra_path/extra/API.html_t
+++ b/tests/roots/test-html_assets/extra/.htpasswd
diff --git a/tests/roots/test-html_assets/extra/API.html_t b/tests/roots/test-html_assets/extra/API.html_t
new file mode 100644
index 000000000..34ecd9df1
--- /dev/null
+++ b/tests/roots/test-html_assets/extra/API.html_t
@@ -0,0 +1 @@
+{{ project }}-{{ version }}
diff --git a/tests/roots/test-html_extra_path/extra/css/style.css b/tests/roots/test-html_assets/extra/css/style.css
index e69de29bb..e69de29bb 100644
--- a/tests/roots/test-html_extra_path/extra/css/style.css
+++ b/tests/roots/test-html_assets/extra/css/style.css
diff --git a/tests/roots/test-html_assets/extra/rimg.png b/tests/roots/test-html_assets/extra/rimg.png
new file mode 100644
index 000000000..fda6cd29e
--- /dev/null
+++ b/tests/roots/test-html_assets/extra/rimg.png
Binary files differ
diff --git a/tests/roots/test-html_extra_path/subdir/_build/index.html b/tests/roots/test-html_assets/extra/subdir/.htaccess
index e69de29bb..e69de29bb 100644
--- a/tests/roots/test-html_extra_path/subdir/_build/index.html
+++ b/tests/roots/test-html_assets/extra/subdir/.htaccess
diff --git a/tests/roots/test-html_assets/extra/subdir/.htpasswd b/tests/roots/test-html_assets/extra/subdir/.htpasswd
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/roots/test-html_assets/extra/subdir/.htpasswd
diff --git a/tests/roots/test-html_extra_path/index.rst b/tests/roots/test-html_assets/index.rst
index 6d5619455..6d5619455 100644
--- a/tests/roots/test-html_extra_path/index.rst
+++ b/tests/roots/test-html_assets/index.rst
diff --git a/tests/roots/test-html_assets/static/.htaccess b/tests/roots/test-html_assets/static/.htaccess
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/roots/test-html_assets/static/.htaccess
diff --git a/tests/roots/test-html_assets/static/.htpasswd b/tests/roots/test-html_assets/static/.htpasswd
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/roots/test-html_assets/static/.htpasswd
diff --git a/tests/roots/test-html_assets/static/API.html_t b/tests/roots/test-html_assets/static/API.html_t
new file mode 100644
index 000000000..34ecd9df1
--- /dev/null
+++ b/tests/roots/test-html_assets/static/API.html_t
@@ -0,0 +1 @@
+{{ project }}-{{ version }}
diff --git a/tests/roots/test-html_assets/static/css/style.css b/tests/roots/test-html_assets/static/css/style.css
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/roots/test-html_assets/static/css/style.css
diff --git a/tests/roots/test-html_assets/static/rimg.png b/tests/roots/test-html_assets/static/rimg.png
new file mode 100644
index 000000000..fda6cd29e
--- /dev/null
+++ b/tests/roots/test-html_assets/static/rimg.png
Binary files differ
diff --git a/tests/roots/test-html_assets/static/subdir/.htaccess b/tests/roots/test-html_assets/static/subdir/.htaccess
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/roots/test-html_assets/static/subdir/.htaccess
diff --git a/tests/roots/test-html_assets/static/subdir/.htpasswd b/tests/roots/test-html_assets/static/subdir/.htpasswd
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/roots/test-html_assets/static/subdir/.htpasswd
diff --git a/tests/roots/test-html_assets/subdir/_build/index.html b/tests/roots/test-html_assets/subdir/_build/index.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/roots/test-html_assets/subdir/_build/index.html
diff --git a/tests/roots/test-html_assets/subdir/background.png b/tests/roots/test-html_assets/subdir/background.png
new file mode 100644
index 000000000..fda6cd29e
--- /dev/null
+++ b/tests/roots/test-html_assets/subdir/background.png
Binary files differ
diff --git a/tests/roots/test-html_extra_path/extra/rimg.png b/tests/roots/test-html_extra_path/extra/rimg.png
deleted file mode 100644
index 1081dc143..000000000
--- a/tests/roots/test-html_extra_path/extra/rimg.png
+++ /dev/null
Binary files differ
diff --git a/tests/roots/test-html_extra_path/subdir/background.png b/tests/roots/test-html_extra_path/subdir/background.png
deleted file mode 100644
index 1081dc143..000000000
--- a/tests/roots/test-html_extra_path/subdir/background.png
+++ /dev/null
Binary files differ
diff --git a/tests/roots/test-image-glob/img.ja.png b/tests/roots/test-image-glob/img.ja.png
index 4c8f89929..a97e86d66 100644
--- a/tests/roots/test-image-glob/img.ja.png
+++ b/tests/roots/test-image-glob/img.ja.png
Binary files differ
diff --git a/tests/roots/test-image-glob/img.png b/tests/roots/test-image-glob/img.png
index 4c8f89929..a97e86d66 100644
--- a/tests/roots/test-image-glob/img.png
+++ b/tests/roots/test-image-glob/img.png
Binary files differ
diff --git a/tests/roots/test-image-glob/img.zh.png b/tests/roots/test-image-glob/img.zh.png
index 4c8f89929..a97e86d66 100644
--- a/tests/roots/test-image-glob/img.zh.png
+++ b/tests/roots/test-image-glob/img.zh.png
Binary files differ
diff --git a/tests/roots/test-image-glob/rimg.png b/tests/roots/test-image-glob/rimg.png
index 1081dc143..fda6cd29e 100644
--- a/tests/roots/test-image-glob/rimg.png
+++ b/tests/roots/test-image-glob/rimg.png
Binary files differ
diff --git a/tests/roots/test-image-glob/rimg.xx.png b/tests/roots/test-image-glob/rimg.xx.png
index 1081dc143..fda6cd29e 100644
--- a/tests/roots/test-image-glob/rimg.xx.png
+++ b/tests/roots/test-image-glob/rimg.xx.png
Binary files differ
diff --git a/tests/roots/test-image-glob/subdir/rimg.png b/tests/roots/test-image-glob/subdir/rimg.png
index 1081dc143..fda6cd29e 100644
--- a/tests/roots/test-image-glob/subdir/rimg.png
+++ b/tests/roots/test-image-glob/subdir/rimg.png
Binary files differ
diff --git a/tests/roots/test-image-glob/subdir/rimg.xx.png b/tests/roots/test-image-glob/subdir/rimg.xx.png
index 1081dc143..fda6cd29e 100644
--- a/tests/roots/test-image-glob/subdir/rimg.xx.png
+++ b/tests/roots/test-image-glob/subdir/rimg.xx.png
Binary files differ
diff --git a/tests/roots/test-image-glob/testimäge.png b/tests/roots/test-image-glob/testimäge.png
index 4c8f89929..a97e86d66 100644
--- a/tests/roots/test-image-glob/testimäge.png
+++ b/tests/roots/test-image-glob/testimäge.png
Binary files differ
diff --git a/tests/roots/test-image-in-section/pic.png b/tests/roots/test-image-in-section/pic.png
index 1081dc143..fda6cd29e 100644
--- a/tests/roots/test-image-in-section/pic.png
+++ b/tests/roots/test-image-in-section/pic.png
Binary files differ
diff --git a/tests/roots/test-intl/contents.po b/tests/roots/test-intl/contents.po
new file mode 100644
index 000000000..76ef049f0
--- /dev/null
+++ b/tests/roots/test-intl/contents.po
@@ -0,0 +1,26 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) 2010, Georg Brandl & Team
+# This file is distributed under the same license as the Sphinx <Tests> package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Sphinx <Tests> 0.6\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-12-16 14:11+0000\n"
+"PO-Revision-Date: 2012-12-18 06:14+0900\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Table of Contents"
+msgstr "TABLE OF CONTENTS"
+
+msgid "testdata for i18n"
+msgstr "TESTDATA FOR I18N"
+
+msgid "i18n, sphinx, markup"
+msgstr "I18N, SPHINX, MARKUP"
diff --git a/tests/roots/test-intl/contents.txt b/tests/roots/test-intl/contents.txt
index 8882137f3..e2336856c 100644
--- a/tests/roots/test-intl/contents.txt
+++ b/tests/roots/test-intl/contents.txt
@@ -1,9 +1,14 @@
CONTENTS
========
+.. meta::
+ :description: testdata for i18n
+ :keywords: i18n, sphinx, markup
+
.. toctree::
:maxdepth: 2
:numbered:
+ :caption: Table of Contents
subdir/contents
bom
diff --git a/tests/roots/test-intl/i18n.png b/tests/roots/test-intl/i18n.png
index 4c8f89929..a97e86d66 100644
--- a/tests/roots/test-intl/i18n.png
+++ b/tests/roots/test-intl/i18n.png
Binary files differ
diff --git a/tests/roots/test-intl/img.png b/tests/roots/test-intl/img.png
index 4c8f89929..a97e86d66 100644
--- a/tests/roots/test-intl/img.png
+++ b/tests/roots/test-intl/img.png
Binary files differ
diff --git a/tests/roots/test-intl/only.po b/tests/roots/test-intl/only.po
new file mode 100644
index 000000000..43eb7d60f
--- /dev/null
+++ b/tests/roots/test-intl/only.po
@@ -0,0 +1,29 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) 2010, Georg Brandl & Team
+# This file is distributed under the same license as the Sphinx <Tests> package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Sphinx <Tests> 0.6\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-02-04 13:06+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Only directive"
+msgstr "ONLY DIRECTIVE"
+
+msgid "In HTML."
+msgstr "IN HTML."
+
+msgid "In LaTeX."
+msgstr "IN LATEX."
+
+msgid "In both."
+msgstr "IN BOTH."
diff --git a/tests/roots/test-intl/only.txt b/tests/roots/test-intl/only.txt
new file mode 100644
index 000000000..2c8990e5f
--- /dev/null
+++ b/tests/roots/test-intl/only.txt
@@ -0,0 +1,14 @@
+Only directive
+--------------
+
+.. only:: html
+
+ In HTML.
+
+.. only:: latex
+
+ In LaTeX.
+
+.. only:: html or latex
+
+ In both.
diff --git a/tests/roots/test-keep_warnings/conf.py b/tests/roots/test-keep_warnings/conf.py
new file mode 100644
index 000000000..d0db3db83
--- /dev/null
+++ b/tests/roots/test-keep_warnings/conf.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+
+master_doc = 'index'
+keep_warnings = True
diff --git a/tests/roots/test-keep_warnings/index.rst b/tests/roots/test-keep_warnings/index.rst
new file mode 100644
index 000000000..1e2d5977f
--- /dev/null
+++ b/tests/roots/test-keep_warnings/index.rst
@@ -0,0 +1,2 @@
+keep_warnings
+=====
diff --git a/tests/roots/test-linkcheck/conf.py b/tests/roots/test-linkcheck/conf.py
new file mode 100644
index 000000000..ae8ef24b7
--- /dev/null
+++ b/tests/roots/test-linkcheck/conf.py
@@ -0,0 +1,4 @@
+master_doc = 'links'
+source_suffix = '.txt'
+exclude_patterns = ['_build']
+linkcheck_anchors = True
diff --git a/tests/roots/test-linkcheck/links.txt b/tests/roots/test-linkcheck/links.txt
new file mode 100644
index 000000000..36376bef4
--- /dev/null
+++ b/tests/roots/test-linkcheck/links.txt
@@ -0,0 +1,11 @@
+This is from CPython documentation.
+
+* Also, if there is a `default namespace <https://www.w3.org/TR/2006/REC-xml-names-20060816/#defaulting>`__, that full URI gets prepended to all of the non-prefixed tags.
+
+* The URL having anchor: `http://www.sphinx-doc.org/en/1.4.8/tutorial.html#install-sphinx`_
+
+Some additional anchors to exercise ignore code
+
+* `Example Bar invalid <http://example.com/#!bar>`_
+* `Example Bar invalid <http://example.com#!bar>`_ tests that default ignore anchor of #! does not need to be prefixed with /
+* `Example Bar invalid <http://example.com/#top>`_
diff --git a/tests/roots/test-maxlistdepth/conf.py b/tests/roots/test-maxlistdepth/conf.py
new file mode 100644
index 000000000..5a43b67bf
--- /dev/null
+++ b/tests/roots/test-maxlistdepth/conf.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+
+master_doc = 'index'
+html_theme = 'classic'
+exclude_patterns = ['_build']
+
+latex_documents = [
+ ('index', 'SphinxTests.tex', 'Testing maxlistdepth=10',
+ 'Georg Brandl', 'howto'),
+ ]
+
+latex_elements = {
+ 'maxlistdepth': '10',
+}
diff --git a/tests/roots/test-maxlistdepth/index.rst b/tests/roots/test-maxlistdepth/index.rst
new file mode 100644
index 000000000..5d9bc2193
--- /dev/null
+++ b/tests/roots/test-maxlistdepth/index.rst
@@ -0,0 +1,57 @@
+test-maxlistdepth
+=================
+
+
+1. 1
+
+ 1. 2
+
+ 1. 3
+
+ 1. 4
+
+ 1. 5
+
+ 1. 6
+
+ 1. 7
+
+ 1. 8
+
+ 1. 9
+
+ 10a
+
+ - 10b
+
+ .. code-block:: python
+
+ def foo():
+
+
+- 1
+
+ - 2
+
+ - 3
+
+ - 4
+
+ - 5
+
+ - 6
+
+ - 7
+
+ - 8
+
+ 1. 9
+
+ 10a
+
+ 1. 10b
+
+ .. code-block:: python
+
+ def foo():
+
diff --git a/tests/roots/test-numfig/bar.rst b/tests/roots/test-numfig/bar.rst
index f86e7475a..c4367c5b8 100644
--- a/tests/roots/test-numfig/bar.rst
+++ b/tests/roots/test-numfig/bar.rst
@@ -1,7 +1,11 @@
+.. _bar:
+
===
Bar
===
+.. _bar_a:
+
Bar A
=====
@@ -37,9 +41,13 @@ Bar A
print('hello world')
+.. _bar_b:
+
Bar B
=====
+.. _bar_b1:
+
Bar B1
------
diff --git a/tests/roots/test-numfig/baz.rst b/tests/roots/test-numfig/baz.rst
index 42fcb06d1..3ac684b43 100644
--- a/tests/roots/test-numfig/baz.rst
+++ b/tests/roots/test-numfig/baz.rst
@@ -1,3 +1,5 @@
+.. _baz_a:
+
Baz A
-----
diff --git a/tests/roots/test-numfig/foo.rst b/tests/roots/test-numfig/foo.rst
index ef713574a..6b6a8651c 100644
--- a/tests/roots/test-numfig/foo.rst
+++ b/tests/roots/test-numfig/foo.rst
@@ -1,3 +1,5 @@
+.. _foo:
+
===
Foo
===
@@ -16,6 +18,8 @@ Foo
print('hello world')
+.. _foo_a:
+
Foo A
=====
@@ -47,12 +51,18 @@ Foo A
print('hello world')
+.. _foo_a1:
+
Foo A1
------
+.. _foo_b:
+
Foo B
=====
+.. _foo_b1:
+
Foo B1
------
diff --git a/tests/roots/test-numfig/index.rst b/tests/roots/test-numfig/index.rst
index 6dd39a93a..939903839 100644
--- a/tests/roots/test-numfig/index.rst
+++ b/tests/roots/test-numfig/index.rst
@@ -1,3 +1,5 @@
+.. _index:
+
test-tocdepth
=============
@@ -48,5 +50,10 @@ test-tocdepth
* Table.2.2 is :numref:`Table:%s <table22>`
* List.1 is :numref:`CODE_1`
* List.2.2 is :numref:`Code-%s <CODE22>`
+* Section.1 is :numref:`foo`
+* Section.2.1 is :numref:`bar_a`
+* Unnumbered section is :numref:`index`
* Invalid numfig_format 01: :numref:`invalid <fig1>`
* Invalid numfig_format 02: :numref:`Fig %s %s <fig1>`
+* Fig.1 is :numref:`Fig.{number} {name} <fig1>`
+* Section.1 is :numref:`Sect.{number} {name} <foo>`
diff --git a/tests/roots/test-numfig/rimg.png b/tests/roots/test-numfig/rimg.png
index 1081dc143..fda6cd29e 100644
--- a/tests/roots/test-numfig/rimg.png
+++ b/tests/roots/test-numfig/rimg.png
Binary files differ
diff --git a/tests/roots/test-refonly_bullet_list/conf.py b/tests/roots/test-refonly_bullet_list/conf.py
new file mode 100644
index 000000000..68357c9a4
--- /dev/null
+++ b/tests/roots/test-refonly_bullet_list/conf.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+master_doc = 'index'
+html_compact_lists = False
+
+latex_documents = [
+ (master_doc, 'test.tex', 'The basic Sphinx documentation for testing', 'Sphinx', 'report')
+]
diff --git a/tests/roots/test-refonly_bullet_list/index.rst b/tests/roots/test-refonly_bullet_list/index.rst
new file mode 100644
index 000000000..9d8539dba
--- /dev/null
+++ b/tests/roots/test-refonly_bullet_list/index.rst
@@ -0,0 +1,14 @@
+test-refonly_bullet_list
+========================
+
+List A:
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+List B:
+
+* Hello
+* Sphinx
+* World
diff --git a/tests/roots/test-search/conf.py b/tests/roots/test-search/conf.py
new file mode 100644
index 000000000..38b8b28c5
--- /dev/null
+++ b/tests/roots/test-search/conf.py
@@ -0,0 +1,3 @@
+master_doc = 'index'
+exclude_patterns = ['_build']
+html_search_language = 'en'
diff --git a/tests/roots/test-search/index.rst b/tests/roots/test-search/index.rst
new file mode 100644
index 000000000..1e0dd93de
--- /dev/null
+++ b/tests/roots/test-search/index.rst
@@ -0,0 +1,30 @@
+meta keywords
+=============
+
+.. meta::
+ :keywords lang=en: findthiskey, thistoo, notgerman
+ :keywords: thisonetoo
+ :keywords lang=de: onlygerman, onlytoogerman
+ :description: thisnoteither
+
+Stemmer
+=======
+
+zfs
+findthisstemmedkey
+
+textinheading
+
+International
+
+.. toctree::
+
+ tocitem
+
+.. raw:: html
+
+ <span class="raw">rawword"</span>
+
+.. raw:: latex
+
+ latex_keyword
diff --git a/tests/roots/test-search/tocitem.rst b/tests/roots/test-search/tocitem.rst
new file mode 100644
index 000000000..61c42a242
--- /dev/null
+++ b/tests/roots/test-search/tocitem.rst
@@ -0,0 +1,10 @@
+heading 1
+=========
+
+lorem ipsum
+
+
+textinheading
+=============
+
+lorem ipsum \ No newline at end of file
diff --git a/tests/roots/test-toctree-glob/index.rst b/tests/roots/test-toctree-glob/index.rst
index 079cd6027..a3c198ce3 100644
--- a/tests/roots/test-toctree-glob/index.rst
+++ b/tests/roots/test-toctree-glob/index.rst
@@ -1,8 +1,24 @@
test-toctree-glob
=================
+normal order
+------------
+
+.. toctree::
+ :glob:
+
+ foo
+ bar/index
+ bar/*
+ baz
+ qux/index
+
+reversed order
+-------------
+
.. toctree::
:glob:
+ :reversed:
foo
bar/index
diff --git a/tests/roots/test-toctree-maxdepth/qux.rst b/tests/roots/test-toctree-maxdepth/qux.rst
new file mode 100644
index 000000000..35e9ac127
--- /dev/null
+++ b/tests/roots/test-toctree-maxdepth/qux.rst
@@ -0,0 +1,9 @@
+test-toctree-max-depth
+======================
+
+.. toctree::
+ :numbered:
+ :maxdepth: 4
+
+ foo
+ bar
diff --git a/tests/roots/test-toctree/bar.rst b/tests/roots/test-toctree/bar.rst
new file mode 100644
index 000000000..1cccd3cb7
--- /dev/null
+++ b/tests/roots/test-toctree/bar.rst
@@ -0,0 +1,2 @@
+bar
+===
diff --git a/tests/roots/test-toctree/baz.rst b/tests/roots/test-toctree/baz.rst
new file mode 100644
index 000000000..52e2e72ac
--- /dev/null
+++ b/tests/roots/test-toctree/baz.rst
@@ -0,0 +1,2 @@
+baz
+===
diff --git a/tests/roots/test-toctree/conf.py b/tests/roots/test-toctree/conf.py
new file mode 100644
index 000000000..31e7a6ed4
--- /dev/null
+++ b/tests/roots/test-toctree/conf.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+
+master_doc = 'index'
+
+latex_documents = [
+ (master_doc, 'test.tex', 'The basic Sphinx documentation for testing', 'Sphinx', 'report')
+]
diff --git a/tests/roots/test-toctree/foo.rst b/tests/roots/test-toctree/foo.rst
new file mode 100644
index 000000000..49f4d4b97
--- /dev/null
+++ b/tests/roots/test-toctree/foo.rst
@@ -0,0 +1,15 @@
+foo
+===
+
+.. toctree::
+
+ quux
+
+foo.1
+-----
+
+foo.1-1
+^^^^^^^
+
+foo.2
+-----
diff --git a/tests/roots/test-toctree/index.rst b/tests/roots/test-toctree/index.rst
new file mode 100644
index 000000000..dc7fd2e4a
--- /dev/null
+++ b/tests/roots/test-toctree/index.rst
@@ -0,0 +1,54 @@
+.. Sphinx Tests documentation master file, created by sphinx-quickstart on Wed Jun 4 23:49:58 2008.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to Sphinx Tests's documentation!
+========================================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+ :caption: Table of Contents
+ :name: mastertoc
+
+ foo
+ bar
+ http://sphinx-doc.org/
+
+.. only:: html
+
+ Section for HTML
+ ----------------
+
+ .. toctree::
+
+ baz
+
+----------
+subsection
+----------
+
+subsubsection
+-------------
+
+Test for issue #1157
+====================
+
+This used to crash:
+
+.. toctree::
+
+.. toctree::
+ :hidden:
+
+ Latest reference <http://sphinx-doc.org/latest/>
+ Python <http://python.org/>
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/tests/roots/test-toctree/quux.rst b/tests/roots/test-toctree/quux.rst
new file mode 100644
index 000000000..07dd0a0a3
--- /dev/null
+++ b/tests/roots/test-toctree/quux.rst
@@ -0,0 +1,2 @@
+quux
+====
diff --git a/tests/roots/test-toctree/qux.rst b/tests/roots/test-toctree/qux.rst
new file mode 100644
index 000000000..26176b947
--- /dev/null
+++ b/tests/roots/test-toctree/qux.rst
@@ -0,0 +1 @@
+qux.rst has no section title
diff --git a/tests/roots/test-toctree/tocdepth.rst b/tests/roots/test-toctree/tocdepth.rst
new file mode 100644
index 000000000..1069b4cb4
--- /dev/null
+++ b/tests/roots/test-toctree/tocdepth.rst
@@ -0,0 +1,15 @@
+:tocdepth: 2
+
+=======
+level 1
+=======
+
+level 2
+=======
+
+-------
+level 3
+-------
+
+level 4
+-------
diff --git a/tests/run.py b/tests/run.py
index 0ca6ad1ae..d2d3b9fc8 100755
--- a/tests/run.py
+++ b/tests/run.py
@@ -24,7 +24,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(testroot, os.path.pardir)))
# check dependencies before testing
print('Checking dependencies...')
for modname in ('nose', 'mock', 'six', 'docutils', 'jinja2', 'pygments',
- 'snowballstemmer', 'babel'):
+ 'snowballstemmer', 'babel', 'html5lib'):
try:
__import__(modname)
except ImportError as err:
@@ -48,4 +48,4 @@ tempdir.makedirs()
print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0])
sys.stdout.flush()
-nose.main()
+nose.main(argv=sys.argv)
diff --git a/tests/test_api_translator.py b/tests/test_api_translator.py
index e8cfcb458..7a70fd4c8 100644
--- a/tests/test_api_translator.py
+++ b/tests/test_api_translator.py
@@ -57,7 +57,7 @@ def test_html_with_set_translator_for_html_(app, status, warning):
@with_app('html', testroot='api-set-translator',
- confoverrides={'html_translator_class': 'ext.ExtHTMLTranslator'})
+ confoverrides={'html_translator_class': 'translator.ExtHTMLTranslator'})
def test_html_with_set_translator_for_html_and_html_translator_class(
app, status, warning):
# use set_translator() and html_translator_class.
diff --git a/tests/test_apidoc.py b/tests/test_apidoc.py
index 596890041..ff6a147ca 100644
--- a/tests/test_apidoc.py
+++ b/tests/test_apidoc.py
@@ -44,6 +44,94 @@ def test_simple(tempdir):
@with_tempdir
+def test_pep_0420_enabled(tempdir):
+ codedir = rootdir / 'root' / 'pep_0420'
+ outdir = tempdir / 'out'
+ args = ['sphinx-apidoc', '-o', outdir, '-F', codedir, "--implicit-namespaces"]
+ apidoc.main(args)
+
+ assert (outdir / 'conf.py').isfile()
+ assert (outdir / 'a.b.c.rst').isfile()
+ assert (outdir / 'a.b.x.rst').isfile()
+
+ with open(outdir / 'a.b.c.rst') as f:
+ rst = f.read()
+ assert "a.b.c package\n" in rst
+ assert "automodule:: a.b.c.d\n" in rst
+ assert "automodule:: a.b.c\n" in rst
+
+ with open(outdir / 'a.b.x.rst') as f:
+ rst = f.read()
+ assert "a.b.x namespace\n" in rst
+ assert "automodule:: a.b.x.y\n" in rst
+ assert "automodule:: a.b.x\n" not in rst
+
+ @with_app('text', srcdir=outdir)
+ def assert_build(app, status, warning):
+ app.build()
+ print(status.getvalue())
+ print(warning.getvalue())
+
+ sys.path.append(codedir)
+ try:
+ assert_build()
+ finally:
+ sys.path.remove(codedir)
+
+
+@with_tempdir
+def test_pep_0420_disabled(tempdir):
+ codedir = rootdir / 'root' / 'pep_0420'
+ outdir = tempdir / 'out'
+ args = ['sphinx-apidoc', '-o', outdir, '-F', codedir]
+ apidoc.main(args)
+
+ assert (outdir / 'conf.py').isfile()
+ assert not (outdir / 'a.b.c.rst').exists()
+ assert not (outdir / 'a.b.x.rst').exists()
+
+ @with_app('text', srcdir=outdir)
+ def assert_build(app, status, warning):
+ app.build()
+ print(status.getvalue())
+ print(warning.getvalue())
+
+ sys.path.append(codedir)
+ try:
+ assert_build()
+ finally:
+ sys.path.remove(codedir)
+
+@with_tempdir
+def test_pep_0420_disabled_top_level_verify(tempdir):
+ codedir = rootdir / 'root' / 'pep_0420' / 'a' / 'b'
+ outdir = tempdir / 'out'
+ args = ['sphinx-apidoc', '-o', outdir, '-F', codedir]
+ apidoc.main(args)
+
+ assert (outdir / 'conf.py').isfile()
+ assert (outdir / 'c.rst').isfile()
+ assert not (outdir / 'x.rst').exists()
+
+ with open(outdir / 'c.rst') as f:
+ rst = f.read()
+ assert "c package\n" in rst
+ assert "automodule:: c.d\n" in rst
+ assert "automodule:: c\n" in rst
+
+ @with_app('text', srcdir=outdir)
+ def assert_build(app, status, warning):
+ app.build()
+ print(status.getvalue())
+ print(warning.getvalue())
+
+ sys.path.append(codedir)
+ try:
+ assert_build()
+ finally:
+ sys.path.remove(codedir)
+
+@with_tempdir
def test_multibyte_parameters(tempdir):
codedir = rootdir / 'root'
outdir = tempdir / 'out'
diff --git a/tests/test_application.py b/tests/test_application.py
index 420680451..ad4f84870 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -14,7 +14,7 @@ from docutils import nodes
from sphinx.application import ExtensionError
from sphinx.domains import Domain
-from util import with_app, raises_msg
+from util import with_app, raises_msg, strip_escseq
@with_app()
@@ -60,20 +60,21 @@ def test_output(app, status, warning):
old_count = app._warncount
app.warn("Bad news!")
- assert warning.getvalue() == "WARNING: Bad news!\n"
+ assert strip_escseq(warning.getvalue()) == "WARNING: Bad news!\n"
assert app._warncount == old_count + 1
@with_app()
def test_extensions(app, status, warning):
app.setup_extension('shutil')
- assert warning.getvalue().startswith("WARNING: extension 'shutil'")
+ assert strip_escseq(warning.getvalue()).startswith("WARNING: extension 'shutil'")
@with_app()
def test_extension_in_blacklist(app, status, warning):
app.setup_extension('sphinxjp.themecore')
- assert warning.getvalue().startswith("WARNING: the extension 'sphinxjp.themecore' was")
+ msg = strip_escseq(warning.getvalue())
+ assert msg.startswith("WARNING: the extension 'sphinxjp.themecore' was")
@with_app()
diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py
index 711e5e807..d2ba95608 100644
--- a/tests/test_autodoc.py
+++ b/tests/test_autodoc.py
@@ -14,6 +14,7 @@
from util import TestApp, Struct, raises, SkipTest # NOQA
from nose.tools import with_setup, eq_
+import enum
from six import StringIO
from docutils.statemachine import ViewList
@@ -825,6 +826,26 @@ def test_generate():
del directive.env.temp_data['autodoc:module']
del directive.env.ref_context['py:module']
+ # test members with enum attributes
+ directive.env.ref_context['py:module'] = 'test_autodoc'
+ options.inherited_members = False
+ options.undoc_members = False
+ options.members = ALL
+ assert_processes([
+ ('class', 'test_autodoc.EnumCls'),
+ ('attribute', 'test_autodoc.EnumCls.val1'),
+ ('attribute', 'test_autodoc.EnumCls.val2'),
+ ('attribute', 'test_autodoc.EnumCls.val3'),
+ ], 'class', 'EnumCls')
+ assert_result_contains(
+ ' :annotation: = 12', 'attribute', 'EnumCls.val1')
+ assert_result_contains(
+ ' :annotation: = 23', 'attribute', 'EnumCls.val2')
+ assert_result_contains(
+ ' :annotation: = 34', 'attribute', 'EnumCls.val3')
+ del directive.env.temp_data['autodoc:class']
+ del directive.env.temp_data['autodoc:module']
+
# test descriptor class documentation
options.members = ['CustomDataDescriptor']
assert_result_contains('.. py:class:: CustomDataDescriptor(doc)',
@@ -832,6 +853,17 @@ def test_generate():
assert_result_contains(' .. py:method:: CustomDataDescriptor.meth()',
'module', 'test_autodoc')
+ # test mocked module imports
+ options.members = ['TestAutodoc']
+ options.undoc_members = False
+ assert_result_contains('.. py:class:: TestAutodoc',
+ 'module', 'autodoc_missing_imports')
+ assert_result_contains(' .. py:method:: TestAutodoc.decoratedMethod()',
+ 'module', 'autodoc_missing_imports')
+ options.members = ['decoratedFunction']
+ assert_result_contains('.. py:function:: decoratedFunction()',
+ 'module', 'autodoc_missing_imports')
+
# --- generate fodder ------------
__all__ = ['Class']
@@ -1020,12 +1052,24 @@ class InstAttCls(object):
"""Docstring for instance attribute InstAttCls.ia2."""
+class EnumCls(enum.Enum):
+ """
+ this is enum class
+ """
+
+ #: doc for val1
+ val1 = 12
+ val2 = 23 #: doc for val2
+ val3 = 34
+ """doc for val3"""
+
+
def test_type_hints():
from sphinx.ext.autodoc import formatargspec
from sphinx.util.inspect import getargspec
try:
- from typing_test_data import f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10
+ from typing_test_data import f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11
except (ImportError, SyntaxError):
raise SkipTest('Cannot import Python code with function annotations')
@@ -1052,16 +1096,19 @@ def test_type_hints():
# Keyword-only arguments
verify_arg_spec(f5, '(x: int, *, y: str, z: str) -> None')
+ # Keyword-only arguments with varargs
+ verify_arg_spec(f6, '(x: int, *args, y: str, z: str) -> None')
+
# Space around '=' for defaults
- verify_arg_spec(f6, '(x: int = None, y: dict = {}) -> None')
+ verify_arg_spec(f7, '(x: int = None, y: dict = {}) -> None')
# Callable types
- verify_arg_spec(f7, '(x: typing.Callable[[int, str], int]) -> None')
- verify_arg_spec(f8, '(x: typing.Callable) -> None')
+ verify_arg_spec(f8, '(x: typing.Callable[[int, str], int]) -> None')
+ verify_arg_spec(f9, '(x: typing.Callable) -> None')
# Tuple types
- verify_arg_spec(f9, '(x: typing.Tuple[int, str],'
- ' y: typing.Tuple[int, ...]) -> None')
+ verify_arg_spec(f10, '(x: typing.Tuple[int, str],'
+ ' y: typing.Tuple[int, ...]) -> None')
# Instance annotations
- verify_arg_spec(f10, '(x: CustomAnnotation, y: 123) -> None')
+ verify_arg_spec(f11, '(x: CustomAnnotation, y: 123) -> None')
diff --git a/tests/test_build.py b/tests/test_build.py
index 507a1cab3..cc34de2c1 100644
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -13,6 +13,7 @@ from six import BytesIO
import pickle
from docutils import nodes
+import mock
from textwrap import dedent
from sphinx.errors import SphinxError
import sphinx.builders.linkcheck
@@ -25,14 +26,11 @@ except ImportError:
ManWriter = None
-class MockOpener(object):
- def open(self, req, **kwargs):
- class result(BytesIO):
- headers = None
- url = req.url
- return result()
-
-sphinx.builders.linkcheck.opener = MockOpener()
+def request_session_head(url, **kwargs):
+ response = mock.Mock()
+ response.status_code = 200
+ response.url = url
+ return response
def verify_build(buildername, srcdir):
@@ -68,12 +66,15 @@ def test_build_all():
""" % {'test_name': test_name})
)
- # note: no 'html' - if it's ok with dirhtml it's ok with html
- for buildername in ['dirhtml', 'singlehtml', 'latex', 'texinfo', 'pickle',
- 'json', 'text', 'htmlhelp', 'qthelp', 'epub', 'epub3',
- 'applehelp', 'changes', 'xml', 'pseudoxml', 'man',
- 'linkcheck']:
- yield verify_build, buildername, srcdir
+ with mock.patch('sphinx.builders.linkcheck.requests') as requests:
+ requests.head = request_session_head
+
+ # note: no 'html' - if it's ok with dirhtml it's ok with html
+ for buildername in ['dirhtml', 'singlehtml', 'latex', 'texinfo', 'pickle',
+ 'json', 'text', 'htmlhelp', 'qthelp', 'epub2', 'epub',
+ 'applehelp', 'changes', 'xml', 'pseudoxml', 'man',
+ 'linkcheck']:
+ yield verify_build, buildername, srcdir
@with_tempdir
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index d77867c0e..d8aff88ab 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -13,13 +13,16 @@ import os
import re
from six import PY3, iteritems
-from six.moves import html_entities
from sphinx import __display_version__
-from util import remove_unicode_literals, gen_with_app, with_app
-from etree13 import ElementTree as ET
+from util import remove_unicode_literals, gen_with_app, with_app, strip_escseq
+from etree13 import ElementTree
+from html5lib import getTreeBuilder, HTMLParser
+TREE_BUILDER = getTreeBuilder('etree', implementation=ElementTree)
+HTML_PARSER = HTMLParser(TREE_BUILDER, namespaceHTMLElements=False)
+
ENV_WARNINGS = """\
(%(root)s/autodoc_fodder.py:docstring of autodoc_fodder.MarkupError:\\d+: \
WARNING: duplicate object description of autodoc_fodder.MarkupError, other \
@@ -65,6 +68,7 @@ HTML_XPATH = {
(".//img[@src='_images/img1.png']", ''),
(".//img[@src='_images/simg.png']", ''),
(".//img[@src='_images/svgimg.svg']", ''),
+ (".//a[@href='_sources/images.txt']", ''),
],
'subdir/images.html': [
(".//img[@src='../_images/img1.png']", ''),
@@ -174,7 +178,7 @@ HTML_XPATH = {
# ``seealso`` directive
(".//div/p[@class='first admonition-title']", 'See also'),
# a ``hlist`` directive
- (".//table[@class='hlist']/tr/td/ul/li", '^This$'),
+ (".//table[@class='hlist']/tbody/tr/td/ul/li", '^This$'),
# a ``centered`` directive
(".//p[@class='centered']/strong", 'LICENSE'),
# a glossary
@@ -203,6 +207,7 @@ HTML_XPATH = {
# docfields
(".//a[@class='reference internal'][@href='#TimeInt']/em", 'TimeInt'),
(".//a[@class='reference internal'][@href='#Time']", 'Time'),
+ (".//a[@class='reference internal'][@href='#errmod.Error']/strong", 'Error'),
# C references
(".//span[@class='pre']", 'CFunction()'),
(".//a[@href='#c.Sphinx_DoSomething']", ''),
@@ -235,10 +240,15 @@ HTML_XPATH = {
(".//td[@class='field-body']/ul/li/em", '^DuplicateType$'),
(".//td[@class='field-body']/ul/li/em", tail_check(r'.* Some parameter')),
# others
- (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-+p']/code/span",
+ (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-p']/code/span",
'perl'),
- (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-+p']/code/span",
+ (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-p']/code/span",
'\+p'),
+ (".//a[@class='reference internal'][@href='#cmdoption-perl-plugin-option']/code/span",
+ '--plugin.option'),
+ (".//a[@class='reference internal'][@href='#cmdoption-perl-arg-create-auth-token']"
+ "/code/span",
+ 'create-auth-token'),
(".//a[@class='reference internal'][@href='#cmdoption-perl-arg-arg']/code/span",
'arg'),
(".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span",
@@ -297,7 +307,7 @@ HTML_XPATH = {
(".//a/strong", "[1]"),
(".//a/strong", "Other"),
(".//a", "entry"),
- (".//dt/a", "double"),
+ (".//li/a", "double"),
],
'footnote.html': [
(".//a[@class='footnote-reference'][@href='#id7'][@id='id1']", r"\[1\]"),
@@ -315,25 +325,11 @@ HTML_XPATH = {
],
'otherext.html': [
(".//h1", "Generated section"),
+ (".//a[@href='_sources/otherext.foo.txt']", ''),
]
}
-class NslessParser(ET.XMLParser):
- """XMLParser that throws away namespaces in tag names."""
-
- def _fixname(self, key):
- try:
- return self._names[key]
- except KeyError:
- name = key
- br = name.find('}')
- if br > 0:
- name = name[br+1:]
- self._names[key] = name = self._fixtext(name)
- return name
-
-
def check_xpath(etree, fname, path, check, be_found=True):
nodes = list(etree.findall(path))
if check is None:
@@ -394,8 +390,7 @@ def check_extra_entries(outdir):
@with_app(buildername='html', testroot='warnings', freshenv=True)
def test_html_warnings(app, status, warning):
app.builder.build_all()
-
- html_warnings = warning.getvalue().replace(os.sep, '/')
+ html_warnings = strip_escseq(warning.getvalue().replace(os.sep, '/'))
html_warnings_exp = HTML_WARNINGS % {
'root': re.escape(app.srcdir.replace(os.sep, '/'))}
assert re.match(html_warnings_exp + '$', html_warnings), \
@@ -409,10 +404,8 @@ def test_html_warnings(app, status, warning):
def test_html_output(app, status, warning):
app.builder.build_all()
for fname, paths in iteritems(HTML_XPATH):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for path, check in paths:
yield check_xpath, etree, fname, path, check
@@ -459,10 +452,8 @@ def test_tocdepth(app, status, warning):
}
for fname, paths in iteritems(expects):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@@ -501,10 +492,8 @@ def test_tocdepth_singlehtml(app, status, warning):
}
for fname, paths in iteritems(expects):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@@ -514,10 +503,11 @@ def test_tocdepth_singlehtml(app, status, warning):
def test_numfig_disabled(app, status, warning):
app.builder.build_all()
- assert ('index.rst:45: WARNING: numfig is disabled. :numref: is ignored.'
- in warning.getvalue())
- assert 'index.rst:51: WARNING: invalid numfig_format: invalid' not in warning.getvalue()
- assert 'index.rst:52: WARNING: invalid numfig_format: Fig %s %s' not in warning.getvalue()
+ warnings = warning.getvalue()
+ assert 'index.rst:47: WARNING: numfig is disabled. :numref: is ignored.' in warnings
+ assert 'index.rst:55: WARNING: no number is assigned for section: index' not in warnings
+ assert 'index.rst:56: WARNING: invalid numfig_format: invalid' not in warnings
+ assert 'index.rst:57: WARNING: invalid numfig_format: Fig %s %s' not in warnings
expects = {
'index.html': [
@@ -532,6 +522,10 @@ def test_numfig_disabled(app, status, warning):
(".//li/code/span", '^Table:%s$', True),
(".//li/code/span", '^CODE_1$', True),
(".//li/code/span", '^Code-%s$', True),
+ (".//li/code/span", '^foo$', True),
+ (".//li/code/span", '^bar_a$', True),
+ (".//li/code/span", '^Fig.{number}$', True),
+ (".//li/code/span", '^Sect.{number}$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']/"
@@ -557,10 +551,8 @@ def test_numfig_disabled(app, status, warning):
}
for fname, paths in iteritems(expects):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@@ -575,10 +567,11 @@ def test_numfig_without_numbered_toctree(app, status, warning):
(app.srcdir / 'index.rst').write_text(index, encoding='utf-8')
app.builder.build_all()
- assert ('index.rst:45: WARNING: numfig is disabled. :numref: is ignored.'
- not in warning.getvalue())
- assert 'index.rst:51: WARNING: invalid numfig_format: invalid' in warning.getvalue()
- assert 'index.rst:52: WARNING: invalid numfig_format: Fig %s %s' in warning.getvalue()
+ warnings = warning.getvalue()
+ assert 'index.rst:47: WARNING: numfig is disabled. :numref: is ignored.' not in warnings
+ assert 'index.rst:55: WARNING: no number is assigned for section: index' in warnings
+ assert 'index.rst:56: WARNING: invalid numfig_format: invalid' in warnings
+ assert 'index.rst:57: WARNING: invalid numfig_format: Fig %s %s' in warnings
expects = {
'index.html': [
@@ -600,6 +593,10 @@ def test_numfig_without_numbered_toctree(app, status, warning):
(".//li/a/span", '^Table:6$', True),
(".//li/a/span", '^Listing 9$', True),
(".//li/a/span", '^Code-6$', True),
+ (".//li/code/span", '^foo$', True),
+ (".//li/code/span", '^bar_a$', True),
+ (".//li/a/span", '^Fig.9 should be Fig.1$', True),
+ (".//li/code/span", '^Sect.{number}$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']/"
@@ -658,10 +655,8 @@ def test_numfig_without_numbered_toctree(app, status, warning):
}
for fname, paths in iteritems(expects):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@@ -672,10 +667,11 @@ def test_numfig_without_numbered_toctree(app, status, warning):
def test_numfig_with_numbered_toctree(app, status, warning):
app.builder.build_all()
- assert ('index.rst:45: WARNING: numfig is disabled. :numref: is ignored.'
- not in warning.getvalue())
- assert 'index.rst:51: WARNING: invalid numfig_format: invalid' in warning.getvalue()
- assert 'index.rst:52: WARNING: invalid numfig_format: Fig %s %s' in warning.getvalue()
+ warnings = warning.getvalue()
+ assert 'index.rst:47: WARNING: numfig is disabled. :numref: is ignored.' not in warnings
+ assert 'index.rst:55: WARNING: no number is assigned for section: index' in warnings
+ assert 'index.rst:56: WARNING: invalid numfig_format: invalid' in warnings
+ assert 'index.rst:57: WARNING: invalid numfig_format: Fig %s %s' in warnings
expects = {
'index.html': [
@@ -697,6 +693,10 @@ def test_numfig_with_numbered_toctree(app, status, warning):
(".//li/a/span", '^Table:2.2$', True),
(".//li/a/span", '^Listing 1$', True),
(".//li/a/span", '^Code-2.2$', True),
+ (".//li/a/span", '^Section.1$', True),
+ (".//li/a/span", '^Section.2.1$', True),
+ (".//li/a/span", '^Fig.1 should be Fig.1$', True),
+ (".//li/a/span", '^Sect.1 Foo$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']/"
@@ -755,10 +755,8 @@ def test_numfig_with_numbered_toctree(app, status, warning):
}
for fname, paths in iteritems(expects):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@@ -768,14 +766,16 @@ def test_numfig_with_numbered_toctree(app, status, warning):
confoverrides={'numfig': True,
'numfig_format': {'figure': 'Figure:%s',
'table': 'Tab_%s',
- 'code-block': 'Code-%s'}})
+ 'code-block': 'Code-%s',
+ 'section': 'SECTION-%s'}})
def test_numfig_with_prefix(app, status, warning):
app.builder.build_all()
- assert ('index.rst:45: WARNING: numfig is disabled. :numref: is ignored.'
- not in warning.getvalue())
- assert 'index.rst:51: WARNING: invalid numfig_format: invalid' in warning.getvalue()
- assert 'index.rst:52: WARNING: invalid numfig_format: Fig %s %s' in warning.getvalue()
+ warnings = warning.getvalue()
+ assert 'index.rst:47: WARNING: numfig is disabled. :numref: is ignored.' not in warnings
+ assert 'index.rst:55: WARNING: no number is assigned for section: index' in warnings
+ assert 'index.rst:56: WARNING: invalid numfig_format: invalid' in warnings
+ assert 'index.rst:57: WARNING: invalid numfig_format: Fig %s %s' in warnings
expects = {
'index.html': [
@@ -797,6 +797,10 @@ def test_numfig_with_prefix(app, status, warning):
(".//li/a/span", '^Table:2.2$', True),
(".//li/a/span", '^Code-1$', True),
(".//li/a/span", '^Code-2.2$', True),
+ (".//li/a/span", '^SECTION-1$', True),
+ (".//li/a/span", '^SECTION-2.1$', True),
+ (".//li/a/span", '^Fig.1 should be Fig.1$', True),
+ (".//li/a/span", '^Sect.1 Foo$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']/"
@@ -855,10 +859,8 @@ def test_numfig_with_prefix(app, status, warning):
}
for fname, paths in iteritems(expects):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@@ -869,10 +871,11 @@ def test_numfig_with_prefix(app, status, warning):
def test_numfig_with_secnum_depth(app, status, warning):
app.builder.build_all()
- assert ('index.rst:45: WARNING: numfig is disabled. :numref: is ignored.'
- not in warning.getvalue())
- assert 'index.rst:51: WARNING: invalid numfig_format: invalid' in warning.getvalue()
- assert 'index.rst:52: WARNING: invalid numfig_format: Fig %s %s' in warning.getvalue()
+ warnings = warning.getvalue()
+ assert 'index.rst:47: WARNING: numfig is disabled. :numref: is ignored.' not in warnings
+ assert 'index.rst:55: WARNING: no number is assigned for section: index' in warnings
+ assert 'index.rst:56: WARNING: invalid numfig_format: invalid' in warnings
+ assert 'index.rst:57: WARNING: invalid numfig_format: Fig %s %s' in warnings
expects = {
'index.html': [
@@ -894,6 +897,10 @@ def test_numfig_with_secnum_depth(app, status, warning):
(".//li/a/span", '^Table:2.1.2$', True),
(".//li/a/span", '^Listing 1$', True),
(".//li/a/span", '^Code-2.1.2$', True),
+ (".//li/a/span", '^Section.1$', True),
+ (".//li/a/span", '^Section.2.1$', True),
+ (".//li/a/span", '^Fig.1 should be Fig.1$', True),
+ (".//li/a/span", '^Sect.1 Foo$', True),
],
'foo.html': [
(".//div[@class='figure']/p[@class='caption']/"
@@ -952,10 +959,8 @@ def test_numfig_with_secnum_depth(app, status, warning):
}
for fname, paths in iteritems(expects):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@@ -986,6 +991,10 @@ def test_numfig_with_singlehtml(app, status, warning):
(".//li/a/span", '^Table:2.2$', True),
(".//li/a/span", '^Listing 1$', True),
(".//li/a/span", '^Code-2.2$', True),
+ (".//li/a/span", '^Section.1$', True),
+ (".//li/a/span", '^Section.2.1$', True),
+ (".//li/a/span", '^Fig.1 should be Fig.1$', True),
+ (".//li/a/span", '^Sect.1 Foo$', True),
(".//div[@class='figure']/p[@class='caption']/"
"span[@class='caption-number']", '^Fig. 1.1 $', True),
(".//div[@class='figure']/p[@class='caption']/"
@@ -1038,10 +1047,8 @@ def test_numfig_with_singlehtml(app, status, warning):
}
for fname, paths in iteritems(expects):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
@@ -1070,19 +1077,30 @@ def test_enumerable_node(app, status, warning):
}
for fname, paths in iteritems(expects):
- parser = NslessParser()
- parser.entity.update(html_entities.entitydefs)
with (app.outdir / fname).open('rb') as fp:
- etree = ET.parse(fp, parser)
+ etree = HTML_PARSER.parse(fp)
for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found
-@with_app(buildername='html', testroot='html_extra_path')
-def test_html_extra_path(app, status, warning):
+@with_app(buildername='html', testroot='html_assets')
+def test_html_assets(app, status, warning):
app.builder.build_all()
+ # html_static_path
+ assert not (app.outdir / '_static' / '.htaccess').exists()
+ assert not (app.outdir / '_static' / '.htpasswd').exists()
+ assert (app.outdir / '_static' / 'API.html').exists()
+ assert (app.outdir / '_static' / 'API.html').text() == 'Sphinx-1.4.4'
+ assert (app.outdir / '_static' / 'css/style.css').exists()
+ assert (app.outdir / '_static' / 'rimg.png').exists()
+ assert not (app.outdir / '_static' / '_build/index.html').exists()
+ assert (app.outdir / '_static' / 'background.png').exists()
+ assert not (app.outdir / '_static' / 'subdir' / '.htaccess').exists()
+ assert not (app.outdir / '_static' / 'subdir' / '.htpasswd').exists()
+
+ # html_extra_path
assert (app.outdir / '.htaccess').exists()
assert not (app.outdir / '.htpasswd').exists()
assert (app.outdir / 'API.html_t').exists()
@@ -1090,3 +1108,17 @@ def test_html_extra_path(app, status, warning):
assert (app.outdir / 'rimg.png').exists()
assert not (app.outdir / '_build/index.html').exists()
assert (app.outdir / 'background.png').exists()
+ assert (app.outdir / 'subdir' / '.htaccess').exists()
+ assert not (app.outdir / 'subdir' / '.htpasswd').exists()
+
+
+@with_app(buildername='html', confoverrides={'html_sourcelink_suffix': ''})
+def test_html_sourcelink_suffix(app, status, warning):
+ app.builder.build_all()
+ content_otherext = (app.outdir / 'otherext.html').text()
+ content_images = (app.outdir / 'images.html').text()
+
+ assert '<a href="_sources/otherext.foo"' in content_otherext
+ assert '<a href="_sources/images.txt"' in content_images
+ assert (app.outdir / '_sources' / 'otherext.foo').exists()
+ assert (app.outdir / '_sources' / 'images.txt').exists()
diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py
index 77ba4ca85..fcef77be6 100644
--- a/tests/test_build_latex.py
+++ b/tests/test_build_latex.py
@@ -12,17 +12,26 @@ from __future__ import print_function
import os
import re
+from functools import wraps
+from itertools import product
from subprocess import Popen, PIPE
from six import PY3
from sphinx.errors import SphinxError
+from sphinx.util.osutil import cd, ensuredir
from sphinx.writers.latex import LaTeXTranslator
-from util import SkipTest, remove_unicode_literals, with_app
+from util import SkipTest, remove_unicode_literals, with_app, strip_escseq, skip_if
from test_build_html import ENV_WARNINGS
+LATEX_ENGINES = ['pdflatex', 'lualatex', 'xelatex']
+DOCCLASSES = ['howto', 'manual']
+STYLEFILES = ['article.cls', 'fancyhdr.sty', 'titlesec.sty', 'amsmath.sty',
+ 'framed.sty', 'color.sty', 'fancyvrb.sty', 'threeparttable.sty',
+ 'fncychap.sty', 'geometry.sty', 'kvoptions.sty', 'hyperref.sty']
+
LATEX_WARNINGS = ENV_WARNINGS + """\
%(root)s/index.rst:\\d+: WARNING: unknown option: &option
%(root)s/index.rst:\\d+: WARNING: citation not found: missing
@@ -34,70 +43,71 @@ if PY3:
LATEX_WARNINGS = remove_unicode_literals(LATEX_WARNINGS)
-def run_latex(outdir):
- """Run pdflatex, xelatex, and lualatex in the outdir"""
- cwd = os.getcwd()
- os.chdir(outdir)
+# only run latex if all needed packages are there
+def kpsetest(*filenames):
try:
- latexes = ('pdflatex', 'xelatex', 'lualatex')
- available_latexes = len(latexes)
- for latex in latexes:
- try:
- os.mkdir(latex)
- p = Popen([latex, '--interaction=nonstopmode',
- '-output-directory=%s' % latex, 'SphinxTests.tex'],
- stdout=PIPE, stderr=PIPE)
- except OSError: # most likely the latex executable was not found
- available_latexes -= 1
- else:
- stdout, stderr = p.communicate()
- if p.returncode != 0:
- print(stdout)
- print(stderr)
- assert False, '%s exited with return code %s' % (
- latex, p.returncode)
- finally:
- os.chdir(cwd)
-
- if available_latexes == 0: # no latex is available, skip the test
- raise SkipTest
+ p = Popen(['kpsewhich'] + list(filenames), stdout=PIPE)
+ except OSError:
+ # no kpsewhich... either no tex distribution is installed or it is
+ # a "strange" one -- don't bother running latex
+ return None
+ else:
+ p.communicate()
+ if p.returncode != 0:
+ # not found
+ return False
+ # found
+ return True
+
+
+# compile latex document with app.config.latex_engine
+def compile_latex_document(app):
+ # now, try to run latex over it
+ with cd(app.outdir):
+ try:
+ ensuredir(app.config.latex_engine)
+ p = Popen([app.config.latex_engine,
+ '--interaction=nonstopmode',
+ '-output-directory=%s' % app.config.latex_engine,
+ 'SphinxTests.tex'],
+ stdout=PIPE, stderr=PIPE)
+ except OSError: # most likely the latex executable was not found
+ raise SkipTest
+ else:
+ stdout, stderr = p.communicate()
+ if p.returncode != 0:
+ print(stdout)
+ print(stderr)
+ assert False, '%s exited with return code %s' % (
+ app.config.latex_engine, p.returncode)
+
+def skip_if_stylefiles_notfound(testfunc):
+ if kpsetest(*STYLEFILES) is False:
+ return skip_if(testfunc,
+ 'not running latex, the required styles do not seem to be installed')
+ else:
+ return testfunc
+
+def test_latex():
+ for engine, docclass in product(LATEX_ENGINES, DOCCLASSES):
+ yield build_latex_doc, engine, docclass
+
+
+@skip_if_stylefiles_notfound
@with_app(buildername='latex')
-def test_latex(app, status, warning):
+def build_latex_doc(app, status, warning, engine, docclass):
+ app.config.latex_engine = engine
+ app.config.latex_documents[0] = app.config.latex_documents[0][:4] + (docclass,)
+
LaTeXTranslator.ignore_missing_images = True
app.builder.build_all()
# file from latex_additional_files
assert (app.outdir / 'svgimg.svg').isfile()
- # only run latex if all needed packages are there
- def kpsetest(filename):
- try:
- p = Popen(['kpsewhich', filename], stdout=PIPE)
- except OSError:
- # no kpsewhich... either no tex distribution is installed or it is
- # a "strange" one -- don't bother running latex
- return None
- else:
- p.communicate()
- if p.returncode != 0:
- # not found
- return False
- # found
- return True
-
- if kpsetest('article.sty') is None:
- raise SkipTest('not running latex, it doesn\'t seem to be installed')
- for filename in ['fancyhdr.sty', 'fancybox.sty', 'titlesec.sty',
- 'amsmath.sty', 'framed.sty', 'color.sty', 'fancyvrb.sty',
- 'threeparttable.sty']:
- if not kpsetest(filename):
- raise SkipTest('not running latex, the %s package doesn\'t '
- 'seem to be installed' % filename)
-
- # now, try to run latex over it
- run_latex(app.outdir)
+ compile_latex_document(app)
@with_app(buildername='latex')
@@ -126,53 +136,11 @@ def test_writer(app, status, warning):
'\\end{wrapfigure}' in result)
-@with_app(buildername='latex',
- confoverrides={'latex_documents': [
- ('contents', 'SphinxTests.tex', 'Sphinx Tests Documentation',
- 'Georg Brandl \\and someone else', 'howto'),
- ]},
- srcdir='latex_howto')
-def test_latex_howto(app, status, warning):
- LaTeXTranslator.ignore_missing_images = True
- app.builder.build_all()
-
- # file from latex_additional_files
- assert (app.outdir / 'svgimg.svg').isfile()
-
- # only run latex if all needed packages are there
- def kpsetest(filename):
- try:
- p = Popen(['kpsewhich', filename], stdout=PIPE)
- except OSError:
- # no kpsewhich... either no tex distribution is installed or it is
- # a "strange" one -- don't bother running latex
- return None
- else:
- p.communicate()
- if p.returncode != 0:
- # not found
- return False
- # found
- return True
-
- if kpsetest('article.sty') is None:
- raise SkipTest('not running latex, it doesn\'t seem to be installed')
- for filename in ['fancyhdr.sty', 'fancybox.sty', 'titlesec.sty',
- 'amsmath.sty', 'framed.sty', 'color.sty', 'fancyvrb.sty',
- 'threeparttable.sty']:
- if not kpsetest(filename):
- raise SkipTest('not running latex, the %s package doesn\'t '
- 'seem to be installed' % filename)
-
- # now, try to run latex over it
- run_latex(app.outdir)
-
-
@with_app(buildername='latex', testroot='warnings', freshenv=True)
def test_latex_warnings(app, status, warning):
app.builder.build_all()
- warnings = warning.getvalue().replace(os.sep, '/')
+ warnings = strip_escseq(warning.getvalue().replace(os.sep, '/'))
warnings_exp = LATEX_WARNINGS % {
'root': re.escape(app.srcdir.replace(os.sep, '/'))}
assert re.match(warnings_exp + '$', warnings), \
@@ -191,20 +159,25 @@ def test_numref(app, status, warning):
print(warning.getvalue())
assert '\\addto\\captionsenglish{\\renewcommand{\\figurename}{Fig.\\@ }}' in result
assert '\\addto\\captionsenglish{\\renewcommand{\\tablename}{Table }}' in result
- assert '\\SetupFloatingEnvironment{literal-block}{name=Listing }' in result
+ assert '\\addto\\captionsenglish{\\renewcommand{\\literalblockname}{Listing }}' in result
assert '\\hyperref[index:fig1]{Fig.\\@ \\ref{index:fig1}}' in result
assert '\\hyperref[baz:fig22]{Figure\\ref{baz:fig22}}' in result
assert '\\hyperref[index:table-1]{Table \\ref{index:table-1}}' in result
assert '\\hyperref[baz:table22]{Table:\\ref{baz:table22}}' in result
assert '\\hyperref[index:code-1]{Listing \\ref{index:code-1}}' in result
assert '\\hyperref[baz:code22]{Code-\\ref{baz:code22}}' in result
+ assert '\\hyperref[foo:foo]{Section \\ref{foo:foo}}' in result
+ assert '\\hyperref[bar:bar-a]{Section \\ref{bar:bar-a}}' in result
+ assert '\\hyperref[index:fig1]{Fig.\\ref{index:fig1} \\nameref{index:fig1}}' in result
+ assert '\\hyperref[foo:foo]{Sect.\\ref{foo:foo} \\nameref{foo:foo}}' in result
@with_app(buildername='latex', testroot='numfig',
confoverrides={'numfig': True,
'numfig_format': {'figure': 'Figure:%s',
'table': 'Tab_%s',
- 'code-block': 'Code-%s'}})
+ 'code-block': 'Code-%s',
+ 'section': 'SECTION-%s'}})
def test_numref_with_prefix1(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8')
@@ -213,7 +186,7 @@ def test_numref_with_prefix1(app, status, warning):
print(warning.getvalue())
assert '\\addto\\captionsenglish{\\renewcommand{\\figurename}{Figure:}}' in result
assert '\\addto\\captionsenglish{\\renewcommand{\\tablename}{Tab\\_}}' in result
- assert '\\SetupFloatingEnvironment{literal-block}{name=Code-}' in result
+ assert '\\addto\\captionsenglish{\\renewcommand{\\literalblockname}{Code-}}' in result
assert '\\ref{index:fig1}' in result
assert '\\ref{baz:fig22}' in result
assert '\\ref{index:table-1}' in result
@@ -226,13 +199,18 @@ def test_numref_with_prefix1(app, status, warning):
assert '\\hyperref[baz:table22]{Table:\\ref{baz:table22}}' in result
assert '\\hyperref[index:code-1]{Code-\\ref{index:code-1}}' in result
assert '\\hyperref[baz:code22]{Code-\\ref{baz:code22}}' in result
+ assert '\\hyperref[foo:foo]{SECTION-\\ref{foo:foo}}' in result
+ assert '\\hyperref[bar:bar-a]{SECTION-\\ref{bar:bar-a}}' in result
+ assert '\\hyperref[index:fig1]{Fig.\\ref{index:fig1} \\nameref{index:fig1}}' in result
+ assert '\\hyperref[foo:foo]{Sect.\\ref{foo:foo} \\nameref{foo:foo}}' in result
@with_app(buildername='latex', testroot='numfig',
confoverrides={'numfig': True,
'numfig_format': {'figure': 'Figure:%s.',
'table': 'Tab_%s:',
- 'code-block': 'Code-%s | '}})
+ 'code-block': 'Code-%s | ',
+ 'section': 'SECTION_%s_'}})
def test_numref_with_prefix2(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8')
@@ -243,13 +221,17 @@ def test_numref_with_prefix2(app, status, warning):
assert '\\def\\fnum@figure{\\figurename\\thefigure.\\@}' in result
assert '\\addto\\captionsenglish{\\renewcommand{\\tablename}{Tab\\_}}' in result
assert '\\def\\fnum@table{\\tablename\\thetable:}' in result
- assert '\\SetupFloatingEnvironment{literal-block}{name=Code-}' in result
+ assert '\\addto\\captionsenglish{\\renewcommand{\\literalblockname}{Code-}}' in result
assert '\\hyperref[index:fig1]{Figure:\\ref{index:fig1}.\\@}' in result
assert '\\hyperref[baz:fig22]{Figure\\ref{baz:fig22}}' in result
assert '\\hyperref[index:table-1]{Tab\\_\\ref{index:table-1}:}' in result
assert '\\hyperref[baz:table22]{Table:\\ref{baz:table22}}' in result
assert '\\hyperref[index:code-1]{Code-\\ref{index:code-1} \\textbar{} }' in result
assert '\\hyperref[baz:code22]{Code-\\ref{baz:code22}}' in result
+ assert '\\hyperref[foo:foo]{SECTION\\_\\ref{foo:foo}\\_}' in result
+ assert '\\hyperref[bar:bar-a]{SECTION\\_\\ref{bar:bar-a}\\_}' in result
+ assert '\\hyperref[index:fig1]{Fig.\\ref{index:fig1} \\nameref{index:fig1}}' in result
+ assert '\\hyperref[foo:foo]{Sect.\\ref{foo:foo} \\nameref{foo:foo}}' in result
@with_app(buildername='latex', testroot='numfig',
@@ -262,13 +244,17 @@ def test_numref_with_language_ja(app, status, warning):
print(warning.getvalue())
assert u'\\renewcommand{\\figurename}{\u56f3 }' in result
assert '\\renewcommand{\\tablename}{TABLE }' in result
- assert '\\SetupFloatingEnvironment{literal-block}{name=LIST }' in result
+ assert '\\renewcommand{\\literalblockname}{LIST }' in result
assert u'\\hyperref[index:fig1]{\u56f3 \\ref{index:fig1}}' in result
assert '\\hyperref[baz:fig22]{Figure\\ref{baz:fig22}}' in result
assert '\\hyperref[index:table-1]{TABLE \\ref{index:table-1}}' in result
assert '\\hyperref[baz:table22]{Table:\\ref{baz:table22}}' in result
assert '\\hyperref[index:code-1]{LIST \\ref{index:code-1}}' in result
assert '\\hyperref[baz:code22]{Code-\\ref{baz:code22}}' in result
+ assert '\\hyperref[foo:foo]{Section \\ref{foo:foo}}' in result
+ assert '\\hyperref[bar:bar-a]{Section \\ref{bar:bar-a}}' in result
+ assert '\\hyperref[index:fig1]{Fig.\\ref{index:fig1} \\nameref{index:fig1}}' in result
+ assert '\\hyperref[foo:foo]{Sect.\\ref{foo:foo} \\nameref{foo:foo}}' in result
@with_app(buildername='latex')
@@ -408,22 +394,26 @@ def test_footnote(app, status, warning):
print(result)
print(status.getvalue())
print(warning.getvalue())
- assert '\\footnote[1]{\sphinxAtStartFootnote%\nnumbered\n}' in result
- assert '\\footnote[2]{\sphinxAtStartFootnote%\nauto numbered\n}' in result
- assert '\\footnote[3]{\sphinxAtStartFootnote%\nnamed\n}' in result
+ assert ('\\begin{footnote}[1]\\sphinxAtStartFootnote\nnumbered\n%\n'
+ '\\end{footnote}') in result
+ assert ('\\begin{footnote}[2]\\sphinxAtStartFootnote\nauto numbered\n%\n'
+ '\\end{footnote}') in result
+ assert '\\begin{footnote}[3]\\sphinxAtStartFootnote\nnamed\n%\n\\end{footnote}' in result
assert '{\\hyperref[footnote:bar]{\\sphinxcrossref{{[}bar{]}}}}' in result
assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} ' in result
assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} \ncite' in result
assert '\\bibitem[bar]{bar}{\\phantomsection\\label{footnote:bar} \ncite\n}' in result
- assert '\\capstart\\caption{Table caption \\protect\\footnotemark[4]}' in result
- assert 'name \\protect\\footnotemark[5]' in result
- assert ('\\end{threeparttable}\n\n'
- '\\footnotetext[4]{\sphinxAtStartFootnote%\nfootnotes in table caption\n}'
- '\\footnotetext[5]{\sphinxAtStartFootnote%\nfootnotes in table\n}' in result)
+ assert '\\caption{Table caption \\sphinxfootnotemark[4]' in result
+ assert 'name \\sphinxfootnotemark[5]' in result
+ assert ('\\end{threeparttable}\n\n%\n'
+ '\\begin{footnotetext}[4]\sphinxAtStartFootnote\n'
+ 'footnotes in table caption\n%\n\\end{footnotetext}%\n'
+ '\\begin{footnotetext}[5]\sphinxAtStartFootnote\n'
+ 'footnotes in table\n%\n\\end{footnotetext}') in result
@with_app(buildername='latex', testroot='footnotes')
-def test_reference_in_caption(app, status, warning):
+def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8')
print(result)
@@ -434,20 +424,27 @@ def test_reference_in_caption(app, status, warning):
assert '\\chapter{The section with a reference to {[}AuthorYear{]}}' in result
assert '\\caption{The table title with a reference to {[}AuthorYear{]}}' in result
assert '\\paragraph{The rubric title with a reference to {[}AuthorYear{]}}' in result
- assert ('\\chapter{The section with a reference to \\protect\\footnotemark[4]}\n'
+ assert ('\\chapter{The section with a reference to \\sphinxfootnotemark[4]}\n'
'\\label{index:the-section-with-a-reference-to}'
- '\\footnotetext[4]{\sphinxAtStartFootnote%\nFootnote in section\n}' in result)
+ '%\n\\begin{footnotetext}[4]\\sphinxAtStartFootnote\n'
+ 'Footnote in section\n%\n\\end{footnotetext}') in result
assert ('\\caption{This is the figure caption with a footnote to '
- '\\protect\\footnotemark[6].}\label{index:id23}\end{figure}\n'
- '\\footnotetext[6]{\sphinxAtStartFootnote%\nFootnote in caption\n}')in result
- assert ('\\caption{footnote \\protect\\footnotemark[7] '
- 'in caption of normal table}') in result
- assert ('\\end{threeparttable}\n\n\\footnotetext[7]{\sphinxAtStartFootnote%\n'
- 'Foot note in table\n}' in result)
- assert ('\\caption{footnote \\protect\\footnotemark[8] in caption of longtable}'
- in result)
- assert ('\end{longtable}\n\n\\footnotetext[8]{\sphinxAtStartFootnote%\n'
- 'Foot note in longtable\n}' in result)
+ '\\sphinxfootnotemark[6].}\label{index:id27}\end{figure}\n'
+ '%\n\\begin{footnotetext}[6]\\sphinxAtStartFootnote\n'
+ 'Footnote in caption\n%\n\\end{footnotetext}')in result
+ assert ('\\caption{footnote \\sphinxfootnotemark[7] '
+ 'in caption of normal table}\\label{index:id28}') in result
+ assert ('\\caption{footnote \\sphinxfootnotemark[8] '
+ 'in caption \sphinxfootnotemark[9] of longtable}') in result
+ assert ('\end{longtable}\n\n%\n\\begin{footnotetext}[8]'
+ '\sphinxAtStartFootnote\n'
+ 'Foot note in longtable\n%\n\\end{footnotetext}' in result)
+ assert ('This is a reference to the code-block in the footnote:\n'
+ '{\hyperref[index:codeblockinfootnote]{\\sphinxcrossref{\\DUrole'
+ '{std,std-ref}{I am in a footnote}}}}') in result
+ assert ('&\nThis is one more footnote with some code in it '
+ '\\sphinxfootnotemark[10].\n\\\\') in result
+ assert '\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]' in result
@with_app(buildername='latex', testroot='footnotes',
@@ -458,29 +455,32 @@ def test_latex_show_urls_is_inline(app, status, warning):
print(result)
print(status.getvalue())
print(warning.getvalue())
- assert ('Same footnote number \\footnote[1]{\sphinxAtStartFootnote%\n'
- 'footnote in bar\n} in bar.rst' in result)
- assert ('Auto footnote number \\footnote[1]{\sphinxAtStartFootnote%\n'
- 'footnote in baz\n} in baz.rst' in result)
- assert ('\\phantomsection\\label{index:id26}{\\hyperref[index:the\\string-section'
+ assert ('Same footnote number %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
+ 'footnote in bar\n%\n\\end{footnote} in bar.rst' in result)
+ assert ('Auto footnote number %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
+ 'footnote in baz\n%\n\\end{footnote} in baz.rst' in result)
+ assert ('\\phantomsection\\label{index:id30}{\\hyperref[index:the\\string-section'
'\\string-with\\string-a\\string-reference\\string-to\\string-authoryear]'
'{\\sphinxcrossref{The section with a reference to '
'\\phantomsection\\label{index:id1}'
'{\\hyperref[index:authoryear]{\\sphinxcrossref{{[}AuthorYear{]}}}}}}}' in result)
- assert ('\\phantomsection\\label{index:id27}{\\hyperref[index:the\\string-section'
+ assert ('\\phantomsection\\label{index:id31}{\\hyperref[index:the\\string-section'
'\\string-with\\string-a\\string-reference\\string-to]'
'{\\sphinxcrossref{The section with a reference to }}}' in result)
- assert 'First footnote: \\footnote[2]{\sphinxAtStartFootnote%\nFirst\n}' in result
- assert 'Second footnote: \\footnote[1]{\sphinxAtStartFootnote%\nSecond\n}' in result
+ assert ('First footnote: %\n\\begin{footnote}[2]\\sphinxAtStartFootnote\n'
+ 'First\n%\n\\end{footnote}') in result
+ assert ('Second footnote: %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
+ 'Second\n%\n\\end{footnote}') in result
assert '\\href{http://sphinx-doc.org/}{Sphinx} (http://sphinx-doc.org/)' in result
- assert 'Third footnote: \\footnote[3]{\sphinxAtStartFootnote%\nThird\n}' in result
+ assert ('Third footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n'
+ 'Third\n%\n\\end{footnote}') in result
assert ('\\href{http://sphinx-doc.org/~test/}{URL including tilde} '
'(http://sphinx-doc.org/\\textasciitilde{}test/)' in result)
assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term} (http://sphinx-doc.org/)}] '
'\\leavevmode\nDescription' in result)
- assert ('\\item[{Footnote in term \\protect\\footnotemark[5]}] '
- '\\leavevmode\\footnotetext[5]{\sphinxAtStartFootnote%\n'
- 'Footnote in term\n}\nDescription' in result)
+ assert ('\\item[{Footnote in term \\sphinxfootnotemark[5]}] '
+ '\\leavevmode%\n\\begin{footnotetext}[5]\\sphinxAtStartFootnote\n'
+ 'Footnote in term\n%\n\\end{footnotetext}\nDescription' in result)
assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist} '
'(http://sphinx-doc.org/)}] \\leavevmode\nDescription' in result)
assert ('\\url{https://github.com/sphinx-doc/sphinx}\n' in result)
@@ -496,40 +496,45 @@ def test_latex_show_urls_is_footnote(app, status, warning):
print(result)
print(status.getvalue())
print(warning.getvalue())
- assert ('Same footnote number \\footnote[1]{\sphinxAtStartFootnote%\n'
- 'footnote in bar\n} in bar.rst' in result)
- assert ('Auto footnote number \\footnote[2]{\sphinxAtStartFootnote%\n'
- 'footnote in baz\n} in baz.rst' in result)
- assert ('\\phantomsection\\label{index:id26}{\\hyperref[index:the\\string-section'
+ assert ('Same footnote number %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
+ 'footnote in bar\n%\n\\end{footnote} in bar.rst' in result)
+ assert ('Auto footnote number %\n\\begin{footnote}[2]\\sphinxAtStartFootnote\n'
+ 'footnote in baz\n%\n\\end{footnote} in baz.rst' in result)
+ assert ('\\phantomsection\\label{index:id30}{\\hyperref[index:the\\string-section'
'\\string-with\\string-a\\string-reference\\string-to\\string-authoryear]'
'{\\sphinxcrossref{The section with a reference '
'to \\phantomsection\\label{index:id1}'
'{\\hyperref[index:authoryear]{\\sphinxcrossref{{[}AuthorYear{]}}}}}}}' in result)
- assert ('\\phantomsection\\label{index:id27}{\\hyperref[index:the\\string-section'
+ assert ('\\phantomsection\\label{index:id31}{\\hyperref[index:the\\string-section'
'\\string-with\\string-a\\string-reference\\string-to]'
'{\\sphinxcrossref{The section with a reference to }}}' in result)
- assert 'First footnote: \\footnote[3]{\sphinxAtStartFootnote%\nFirst\n}' in result
- assert 'Second footnote: \\footnote[1]{\sphinxAtStartFootnote%\nSecond\n}' in result
+ assert ('First footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n'
+ 'First\n%\n\\end{footnote}') in result
+ assert ('Second footnote: %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
+ 'Second\n%\n\\end{footnote}') in result
assert ('\\href{http://sphinx-doc.org/}{Sphinx}'
- '\\footnote[4]{\sphinxAtStartFootnote%\n'
- '\\nolinkurl{http://sphinx-doc.org/}\n}' in result)
- assert 'Third footnote: \\footnote[6]{\sphinxAtStartFootnote%\nThird\n}' in result
+ '%\n\\begin{footnote}[4]\\sphinxAtStartFootnote\n'
+ '\\nolinkurl{http://sphinx-doc.org/}\n%\n\\end{footnote}') in result
+ assert ('Third footnote: %\n\\begin{footnote}[6]\\sphinxAtStartFootnote\n'
+ 'Third\n%\n\\end{footnote}') in result
assert ('\\href{http://sphinx-doc.org/~test/}{URL including tilde}'
- '\\footnote[5]{\sphinxAtStartFootnote%\n'
- '\\nolinkurl{http://sphinx-doc.org/~test/}\n}' in result)
- assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}\\protect\\footnotemark[8]}] '
- '\\leavevmode\\footnotetext[8]{\sphinxAtStartFootnote%\n'
- '\\nolinkurl{http://sphinx-doc.org/}\n}\nDescription' in result)
- assert ('\\item[{Footnote in term \\protect\\footnotemark[10]}] '
- '\\leavevmode\\footnotetext[10]{\sphinxAtStartFootnote%\n'
- 'Footnote in term\n}\nDescription' in result)
- assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}\\protect'
- '\\footnotemark[9]}] '
- '\\leavevmode\\footnotetext[9]{\sphinxAtStartFootnote%\n'
- '\\nolinkurl{http://sphinx-doc.org/}\n}\nDescription' in result)
+ '%\n\\begin{footnote}[5]\\sphinxAtStartFootnote\n'
+ '\\nolinkurl{http://sphinx-doc.org/~test/}\n%\n\\end{footnote}') in result
+ assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}\\sphinxfootnotemark[8]}] '
+ '\\leavevmode%\n\\begin{footnotetext}[8]\\sphinxAtStartFootnote\n'
+ '\\nolinkurl{http://sphinx-doc.org/}\n%\n'
+ '\\end{footnotetext}\nDescription') in result
+ assert ('\\item[{Footnote in term \\sphinxfootnotemark[10]}] '
+ '\\leavevmode%\n\\begin{footnotetext}[10]\\sphinxAtStartFootnote\n'
+ 'Footnote in term\n%\n\\end{footnotetext}\nDescription') in result
+ assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}'
+ '\\sphinxfootnotemark[9]}] '
+ '\\leavevmode%\n\\begin{footnotetext}[9]\\sphinxAtStartFootnote\n'
+ '\\nolinkurl{http://sphinx-doc.org/}\n%\n'
+ '\\end{footnotetext}\nDescription') in result
assert ('\\url{https://github.com/sphinx-doc/sphinx}\n' in result)
assert ('\\href{mailto:sphinx-dev@googlegroups.com}'
- '{sphinx-dev@googlegroups.com}\n' in result)
+ '{sphinx-dev@googlegroups.com}\n') in result
@with_app(buildername='latex', testroot='footnotes',
@@ -540,33 +545,36 @@ def test_latex_show_urls_is_no(app, status, warning):
print(result)
print(status.getvalue())
print(warning.getvalue())
- assert ('Same footnote number \\footnote[1]{\sphinxAtStartFootnote%\n'
- 'footnote in bar\n} in bar.rst' in result)
- assert ('Auto footnote number \\footnote[1]{\sphinxAtStartFootnote%\n'
- 'footnote in baz\n} in baz.rst' in result)
- assert ('\\phantomsection\\label{index:id26}{\\hyperref[index:the\\string-section'
+ assert ('Same footnote number %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
+ 'footnote in bar\n%\n\\end{footnote} in bar.rst') in result
+ assert ('Auto footnote number %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
+ 'footnote in baz\n%\n\\end{footnote} in baz.rst') in result
+ assert ('\\phantomsection\\label{index:id30}{\\hyperref[index:the\\string-section'
'\\string-with\\string-a\\string-reference\\string-to\\string-authoryear]'
'{\\sphinxcrossref{The section with a reference '
'to \\phantomsection\\label{index:id1}'
- '{\\hyperref[index:authoryear]{\\sphinxcrossref{{[}AuthorYear{]}}}}}}}' in result)
- assert ('\\phantomsection\\label{index:id27}{\\hyperref[index:the\\string-section'
+ '{\\hyperref[index:authoryear]{\\sphinxcrossref{{[}AuthorYear{]}}}}}}}') in result
+ assert ('\\phantomsection\\label{index:id31}{\\hyperref[index:the\\string-section'
'\\string-with\\string-a\\string-reference\\string-to]'
'{\\sphinxcrossref{The section with a reference to }}}' in result)
- assert 'First footnote: \\footnote[2]{\sphinxAtStartFootnote%\nFirst\n}' in result
- assert 'Second footnote: \\footnote[1]{\sphinxAtStartFootnote%\nSecond\n}' in result
+ assert ('First footnote: %\n\\begin{footnote}[2]\\sphinxAtStartFootnote\n'
+ 'First\n%\n\\end{footnote}') in result
+ assert ('Second footnote: %\n\\begin{footnote}[1]\\sphinxAtStartFootnote\n'
+ 'Second\n%\n\\end{footnote}') in result
assert '\\href{http://sphinx-doc.org/}{Sphinx}' in result
- assert 'Third footnote: \\footnote[3]{\sphinxAtStartFootnote%\nThird\n}' in result
+ assert ('Third footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n'
+ 'Third\n%\n\\end{footnote}') in result
assert '\\href{http://sphinx-doc.org/~test/}{URL including tilde}' in result
assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}}] '
- '\\leavevmode\nDescription' in result)
- assert ('\\item[{Footnote in term \\protect\\footnotemark[5]}] '
- '\\leavevmode\\footnotetext[5]{\sphinxAtStartFootnote%\n'
- 'Footnote in term\n}\nDescription' in result)
+ '\\leavevmode\nDescription') in result
+ assert ('\\item[{Footnote in term \\sphinxfootnotemark[5]}] '
+ '\\leavevmode%\n\\begin{footnotetext}[5]\\sphinxAtStartFootnote\n'
+ 'Footnote in term\n%\n\\end{footnotetext}\nDescription') in result
assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}}] '
- '\\leavevmode\nDescription' in result)
+ '\\leavevmode\nDescription') in result
assert ('\\url{https://github.com/sphinx-doc/sphinx}\n' in result)
assert ('\\href{mailto:sphinx-dev@googlegroups.com}'
- '{sphinx-dev@googlegroups.com}\n' in result)
+ '{sphinx-dev@googlegroups.com}\n') in result
@with_app(buildername='latex', testroot='image-in-section')
@@ -577,10 +585,10 @@ def test_image_in_section(app, status, warning):
print(status.getvalue())
print(warning.getvalue())
assert ('\\chapter[Test section]{\\lowercase{\\sphinxincludegraphics'
- '[width=15pt,height=15pt]}{{pic}.png} Test section}'
+ '[width=15bp,height=15bp]}{{pic}.png} Test section}'
in result)
assert ('\\chapter[Other {[}blah{]} section]{Other {[}blah{]} '
- '\\lowercase{\\sphinxincludegraphics[width=15pt,height=15pt]}'
+ '\\lowercase{\\sphinxincludegraphics[width=15bp,height=15bp]}'
'{{pic}.png} section}' in result)
assert ('\\chapter{Another section}' in result)
@@ -606,6 +614,7 @@ def test_toctree_maxdepth_manual(app, status, warning):
print(status.getvalue())
print(warning.getvalue())
assert '\\setcounter{tocdepth}{1}' in result
+ assert '\\setcounter{secnumdepth}' not in result
@with_app(buildername='latex', testroot='toctree-maxdepth',
@@ -620,6 +629,7 @@ def test_toctree_maxdepth_howto(app, status, warning):
print(status.getvalue())
print(warning.getvalue())
assert '\\setcounter{tocdepth}{2}' in result
+ assert '\\setcounter{secnumdepth}' not in result
@with_app(buildername='latex', testroot='toctree-maxdepth',
@@ -631,6 +641,7 @@ def test_toctree_not_found(app, status, warning):
print(status.getvalue())
print(warning.getvalue())
assert '\\setcounter{tocdepth}' not in result
+ assert '\\setcounter{secnumdepth}' not in result
@with_app(buildername='latex', testroot='toctree-maxdepth',
@@ -642,6 +653,19 @@ def test_toctree_without_maxdepth(app, status, warning):
print(status.getvalue())
print(warning.getvalue())
assert '\\setcounter{tocdepth}' not in result
+ assert '\\setcounter{secnumdepth}' not in result
+
+
+@with_app(buildername='latex', testroot='toctree-maxdepth',
+ confoverrides={'master_doc': 'qux'})
+def test_toctree_with_deeper_maxdepth(app, status, warning):
+ app.builder.build_all()
+ result = (app.outdir / 'Python.tex').text(encoding='utf8')
+ print(result)
+ print(status.getvalue())
+ print(warning.getvalue())
+ assert '\\setcounter{tocdepth}{3}' in result
+ assert '\\setcounter{secnumdepth}{3}' in result
@with_app(buildername='latex', testroot='toctree-maxdepth',
@@ -686,3 +710,13 @@ def test_latex_toplevel_sectioning_is_section(app, status, warning):
print(status.getvalue())
print(warning.getvalue())
assert '\\section{Foo}' in result
+
+@skip_if_stylefiles_notfound
+@with_app(buildername='latex', testroot='maxlistdepth')
+def test_maxlistdepth_at_ten(app, status, warning):
+ app.builder.build_all()
+ result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
+ print(result)
+ print(status.getvalue())
+ print(warning.getvalue())
+ compile_latex_document(app)
diff --git a/tests/test_build_linkcheck.py b/tests/test_build_linkcheck.py
new file mode 100644
index 000000000..1d75135af
--- /dev/null
+++ b/tests/test_build_linkcheck.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+"""
+ test_build_linkcheck
+ ~~~~~~~~~~~~~~~~~~~~
+
+ Test the build process with manpage builder with the test root.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+from __future__ import print_function
+
+from util import with_app
+
+
+@with_app('linkcheck', testroot='linkcheck', freshenv=True)
+def test_defaults(app, status, warning):
+ app.builder.build_all()
+
+ assert (app.outdir / 'output.txt').exists()
+ content = (app.outdir / 'output.txt').text()
+
+ print(content)
+ # looking for #top should fail
+ assert "Anchor 'top' not found" in content
+ assert len(content.splitlines()) == 1
+
+
+@with_app('linkcheck', testroot='linkcheck', freshenv=True,
+ confoverrides={'linkcheck_anchors_ignore': ["^!", "^top$"]})
+def test_anchors_ignored(app, status, warning):
+ app.builder.build_all()
+
+ assert (app.outdir / 'output.txt').exists()
+ content = (app.outdir / 'output.txt').text()
+
+ # expect all ok when excluding #top
+ assert not content
diff --git a/tests/test_build_texinfo.py b/tests/test_build_texinfo.py
index 47bec2e23..06da311df 100644
--- a/tests/test_build_texinfo.py
+++ b/tests/test_build_texinfo.py
@@ -18,7 +18,7 @@ from six import PY3
from sphinx.writers.texinfo import TexinfoTranslator
-from util import SkipTest, remove_unicode_literals, with_app
+from util import SkipTest, remove_unicode_literals, with_app, strip_escseq
from test_build_html import ENV_WARNINGS
@@ -36,8 +36,7 @@ if PY3:
@with_app(buildername='texinfo', testroot='warnings', freshenv=True)
def test_texinfo_warnings(app, status, warning):
app.builder.build_all()
-
- warnings = warning.getvalue().replace(os.sep, '/')
+ warnings = strip_escseq(warning.getvalue().replace(os.sep, '/'))
warnings_exp = TEXINFO_WARNINGS % {
'root': re.escape(app.srcdir.replace(os.sep, '/'))}
assert re.match(warnings_exp + '$', warnings), \
diff --git a/tests/test_build_text.py b/tests/test_build_text.py
index 613d95d1f..f95e4d2ab 100644
--- a/tests/test_build_text.py
+++ b/tests/test_build_text.py
@@ -65,7 +65,7 @@ def test_nonascii_title_line(app, status, warning):
app.builder.build_update()
result = (app.outdir / 'nonascii_title.txt').text(encoding='utf-8')
expect_underline = '******'
- result_underline = result.splitlines()[2].strip()
+ result_underline = result.splitlines()[1].strip()
assert expect_underline == result_underline
diff --git a/tests/test_config.py b/tests/test_config.py
index 5b18e3101..1b3c94957 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -10,7 +10,7 @@
:license: BSD, see LICENSE for details.
"""
from six import PY3, iteritems
-from util import mock
+import mock
from util import TestApp, with_app, gen_with_app, with_tempdir, \
raises, raises_msg, assert_in, assert_not_in
@@ -38,7 +38,7 @@ def test_core_config(app, status, warning):
# simple default values
assert 'locale_dirs' not in cfg.__dict__
- assert cfg.locale_dirs == []
+ assert cfg.locale_dirs == ['locales']
assert cfg.trim_footnote_reference_space is False
# complex default values
@@ -206,3 +206,15 @@ def test_gen_check_types(app, status, warning):
'override on "%s" should%s raise a type warning' %
(key, '' if should else ' NOT')
)
+
+
+@with_app(testroot='config')
+def test_check_enum(app, status, warning):
+ assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \
+ not in warning.getvalue()
+
+
+@with_app(testroot='config', confoverrides={'value17': 'invalid'})
+def test_check_enum_failed(app, status, warning):
+ assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \
+ "but `invalid` is given." in warning.getvalue()
diff --git a/tests/test_directive_code.py b/tests/test_directive_code.py
index 8209e8f61..a29db6b90 100644
--- a/tests/test_directive_code.py
+++ b/tests/test_directive_code.py
@@ -65,7 +65,7 @@ def test_code_block_caption_html(app, status, warning):
def test_code_block_caption_latex(app, status, warning):
app.builder.build_all()
latex = (app.outdir / 'Python.tex').text(encoding='utf-8')
- caption = '\\sphinxSetupCaptionForVerbatim{literal-block}{caption \\emph{test} rb}'
+ caption = '\\sphinxSetupCaptionForVerbatim{caption \\sphinxstyleemphasis{test} rb}'
label = '\\def\\sphinxLiteralBlockLabel{\\label{caption:id1}}'
link = '\hyperref[caption:name-test-rb]' \
'{Listing \\ref{caption:name-test-rb}}'
@@ -222,17 +222,25 @@ def test_literal_include_lineno_match(app, status, warning):
'14</pre></div></td>')
assert start_after in html
+ start_at_end_at = (
+ '<td class="linenos"><div class="linenodiv"><pre>'
+ ' 9\n'
+ '10\n'
+ '11</pre></div></td>')
+ assert start_at_end_at in html
+
@with_app('latex', testroot='directive-code')
def test_literalinclude_file_whole_of_emptyline(app, status, warning):
app.builder.build_all()
latex = (app.outdir / 'Python.tex').text(encoding='utf-8').replace('\r\n', '\n')
includes = (
- '\\begin{Verbatim}[commandchars=\\\\\\{\\},numbers=left,firstnumber=1,stepnumber=1]\n'
+ '\\begin{sphinxVerbatim}'
+ '[commandchars=\\\\\\{\\},numbers=left,firstnumber=1,stepnumber=1]\n'
'\n'
'\n'
'\n'
- '\\end{Verbatim}\n')
+ '\\end{sphinxVerbatim}\n')
assert includes in latex
@@ -252,7 +260,7 @@ def test_literalinclude_caption_html(app, status, warning):
def test_literalinclude_caption_latex(app, status, warning):
app.builder.build('index')
latex = (app.outdir / 'Python.tex').text(encoding='utf-8')
- caption = '\\sphinxSetupCaptionForVerbatim{literal-block}{caption \\textbf{test} py}'
+ caption = '\\sphinxSetupCaptionForVerbatim{caption \\sphinxstylestrong{test} py}'
label = '\\def\\sphinxLiteralBlockLabel{\\label{caption:id2}}'
link = '\hyperref[caption:name-test-py]' \
'{Listing \\ref{caption:name-test-py}}'
diff --git a/tests/test_directive_only.py b/tests/test_directive_only.py
index 7e499a3a1..def064c5a 100644
--- a/tests/test_directive_only.py
+++ b/tests/test_directive_only.py
@@ -12,6 +12,7 @@
import re
from docutils import nodes
+from sphinx.util.nodes import process_only_nodes
from util import with_app
@@ -46,7 +47,7 @@ def test_sectioning(app, status, warning):
app.builder.build(['only'])
doctree = app.env.get_doctree('only')
- app.env.process_only_nodes(doctree, app.builder)
+ process_only_nodes(doctree, app.builder.tags)
parts = [getsects(n)
for n in [_n for _n in doctree.children if isinstance(_n, nodes.section)]]
diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py
index 778ac1c55..4a505119d 100644
--- a/tests/test_domain_cpp.py
+++ b/tests/test_domain_cpp.py
@@ -24,7 +24,10 @@ ids = []
def parse(name, string):
- parser = DefinitionParser(string, None)
+ class Config(object):
+ cpp_id_attributes = ["id_attr"]
+ cpp_paren_attributes = ["paren_attr"]
+ parser = DefinitionParser(string, None, Config())
ast = parser.parse_declaration(name)
if not parser.eof:
print("Parsing stopped at", parser.pos)
@@ -50,7 +53,7 @@ def check(name, input, idv1output=None, idv2output=None, output=None):
print("Expected: ", output)
raise DefinitionError("")
rootSymbol = Symbol(None, None, None, None, None, None)
- symbol = rootSymbol.add_declaration(ast, docname="Test")
+ symbol = rootSymbol.add_declaration(ast, docname="TestDoc")
parentNode = addnodes.desc()
signode = addnodes.desc_signature(input, '')
parentNode += signode
@@ -138,6 +141,20 @@ def test_type_definitions():
check('type', 'void (*f)(std::function<void(int i)> g)', 'f', '1f')
+def test_concept_definitions():
+ check('concept', 'template<typename Param> A::B::Concept',
+ None, 'I0EN1A1B7ConceptE')
+ check('concept', 'template<typename A, typename B, typename ...C> Foo',
+ None, 'I00DpE3Foo')
+ check('concept', 'template<typename Param> A::B::Concept()',
+ None, 'I0EN1A1B7ConceptE')
+ check('concept', 'template<typename A, typename B, typename ...C> Foo()',
+ None, 'I00DpE3Foo')
+ raises(DefinitionError, parse, 'concept', 'Foo')
+ raises(DefinitionError, parse, 'concept',
+ 'template<typename T> template<typename U> Foo')
+
+
def test_member_definitions():
check('member', ' const std::string & name = 42',
"name__ssCR", "4name", output='const std::string &name = 42')
@@ -401,6 +418,70 @@ def test_templates():
None, "I00ElsRNSt13basic_ostreamI4Char6TraitsEE"
"RK18c_string_view_baseIK4Char6TraitsE")
+ # template introductions
+ raises(DefinitionError, parse, 'enum', 'abc::ns::foo{id_0, id_1, id_2} A')
+ raises(DefinitionError, parse, 'enumerator', 'abc::ns::foo{id_0, id_1, id_2} A')
+ check('class', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar',
+ None, 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE')
+ check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar',
+ None, 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE')
+ check('class', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar<id_0, id_1, id_2>',
+ None, 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barI4id_04id_14id_2EE')
+ check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar<id_0, id_1, id_2...>',
+ None, 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barI4id_04id_1Dp4id_2EE')
+
+ check('class', 'template<> Concept{U} A<int>::B',
+ None, 'IEI0EX7ConceptI1UEEN1AIiE1BE')
+
+ check('type', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar = ghi::qux',
+ None, 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE')
+ check('type', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar = ghi::qux',
+ None, 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE')
+ check('function', 'abc::ns::foo{id_0, id_1, id_2} void xyz::bar()',
+ None, 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barEv')
+ check('function', 'abc::ns::foo{id_0, id_1, ...id_2} void xyz::bar()',
+ None, 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barEv')
+ check('member', 'abc::ns::foo{id_0, id_1, id_2} ghi::qux xyz::bar',
+ None, 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE')
+ check('member', 'abc::ns::foo{id_0, id_1, ...id_2} ghi::qux xyz::bar',
+ None, 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE')
+ check('concept', 'Iterator{T, U} Another',
+ None, 'I00EX8IteratorI1T1UEE7Another')
+ check('concept', 'template<typename ...Pack> Numerics = (... && Numeric<Pack>)',
+ None, 'IDpE8Numerics')
+
+
+def test_attributes():
+ # style: C++
+ check('member', '[[]] int f', 'f__i', '1f')
+ check('member', '[ [ ] ] int f', 'f__i', '1f',
+ # this will fail when the proper grammar is implemented
+ output='[[ ]] int f')
+ check('member', '[[a]] int f', 'f__i', '1f')
+ # style: GNU
+ check('member', '__attribute__(()) int f', 'f__i', '1f')
+ check('member', '__attribute__((a)) int f', 'f__i', '1f')
+ check('member', '__attribute__((a, b)) int f', 'f__i', '1f')
+ # style: user-defined id
+ check('member', 'id_attr int f', 'f__i', '1f')
+ # style: user-defined paren
+ check('member', 'paren_attr() int f', 'f__i', '1f')
+ check('member', 'paren_attr(a) int f', 'f__i', '1f')
+ check('member', 'paren_attr("") int f', 'f__i', '1f')
+ check('member', 'paren_attr(()[{}][]{}) int f', 'f__i', '1f')
+ raises(DefinitionError, parse, 'member', 'paren_attr(() int f')
+ raises(DefinitionError, parse, 'member', 'paren_attr([) int f')
+ raises(DefinitionError, parse, 'member', 'paren_attr({) int f')
+ raises(DefinitionError, parse, 'member', 'paren_attr([)]) int f')
+ raises(DefinitionError, parse, 'member', 'paren_attr((])) int f')
+ raises(DefinitionError, parse, 'member', 'paren_attr({]}) int f')
+
+ # position: decl specs
+ check('function', 'static inline __attribute__(()) void f()',
+ 'f', '1fv',
+ output='__attribute__(()) static inline void f()')
+
+
# def test_print():
# # used for getting all the ids out for checking
diff --git a/tests/test_domain_std.py b/tests/test_domain_std.py
index 2d31ada2e..4f892cb01 100644
--- a/tests/test_domain_std.py
+++ b/tests/test_domain_std.py
@@ -10,9 +10,9 @@
"""
from docutils import nodes
+import mock
from sphinx.domains.std import StandardDomain
-from util import mock
def test_process_doc_handle_figure_caption():
@@ -26,6 +26,7 @@ def test_process_doc_handle_figure_caption():
nameids={'testname': 'testid'},
ids={'testid': figure_node},
)
+ document.traverse.return_value = []
domain = StandardDomain(env)
if 'testname' in domain.data['labels']:
@@ -47,6 +48,7 @@ def test_process_doc_handle_table_title():
nameids={'testname': 'testid'},
ids={'testid': table_node},
)
+ document.traverse.return_value = []
domain = StandardDomain(env)
if 'testname' in domain.data['labels']:
diff --git a/tests/test_environment_indexentries.py b/tests/test_environment_indexentries.py
new file mode 100644
index 000000000..57a3cf52f
--- /dev/null
+++ b/tests/test_environment_indexentries.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+"""
+ test_environment_indexentries
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Test the sphinx.environment.managers.indexentries.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from collections import namedtuple
+from sphinx import locale
+from sphinx.environment.managers.indexentries import IndexEntries
+
+import mock
+
+Environment = namedtuple('Environment', 'indexentries')
+
+dummy_builder = mock.Mock()
+dummy_builder.get_relative_uri.return_value = ''
+
+
+def test_create_single_index():
+ # type, value, tid, main, index_key
+ env = Environment({
+ 'index': [
+ ('single', 'docutils', 'id1', '', None),
+ ('single', 'Python', 'id2', '', None),
+ ('single', 'pip; install', 'id3', '', None),
+ ('single', 'pip; upgrade', 'id4', '', None),
+ ('single', 'Sphinx', 'id5', '', None),
+ ],
+ })
+ index = IndexEntries(env).create_index(dummy_builder)
+ assert len(index) == 3
+ assert index[0] == (u'D', [(u'docutils', [[('', '#id1')], [], None])])
+ assert index[1] == (u'P', [(u'pip', [[], [(u'install', [('', '#id3')]),
+ (u'upgrade', [('', '#id4')])], None]),
+ (u'Python', [[('', '#id2')], [], None])])
+ assert index[2] == (u'S', [(u'Sphinx', [[('', '#id5')], [], None])])
+
+
+def test_create_pair_index():
+ # type, value, tid, main, index_key
+ env = Environment({
+ 'index': [
+ ('pair', 'docutils; reStructuredText', 'id1', '', None),
+ ('pair', 'Python; interpreter', 'id2', '', None),
+ ('pair', 'Sphinx; documentation tool', 'id3', '', None),
+ ],
+ })
+ index = IndexEntries(env).create_index(dummy_builder)
+ assert len(index) == 5
+ assert index[0] == (u'D',
+ [(u'documentation tool', [[], [(u'Sphinx', [('', '#id3')])], None]),
+ (u'docutils', [[], [(u'reStructuredText', [('', '#id1')])], None])])
+ assert index[1] == (u'I', [(u'interpreter', [[], [(u'Python', [('', '#id2')])], None])])
+ assert index[2] == (u'P', [(u'Python', [[], [(u'interpreter', [('', '#id2')])], None])])
+ assert index[3] == (u'R',
+ [(u'reStructuredText', [[], [(u'docutils', [('', '#id1')])], None])])
+ assert index[4] == (u'S',
+ [(u'Sphinx', [[], [(u'documentation tool', [('', '#id3')])], None])])
+
+
+def test_create_triple_index():
+ # type, value, tid, main, index_key
+ env = Environment({
+ 'index': [
+ ('triple', 'foo; bar; baz', 'id1', '', None),
+ ('triple', 'Python; Sphinx; reST', 'id2', '', None),
+ ],
+ })
+ index = IndexEntries(env).create_index(dummy_builder)
+ assert len(index) == 5
+ assert index[0] == (u'B', [(u'bar', [[], [(u'baz, foo', [('', '#id1')])], None]),
+ (u'baz', [[], [(u'foo bar', [('', '#id1')])], None])])
+ assert index[1] == (u'F', [(u'foo', [[], [(u'bar baz', [('', '#id1')])], None])])
+ assert index[2] == (u'P', [(u'Python', [[], [(u'Sphinx reST', [('', '#id2')])], None])])
+ assert index[3] == (u'R', [(u'reST', [[], [(u'Python Sphinx', [('', '#id2')])], None])])
+ assert index[4] == (u'S', [(u'Sphinx', [[], [(u'reST, Python', [('', '#id2')])], None])])
+
+
+def test_create_see_index():
+ locale.init([], None)
+
+ # type, value, tid, main, index_key
+ env = Environment({
+ 'index': [
+ ('see', 'docutils; reStructuredText', 'id1', '', None),
+ ('see', 'Python; interpreter', 'id2', '', None),
+ ('see', 'Sphinx; documentation tool', 'id3', '', None),
+ ],
+ })
+ index = IndexEntries(env).create_index(dummy_builder)
+ assert len(index) == 3
+ assert index[0] == (u'D', [(u'docutils', [[], [(u'see reStructuredText', [])], None])])
+ assert index[1] == (u'P', [(u'Python', [[], [(u'see interpreter', [])], None])])
+ assert index[2] == (u'S', [(u'Sphinx', [[], [(u'see documentation tool', [])], None])])
+
+
+def test_create_seealso_index():
+ locale.init([], None)
+
+ # type, value, tid, main, index_key
+ env = Environment({
+ 'index': [
+ ('seealso', 'docutils; reStructuredText', 'id1', '', None),
+ ('seealso', 'Python; interpreter', 'id2', '', None),
+ ('seealso', 'Sphinx; documentation tool', 'id3', '', None),
+ ],
+ })
+ index = IndexEntries(env).create_index(dummy_builder)
+ assert len(index) == 3
+ assert index[0] == (u'D',
+ [(u'docutils', [[], [(u'see also reStructuredText', [])], None])])
+ assert index[1] == (u'P',
+ [(u'Python', [[], [(u'see also interpreter', [])], None])])
+ assert index[2] == (u'S',
+ [(u'Sphinx', [[], [(u'see also documentation tool', [])], None])])
+
+
+def test_create_index_by_key():
+ # type, value, tid, main, index_key
+ env = Environment({
+ 'index': [
+ ('single', 'docutils', 'id1', '', None),
+ ('single', 'Python', 'id2', '', None),
+ ('single', u'スフィンクス', 'id3', '', u'ス'),
+ ],
+ })
+ index = IndexEntries(env).create_index(dummy_builder)
+ assert len(index) == 3
+ assert index[0] == (u'D', [(u'docutils', [[('', '#id1')], [], None])])
+ assert index[1] == (u'P', [(u'Python', [[('', '#id2')], [], None])])
+ assert index[2] == (u'ス', [(u'スフィンクス', [[('', '#id3')], [], u'ス'])])
diff --git a/tests/test_environment_toctree.py b/tests/test_environment_toctree.py
new file mode 100644
index 000000000..20188c16a
--- /dev/null
+++ b/tests/test_environment_toctree.py
@@ -0,0 +1,332 @@
+# -*- coding: utf-8 -*-
+"""
+ test_environment_toctree
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Test the sphinx.environment.managers.toctree.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from docutils import nodes
+from docutils.nodes import bullet_list, list_item, caption, comment, reference
+from sphinx import addnodes
+from sphinx.addnodes import compact_paragraph, only
+from sphinx.builders.html import StandaloneHTMLBuilder
+
+from util import with_app, gen_with_app, assert_node
+
+
+@gen_with_app('xml', testroot='toctree')
+def test_basic(app, status, warning):
+ app.build()
+ yield _test_process_doc, app
+ yield _test_get_toc_for, app
+ yield _test_get_toc_for_only, app
+ yield _test_get_toc_for_tocdepth, app
+ yield _test_get_toctree_for, app
+ yield _test_get_toctree_for_collapse, app
+ yield _test_get_toctree_for_maxdepth, app
+ yield _test_get_toctree_for_includehidden, app
+
+
+def _test_process_doc(app):
+ # tocs
+ toctree = app.env.tocs['index']
+ assert_node(toctree,
+ [bullet_list, ([list_item, (compact_paragraph, # [0][0]
+ [bullet_list, (addnodes.toctree, # [0][1][0]
+ only, # [0][1][1]
+ list_item)])], # [0][1][2]
+ [list_item, (compact_paragraph, # [1][0]
+ [bullet_list, (addnodes.toctree, # [1][1][0]
+ addnodes.toctree)])], # [1][1][1]
+ list_item)])
+
+ assert_node(toctree[0][0],
+ [compact_paragraph, reference, "Welcome to Sphinx Tests's documentation!"])
+ assert_node(toctree[0][0][0], reference, anchorname='')
+ assert_node(toctree[0][1][0], addnodes.toctree,
+ caption="Table of Contents", glob=False, hidden=False,
+ titlesonly=False, maxdepth=2, numbered=999,
+ entries=[(None, 'foo'), (None, 'bar'), (None, 'http://sphinx-doc.org/')],
+ includefiles=['foo', 'bar'])
+
+ # only branch
+ assert_node(toctree[0][1][1], addnodes.only, expr="html")
+ assert_node(toctree[0][1][1],
+ [only, list_item, ([compact_paragraph, reference, "Section for HTML"],
+ [bullet_list, addnodes.toctree])])
+ assert_node(toctree[0][1][1][0][0][0], reference, anchorname='#section-for-html')
+ assert_node(toctree[0][1][1][0][1][0], addnodes.toctree,
+ caption=None, glob=False, hidden=False, entries=[(None, 'baz')],
+ includefiles=['baz'], titlesonly=False, maxdepth=-1, numbered=0)
+ assert_node(toctree[0][1][2],
+ ([compact_paragraph, reference, "subsection"],
+ [bullet_list, list_item, compact_paragraph, reference, "subsubsection"]))
+
+ assert_node(toctree[1][0],
+ [compact_paragraph, reference, "Test for issue #1157"])
+ assert_node(toctree[1][0][0], reference, anchorname='#test-for-issue-1157')
+ assert_node(toctree[1][1][0], addnodes.toctree,
+ caption=None, entries=[], glob=False, hidden=False,
+ titlesonly=False, maxdepth=-1, numbered=0)
+ assert_node(toctree[1][1][1], addnodes.toctree,
+ caption=None, glob=False, hidden=True,
+ titlesonly=False, maxdepth=-1, numbered=0,
+ entries=[('Latest reference', 'http://sphinx-doc.org/latest/'),
+ ('Python', 'http://python.org/')])
+
+ assert_node(toctree[2][0],
+ [compact_paragraph, reference, "Indices and tables"])
+
+ # other collections
+ assert app.env.toc_num_entries['index'] == 6
+ assert app.env.toctree_includes['index'] == ['foo', 'bar', 'baz']
+ assert app.env.files_to_rebuild['foo'] == set(['index'])
+ assert app.env.files_to_rebuild['bar'] == set(['index'])
+ assert app.env.files_to_rebuild['baz'] == set(['index'])
+ assert app.env.glob_toctrees == set()
+ assert app.env.numbered_toctrees == set(['index'])
+
+ # qux has no section title
+ assert len(app.env.tocs['qux']) == 0
+ assert_node(app.env.tocs['qux'], nodes.bullet_list)
+ assert app.env.toc_num_entries['qux'] == 0
+ assert 'qux' not in app.env.toctree_includes
+
+
+@with_app('dummy', testroot='toctree-glob')
+def test_glob(app, status, warning):
+ includefiles = ['foo', 'bar/index', 'bar/bar_1', 'bar/bar_2',
+ 'bar/bar_3', 'baz', 'qux/index']
+
+ app.build()
+
+ # tocs
+ toctree = app.env.tocs['index']
+ assert_node(toctree,
+ [bullet_list, list_item, (compact_paragraph, # [0][0]
+ [bullet_list, (list_item, # [0][1][0]
+ list_item)])]) # [0][1][1]
+
+ assert_node(toctree[0][0],
+ [compact_paragraph, reference, "test-toctree-glob"])
+ assert_node(toctree[0][1][0],
+ [list_item, ([compact_paragraph, reference, "normal order"],
+ [bullet_list, addnodes.toctree])]) # [0][1][0][1][0]
+ assert_node(toctree[0][1][0][1][0], addnodes.toctree, caption=None,
+ glob=True, hidden=False, titlesonly=False,
+ maxdepth=-1, numbered=0, includefiles=includefiles,
+ entries=[(None, 'foo'), (None, 'bar/index'), (None, 'bar/bar_1'),
+ (None, 'bar/bar_2'), (None, 'bar/bar_3'), (None, 'baz'),
+ (None, 'qux/index')])
+ assert_node(toctree[0][1][1],
+ [list_item, ([compact_paragraph, reference, "reversed order"],
+ [bullet_list, addnodes.toctree])]) # [0][1][1][1][0]
+ assert_node(toctree[0][1][1][1][0], addnodes.toctree, caption=None,
+ glob=True, hidden=False, titlesonly=False,
+ maxdepth=-1, numbered=0, includefiles=includefiles,
+ entries=[(None, 'qux/index'), (None, 'baz'), (None, 'bar/bar_3'),
+ (None, 'bar/bar_2'), (None, 'bar/bar_1'), (None, 'bar/index'),
+ (None, 'foo')])
+ includefiles = ['foo', 'bar/index', 'bar/bar_1', 'bar/bar_2',
+ 'bar/bar_3', 'baz', 'qux/index']
+
+ # other collections
+ assert app.env.toc_num_entries['index'] == 3
+ assert app.env.toctree_includes['index'] == includefiles + includefiles
+ for file in includefiles:
+ assert 'index' in app.env.files_to_rebuild[file]
+ assert 'index' in app.env.glob_toctrees
+ assert app.env.numbered_toctrees == set()
+
+
+def _test_get_toc_for(app):
+ toctree = app.env.get_toc_for('index', app.builder)
+
+ assert_node(toctree,
+ [bullet_list, ([list_item, (compact_paragraph, # [0][0]
+ [bullet_list, (addnodes.toctree, # [0][1][0]
+ comment, # [0][1][1]
+ list_item)])], # [0][1][2]
+ [list_item, (compact_paragraph, # [1][0]
+ [bullet_list, (addnodes.toctree,
+ addnodes.toctree)])],
+ [list_item, compact_paragraph])]) # [2][0]
+ assert_node(toctree[0][0],
+ [compact_paragraph, reference, "Welcome to Sphinx Tests's documentation!"])
+ assert_node(toctree[0][1][2],
+ ([compact_paragraph, reference, "subsection"],
+ [bullet_list, list_item, compact_paragraph, reference, "subsubsection"]))
+ assert_node(toctree[1][0],
+ [compact_paragraph, reference, "Test for issue #1157"])
+ assert_node(toctree[2][0],
+ [compact_paragraph, reference, "Indices and tables"])
+
+
+def _test_get_toc_for_only(app):
+ builder = StandaloneHTMLBuilder(app)
+ toctree = app.env.get_toc_for('index', builder)
+
+ assert_node(toctree,
+ [bullet_list, ([list_item, (compact_paragraph, # [0][0]
+ [bullet_list, (addnodes.toctree, # [0][1][0]
+ list_item, # [0][1][1]
+ list_item)])], # [0][1][2]
+ [list_item, (compact_paragraph, # [1][0]
+ [bullet_list, (addnodes.toctree,
+ addnodes.toctree)])],
+ [list_item, compact_paragraph])]) # [2][0]
+ assert_node(toctree[0][0],
+ [compact_paragraph, reference, "Welcome to Sphinx Tests's documentation!"])
+ assert_node(toctree[0][1][1],
+ ([compact_paragraph, reference, "Section for HTML"],
+ [bullet_list, addnodes.toctree]))
+ assert_node(toctree[0][1][2],
+ ([compact_paragraph, reference, "subsection"],
+ [bullet_list, list_item, compact_paragraph, reference, "subsubsection"]))
+ assert_node(toctree[1][0],
+ [compact_paragraph, reference, "Test for issue #1157"])
+ assert_node(toctree[2][0],
+ [compact_paragraph, reference, "Indices and tables"])
+
+
+def _test_get_toc_for_tocdepth(app):
+ toctree = app.env.get_toc_for('tocdepth', app.builder)
+
+ assert_node(toctree,
+ [bullet_list, list_item, (compact_paragraph, # [0][0]
+ bullet_list)]) # [0][1]
+ assert_node(toctree[0][0],
+ [compact_paragraph, reference, "level 1"])
+ assert_node(toctree[0][1],
+ [bullet_list, list_item, compact_paragraph, reference, "level 2"])
+
+
+def _test_get_toctree_for(app):
+ toctree = app.env.get_toctree_for('index', app.builder, collapse=False)
+ assert_node(toctree,
+ [compact_paragraph, ([caption, "Table of Contents"],
+ bullet_list,
+ bullet_list,
+ bullet_list)])
+
+ assert_node(toctree[1],
+ ([list_item, ([compact_paragraph, reference, "foo"],
+ bullet_list)],
+ [list_item, compact_paragraph, reference, "bar"],
+ [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"]))
+ assert_node(toctree[1][0][1],
+ ([list_item, compact_paragraph, reference, "quux"],
+ [list_item, compact_paragraph, reference, "foo.1"],
+ [list_item, compact_paragraph, reference, "foo.2"]))
+
+ assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,))
+ assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1))
+ assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2))
+ assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3))
+ assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,))
+ assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/")
+
+ assert_node(toctree[2],
+ [bullet_list, list_item, compact_paragraph, reference, "baz"])
+ assert_node(toctree[3],
+ ([list_item, compact_paragraph, reference, "Latest reference"],
+ [list_item, compact_paragraph, reference, "Python"]))
+ assert_node(toctree[3][0][0][0], reference, refuri="http://sphinx-doc.org/latest/")
+ assert_node(toctree[3][1][0][0], reference, refuri="http://python.org/")
+
+
+def _test_get_toctree_for_collapse(app):
+ toctree = app.env.get_toctree_for('index', app.builder, collapse=True)
+ assert_node(toctree,
+ [compact_paragraph, ([caption, "Table of Contents"],
+ bullet_list,
+ bullet_list,
+ bullet_list)])
+
+ assert_node(toctree[1],
+ ([list_item, compact_paragraph, reference, "foo"],
+ [list_item, compact_paragraph, reference, "bar"],
+ [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"]))
+ assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,))
+ assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,))
+ assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/")
+
+ assert_node(toctree[2],
+ [bullet_list, list_item, compact_paragraph, reference, "baz"])
+ assert_node(toctree[3],
+ ([list_item, compact_paragraph, reference, "Latest reference"],
+ [list_item, compact_paragraph, reference, "Python"]))
+ assert_node(toctree[3][0][0][0], reference, refuri="http://sphinx-doc.org/latest/")
+ assert_node(toctree[3][1][0][0], reference, refuri="http://python.org/")
+
+
+def _test_get_toctree_for_maxdepth(app):
+ toctree = app.env.get_toctree_for('index', app.builder, collapse=False, maxdepth=3)
+ assert_node(toctree,
+ [compact_paragraph, ([caption, "Table of Contents"],
+ bullet_list,
+ bullet_list,
+ bullet_list)])
+
+ assert_node(toctree[1],
+ ([list_item, ([compact_paragraph, reference, "foo"],
+ bullet_list)],
+ [list_item, compact_paragraph, reference, "bar"],
+ [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"]))
+ assert_node(toctree[1][0][1],
+ ([list_item, compact_paragraph, reference, "quux"],
+ [list_item, ([compact_paragraph, reference, "foo.1"],
+ bullet_list)],
+ [list_item, compact_paragraph, reference, "foo.2"]))
+ assert_node(toctree[1][0][1][1][1],
+ [bullet_list, list_item, compact_paragraph, reference, "foo.1-1"])
+
+ assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,))
+ assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1))
+ assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2))
+ assert_node(toctree[1][0][1][1][1][0][0][0],
+ reference, refuri="foo#foo-1-1", secnumber=(1, 2, 1))
+ assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3))
+ assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,))
+ assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/")
+
+ assert_node(toctree[2],
+ [bullet_list, list_item, compact_paragraph, reference, "baz"])
+ assert_node(toctree[3],
+ ([list_item, compact_paragraph, reference, "Latest reference"],
+ [list_item, compact_paragraph, reference, "Python"]))
+ assert_node(toctree[3][0][0][0], reference, refuri="http://sphinx-doc.org/latest/")
+ assert_node(toctree[3][1][0][0], reference, refuri="http://python.org/")
+
+
+def _test_get_toctree_for_includehidden(app):
+ toctree = app.env.get_toctree_for('index', app.builder, collapse=False,
+ includehidden=False)
+ assert_node(toctree,
+ [compact_paragraph, ([caption, "Table of Contents"],
+ bullet_list,
+ bullet_list)])
+
+ assert_node(toctree[1],
+ ([list_item, ([compact_paragraph, reference, "foo"],
+ bullet_list)],
+ [list_item, compact_paragraph, reference, "bar"],
+ [list_item, compact_paragraph, reference, "http://sphinx-doc.org/"]))
+ assert_node(toctree[1][0][1],
+ ([list_item, compact_paragraph, reference, "quux"],
+ [list_item, compact_paragraph, reference, "foo.1"],
+ [list_item, compact_paragraph, reference, "foo.2"]))
+
+ assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,))
+ assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1))
+ assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2))
+ assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3))
+ assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,))
+ assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/")
+
+ assert_node(toctree[2],
+ [bullet_list, list_item, compact_paragraph, reference, "baz"])
diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py
new file mode 100644
index 000000000..dad7521af
--- /dev/null
+++ b/tests/test_ext_autodoc.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+"""
+ test_autodoc
+ ~~~~~~~~~~~~
+
+ Test the autodoc extension.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import pickle
+from docutils import nodes
+from sphinx import addnodes
+from util import with_app
+
+
+@with_app(buildername='dummy', testroot='ext-autodoc')
+def test_autodoc(app, status, warning):
+ app.builder.build_all()
+
+ content = pickle.loads((app.doctreedir / 'contents.doctree').bytes())
+ assert isinstance(content[3], addnodes.desc)
+ assert content[3][0].astext() == 'autodoc_dummy_module.test'
+ assert content[3][1].astext() == 'Dummy function using dummy.*'
diff --git a/tests/test_ext_graphviz.py b/tests/test_ext_graphviz.py
index dbab33761..aa97f4135 100644
--- a/tests/test_ext_graphviz.py
+++ b/tests/test_ext_graphviz.py
@@ -55,6 +55,10 @@ def test_graphviz_html(app, status, warning):
html = '<img src=".*?" alt="digraph {\n bar -&gt; baz\n}" />'
assert re.search(html, content, re.M)
+ html = ('<div class="figure align-right" .*?>\s*<img .*?/>\s*<p class="caption">'
+ '<span class="caption-text">on right</span>.*</p>\s*</div>')
+ assert re.search(html, content, re.S)
+
@with_app('latex', testroot='ext-graphviz')
@skip_if_graphviz_not_found
@@ -70,6 +74,11 @@ def test_graphviz_latex(app, status, warning):
macro = 'Hello \\\\includegraphics{graphviz-\w+.pdf} graphviz world'
assert re.search(macro, content, re.S)
+ macro = ('\\\\begin{wrapfigure}{r}{0pt}\n\\\\centering\n'
+ '\\\\includegraphics{graphviz-\w+.pdf}\n'
+ '\\\\caption{on right}\\\\label{.*}\\\\end{wrapfigure}')
+ assert re.search(macro, content, re.S)
+
@with_app('html', testroot='ext-graphviz', confoverrides={'language': 'xx'})
@skip_if_graphviz_not_found
diff --git a/tests/test_ext_inheritance_diagram.py b/tests/test_ext_inheritance_diagram.py
index 64446eed8..bf1bbbac0 100644
--- a/tests/test_ext_inheritance_diagram.py
+++ b/tests/test_ext_inheritance_diagram.py
@@ -9,9 +9,34 @@
:license: BSD, see LICENSE for details.
"""
+import re
from util import with_app
+from test_ext_graphviz import skip_if_graphviz_not_found
@with_app('html', testroot='ext-inheritance_diagram')
+@skip_if_graphviz_not_found
def test_inheritance_diagram_html(app, status, warning):
app.builder.build_all()
+
+ content = (app.outdir / 'index.html').text()
+
+ pattern = ('<div class="figure" id="id1">\n'
+ '<img src="_images/inheritance-\w+.png" alt="Inheritance diagram of test.Foo" '
+ 'class="inheritance"/>\n<p class="caption"><span class="caption-text">'
+ 'Test Foo!</span><a class="headerlink" href="#id1" '
+ 'title="Permalink to this image">\xb6</a></p>')
+ assert re.search(pattern, content, re.M)
+
+
+@with_app('latex', testroot='ext-inheritance_diagram')
+@skip_if_graphviz_not_found
+def test_inheritance_diagram_latex(app, status, warning):
+ app.builder.build_all()
+
+ content = (app.outdir / 'Python.tex').text()
+
+ pattern = ('\\\\begin{figure}\\[htbp]\n\\\\centering\n\\\\capstart\n\n'
+ '\\\\includegraphics{inheritance-\\w+.pdf}\n'
+ '\\\\caption{Test Foo!}\\\\label{index:id1}\\\\end{figure}')
+ assert re.search(pattern, content, re.M)
diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py
index deec5a379..e1995e3d3 100644
--- a/tests/test_ext_intersphinx.py
+++ b/tests/test_ext_intersphinx.py
@@ -15,13 +15,15 @@ import zlib
from six import BytesIO
from docutils import nodes
+import mock
from sphinx import addnodes
-from sphinx.ext.intersphinx import read_inventory_v1, read_inventory_v2, \
+from sphinx.ext.intersphinx import setup as intersphinx_setup
+from sphinx.ext.intersphinx import read_inventory, \
load_mappings, missing_reference, _strip_basic_auth, _read_from_url, \
_get_safe_url, fetch_inventory, INVENTORY_FILENAME
-from util import with_app, with_tempdir, mock
+from util import with_app, with_tempdir
inventory_v1 = '''\
@@ -49,8 +51,7 @@ a term including:colon std:term -1 glossary.html#term-a-term-including-colon -
def test_read_inventory_v1():
f = BytesIO(inventory_v1)
- f.readline()
- invdata = read_inventory_v1(f, '/util', posixpath.join)
+ invdata = read_inventory(f, '/util', posixpath.join)
assert invdata['py:module']['module'] == \
('foo', '1.0', '/util/foo.html#module-module', '-')
assert invdata['py:class']['module.cls'] == \
@@ -59,13 +60,11 @@ def test_read_inventory_v1():
def test_read_inventory_v2():
f = BytesIO(inventory_v2)
- f.readline()
- invdata1 = read_inventory_v2(f, '/util', posixpath.join)
+ invdata1 = read_inventory(f, '/util', posixpath.join)
# try again with a small buffer size to test the chunking algorithm
f = BytesIO(inventory_v2)
- f.readline()
- invdata2 = read_inventory_v2(f, '/util', posixpath.join, bufsize=5)
+ invdata2 = read_inventory(f, '/util', posixpath.join, bufsize=5)
assert invdata1 == invdata2
@@ -84,47 +83,48 @@ def test_read_inventory_v2():
@with_app()
-@mock.patch('sphinx.ext.intersphinx.read_inventory_v2')
+@mock.patch('sphinx.ext.intersphinx.read_inventory')
@mock.patch('sphinx.ext.intersphinx._read_from_url')
-def test_fetch_inventory_redirection(app, status, warning, _read_from_url, read_inventory_v2):
+def test_fetch_inventory_redirection(app, status, warning, _read_from_url, read_inventory):
+ intersphinx_setup(app)
_read_from_url().readline.return_value = '# Sphinx inventory version 2'.encode('utf-8')
# same uri and inv, not redirected
- _read_from_url().geturl.return_value = 'http://hostname/' + INVENTORY_FILENAME
+ _read_from_url().url = 'http://hostname/' + INVENTORY_FILENAME
fetch_inventory(app, 'http://hostname/', 'http://hostname/' + INVENTORY_FILENAME)
assert 'intersphinx inventory has moved' not in status.getvalue()
- assert read_inventory_v2.call_args[0][1] == 'http://hostname/'
+ assert read_inventory.call_args[0][1] == 'http://hostname/'
# same uri and inv, redirected
status.seek(0)
status.truncate(0)
- _read_from_url().geturl.return_value = 'http://hostname/new/' + INVENTORY_FILENAME
+ _read_from_url().url = 'http://hostname/new/' + INVENTORY_FILENAME
fetch_inventory(app, 'http://hostname/', 'http://hostname/' + INVENTORY_FILENAME)
assert status.getvalue() == ('intersphinx inventory has moved: '
'http://hostname/%s -> http://hostname/new/%s\n' %
(INVENTORY_FILENAME, INVENTORY_FILENAME))
- assert read_inventory_v2.call_args[0][1] == 'http://hostname/new'
+ assert read_inventory.call_args[0][1] == 'http://hostname/new'
# different uri and inv, not redirected
status.seek(0)
status.truncate(0)
- _read_from_url().geturl.return_value = 'http://hostname/new/' + INVENTORY_FILENAME
+ _read_from_url().url = 'http://hostname/new/' + INVENTORY_FILENAME
fetch_inventory(app, 'http://hostname/', 'http://hostname/new/' + INVENTORY_FILENAME)
assert 'intersphinx inventory has moved' not in status.getvalue()
- assert read_inventory_v2.call_args[0][1] == 'http://hostname/'
+ assert read_inventory.call_args[0][1] == 'http://hostname/'
# different uri and inv, redirected
status.seek(0)
status.truncate(0)
- _read_from_url().geturl.return_value = 'http://hostname/other/' + INVENTORY_FILENAME
+ _read_from_url().url = 'http://hostname/other/' + INVENTORY_FILENAME
fetch_inventory(app, 'http://hostname/', 'http://hostname/new/' + INVENTORY_FILENAME)
assert status.getvalue() == ('intersphinx inventory has moved: '
'http://hostname/new/%s -> http://hostname/other/%s\n' %
(INVENTORY_FILENAME, INVENTORY_FILENAME))
- assert read_inventory_v2.call_args[0][1] == 'http://hostname/'
+ assert read_inventory.call_args[0][1] == 'http://hostname/'
@with_app()
@@ -248,64 +248,23 @@ class TestStripBasicAuth(unittest.TestCase):
"""basic auth creds stripped from URL containing creds"""
url = 'https://user:12345@domain.com/project/objects.inv'
expected = 'https://domain.com/project/objects.inv'
- actual_url, actual_username, actual_password = _strip_basic_auth(url)
- self.assertEqual(expected, actual_url)
- self.assertEqual('user', actual_username)
- self.assertEqual('12345', actual_password)
+ actual = _strip_basic_auth(url)
+ self.assertEqual(expected, actual)
def test_no_auth(self):
"""url unchanged if param doesn't contain basic auth creds"""
url = 'https://domain.com/project/objects.inv'
expected = 'https://domain.com/project/objects.inv'
- actual_url, actual_username, actual_password = _strip_basic_auth(url)
- self.assertEqual(expected, actual_url)
- self.assertEqual(None, actual_username)
- self.assertEqual(None, actual_password)
+ actual = _strip_basic_auth(url)
+ self.assertEqual(expected, actual)
def test_having_port(self):
"""basic auth creds correctly stripped from URL containing creds even if URL
contains port"""
url = 'https://user:12345@domain.com:8080/project/objects.inv'
expected = 'https://domain.com:8080/project/objects.inv'
- actual_url, actual_username, actual_password = _strip_basic_auth(url)
- self.assertEqual(expected, actual_url)
- self.assertEqual('user', actual_username)
- self.assertEqual('12345', actual_password)
-
-
-@mock.patch('six.moves.urllib.request.HTTPBasicAuthHandler')
-@mock.patch('six.moves.urllib.request.HTTPPasswordMgrWithDefaultRealm')
-@mock.patch('six.moves.urllib.request.build_opener')
-def test_readfromurl_authed(m_build_opener, m_HTTPPasswordMgrWithDefaultRealm,
- m_HTTPBasicAuthHandler):
- # read from URL containing basic auth creds
- password_mgr = mock.Mock()
- m_HTTPPasswordMgrWithDefaultRealm.return_value = password_mgr
-
- url = 'https://user:12345@domain.com/project/objects.inv'
- _read_from_url(url)
-
- m_HTTPPasswordMgrWithDefaultRealm.assert_called_once_with()
- password_mgr.add_password.assert_called_with(
- None, 'https://domain.com/project/objects.inv', 'user', '12345')
-
-
-@mock.patch('six.moves.urllib.request.HTTPBasicAuthHandler')
-@mock.patch('six.moves.urllib.request.HTTPPasswordMgrWithDefaultRealm')
-@mock.patch('sphinx.ext.intersphinx.default_opener')
-def test_readfromurl_unauthed(m_default_opener, m_HTTPPasswordMgrWithDefaultRealm,
- m_HTTPBasicAuthHandler):
- # read from URL without auth creds
- password_mgr = mock.Mock()
- m_HTTPPasswordMgrWithDefaultRealm.return_value = password_mgr
-
- url = 'https://domain.com/project/objects.inv'
- _read_from_url(url)
-
- # assert password manager not created
- assert m_HTTPPasswordMgrWithDefaultRealm.call_args is None
- # assert no password added to the password manager
- assert password_mgr.add_password.call_args is None
+ actual = _strip_basic_auth(url)
+ self.assertEqual(expected, actual)
def test_getsafeurl_authed():
@@ -316,6 +275,14 @@ def test_getsafeurl_authed():
assert expected == actual
+def test_getsafeurl_authed_having_port():
+ """_get_safe_url() with a url with basic auth having port"""
+ url = 'https://user:12345@domain.com:8080/project/objects.inv'
+ expected = 'https://user@domain.com:8080/project/objects.inv'
+ actual = _get_safe_url(url)
+ assert expected == actual
+
+
def test_getsafeurl_unauthed():
"""_get_safe_url() with a url without basic auth"""
url = 'https://domain.com/project/objects.inv'
diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py
index c858afcd2..0c7d44e8e 100644
--- a/tests/test_ext_math.py
+++ b/tests/test_ext_math.py
@@ -22,10 +22,13 @@ def test_jsmath(app, status, warning):
assert '<div class="math">\na^2 + b^2 = c^2</div>' in content
assert '<div class="math">\n\\begin{split}a + 1 &lt; b\\end{split}</div>' in content
- assert ('<span class="eqno">(1)</span><div class="math" id="equation-foo">\n'
- 'e^{i\\pi} = 1</div>' in content)
- assert ('<span class="eqno">(2)</span><div class="math">\n'
- 'e^{ix} = \\cos x + i\\sin x</div>' in content)
+ assert (u'<span class="eqno">(1)<a class="headerlink" href="#equation-foo" '
+ u'title="Permalink to this equation">\xb6</a></span>'
+ u'<div class="math" id="equation-foo">\ne^{i\\pi} = 1</div>' in content)
+ assert (u'<span class="eqno">(2)<a class="headerlink" href="#equation-math:0" '
+ u'title="Permalink to this equation">\xb6</a></span>'
+ u'<div class="math" id="equation-math:0">\n'
+ u'e^{ix} = \\cos x + i\\sin x</div>' in content)
assert '<div class="math">\nn \\in \\mathbb N</div>' in content
assert '<div class="math">\na + 1 &lt; b</div>' in content
@@ -80,8 +83,8 @@ def test_math_number_all_mathjax(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'index.html').text()
- html = (r'<div class="math">\s*'
- r'<span class="eqno">\(1\)</span>\\\[a\^2\+b\^2=c\^2\\\]</div>')
+ html = (r'<div class="math" id="equation-index:0">\s*'
+ r'<span class="eqno">\(1\)<a .*>\xb6</a></span>\\\[a\^2\+b\^2=c\^2\\\]</div>')
assert re.search(html, content, re.S)
@@ -109,3 +112,6 @@ def test_math_number_all_latex(app, status, warning):
r'V &= \\frac\{4}\{3} \\pi r\^3\\\\\s*'
r'\\end{aligned}\\end{align\*}')
assert re.search(macro, content, re.S)
+
+ macro = r'Referencing equation \\eqref{equation:math:foo}.'
+ assert re.search(macro, content, re.S)
diff --git a/tests/test_ext_napoleon.py b/tests/test_ext_napoleon.py
index d4ce96001..7ecd08292 100644
--- a/tests/test_ext_napoleon.py
+++ b/tests/test_ext_napoleon.py
@@ -16,7 +16,7 @@ from unittest import TestCase
from sphinx.application import Sphinx
from sphinx.ext.napoleon import (_process_docstring, _skip_member, Config,
setup)
-from util import mock
+import mock
def _private_doc():
diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py
index 17c1a7a56..37dcca90c 100644
--- a/tests/test_ext_napoleon_docstring.py
+++ b/tests/test_ext_napoleon_docstring.py
@@ -19,7 +19,7 @@ from unittest import TestCase
from sphinx.ext.napoleon import Config
from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring
-from util import mock
+import mock
class NamedtupleSubclass(namedtuple('NamedtupleSubclass', ('attr1', 'attr2'))):
@@ -222,6 +222,24 @@ class GoogleDocstringTest(BaseDocstringTest):
"""
Single line summary
+ Args:
+ arg1 (list(int)): Description
+ arg2 (list[int]): Description
+ arg3 (dict(str, int)): Description
+ arg4 (dict[str, int]): Description
+ """,
+ """
+ Single line summary
+
+ :Parameters: * **arg1** (*list(int)*) -- Description
+ * **arg2** (*list[int]*) -- Description
+ * **arg3** (*dict(str, int)*) -- Description
+ * **arg4** (*dict[str, int]*) -- Description
+ """
+ ), (
+ """
+ Single line summary
+
Yield:
str:Extended
description of yielded value
@@ -249,7 +267,11 @@ class GoogleDocstringTest(BaseDocstringTest):
)]
def test_docstrings(self):
- config = Config(napoleon_use_param=False, napoleon_use_rtype=False)
+ config = Config(
+ napoleon_use_param=False,
+ napoleon_use_rtype=False,
+ napoleon_use_keyword=False
+ )
for docstring, expected in self.docstrings:
actual = str(GoogleDocstring(dedent(docstring), config))
expected = dedent(expected)
@@ -325,7 +347,9 @@ Returns:
codecode
"""
expected = """
-:returns: foo::
+:returns:
+
+ foo::
codecode
codecode
@@ -1046,7 +1070,10 @@ class NumpyDocstringTest(BaseDocstringTest):
)]
def test_docstrings(self):
- config = Config(napoleon_use_param=False, napoleon_use_rtype=False)
+ config = Config(
+ napoleon_use_param=False,
+ napoleon_use_rtype=False,
+ napoleon_use_keyword=False)
for docstring, expected in self.docstrings:
actual = str(NumpyDocstring(dedent(docstring), config))
expected = dedent(expected)
@@ -1736,3 +1763,19 @@ definition_after_normal_text : int
config = Config(napoleon_use_param=False)
actual = str(NumpyDocstring(docstring, config))
self.assertEqual(expected, actual)
+
+ def test_keywords_with_types(self):
+ docstring = """\
+Do as you please
+
+Keyword Args:
+ gotham_is_yours (None): shall interfere.
+"""
+ actual = str(GoogleDocstring(docstring))
+ expected = """\
+Do as you please
+
+:keyword gotham_is_yours: shall interfere.
+:kwtype gotham_is_yours: None
+"""
+ self.assertEqual(expected, actual)
diff --git a/tests/test_ext_todo.py b/tests/test_ext_todo.py
new file mode 100644
index 000000000..269a8a2be
--- /dev/null
+++ b/tests/test_ext_todo.py
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+"""
+ test_ext_todo
+ ~~~~~~~~~~~~~
+
+ Test sphinx.ext.todo extension.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+from util import with_app
+
+
+@with_app('html', testroot='ext-todo', freshenv=True,
+ confoverrides={'todo_include_todos': True, 'todo_emit_warnings': True})
+def test_todo(app, status, warning):
+ todos = []
+
+ def on_todo_defined(app, node):
+ todos.append(node)
+
+ app.connect('todo-defined', on_todo_defined)
+ app.builder.build_all()
+
+ # check todolist
+ content = (app.outdir / 'index.html').text()
+ html = ('<p class="first admonition-title">Todo</p>\n'
+ '<p class="last">todo in foo</p>')
+ assert re.search(html, content, re.S)
+
+ html = ('<p class="first admonition-title">Todo</p>\n'
+ '<p class="last">todo in bar</p>')
+ assert re.search(html, content, re.S)
+
+ # check todo
+ content = (app.outdir / 'foo.html').text()
+ html = ('<p class="first admonition-title">Todo</p>\n'
+ '<p class="last">todo in foo</p>')
+ assert re.search(html, content, re.S)
+
+ # check emitted warnings
+ assert 'WARNING: TODO entry found: todo in foo' in warning.getvalue()
+ assert 'WARNING: TODO entry found: todo in bar' in warning.getvalue()
+
+ # check handled event
+ assert len(todos) == 2
+ assert set(todo[1].astext() for todo in todos) == set(['todo in foo', 'todo in bar'])
+
+
+@with_app('html', testroot='ext-todo', freshenv=True,
+ confoverrides={'todo_include_todos': False, 'todo_emit_warnings': True})
+def test_todo_not_included(app, status, warning):
+ todos = []
+
+ def on_todo_defined(app, node):
+ todos.append(node)
+
+ app.connect('todo-defined', on_todo_defined)
+ app.builder.build_all()
+
+ # check todolist
+ content = (app.outdir / 'index.html').text()
+ html = ('<p class="first admonition-title">Todo</p>\n'
+ '<p class="last">todo in foo</p>')
+ assert not re.search(html, content, re.S)
+
+ html = ('<p class="first admonition-title">Todo</p>\n'
+ '<p class="last">todo in bar</p>')
+ assert not re.search(html, content, re.S)
+
+ # check todo
+ content = (app.outdir / 'foo.html').text()
+ html = ('<p class="first admonition-title">Todo</p>\n'
+ '<p class="last">todo in foo</p>')
+ assert not re.search(html, content, re.S)
+
+ # check emitted warnings
+ assert 'WARNING: TODO entry found: todo in foo' in warning.getvalue()
+ assert 'WARNING: TODO entry found: todo in bar' in warning.getvalue()
+
+ # check handled event
+ assert len(todos) == 2
+ assert set(todo[1].astext() for todo in todos) == set(['todo in foo', 'todo in bar'])
diff --git a/tests/test_intl.py b/tests/test_intl.py
index b31f1678b..43cd17c8e 100644
--- a/tests/test_intl.py
+++ b/tests/test_intl.py
@@ -118,6 +118,11 @@ def assert_count(expected_expr, result, count):
def test_text_builder(app, status, warning):
app.builder.build_all()
+ # --- toctree
+
+ result = (app.outdir / 'contents.txt').text(encoding='utf-8')
+ yield assert_startswith, result, u"CONTENTS\n********\n\nTABLE OF CONTENTS\n"
+
# --- warnings in translation
warnings = getwarning(warning)
@@ -126,7 +131,7 @@ def test_text_builder(app, status, warning):
yield assert_re_search, warning_expr, warnings
result = (app.outdir / 'warnings.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH REST WARNINGS"
+ expect = (u"I18N WITH REST WARNINGS"
u"\n***********************\n"
u"\nLINE OF >>``<<BROKEN LITERAL MARKUP.\n")
yield assert_equal, result, expect
@@ -134,7 +139,7 @@ def test_text_builder(app, status, warning):
# --- simple translation; check title underlines
result = (app.outdir / 'bom.txt').text(encoding='utf-8')
- expect = (u"\nDatei mit UTF-8"
+ expect = (u"Datei mit UTF-8"
u"\n***************\n" # underline matches new translation
u"\nThis file has umlauts: äöü.\n")
yield assert_equal, result, expect
@@ -142,12 +147,12 @@ def test_text_builder(app, status, warning):
# --- check translation in subdirs
result = (app.outdir / 'subdir' / 'contents.txt').text(encoding='utf-8')
- yield assert_startswith, result, u"\nsubdir contents\n***************\n"
+ yield assert_startswith, result, u"subdir contents\n***************\n"
# --- check warnings for inconsistency in number of references
result = (app.outdir / 'refs_inconsistency.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH REFS INCONSISTENCY"
+ expect = (u"I18N WITH REFS INCONSISTENCY"
u"\n****************************\n"
u"\n* FOR FOOTNOTE [ref2].\n"
u"\n* reference FOR reference.\n"
@@ -169,7 +174,7 @@ def test_text_builder(app, status, warning):
# --- check warning for literal block
result = (app.outdir / 'literalblock.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH LITERAL BLOCK"
+ expect = (u"I18N WITH LITERAL BLOCK"
u"\n***********************\n"
u"\nCORRECT LITERAL BLOCK:\n"
u"\n this is"
@@ -186,7 +191,7 @@ def test_text_builder(app, status, warning):
# --- definition terms: regression test for #975, #2198, #2205
result = (app.outdir / 'definition_terms.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH DEFINITION TERMS"
+ expect = (u"I18N WITH DEFINITION TERMS"
u"\n**************************\n"
u"\nSOME TERM"
u"\n THE CORRESPONDING DEFINITION\n"
@@ -202,7 +207,7 @@ def test_text_builder(app, status, warning):
# --- glossary terms: regression test for #1090
result = (app.outdir / 'glossary_terms.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH GLOSSARY TERMS"
+ expect = (u"I18N WITH GLOSSARY TERMS"
u"\n************************\n"
u"\nSOME NEW TERM"
u"\n THE CORRESPONDING GLOSSARY\n"
@@ -216,7 +221,7 @@ def test_text_builder(app, status, warning):
# --- glossary term inconsistencies: regression test for #1090
result = (app.outdir / 'glossary_terms_inconsistency.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH GLOSSARY TERMS INCONSISTENCY"
+ expect = (u"I18N WITH GLOSSARY TERMS INCONSISTENCY"
u"\n**************************************\n"
u"\n1. LINK TO *SOME NEW TERM*.\n")
yield assert_equal, result, expect
@@ -230,7 +235,7 @@ def test_text_builder(app, status, warning):
# --- seealso
result = (app.outdir / 'seealso.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH SEEALSO"
+ expect = (u"I18N WITH SEEALSO"
u"\n*****************\n"
u"\nSee also: SHORT TEXT 1\n"
u"\nSee also: LONG TEXT 1\n"
@@ -241,7 +246,7 @@ def test_text_builder(app, status, warning):
# --- figure captions: regression test for #940
result = (app.outdir / 'figure.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH FIGURE CAPTION"
+ expect = (u"I18N WITH FIGURE CAPTION"
u"\n************************\n"
u"\n [image]MY CAPTION OF THE FIGURE\n"
u"\n MY DESCRIPTION PARAGRAPH1 OF THE FIGURE.\n"
@@ -267,7 +272,7 @@ def test_text_builder(app, status, warning):
# --- rubric: regression test for pull request #190
result = (app.outdir / 'rubric.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH RUBRIC"
+ expect = (u"I18N WITH RUBRIC"
u"\n****************\n"
u"\n-[ RUBRIC TITLE ]-\n"
u"\n"
@@ -280,7 +285,7 @@ def test_text_builder(app, status, warning):
# --- docfields
result = (app.outdir / 'docfields.txt').text(encoding='utf-8')
- expect = (u"\nI18N WITH DOCFIELDS"
+ expect = (u"I18N WITH DOCFIELDS"
u"\n*******************\n"
u"\nclass Cls1\n"
u"\n Parameters:"
@@ -318,6 +323,12 @@ def test_text_builder(app, status, warning):
def test_gettext_builder(app, status, warning):
app.builder.build_all()
+ # --- toctree
+ expect = read_po(app.srcdir / 'contents.po')
+ actual = read_po(app.outdir / 'contents.pot')
+ for expect_msg in [m for m in expect if m.id]:
+ yield assert_in, expect_msg.id, [m.id for m in actual if m.id]
+
# --- definition terms: regression test for #2198, #2205
expect = read_po(app.srcdir / 'definition_terms.po')
actual = read_po(app.outdir / 'definition_terms.pot')
@@ -338,11 +349,25 @@ def test_gettext_builder(app, status, warning):
for expect_msg in [m for m in expect if m.id]:
yield assert_in, expect_msg.id, [m.id for m in actual if m.id]
+ # --- gettext builder always ignores ``only`` directive
+ expect = read_po(app.srcdir / 'only.po')
+ actual = read_po(app.outdir / 'only.pot')
+ for expect_msg in [m for m in expect if m.id]:
+ yield assert_in, expect_msg.id, [m.id for m in actual if m.id]
+
@gen_with_intl_app('html', freshenv=True)
def test_html_builder(app, status, warning):
app.builder.build_all()
+ # --- test for meta
+
+ result = (app.outdir / 'contents.html').text(encoding='utf-8')
+ expected_expr = '<meta content="TESTDATA FOR I18N" name="description" />'
+ yield assert_in, expected_expr, result
+ expected_expr = '<meta content="I18N, SPHINX, MARKUP" name="keywords" />'
+ yield assert_in, expected_expr, result
+
# --- test for #955 cant-build-html-with-footnotes-when-using
# expect no error by build
@@ -373,7 +398,10 @@ def test_html_builder(app, status, warning):
start_tag = "<%s[^>]*>" % tag
end_tag = "</%s>" % tag
return r"%s\s*%s\s*%s" % (start_tag, keyword, end_tag)
-
+ def wrap_nest(parenttag, childtag, keyword):
+ start_tag1 = "<%s[^>]*>" % parenttag
+ start_tag2 = "<%s[^>]*>" % childtag
+ return r"%s\s*%s\s*%s" % (start_tag1, keyword, start_tag2)
expected_exprs = [
wrap('a', 'NEWSLETTER'),
wrap('a', 'MAILING LIST'),
@@ -381,8 +409,8 @@ def test_html_builder(app, status, warning):
wrap('a', 'FIRST SECOND'),
wrap('a', 'SECOND THIRD'),
wrap('a', 'THIRD, FIRST'),
- wrap('dt', 'ENTRY'),
- wrap('dt', 'SEE'),
+ wrap_nest('li', 'ul', 'ENTRY'),
+ wrap_nest('li', 'ul', 'SEE'),
wrap('a', 'MODULE'),
wrap('a', 'KEYWORD'),
wrap('a', 'OPERATOR'),
@@ -603,7 +631,7 @@ def test_xml_builder(app, status, warning):
yield (assert_elem,
para2[3],
['LINK TO', '--module', 'AND', '-m', '.'],
- ['cmdoption--module', 'cmdoption-m'])
+ ['cmdoption-module', 'cmdoption-m'])
yield (assert_elem,
para2[4],
['LINK TO', 'env2', 'AND', 'env1', '.'],
diff --git a/tests/test_markup.py b/tests/test_markup.py
index 2fde2306c..ec203447f 100644
--- a/tests/test_markup.py
+++ b/tests/test_markup.py
@@ -15,31 +15,35 @@ import pickle
from docutils import frontend, utils, nodes
from docutils.parsers import rst
+from sphinx import addnodes
from sphinx.util import texescape
+from sphinx.util.docutils import sphinx_domains
from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator
from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator
from util import TestApp, with_app, assert_node
-app = settings = parser = None
+app = settings = parser = domain_context = None
def setup_module():
- global app, settings, parser
+ global app, settings, parser, domain_context
texescape.init() # otherwise done by the latex builder
app = TestApp()
optparser = frontend.OptionParser(
components=(rst.Parser, HTMLWriter, LaTeXWriter))
settings = optparser.get_default_values()
settings.env = app.builder.env
- settings.env.patch_lookup_functions()
settings.env.temp_data['docname'] = 'dummy'
parser = rst.Parser()
+ domain_context = sphinx_domains(settings.env)
+ domain_context.enable()
def teardown_module():
app.cleanup()
+ domain_context.disable()
# since we're not resolving the markup afterwards, these nodes may remain
@@ -101,7 +105,7 @@ def test_inline():
'<p><code class="samp docutils literal"><span class="pre">a</span>'
'<em><span class="pre">b</span></em>'
'<span class="pre">c</span></code></p>',
- '\\sphinxcode{a\\emph{b}c}')
+ '\\sphinxcode{a\\sphinxstyleemphasis{b}c}')
# interpolation of arrows in menuselection
yield (verify, ':menuselection:`a --> b`',
@@ -131,7 +135,7 @@ def test_inline():
# verify classes for inline roles
yield (verify, ':manpage:`mp(1)`',
'<p><em class="manpage">mp(1)</em></p>',
- '\\emph{\\texttt{mp(1)}}')
+ '\\sphinxstyleliteralemphasis{mp(1)}')
def test_latex_escaping():
@@ -140,9 +144,9 @@ def test_latex_escaping():
r'\(\Gamma\)\textbackslash{}\(\infty\)\$')
# in verbatim code fragments
yield (verify, u'::\n\n @Γ\\∞${}', None,
- u'\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n'
+ u'\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]\n'
u'@\\(\\Gamma\\)\\PYGZbs{}\\(\\infty\\)\\PYGZdl{}\\PYGZob{}\\PYGZcb{}\n'
- u'\\end{Verbatim}')
+ u'\\end{sphinxVerbatim}')
# in URIs
yield (verify_re, u'`test <http://example.com/~me/>`_', None,
r'\\href{http://example.com/~me/}{test}.*')
@@ -170,3 +174,39 @@ def test_rst_prolog(app, status, warning):
# rst_prolog & rst_epilog on exlucding reST parser
assert not md.rawsource.startswith('*Hello world*.')
assert not md.rawsource.endswith('*Good-bye world*.\n')
+
+
+@with_app(buildername='dummy', testroot='keep_warnings')
+def test_keep_warnings_is_True(app, status, warning):
+ app.builder.build_all()
+ doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())
+ assert_node(doctree[0], nodes.section)
+ assert len(doctree[0]) == 2
+ assert_node(doctree[0][1], nodes.system_message)
+
+
+@with_app(buildername='dummy', testroot='keep_warnings',
+ confoverrides={'keep_warnings': False})
+def test_keep_warnings_is_False(app, status, warning):
+ app.builder.build_all()
+ doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())
+ assert_node(doctree[0], nodes.section)
+ assert len(doctree[0]) == 1
+
+
+@with_app(buildername='dummy', testroot='refonly_bullet_list')
+def test_compact_refonly_bullet_list(app, status, warning):
+ app.builder.build_all()
+ doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())
+ assert_node(doctree[0], nodes.section)
+ assert len(doctree[0]) == 5
+
+ assert doctree[0][1].astext() == 'List A:'
+ assert_node(doctree[0][2], nodes.bullet_list)
+ assert_node(doctree[0][2][0][0], addnodes.compact_paragraph)
+ assert doctree[0][2][0][0].astext() == 'genindex'
+
+ assert doctree[0][3].astext() == 'List B:'
+ assert_node(doctree[0][4], nodes.bullet_list)
+ assert_node(doctree[0][4][0][0], nodes.paragraph)
+ assert doctree[0][4][0][0].astext() == 'Hello'
diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py
index ac6507ce5..7a77ce225 100644
--- a/tests/test_quickstart.py
+++ b/tests/test_quickstart.py
@@ -298,3 +298,16 @@ def test_default_filename(tempdir):
assert ns['latex_documents'][0][1] == 'sphinx.tex'
assert ns['man_pages'][0][1] == 'sphinx'
assert ns['texinfo_documents'][0][1] == 'sphinx'
+
+
+@with_tempdir
+def test_extensions(tempdir):
+ qs.main(['sphinx-quickstart', '-q',
+ '-p', 'project_name', '-a', 'author',
+ '--extensions', 'foo,bar,baz', tempdir])
+
+ conffile = tempdir / 'conf.py'
+ assert conffile.isfile()
+ ns = {}
+ execfile_(conffile, ns)
+ assert ns['extensions'] == ['foo', 'bar', 'baz']
diff --git a/tests/test_search.py b/tests/test_search.py
index b7c38674f..fb7d47d6f 100644
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+import os
from docutils import frontend, utils
from docutils.parsers import rst
@@ -28,6 +29,17 @@ def setup_module():
parser = rst.Parser()
+def jsload(path):
+ searchindex = path.text()
+ assert searchindex.startswith('Search.setIndex(')
+
+ return jsdump.loads(searchindex[16:-2])
+
+
+def is_registered_term(index, keyword):
+ return index['terms'].get(keyword, []) != []
+
+
FILE_CONTENTS = '''\
.. test that comments are not indexed: boson
@@ -41,7 +53,7 @@ def test_wordcollector():
parser.parse(FILE_CONTENTS, doc)
ix = IndexBuilder(None, 'en', {}, None)
- ix.feed('filename', 'title', doc)
+ ix.feed('docname', 'filename', 'title', doc)
assert 'boson' not in ix._mapping
assert 'fermion' in ix._mapping
@@ -54,3 +66,62 @@ def test_objects_are_escaped(app, status, warning):
index = jsdump.loads(searchindex[16:-2])
assert 'n::Array&lt;T, d&gt;' in index.get('objects').get('') # n::Array<T,d> is escaped
+
+
+@with_app(testroot='search')
+def test_meta_keys_are_handled_for_language_en(app, status, warning):
+ app.builder.build_all()
+ searchindex = jsload(app.outdir / 'searchindex.js')
+ assert not is_registered_term(searchindex, 'thisnoteith')
+ assert is_registered_term(searchindex, 'thisonetoo')
+ assert is_registered_term(searchindex, 'findthiskei')
+ assert is_registered_term(searchindex, 'thistoo')
+ assert not is_registered_term(searchindex, 'onlygerman')
+ assert is_registered_term(searchindex, 'notgerman')
+ assert not is_registered_term(searchindex, 'onlytoogerman')
+
+
+@with_app(testroot='search', confoverrides={'html_search_language': 'de'})
+def test_meta_keys_are_handled_for_language_de(app, status, warning):
+ app.builder.build_all()
+ searchindex = jsload(app.outdir / 'searchindex.js')
+ assert not is_registered_term(searchindex, 'thisnoteith')
+ assert is_registered_term(searchindex, 'thisonetoo')
+ assert not is_registered_term(searchindex, 'findthiskei')
+ assert not is_registered_term(searchindex, 'thistoo')
+ assert is_registered_term(searchindex, 'onlygerman')
+ assert not is_registered_term(searchindex, 'notgerman')
+ assert is_registered_term(searchindex, 'onlytoogerman')
+
+
+@with_app(testroot='search')
+def test_stemmer_does_not_remove_short_words(app, status, warning):
+ app.builder.build_all()
+ searchindex = (app.outdir / 'searchindex.js').text()
+ assert 'zfs' in searchindex
+
+
+@with_app(testroot='search')
+def test_stemmer(app, status, warning):
+ searchindex = jsload(app.outdir / 'searchindex.js')
+ print(searchindex)
+ assert is_registered_term(searchindex, 'findthisstemmedkei')
+ assert is_registered_term(searchindex, 'intern')
+
+
+@with_app(testroot='search')
+def test_term_in_heading_and_section(app, status, warning):
+ searchindex = (app.outdir / 'searchindex.js').text()
+ # if search term is in the title of one doc and in the text of another
+ # both documents should be a hit in the search index as a title,
+ # respectively text hit
+ assert 'textinhead:1' in searchindex
+ assert 'textinhead:0' in searchindex
+
+
+@with_app(testroot='search')
+def test_term_in_raw_directive(app, status, warning):
+ searchindex = jsload(app.outdir / 'searchindex.js')
+ assert not is_registered_term(searchindex, 'raw')
+ assert is_registered_term(searchindex, 'rawword')
+ assert not is_registered_term(searchindex, 'latex_keyword')
diff --git a/tests/test_searchadapters.py b/tests/test_searchadapters.py
index 78f9b64ab..ee350182f 100644
--- a/tests/test_searchadapters.py
+++ b/tests/test_searchadapters.py
@@ -41,7 +41,7 @@ def search_adapter_helper(adapter):
# Make sure documents are properly updated by the search adapter.
s.init_indexing(changed=['markup'])
- s.add_document(u'markup', u'title', u'SomeLongRandomWord')
+ s.add_document(u'markup', u'filename', u'title', u'SomeLongRandomWord')
s.finish_indexing()
# Now a search for "Epigraph" should return zero results.
results = s.query(u'Epigraph')
diff --git a/tests/test_setup_command.py b/tests/test_setup_command.py
index 77c9ade46..c92f6220f 100644
--- a/tests/test_setup_command.py
+++ b/tests/test_setup_command.py
@@ -108,3 +108,25 @@ def test_build_sphinx_return_nonzero_status(pkgroot, proc):
print(out)
print(err)
assert proc.returncode != 0, 'expect non-zero status for setup.py'
+
+
+@with_setup_command(root)
+def test_build_sphinx_warning_return_zero_status(pkgroot, proc):
+ srcdir = (pkgroot / 'doc')
+ (srcdir / 'contents.txt').write_text(
+ 'See :ref:`unexisting-reference-label`')
+ out, err = proc.communicate()
+ print(out)
+ print(err)
+ assert proc.returncode == 0
+
+
+@with_setup_command(root, '--warning-is-error')
+def test_build_sphinx_warning_is_error_return_nonzero_status(pkgroot, proc):
+ srcdir = (pkgroot / 'doc')
+ (srcdir / 'contents.txt').write_text(
+ 'See :ref:`unexisting-reference-label`')
+ out, err = proc.communicate()
+ print(out)
+ print(err)
+ assert proc.returncode != 0, 'expect non-zero status for setup.py'
diff --git a/tests/test_theming.py b/tests/test_theming.py
index 07787ecca..b62cbcd72 100644
--- a/tests/test_theming.py
+++ b/tests/test_theming.py
@@ -12,9 +12,11 @@
import os
import zipfile
+import mock
+
from sphinx.theming import Theme, ThemeError
-from util import with_app, raises, mock, path
+from util import with_app, raises, path
@with_app(confoverrides={'html_theme': 'ziptheme',
@@ -26,7 +28,7 @@ def test_theme_api(app, status, warning):
assert set(Theme.themes.keys()) == \
set(['basic', 'default', 'scrolls', 'agogo', 'sphinxdoc', 'haiku',
'traditional', 'testtheme', 'ziptheme', 'epub', 'nature',
- 'pyramid', 'bizstyle', 'classic'])
+ 'pyramid', 'bizstyle', 'classic', 'nonav'])
assert Theme.themes['testtheme'][1] is None
assert isinstance(Theme.themes['ziptheme'][1], zipfile.ZipFile)
@@ -66,7 +68,7 @@ def test_js_source(app, status, warning):
app.builder.build(['contents'])
- v = '1.11.1'
+ v = '3.1.0'
msg = 'jquery.js version does not match to {v}'.format(v=v)
jquery_min = (app.outdir / '_static' / 'jquery.js').text()
assert 'jQuery v{v}'.format(v=v) in jquery_min, msg
diff --git a/tests/test_util_fileutil.py b/tests/test_util_fileutil.py
new file mode 100644
index 000000000..5810dd2a8
--- /dev/null
+++ b/tests/test_util_fileutil.py
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+"""
+ test_util_fileutil
+ ~~~~~~~~~~~~~~~~~~
+
+ Tests sphinx.util.fileutil functions.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+from sphinx.util.fileutil import copy_asset, copy_asset_file
+from sphinx.jinja2glue import BuiltinTemplateLoader
+
+import mock
+from util import with_tempdir
+
+
+class DummyTemplateLoader(BuiltinTemplateLoader):
+ def __init__(self):
+ BuiltinTemplateLoader.__init__(self)
+ builder = mock.Mock()
+ builder.config.templates_path = []
+ builder.app.translater = None
+ self.init(builder)
+
+
+@with_tempdir
+def test_copy_asset_file(tmpdir):
+ renderer = DummyTemplateLoader()
+
+ # copy normal file
+ src = (tmpdir / 'asset.txt')
+ src.write_text('# test data')
+ dest = (tmpdir / 'output.txt')
+
+ copy_asset_file(src, dest)
+ assert dest.exists()
+ assert src.text() == dest.text()
+
+ # copy template file
+ src = (tmpdir / 'asset.txt_t')
+ src.write_text('# {{var1}} data')
+ dest = (tmpdir / 'output.txt_t')
+
+ copy_asset_file(src, dest, {'var1': 'template'}, renderer)
+ assert not dest.exists()
+ assert (tmpdir / 'output.txt').exists()
+ assert (tmpdir / 'output.txt').text() == '# template data'
+
+ # copy template file to subdir
+ src = (tmpdir / 'asset.txt_t')
+ src.write_text('# {{var1}} data')
+ subdir1 = (tmpdir / 'subdir')
+ subdir1.makedirs()
+
+ copy_asset_file(src, subdir1, {'var1': 'template'}, renderer)
+ assert (subdir1 / 'asset.txt').exists()
+ assert (subdir1 / 'asset.txt').text() == '# template data'
+
+ # copy template file without context
+ src = (tmpdir / 'asset.txt_t')
+ subdir2 = (tmpdir / 'subdir2')
+ subdir2.makedirs()
+
+ copy_asset_file(src, subdir2)
+ assert not (subdir2 / 'asset.txt').exists()
+ assert (subdir2 / 'asset.txt_t').exists()
+ assert (subdir2 / 'asset.txt_t').text() == '# {{var1}} data'
+
+
+@with_tempdir
+def test_copy_asset(tmpdir):
+ renderer = DummyTemplateLoader()
+
+ # prepare source files
+ source = (tmpdir / 'source')
+ source.makedirs()
+ (source / 'index.rst').write_text('index.rst')
+ (source / 'foo.rst_t').write_text('{{var1}}.rst')
+ (source / '_static').makedirs()
+ (source / '_static' / 'basic.css').write_text('basic.css')
+ (source / '_templates').makedirs()
+ (source / '_templates' / 'layout.html').write_text('layout.html')
+ (source / '_templates' / 'sidebar.html_t').write_text('sidebar: {{var2}}')
+
+ # copy a single file
+ assert not (tmpdir / 'test1').exists()
+ copy_asset(source / 'index.rst', tmpdir / 'test1')
+ assert (tmpdir / 'test1').exists()
+ assert (tmpdir / 'test1/index.rst').exists()
+
+ # copy directories
+ destdir = tmpdir / 'test2'
+ copy_asset(source, destdir, context=dict(var1='bar', var2='baz'), renderer=renderer)
+ assert (destdir / 'index.rst').exists()
+ assert (destdir / 'foo.rst').exists()
+ assert (destdir / 'foo.rst').text() == 'bar.rst'
+ assert (destdir / '_static' / 'basic.css').exists()
+ assert (destdir / '_templates' / 'layout.html').exists()
+ assert (destdir / '_templates' / 'sidebar.html').exists()
+ assert (destdir / '_templates' / 'sidebar.html').text() == 'sidebar: baz'
+
+ # copy with exclusion
+ def excluded(path):
+ return ('sidebar.html' in path or 'basic.css' in path)
+
+ destdir = tmpdir / 'test3'
+ copy_asset(source, destdir, excluded,
+ context=dict(var1='bar', var2='baz'), renderer=renderer)
+ assert (destdir / 'index.rst').exists()
+ assert (destdir / 'foo.rst').exists()
+ assert not (destdir / '_static' / 'basic.css').exists()
+ assert (destdir / '_templates' / 'layout.html').exists()
+ assert not (destdir / '_templates' / 'sidebar.html').exists()
diff --git a/tests/test_util_i18n.py b/tests/test_util_i18n.py
index 3e0cfd5f3..849796a8f 100644
--- a/tests/test_util_i18n.py
+++ b/tests/test_util_i18n.py
@@ -255,6 +255,18 @@ def test_get_filename_for_language():
'../foo.png', app.env) == 'images/en/../foo.png'
assert i18n.get_image_filename_for_language('foo', app.env) == 'images/en/foo'
+ # new path and basename tokens
+ app.env.config.language = 'en'
+ app.env.config.figure_language_filename = '{path}{language}/{basename}{ext}'
+ assert i18n.get_image_filename_for_language('foo.png', app.env) == 'en/foo.png'
+ assert i18n.get_image_filename_for_language(
+ 'foo.bar.png', app.env) == 'en/foo.bar.png'
+ assert i18n.get_image_filename_for_language(
+ 'subdir/foo.png', app.env) == 'subdir/en/foo.png'
+ assert i18n.get_image_filename_for_language(
+ '../foo.png', app.env) == '../en/foo.png'
+ assert i18n.get_image_filename_for_language('foo', app.env) == 'en/foo'
+
# invalid figure_language_filename
app.env.config.figure_language_filename = '{root}.{invalid}{ext}'
raises(SphinxError, i18n.get_image_filename_for_language, 'foo.png', app.env)
diff --git a/tests/test_util_matching.py b/tests/test_util_matching.py
new file mode 100644
index 000000000..9e99a5322
--- /dev/null
+++ b/tests/test_util_matching.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+"""
+ test_util_matching
+ ~~~~~~~~~~~~~~~~~~
+
+ Tests sphinx.util.matching functions.
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+from sphinx.util.matching import compile_matchers, Matcher
+
+
+def test_compile_matchers():
+ # exact matching
+ pat = compile_matchers(['hello.py']).pop()
+ assert pat('hello.py')
+ assert not pat('hello-py')
+ assert not pat('subdir/hello.py')
+
+ # wild card (*)
+ pat = compile_matchers(['hello.*']).pop()
+ assert pat('hello.py')
+ assert pat('hello.rst')
+
+ pat = compile_matchers(['*.py']).pop()
+ assert pat('hello.py')
+ assert pat('world.py')
+ assert not pat('subdir/hello.py')
+
+ # wild card (**)
+ pat = compile_matchers(['hello.**']).pop()
+ assert pat('hello.py')
+ assert pat('hello.rst')
+ assert pat('hello.py/world.py')
+
+ pat = compile_matchers(['**.py']).pop()
+ assert pat('hello.py')
+ assert pat('world.py')
+ assert pat('subdir/hello.py')
+
+ pat = compile_matchers(['**/hello.py']).pop()
+ assert not pat('hello.py')
+ assert pat('subdir/hello.py')
+ assert pat('subdir/subdir/hello.py')
+
+ # wild card (?)
+ pat = compile_matchers(['hello.?']).pop()
+ assert pat('hello.c')
+ assert not pat('hello.py')
+
+ # pattern ([...])
+ pat = compile_matchers(['hello[12\\].py']).pop()
+ assert pat('hello1.py')
+ assert pat('hello2.py')
+ assert pat('hello\\.py')
+ assert not pat('hello3.py')
+
+ pat = compile_matchers(['hello[^12].py']).pop() # "^" is not negative identifier
+ assert pat('hello1.py')
+ assert pat('hello2.py')
+ assert pat('hello^.py')
+ assert not pat('hello3.py')
+
+ # negative pattern ([!...])
+ pat = compile_matchers(['hello[!12].py']).pop()
+ assert not pat('hello1.py')
+ assert not pat('hello2.py')
+ assert not pat('hello/.py') # negative pattern does not match to "/"
+ assert pat('hello3.py')
+
+ # non patterns
+ pat = compile_matchers(['hello[.py']).pop()
+ assert pat('hello[.py')
+ assert not pat('hello.py')
+
+ pat = compile_matchers(['hello[].py']).pop()
+ assert pat('hello[].py')
+ assert not pat('hello.py')
+
+ pat = compile_matchers(['hello[!].py']).pop()
+ assert pat('hello[!].py')
+ assert not pat('hello.py')
+
+
+def test_Matcher():
+ matcher = Matcher(['hello.py', '**/world.py'])
+ assert matcher('hello.py')
+ assert not matcher('subdir/hello.py')
+ assert matcher('world.py')
+ assert matcher('subdir/world.py')
diff --git a/tests/test_writer_latex.py b/tests/test_writer_latex.py
new file mode 100644
index 000000000..72eb7ed2a
--- /dev/null
+++ b/tests/test_writer_latex.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+"""
+ test_writer_latex
+ ~~~~~~~~~~~~~~~~
+
+ Test the LaTeX writer
+
+ :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+from __future__ import print_function
+from sphinx.writers.latex import rstdim_to_latexdim
+
+from util import raises
+
+
+def test_rstdim_to_latexdim():
+ # Length units docutils supported
+ # http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#length-units
+ assert rstdim_to_latexdim('160em') == '160em'
+ assert rstdim_to_latexdim('160px') == '160\\sphinxpxdimen'
+ assert rstdim_to_latexdim('160in') == '160in'
+ assert rstdim_to_latexdim('160cm') == '160cm'
+ assert rstdim_to_latexdim('160mm') == '160mm'
+ assert rstdim_to_latexdim('160pt') == '160bp'
+ assert rstdim_to_latexdim('160pc') == '160pc'
+ assert rstdim_to_latexdim('30%') == '0.300\\linewidth'
+ assert rstdim_to_latexdim('160') == '160\\sphinxpxdimen'
+
+ # flaot values
+ assert rstdim_to_latexdim('160.0em') == '160.0em'
+ assert rstdim_to_latexdim('.5em') == '.5em'
+
+ # unknown values (it might be generated by 3rd party extension)
+ raises(ValueError, rstdim_to_latexdim, 'unknown')
+ assert rstdim_to_latexdim('160.0unknown') == '160.0unknown'
diff --git a/tests/typing_test_data.py b/tests/typing_test_data.py
index 3c3126b07..84bb3377b 100644
--- a/tests/typing_test_data.py
+++ b/tests/typing_test_data.py
@@ -35,20 +35,24 @@ def f5(x: int, *, y: str, z: str) -> None:
pass
-def f6(x: int = None, y: dict = {}) -> None:
+def f6(x: int, *args, y: str, z: str) -> None:
pass
-def f7(x: Callable[[int, str], int]) -> None:
+def f7(x: int = None, y: dict = {}) -> None:
+ pass
+
+
+def f8(x: Callable[[int, str], int]) -> None:
# See https://github.com/ambv/typehinting/issues/149 for Callable[..., int]
pass
-def f8(x: Callable) -> None:
+def f9(x: Callable) -> None:
pass
-def f9(x: Tuple[int, str], y: Tuple[int, ...]) -> None:
+def f10(x: Tuple[int, str], y: Tuple[int, ...]) -> None:
pass
@@ -57,5 +61,5 @@ class CustomAnnotation:
return 'CustomAnnotation'
-def f10(x: CustomAnnotation(), y: 123) -> None:
+def f11(x: CustomAnnotation(), y: 123) -> None:
pass
diff --git a/tests/util.py b/tests/util.py
index cb0d3f7a0..120492d47 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -13,7 +13,7 @@ import sys
import tempfile
from functools import wraps
-from six import StringIO
+from six import StringIO, string_types
from nose import tools, SkipTest
@@ -28,12 +28,6 @@ from sphinx.pycode import ModuleAnalyzer
from path import path, repr_as # NOQA
-try:
- # Python >=3.3
- from unittest import mock
-except ImportError:
- import mock
-
__all__ = [
'rootdir', 'tempdir', 'raises', 'raises_msg',
@@ -41,7 +35,6 @@ __all__ = [
'ListOutput', 'TestApp', 'with_app', 'gen_with_app',
'path', 'with_tempdir',
'sprint', 'remove_unicode_literals',
- 'mock',
]
@@ -94,14 +87,33 @@ def assert_startswith(thing, prefix):
assert False, '%r does not start with %r' % (thing, prefix)
-def assert_node(node, cls=None, **kwargs):
+def assert_node(node, cls=None, xpath="", **kwargs):
if cls:
- assert isinstance(node, cls), '%r is not subclass of %r' % (node, cls)
+ if isinstance(cls, list):
+ assert_node(node, cls[0], xpath=xpath, **kwargs)
+ if cls[1:]:
+ if isinstance(cls[1], tuple):
+ assert_node(node, cls[1], xpath=xpath, **kwargs)
+ else:
+ assert len(node) == 1, \
+ 'The node%s has %d child nodes, not one' % (xpath, len(node))
+ assert_node(node[0], cls[1:], xpath=xpath + "[0]", **kwargs)
+ elif isinstance(cls, tuple):
+ assert len(node) == len(cls), \
+ 'The node%s has %d child nodes, not %r' % (xpath, len(node), len(cls))
+ for i, nodecls in enumerate(cls):
+ path = xpath + "[%d]" % i
+ assert_node(node[i], nodecls, xpath=path, **kwargs)
+ elif isinstance(cls, string_types):
+ assert node == cls, 'The node %r is not %r: %r' % (xpath, cls, node)
+ else:
+ assert isinstance(node, cls), \
+ 'The node%s is not subclass of %r: %r' % (xpath, cls, node)
for key, value in kwargs.items():
- assert key in node, '%r does not have %r attribute' % (node, key)
+ assert key in node, 'The node%s does not have %r attribute: %r' % (xpath, key, node)
assert node[key] == value, \
- '%r[%s]: %r does not equals %r' % (node, key, node[key], value)
+ 'The node%s[%s] is not %r: %r' % (xpath, key, value, node[key])
try:
@@ -309,3 +321,7 @@ def find_files(root, suffix=None):
for f in [f for f in files if not suffix or f.endswith(suffix)]:
fpath = dirpath / f
yield os.path.relpath(fpath, root)
+
+
+def strip_escseq(text):
+ return re.sub('\x1b.*?m', '', text)
diff --git a/tox.ini b/tox.ini
index 112017b77..ca3cac99b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,11 +1,15 @@
[tox]
-envlist=flake8,py26,py27,py33,py34,py35,pypy,du12,du11,du10
+envlist=flake8,py27,py34,py35,pypy,du12,du11,du10
[testenv]
deps=
+ six
nose
+ docutils
sqlalchemy
whoosh
+ html5lib
+ mock
typing
setenv =
SPHINX_TEST_TEMPDIR = {envdir}/testbuild
@@ -13,37 +17,23 @@ commands=
{envpython} tests/run.py -I py35 -m '^[tT]est' {posargs}
sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html
-[testenv:py26]
-deps=
- mock
- {[testenv]deps}
-
-[testenv:py27]
-deps=
- mock
- {[testenv]deps}
-
[testenv:pypy]
deps=
- mock
simplejson
{[testenv]deps}
[testenv:du10]
deps=
- mock
docutils==0.10
{[testenv]deps}
[testenv:du11]
deps=
- mock
docutils==0.11
{[testenv]deps}
[testenv:du12]
deps=
- mock
docutils==0.12
{[testenv]deps}
@@ -51,6 +41,11 @@ deps=
deps=flake8
commands=flake8
+[testenv:py27]
+deps=
+ enum34
+ {[testenv]deps}
+
[testenv:py35]
commands=
{envpython} tests/run.py -m '^[tT]est' {posargs}
diff --git a/utils/check_sources.py b/utils/check_sources.py
index 16bc918cb..18d444057 100755
--- a/utils/check_sources.py
+++ b/utils/check_sources.py
@@ -223,11 +223,8 @@ def main(argv):
print("Checking %s..." % fn)
try:
- f = open(fn, 'rb')
- try:
+ with open(fn, 'rb') as f:
lines = list(f)
- finally:
- f.close()
except (IOError, OSError) as err:
print("%s: cannot open: %s" % (fn, err))
num += 1
diff --git a/utils/reindent.py b/utils/reindent.py
index 9af46d3fc..a4fe93e24 100755
--- a/utils/reindent.py
+++ b/utils/reindent.py
@@ -127,8 +127,8 @@ def check(file):
errprint("%s: I/O Error: %s" % (file, str(msg)))
return
- r = Reindenter(f)
- f.close()
+ with f:
+ r = Reindenter(f)
if r.run():
if verbose:
print("changed.")
@@ -140,9 +140,8 @@ def check(file):
shutil.copyfile(file, bak)
if verbose:
print("backed up", file, "to", bak)
- f = open(file, "w")
- r.write(f)
- f.close()
+ with open(file, "w") as f:
+ r.write(f)
if verbose:
print("wrote new", file)
return True
diff --git a/utils/release-checklist b/utils/release-checklist
index 3dd52158c..b73a191f9 100644
--- a/utils/release-checklist
+++ b/utils/release-checklist
@@ -9,6 +9,7 @@ Release checklist
* Update release date in CHANGES
* `git commit -am 'Bump to x.y.z final'`
* `make clean`
+* `python setup.py compile_grammar`
* `python setup.py release bdist_wheel sdist upload --identity=[your key]`
* Check PyPI release page for obvious errors
* `git tag` with version number