From adbf5e6de33cd6a6b6faffedb6453c3f0de4b6e6 Mon Sep 17 00:00:00 2001 From: Daniel Fremont Date: Sun, 12 Apr 2020 10:58:22 -0700 Subject: [PATCH 01/40] autosummary includes module attributes --- sphinx/ext/autosummary/generate.py | 15 +++++++++++++++ .../autosummary/templates/autosummary/module.rst | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 7b128bea5..bbc1c409b 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -197,6 +197,21 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, get_members(obj, {'class'}, imported=imported_members) ns['exceptions'], ns['all_exceptions'] = \ get_members(obj, {'exception'}, imported=imported_members) + + # Find module attributes with docstrings + attrs, public = [], [] + from sphinx.pycode import ModuleAnalyzer, PycodeError + try: + analyzer = ModuleAnalyzer.for_module(name) + attr_docs = analyzer.find_attr_docs() + for _, attr_name in attr_docs: + if attr_name in ns['members']: + attrs.append(attr_name) + if not attr_name.startswith('_'): + public.append(attr_name) + except PycodeError as err: + pass + ns['attributes'], ns['all_attributes'] = attrs, public elif doc.objtype == 'class': ns['members'] = dir(obj) ns['inherited_members'] = \ diff --git a/sphinx/ext/autosummary/templates/autosummary/module.rst b/sphinx/ext/autosummary/templates/autosummary/module.rst index 6ec89e05e..2eff53843 100644 --- a/sphinx/ext/autosummary/templates/autosummary/module.rst +++ b/sphinx/ext/autosummary/templates/autosummary/module.rst @@ -2,6 +2,17 @@ .. automodule:: {{ fullname }} + {% block attributes %} + {% if attributes %} + .. rubric:: Module Attributes + + .. autosummary:: + {% for item in attributes %} + {{item}} + {%- endfor %} + {% endif %} + {% endblock %} + {% block functions %} {% if functions %} .. rubric:: Functions From 8ee7d908f3deefb90c9d75453b190f13c89a8142 Mon Sep 17 00:00:00 2001 From: Daniel Fremont Date: Sun, 12 Apr 2020 12:06:14 -0700 Subject: [PATCH 02/40] updated corresponding documentation --- doc/usage/extensions/autosummary.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/usage/extensions/autosummary.rst b/doc/usage/extensions/autosummary.rst index cedc8a42f..c3a0bfed8 100644 --- a/doc/usage/extensions/autosummary.rst +++ b/doc/usage/extensions/autosummary.rst @@ -260,8 +260,8 @@ The following variables available in the templates: .. data:: attributes - List containing names of "public" attributes in the class. Only available - for classes. + List containing names of "public" attributes in the class/module. Only + available for classes and modules. Additionally, the following filters are available From 3a81ffa79afc42a409bb073a8ad83bbaefb271c4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 10 May 2020 23:10:18 +0900 Subject: [PATCH 03/40] Fix #7650: autodoc: undecorated signature is shown for decorated functions --- CHANGES | 1 + sphinx/ext/autodoc/__init__.py | 27 ++++++++++++------- sphinx/util/inspect.py | 11 ++++++-- .../test-ext-autodoc/target/decorator.py | 15 +++++++++++ tests/test_ext_autodoc.py | 25 ++++++++++++++++- tests/test_util_inspect.py | 2 +- 6 files changed, 68 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index ab978ac87..8b0e7e20f 100644 --- a/CHANGES +++ b/CHANGES @@ -88,6 +88,7 @@ Bugs fixed autodoc_typehints='description' mode * #7551: autodoc: failed to import nested class * #7362: autodoc: does not render correct signatures for built-in functions +* #7650: autodoc: undecorated signature is shown for decorated functions * #7551: autosummary: a nested class is indexed as non-nested class * #7535: sphinx-autogen: crashes when custom template uses inheritance * #7536: sphinx-autogen: crashes when template uses i18n feature diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 80bcc0e8d..952a0e71b 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1051,10 +1051,12 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ if self.env.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) - unwrapped = inspect.unwrap(self.object) try: - self.env.app.emit('autodoc-before-process-signature', unwrapped, False) - sig = inspect.signature(unwrapped) + self.env.app.emit('autodoc-before-process-signature', self.object, False) + if inspect.is_singledispatch_function(self.object): + sig = inspect.signature(self.object, follow_wrapped=True) + else: + sig = inspect.signature(self.object) args = stringify_signature(sig, **kwargs) except TypeError: args = '' @@ -1447,7 +1449,6 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: if self.env.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) - unwrapped = inspect.unwrap(self.object) try: if self.object == object.__init__ and self.parent != object: # Classes not having own __init__() method are shown as no arguments. @@ -1456,12 +1457,18 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: # But it makes users confused. args = '()' else: - if inspect.isstaticmethod(unwrapped, cls=self.parent, name=self.object_name): - self.env.app.emit('autodoc-before-process-signature', unwrapped, False) - sig = inspect.signature(unwrapped, bound_method=False) + if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name): + self.env.app.emit('autodoc-before-process-signature', self.object, False) + sig = inspect.signature(self.object, bound_method=False) else: - self.env.app.emit('autodoc-before-process-signature', unwrapped, True) - sig = inspect.signature(unwrapped, bound_method=True) + self.env.app.emit('autodoc-before-process-signature', self.object, True) + + meth = self.parent.__dict__.get(self.objpath[-1], None) + if meth and inspect.is_singledispatch_method(meth): + sig = inspect.signature(self.object, bound_method=True, + follow_wrapped=True) + else: + sig = inspect.signature(self.object, bound_method=True) args = stringify_signature(sig, **kwargs) except ValueError: args = '' @@ -1514,7 +1521,9 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: self.annotate_to_first_argument(func, typ) documenter = MethodDocumenter(self.directive, '') + documenter.parent = self.parent documenter.object = func + documenter.objpath = self.objpath self.add_line(' %s%s' % (self.format_name(), documenter.format_signature()), sourcename) diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 42defa6f8..6ba698eed 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -408,13 +408,20 @@ def is_builtin_class_method(obj: Any, attr_name: str) -> bool: return getattr(builtins, name, None) is cls -def signature(subject: Callable, bound_method: bool = False) -> inspect.Signature: +def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = False + ) -> inspect.Signature: """Return a Signature object for the given *subject*. :param bound_method: Specify *subject* is a bound method or not + :param follow_wrapped: Same as ``inspect.signature()``. + Defaults to ``False`` (get a signature of *subject*). """ try: - signature = inspect.signature(subject) + try: + signature = inspect.signature(subject, follow_wrapped=follow_wrapped) + except ValueError: + # follow built-in wrappers up (ex. functools.lru_cache) + signature = inspect.signature(subject) parameters = list(signature.parameters.values()) return_annotation = signature.return_annotation except IndexError: diff --git a/tests/roots/test-ext-autodoc/target/decorator.py b/tests/roots/test-ext-autodoc/target/decorator.py index 4ccfedf28..61398b324 100644 --- a/tests/roots/test-ext-autodoc/target/decorator.py +++ b/tests/roots/test-ext-autodoc/target/decorator.py @@ -1,5 +1,9 @@ +from functools import wraps + + def deco1(func): """docstring for deco1""" + @wraps(func) def wrapper(): return func() @@ -14,3 +18,14 @@ def deco2(condition, message): return wrapper return decorator + + +@deco1 +def foo(name=None, age=None): + pass + + +class Bar: + @deco1 + def meth(self, name=None, age=None): + pass diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 76b970dbb..f56b84f06 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -142,6 +142,7 @@ def test_format_signature(app): inst = app.registry.documenters[objtype](directive, name) inst.fullname = name inst.doc_as_attr = False # for class objtype + inst.parent = object # dummy inst.object = obj inst.objpath = [name] inst.args = args @@ -1243,6 +1244,17 @@ def test_autofunction_for_methoddescriptor(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autofunction_for_decorated(app): + actual = do_autodoc(app, 'function', 'target.decorator.foo') + assert list(actual) == [ + '', + '.. py:function:: foo()', + ' :module: target.decorator', + '', + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_automethod_for_builtin(app): actual = do_autodoc(app, 'method', 'builtins.int.__add__') @@ -1256,6 +1268,17 @@ def test_automethod_for_builtin(app): ] +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_automethod_for_decorated(app): + actual = do_autodoc(app, 'method', 'target.decorator.Bar.meth') + assert list(actual) == [ + '', + '.. py:method:: Bar.meth()', + ' :module: target.decorator', + '', + ] + + @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_abstractmethods(app): options = {"members": None, @@ -1415,7 +1438,7 @@ def test_coroutine(app): actual = do_autodoc(app, 'function', 'target.coroutine.sync_func') assert list(actual) == [ '', - '.. py:function:: sync_func()', + '.. py:function:: sync_func(*args, **kwargs)', ' :module: target.coroutine', '', ] diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index 1e8f8bd24..ff51dc68e 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -97,7 +97,7 @@ def test_signature_methods(): # wrapped bound method sig = inspect.signature(wrapped_bound_method) - assert stringify_signature(sig) == '(arg1, **kwargs)' + assert stringify_signature(sig) == '(*args, **kwargs)' def test_signature_partialmethod(): From 90dd745cea3d9c4f34db4ff9342bd0c596459469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar?= Date: Sun, 10 May 2020 23:59:46 +0200 Subject: [PATCH 04/40] Fix multiple directory creation on quickstart script called with nested relative path. --- sphinx/cmd/quickstart.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 0c9020bd5..626d07c66 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -11,6 +11,7 @@ import argparse import locale import os +import pathlib import re import sys import time @@ -357,6 +358,7 @@ def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir: d.setdefault('extensions', []) d['copyright'] = time.strftime('%Y') + ', ' + d['author'] + d["path"] = pathlib.Path(d['path']).resolve() ensuredir(d['path']) srcdir = path.join(d['path'], 'source') if d['sep'] else d['path'] From 97bc24500a7e62c34f92da2d53a36221fdd7c95d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar?= Date: Mon, 11 May 2020 00:22:36 +0200 Subject: [PATCH 05/40] Fix py35 incompatibility with PosixPath --- sphinx/cmd/quickstart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 626d07c66..72434c18b 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -358,7 +358,7 @@ def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir: d.setdefault('extensions', []) d['copyright'] = time.strftime('%Y') + ', ' + d['author'] - d["path"] = pathlib.Path(d['path']).resolve() + d["path"] = str(pathlib.Path(d['path']).resolve()) ensuredir(d['path']) srcdir = path.join(d['path'], 'source') if d['sep'] else d['path'] From 182712fe31c686dbcb405a3fa0aa0c4f85ac1e96 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 9 May 2020 22:25:30 +0900 Subject: [PATCH 06/40] Fix #7629: autodoc: autofunction emits an unfriendly warning --- CHANGES | 2 ++ sphinx/ext/autodoc/__init__.py | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 3ee4586a9..d6621621e 100644 --- a/CHANGES +++ b/CHANGES @@ -90,6 +90,8 @@ Bugs fixed * #7362: autodoc: does not render correct signatures for built-in functions * #7654: autodoc: ``Optional[Union[foo, bar]]`` is presented as ``Union[foo, bar, None]`` +* #7629: autodoc: autofunction emits an unfriendly warning if an invalid object + specified * #7551: autosummary: a nested class is indexed as non-nested class * #7535: sphinx-autogen: crashes when custom template uses inheritance * #7536: sphinx-autogen: crashes when template uses i18n feature diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 80bcc0e8d..3bd3630c3 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1056,7 +1056,11 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ self.env.app.emit('autodoc-before-process-signature', unwrapped, False) sig = inspect.signature(unwrapped) args = stringify_signature(sig, **kwargs) - except TypeError: + except TypeError as exc: + logger.warning(__("Failed to get a function signature for %s: %s"), + self.fullname, exc) + return None + except ValueError: args = '' if self.env.config.strip_signature_backslash: From 8076307ee196b072f6f1e5f38654e0b348b41177 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 9 May 2020 22:30:32 +0900 Subject: [PATCH 07/40] Fix #7629: autodoc: automethod shows an unfriendly warning --- sphinx/ext/autodoc/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 3bd3630c3..ab7d7c3d3 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -942,7 +942,7 @@ class ClassLevelDocumenter(Documenter): try: modname, qualname = split_full_qualified_name(mod_cls) - parents = qualname.split(".") + parents = qualname.split(".") if qualname else [] except ImportError: parents = mod_cls.split(".") @@ -1467,6 +1467,10 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: self.env.app.emit('autodoc-before-process-signature', unwrapped, True) sig = inspect.signature(unwrapped, bound_method=True) args = stringify_signature(sig, **kwargs) + except TypeError as exc: + logger.warning(__("Failed to get a method signature for %s: %s"), + self.fullname, exc) + return None except ValueError: args = '' From 1dcfc44ace8f3da33f4ee62448aadee67edd80cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar?= Date: Thu, 14 May 2020 17:06:12 +0200 Subject: [PATCH 08/40] Fix automsummary directive wrong processing for invalid modules. --- sphinx/ext/autosummary/__init__.py | 3 +-- tests/test_ext_autosummary.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index ed49c56df..0cdd88feb 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -302,8 +302,7 @@ class Autosummary(SphinxDirective): with mock(self.config.autosummary_mock_imports): real_name, obj, parent, modname = import_by_name(name, prefixes=prefixes) except ImportError: - logger.warning(__('failed to import %s'), name) - items.append((name, '', '', name)) + logger.warning(__('autosummary: failed to import %s'), name) continue self.bridge.result = StringList() # initialize for each documenter diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 365a5a53c..dadedde70 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -397,7 +397,7 @@ def test_autosummary_template(app): confoverrides={'autosummary_generate': []}) def test_empty_autosummary_generate(app, status, warning): app.build() - assert ("WARNING: autosummary: stub file not found 'autosummary_importfail'" + assert ("WARNING: autosummary: failed to import autosummary_importfail" in warning.getvalue()) From a40f1ad473ee39d0d364b9bd43771d3944f7f2e3 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 14 May 2020 19:05:51 +0200 Subject: [PATCH 09/40] Fix astext() for two Sphinx nodes --- sphinx/addnodes.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 847a6d715..5e191e989 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -112,6 +112,13 @@ class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement): In that case all child nodes must be ``desc_signature_line`` nodes. """ + @property + def child_text_separator(self): + if self.get('is_multiline'): + return ' ' + else: + return super().child_text_separator + class desc_signature_line(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a line in a multi-line object signatures. @@ -150,6 +157,9 @@ class desc_parameterlist(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a general parameter list.""" child_text_separator = ', ' + def astext(self): + return '({})'.format(super().astext()) + class desc_parameter(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a single parameter.""" From 02d5cd439f2e61278425a279a5c72e1a416becdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar?= Date: Thu, 14 May 2020 19:16:45 +0200 Subject: [PATCH 10/40] Update 'test_autosummary_generate' test. --- tests/test_ext_autosummary.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index dadedde70..aa075a9e6 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -203,17 +203,16 @@ def test_autosummary_generate(app, status, warning): [autosummary_table, nodes.table, nodes.tgroup, (nodes.colspec, nodes.colspec, [nodes.tbody, (nodes.row, - nodes.row, nodes.row, nodes.row, nodes.row)])]) assert_node(doctree[4][0], addnodes.toctree, caption="An autosummary") + assert len(doctree[3][0][0][2]) == 4 assert doctree[3][0][0][2][0].astext() == 'autosummary_dummy_module\n\n' assert doctree[3][0][0][2][1].astext() == 'autosummary_dummy_module.Foo()\n\n' assert doctree[3][0][0][2][2].astext() == 'autosummary_dummy_module.Foo.Bar\n\n' assert doctree[3][0][0][2][3].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n' - assert doctree[3][0][0][2][4].astext() == 'autosummary_importfail\n\n' module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').read_text() assert (' .. autosummary::\n' From 41971382f820f950b961e9366bbb85e6ab518f55 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 14 May 2020 19:41:17 +0200 Subject: [PATCH 11/40] ... and don't break tests. --- tests/test_domain_py.py | 16 ++++++++-------- tests/test_ext_autodoc.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 08b3da21e..98b295b99 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -40,22 +40,22 @@ def parse(sig): def test_function_signatures(): rv = parse('func(a=1) -> int object') - assert rv == 'a=1' + assert rv == '(a=1)' rv = parse('func(a=1, [b=None])') - assert rv == 'a=1, [b=None]' + assert rv == '(a=1, [b=None])' rv = parse('func(a=1[, b=None])') - assert rv == 'a=1, [b=None]' + assert rv == '(a=1, [b=None])' rv = parse("compile(source : string, filename, symbol='file')") - assert rv == "source : string, filename, symbol='file'" + assert rv == "(source : string, filename, symbol='file')" rv = parse('func(a=[], [b=None])') - assert rv == 'a=[], [b=None]' + assert rv == '(a=[], [b=None])' rv = parse('func(a=[][, b=None])') - assert rv == 'a=[], [b=None]' + assert rv == '(a=[], [b=None])' @pytest.mark.sphinx('dummy', testroot='domain-py') @@ -453,8 +453,8 @@ def test_pyobject_prefix(app): desc, addnodes.index, desc)])])) - assert doctree[1][1][1].astext().strip() == 'say' # prefix is stripped - assert doctree[1][1][3].astext().strip() == 'FooBar.say' # not stripped + assert doctree[1][1][1].astext().strip() == 'say()' # prefix is stripped + assert doctree[1][1][3].astext().strip() == 'FooBar.say()' # not stripped def test_pydata(app): diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 76b970dbb..2fb9134d9 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -1775,7 +1775,7 @@ def test_autodoc(app, status, warning): content = app.env.get_doctree('index') assert isinstance(content[3], addnodes.desc) - assert content[3][0].astext() == 'autodoc_dummy_module.test' + assert content[3][0].astext() == 'autodoc_dummy_module.test()' assert content[3][1].astext() == 'Dummy function using dummy.*' # issue sphinx-doc/sphinx#2437 From 5a2942be1e8af3a22c190aa7d914c65fa5116717 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 14 May 2020 22:08:35 +0200 Subject: [PATCH 12/40] C++, add debug config variables --- sphinx/domains/cpp.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 4dc8809ec..0755ce229 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3722,8 +3722,8 @@ class LookupKey: class Symbol: debug_indent = 0 debug_indent_string = " " - debug_lookup = False - debug_show_tree = False + debug_lookup = False # overridden by the corresponding config value + debug_show_tree = False # overridden by the corresponding config value @staticmethod def debug_print(*args: Any) -> None: @@ -7383,9 +7383,18 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value("cpp_paren_attributes", [], 'env') app.add_post_transform(AliasTransform) + # debug stuff + app.add_config_value("cpp_debug_lookup", False, '') + app.add_config_value("cpp_debug_show_tree", False, '') + + def setDebugFlags(app): + Symbol.debug_lookup = app.config.cpp_debug_lookup + Symbol.debug_show_tree = app.config.cpp_debug_show_tree + app.connect("builder-inited", setDebugFlags) + return { 'version': 'builtin', - 'env_version': 2, + 'env_version': 3, 'parallel_read_safe': True, 'parallel_write_safe': True, } From e95567c349750edb2fdb4ec311e6b0e03c8d6b94 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 16 May 2020 17:57:44 +0900 Subject: [PATCH 13/40] Update CHANGES for PR #7661 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 714937984..af1da611c 100644 --- a/CHANGES +++ b/CHANGES @@ -94,6 +94,8 @@ Bugs fixed specified * #7650: autodoc: undecorated signature is shown for decorated functions * #7551: autosummary: a nested class is indexed as non-nested class +* #7661: autosummary: autosummary directive emits warnings twices if failed to + import the target module * #7535: sphinx-autogen: crashes when custom template uses inheritance * #7536: sphinx-autogen: crashes when template uses i18n feature * #2785: html: Bad alignment of equation links From b9793e5519a3e974886f8316fa1e74339075a1d2 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 14 May 2020 00:47:16 +0900 Subject: [PATCH 14/40] Fix: handle errors on event handlers (refs: #7629) --- CHANGES | 1 + sphinx/events.py | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index af1da611c..c1c3d5cb6 100644 --- a/CHANGES +++ b/CHANGES @@ -103,6 +103,7 @@ Bugs fixed * #7628: imgconverter: runs imagemagick once unnecessary for builders not supporting images * #7610: incorrectly renders consecutive backslashes for docutils-0.16 +* #7646: handle errors on event handlers Testing -------- diff --git a/sphinx/events.py b/sphinx/events.py index ff49f290c..0f0f47b65 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -16,7 +16,7 @@ from operator import attrgetter from typing import Any, Callable, Dict, List, NamedTuple from sphinx.deprecation import RemovedInSphinx40Warning -from sphinx.errors import ExtensionError +from sphinx.errors import ExtensionError, SphinxError from sphinx.locale import __ from sphinx.util import logging @@ -100,11 +100,17 @@ class EventManager: results = [] listeners = sorted(self.listeners[name], key=attrgetter("priority")) for listener in listeners: - if self.app is None: - # for compatibility; RemovedInSphinx40Warning - results.append(listener.handler(*args)) - else: - results.append(listener.handler(self.app, *args)) + try: + if self.app is None: + # for compatibility; RemovedInSphinx40Warning + results.append(listener.handler(*args)) + else: + results.append(listener.handler(self.app, *args)) + except SphinxError: + raise + except Exception as exc: + raise ExtensionError(__("Handler %r for event %r threw an exception") % + (listener.handler, name)) from exc return results def emit_firstresult(self, name: str, *args: Any) -> Any: From 404557c516e22636b791f7013b50cfad38531fd0 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 16 May 2020 11:52:42 +0200 Subject: [PATCH 15/40] C++, fix rendering of rooted nested names Also, test doctree generation via astext(). --- CHANGES | 2 + sphinx/domains/cpp.py | 8 +- tests/test_domain_cpp.py | 264 ++++++++++++++++++++++----------------- 3 files changed, 157 insertions(+), 117 deletions(-) diff --git a/CHANGES b/CHANGES index c1c3d5cb6..227d941ac 100644 --- a/CHANGES +++ b/CHANGES @@ -104,6 +104,8 @@ Bugs fixed supporting images * #7610: incorrectly renders consecutive backslashes for docutils-0.16 * #7646: handle errors on event handlers +* C++, fix rendering and xrefs in nested names explicitly starting + in global scope, e.g., ``::A::B``. Testing -------- diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 0755ce229..b801f4030 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -752,11 +752,17 @@ class ASTNestedName(ASTBase): names = self.names[:-1] if mode == 'lastIsName' else self.names # If lastIsName, then wrap all of the prefix in a desc_addname, # else append directly to signode. - # NOTE: Breathe relies on the prefix being in the desc_addname node, + # NOTE: Breathe previously relied on the prefix being in the desc_addname node, # so it can remove it in inner declarations. dest = signode if mode == 'lastIsName': dest = addnodes.desc_addname() + if self.rooted: + prefix += '::' + if mode == 'lastIsName' and len(names) == 0: + signode += nodes.Text('::') + else: + dest += nodes.Text('::') for i in range(len(names)): nne = names[i] template = self.templates[i] diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index bfb6934cf..38c89d282 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -33,15 +33,29 @@ def parse(name, string): return ast -def _check(name, input, idDict, output): +def _check(name, input, idDict, output, key, asTextOutput): + if key is None: + key = name + key += ' ' + if name in ('function', 'member'): + inputActual = input + outputAst = output + outputAsText = output + else: + inputActual = input.format(key='') + outputAst = output.format(key='') + outputAsText = output.format(key=key) + if asTextOutput is not None: + outputAsText = asTextOutput + # first a simple check of the AST - ast = parse(name, input) + ast = parse(name, inputActual) res = str(ast) - if res != output: + if res != outputAst: print("") print("Input: ", input) print("Result: ", res) - print("Expected: ", output) + print("Expected: ", outputAst) raise DefinitionError("") rootSymbol = Symbol(None, None, None, None, None, None) symbol = rootSymbol.add_declaration(ast, docname="TestDoc") @@ -49,6 +63,13 @@ def _check(name, input, idDict, output): signode = addnodes.desc_signature(input, '') parentNode += signode ast.describe_signature(signode, 'lastIsName', symbol, options={}) + resAsText = parentNode.astext() + if resAsText != outputAsText: + print("") + print("Input: ", input) + print("astext(): ", resAsText) + print("Expected: ", outputAsText) + raise DefinitionError("") idExpected = [None] for i in range(1, _max_id + 1): @@ -81,13 +102,14 @@ def _check(name, input, idDict, output): raise DefinitionError("") -def check(name, input, idDict, output=None): +def check(name, input, idDict, output=None, key=None, asTextOutput=None): if output is None: output = input # First, check without semicolon - _check(name, input, idDict, output) + _check(name, input, idDict, output, key, asTextOutput) # Second, check with semicolon - _check(name, input + ' ;', idDict, output + ';') + _check(name, input + ' ;', idDict, output + ';', key, + asTextOutput + ';' if asTextOutput is not None else None) def test_fundamental_types(): @@ -113,10 +135,11 @@ def test_fundamental_types(): def test_expressions(): def exprCheck(expr, id, id4=None): ids = 'IE1CIA%s_1aE' - idDict = {2: ids % expr, 3: ids % id} + # call .format() on the expr to unescape double curly braces + idDict = {2: ids % expr.format(), 3: ids % id} if id4 is not None: idDict[4] = ids % id4 - check('class', 'template<> C' % expr, idDict) + check('class', 'template<> {key}C' % expr, idDict) class Config: cpp_id_attributes = ["id_attr"] @@ -229,8 +252,8 @@ def test_expressions(): exprCheck('new int()', 'nw_ipiE') exprCheck('new int(5, 42)', 'nw_ipiL5EL42EE') exprCheck('::new int', 'nw_iE') - exprCheck('new int{}', 'nw_iilE') - exprCheck('new int{5, 42}', 'nw_iilL5EL42EE') + exprCheck('new int{{}}', 'nw_iilE') + exprCheck('new int{{5, 42}}', 'nw_iilL5EL42EE') # delete-expression exprCheck('delete p', 'dl1p') exprCheck('delete [] p', 'da1p') @@ -291,7 +314,7 @@ def test_expressions(): exprCheck('a xor_eq 5', 'eO1aL5E') exprCheck('a |= 5', 'oR1aL5E') exprCheck('a or_eq 5', 'oR1aL5E') - exprCheck('a = {1, 2, 3}', 'aS1ailL1EL2EL3EE') + exprCheck('a = {{1, 2, 3}}', 'aS1ailL1EL2EL3EE') # comma operator exprCheck('a, 5', 'cm1aL5E') @@ -301,8 +324,8 @@ def test_expressions(): check('function', 'template<> void f(A &v)', {2: "IE1fR1AI1BX2EE", 3: "IE1fR1AI1BXL2EEE", 4: "IE1fvR1AI1BXL2EEE"}) exprCheck('A<1>::value', 'N1AIXL1EEE5valueE') - check('class', "template A", {2: "I_iE1A"}) - check('enumerator', 'A = std::numeric_limits::max()', {2: "1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) + check('enumerator', '{key}A = std::numeric_limits::max()', {2: "1A"}) exprCheck('operator()()', 'clclE') exprCheck('operator()()', 'clclIiEE') @@ -312,58 +335,59 @@ def test_expressions(): def test_type_definitions(): - check("type", "public bool b", {1: "b", 2: "1b"}, "bool b") - check("type", "bool A::b", {1: "A::b", 2: "N1A1bE"}) - check("type", "bool *b", {1: "b", 2: "1b"}) - check("type", "bool *const b", {1: "b", 2: "1b"}) - check("type", "bool *volatile const b", {1: "b", 2: "1b"}) - check("type", "bool *volatile const b", {1: "b", 2: "1b"}) - check("type", "bool *volatile const *b", {1: "b", 2: "1b"}) - check("type", "bool &b", {1: "b", 2: "1b"}) - check("type", "bool b[]", {1: "b", 2: "1b"}) - check("type", "std::pair coord", {1: "coord", 2: "5coord"}) - check("type", "long long int foo", {1: "foo", 2: "3foo"}) - check("type", 'std::vector> module::blah', - {1: "module::blah", 2: "N6module4blahE"}) - check("type", "std::function F", {1: "F", 2: "1F"}) - check("type", "std::function F", {1: "F", 2: "1F"}) - check("type", "std::function F", {1: "F", 2: "1F"}) - check("type", "std::function F", {1: "F", 2: "1F"}) - check("type", "MyContainer::const_iterator", + check("type", "public bool b", {1: "b", 2: "1b"}, "{key}bool b", key='typedef') + check("type", "{key}bool A::b", {1: "A::b", 2: "N1A1bE"}, key='typedef') + check("type", "{key}bool *b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool *const b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool *volatile const b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool *volatile const b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool *volatile const *b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool &b", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}bool b[]", {1: "b", 2: "1b"}, key='typedef') + check("type", "{key}std::pair coord", {1: "coord", 2: "5coord"}, key='typedef') + check("type", "{key}long long int foo", {1: "foo", 2: "3foo"}, key='typedef') + check("type", '{key}std::vector> module::blah', + {1: "module::blah", 2: "N6module4blahE"}, key='typedef') + check("type", "{key}std::function F", {1: "F", 2: "1F"}, key='typedef') + check("type", "{key}std::function F", {1: "F", 2: "1F"}, key='typedef') + check("type", "{key}std::function F", {1: "F", 2: "1F"}, key='typedef') + check("type", "{key}std::function F", {1: "F", 2: "1F"}, key='typedef') + check("type", "{key}MyContainer::const_iterator", {1: "MyContainer::const_iterator", 2: "N11MyContainer14const_iteratorE"}) check("type", "public MyContainer::const_iterator", {1: "MyContainer::const_iterator", 2: "N11MyContainer14const_iteratorE"}, - output="MyContainer::const_iterator") + output="{key}MyContainer::const_iterator") # test decl specs on right - check("type", "bool const b", {1: "b", 2: "1b"}) + check("type", "{key}bool const b", {1: "b", 2: "1b"}, key='typedef') # test name in global scope - check("type", "bool ::B::b", {1: "B::b", 2: "N1B1bE"}) + check("type", "{key}bool ::B::b", {1: "B::b", 2: "N1B1bE"}, key='typedef') - check('type', 'A = B', {2: '1A'}) - check('type', 'A = decltype(b)', {2: '1A'}) + check('type', '{key}A = B', {2: '1A'}, key='using') + check('type', '{key}A = decltype(b)', {2: '1A'}, key='using') # from breathe#267 (named function parameters for function pointers - check('type', 'void (*gpio_callback_t)(struct device *port, uint32_t pin)', - {1: 'gpio_callback_t', 2: '15gpio_callback_t'}) - check('type', 'void (*f)(std::function g)', {1: 'f', 2: '1f'}) + check('type', '{key}void (*gpio_callback_t)(struct device *port, uint32_t pin)', + {1: 'gpio_callback_t', 2: '15gpio_callback_t'}, key='typedef') + check('type', '{key}void (*f)(std::function g)', {1: 'f', 2: '1f'}, + key='typedef') - check('type', 'T = A::template B::template C', {2: '1T'}) + check('type', '{key}T = A::template B::template C', {2: '1T'}, key='using') - check('type', 'T = Q', {2: '1T'}) - check('type', 'T = Q>', {2: '1T'}) - check('type', 'T = Q', {2: '1T'}) + check('type', '{key}T = Q', {2: '1T'}, key='using') + check('type', '{key}T = Q>', {2: '1T'}, key='using') + check('type', '{key}T = Q', {2: '1T'}, key='using') def test_concept_definitions(): - check('concept', 'template A::B::Concept', + check('concept', 'template {key}A::B::Concept', {2: 'I0EN1A1B7ConceptE'}) - check('concept', 'template Foo', + check('concept', 'template {key}Foo', {2: 'I00DpE3Foo'}) with pytest.raises(DefinitionError): - parse('concept', 'Foo') + parse('concept', '{key}Foo') with pytest.raises(DefinitionError): - parse('concept', 'template template Foo') + parse('concept', 'template template {key}Foo') def test_member_definitions(): @@ -639,95 +663,102 @@ def test_operators(): check('function', 'void operator[]()', {1: "subscript-operator", 2: "ixv"}) +class test_nested_name(): + check('class', '{key}::A', {1: "A", 2: "1A"}) + check('class', '{key}::A::B', {1: "A::B", 2: "N1A1BE"}) + check('function', 'void f(::A a)', {1: "f__A", 2: "1f1A"}) + check('function', 'void f(::A::B a)', {1: "f__A::B", 2: "1fN1A1BE"}) + + def test_class_definitions(): - check('class', 'public A', {1: "A", 2: "1A"}, output='A') - check('class', 'private A', {1: "A", 2: "1A"}) - check('class', 'A final', {1: 'A', 2: '1A'}) + check('class', 'public A', {1: "A", 2: "1A"}, output='{key}A') + check('class', 'private {key}A', {1: "A", 2: "1A"}) + check('class', '{key}A final', {1: 'A', 2: '1A'}) # test bases - check('class', 'A', {1: "A", 2: "1A"}) - check('class', 'A::B::C', {1: "A::B::C", 2: "N1A1B1CE"}) - check('class', 'A : B', {1: "A", 2: "1A"}) - check('class', 'A : private B', {1: "A", 2: "1A"}) - check('class', 'A : public B', {1: "A", 2: "1A"}) - check('class', 'A : B, C', {1: "A", 2: "1A"}) - check('class', 'A : B, protected C, D', {1: "A", 2: "1A"}) - check('class', 'A : virtual private B', {1: 'A', 2: '1A'}, output='A : private virtual B') - check('class', 'A : private virtual B', {1: 'A', 2: '1A'}) - check('class', 'A : B, virtual C', {1: 'A', 2: '1A'}) - check('class', 'A : public virtual B', {1: 'A', 2: '1A'}) - check('class', 'A : B, C...', {1: 'A', 2: '1A'}) - check('class', 'A : B..., C', {1: 'A', 2: '1A'}) + check('class', '{key}A', {1: "A", 2: "1A"}) + check('class', '{key}A::B::C', {1: "A::B::C", 2: "N1A1B1CE"}) + check('class', '{key}A : B', {1: "A", 2: "1A"}) + check('class', '{key}A : private B', {1: "A", 2: "1A"}) + check('class', '{key}A : public B', {1: "A", 2: "1A"}) + check('class', '{key}A : B, C', {1: "A", 2: "1A"}) + check('class', '{key}A : B, protected C, D', {1: "A", 2: "1A"}) + check('class', 'A : virtual private B', {1: 'A', 2: '1A'}, output='{key}A : private virtual B') + check('class', '{key}A : private virtual B', {1: 'A', 2: '1A'}) + check('class', '{key}A : B, virtual C', {1: 'A', 2: '1A'}) + check('class', '{key}A : public virtual B', {1: 'A', 2: '1A'}) + check('class', '{key}A : B, C...', {1: 'A', 2: '1A'}) + check('class', '{key}A : B..., C', {1: 'A', 2: '1A'}) # from #4094 - check('class', 'template> has_var', {2: 'I00E7has_var'}) - check('class', 'template has_var>', + check('class', 'template> {key}has_var', {2: 'I00E7has_var'}) + check('class', 'template {key}has_var>', {2: 'I0E7has_varI1TNSt6void_tIDTadN1T3varEEEEE'}) - check('class', 'template T', + check('class', 'template {key}T', {2: 'IDpE1TIJPFi2TsEEE'}) - check('class', 'template T<(Is)...>', + check('class', 'template {key}T<(Is)...>', {2: 'I_DpiE1TIJX(Is)EEE', 3: 'I_DpiE1TIJX2IsEEE'}) def test_union_definitions(): - check('union', 'A', {2: "1A"}) + check('union', '{key}A', {2: "1A"}) def test_enum_definitions(): - check('enum', 'A', {2: "1A"}) - check('enum', 'A : std::underlying_type::type', {2: "1A"}) - check('enum', 'A : unsigned int', {2: "1A"}) - check('enum', 'public A', {2: "1A"}, output='A') - check('enum', 'private A', {2: "1A"}) + check('enum', '{key}A', {2: "1A"}) + check('enum', '{key}A : std::underlying_type::type', {2: "1A"}) + check('enum', '{key}A : unsigned int', {2: "1A"}) + check('enum', 'public A', {2: "1A"}, output='{key}A') + check('enum', 'private {key}A', {2: "1A"}) - check('enumerator', 'A', {2: "1A"}) - check('enumerator', 'A = std::numeric_limits::max()', {2: "1A"}) + check('enumerator', '{key}A', {2: "1A"}) + check('enumerator', '{key}A = std::numeric_limits::max()', {2: "1A"}) def test_anon_definitions(): - check('class', '@a', {3: "Ut1_a"}) - check('union', '@a', {3: "Ut1_a"}) - check('enum', '@a', {3: "Ut1_a"}) - check('class', '@1', {3: "Ut1_1"}) - check('class', '@a::A', {3: "NUt1_a1AE"}) + check('class', '@a', {3: "Ut1_a"}, asTextOutput='class [anonymous]') + check('union', '@a', {3: "Ut1_a"}, asTextOutput='union [anonymous]') + check('enum', '@a', {3: "Ut1_a"}, asTextOutput='enum [anonymous]') + check('class', '@1', {3: "Ut1_1"}, asTextOutput='class [anonymous]') + check('class', '@a::A', {3: "NUt1_a1AE"}, asTextOutput='class [anonymous]::A') def test_templates(): - check('class', "A", {2: "IE1AI1TE"}, output="template<> A") + check('class', "A", {2: "IE1AI1TE"}, output="template<> {key}A") # first just check which objects support templating - check('class', "template<> A", {2: "IE1A"}) + check('class', "template<> {key}A", {2: "IE1A"}) check('function', "template<> void A()", {2: "IE1Av", 4: "IE1Avv"}) check('member', "template<> A a", {2: "IE1a"}) - check('type', "template<> a = A", {2: "IE1a"}) + check('type', "template<> {key}a = A", {2: "IE1a"}, key='using') with pytest.raises(DefinitionError): parse('enum', "template<> A") with pytest.raises(DefinitionError): parse('enumerator', "template<> A") # then all the real tests - check('class', "template A", {2: "I00E1A"}) - check('type', "template<> a", {2: "IE1a"}) + check('class', "template {key}A", {2: "I00E1A"}) + check('type', "template<> {key}a", {2: "IE1a"}, key='using') - check('class', "template A", {2: "I0E1A"}) - check('class', "template A", {2: "I0E1A"}) - check('class', "template A", {2: "IDpE1A"}) - check('class', "template A", {2: "IDpE1A"}) - check('class', "template A", {2: "I0E1A"}) - check('class', "template A", {2: "I0E1A"}) + check('class', "template {key}A", {2: "I0E1A"}) + check('class', "template {key}A", {2: "I0E1A"}) + check('class', "template {key}A", {2: "IDpE1A"}) + check('class', "template {key}A", {2: "IDpE1A"}) + check('class', "template {key}A", {2: "I0E1A"}) + check('class', "template {key}A", {2: "I0E1A"}) - check('class', "template typename T> A", {2: "II0E0E1A"}) - check('class', "template typename> A", {2: "II0E0E1A"}) - check('class', "template typename ...T> A", {2: "II0EDpE1A"}) - check('class', "template typename...> A", {2: "II0EDpE1A"}) + check('class', "template typename T> {key}A", {2: "II0E0E1A"}) + check('class', "template typename> {key}A", {2: "II0E0E1A"}) + check('class', "template typename ...T> {key}A", {2: "II0EDpE1A"}) + check('class', "template typename...> {key}A", {2: "II0EDpE1A"}) - check('class', "template A", {2: "I_iE1A"}) - check('class', "template A", {2: "I_iE1A"}) - check('class', "template A", {2: "I_DpiE1A"}) - check('class', "template A", {2: "I_iE1A"}) - check('class', "template A", {2: "I_iE1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) + check('class', "template {key}A", {2: "I_DpiE1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) + check('class', "template {key}A", {2: "I_iE1A"}) - check('class', "template<> A>", {2: "IE1AIN2NS1BIEEE"}) + check('class', "template<> {key}A>", {2: "IE1AIN2NS1BIEEE"}) # from #2058 check('function', @@ -747,21 +778,21 @@ def test_templates(): parse('enum', 'abc::ns::foo{id_0, id_1, id_2} A') with pytest.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', + check('class', 'abc::ns::foo{{id_0, id_1, id_2}} {key}xyz::bar', {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) - check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar', + check('class', 'abc::ns::foo{{id_0, id_1, ...id_2}} {key}xyz::bar', {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) - check('class', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar', + check('class', 'abc::ns::foo{{id_0, id_1, id_2}} {key}xyz::bar', {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barI4id_04id_14id_2EE'}) - check('class', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar', + check('class', 'abc::ns::foo{{id_0, id_1, ...id_2}} {key}xyz::bar', {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barI4id_04id_1Dp4id_2EE'}) - check('class', 'template<> Concept{U} A::B', {2: 'IEI0EX7ConceptI1UEEN1AIiE1BE'}) + check('class', 'template<> Concept{{U}} {key}A::B', {2: 'IEI0EX7ConceptI1UEEN1AIiE1BE'}) - check('type', 'abc::ns::foo{id_0, id_1, id_2} xyz::bar = ghi::qux', - {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) - check('type', 'abc::ns::foo{id_0, id_1, ...id_2} xyz::bar = ghi::qux', - {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) + check('type', 'abc::ns::foo{{id_0, id_1, id_2}} {key}xyz::bar = ghi::qux', + {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}, key='using') + check('type', 'abc::ns::foo{{id_0, id_1, ...id_2}} {key}xyz::bar = ghi::qux', + {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}, key='using') check('function', 'abc::ns::foo{id_0, id_1, id_2} void xyz::bar()', {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barEv', 4: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barEvv'}) @@ -772,8 +803,8 @@ def test_templates(): {2: 'I000EXN3abc2ns3fooEI4id_04id_14id_2EEN3xyz3barE'}) check('member', 'abc::ns::foo{id_0, id_1, ...id_2} ghi::qux xyz::bar', {2: 'I00DpEXN3abc2ns3fooEI4id_04id_1sp4id_2EEN3xyz3barE'}) - check('concept', 'Iterator{T, U} Another', {2: 'I00EX8IteratorI1T1UEE7Another'}) - check('concept', 'template Numerics = (... && Numeric)', + check('concept', 'Iterator{{T, U}} {key}Another', {2: 'I00EX8IteratorI1T1UEE7Another'}) + check('concept', 'template {key}Numerics = (... && Numeric)', {2: 'IDpE8Numerics'}) # explicit specializations of members @@ -785,7 +816,7 @@ def test_templates(): output='template<> template<> int A::B::b') # same as above # defaulted constrained type parameters - check('type', 'template A', {2: 'I_1CE1A'}) + check('type', 'template {key}A', {2: 'I_1CE1A'}, key='using') def test_template_args(): @@ -797,9 +828,10 @@ def test_template_args(): 3: "I0E5allowP1FN4funcI1F1BXne1GL1EEE4typeE", 4: "I0E5allowvP1FN4funcI1F1BXne1GL1EEE4typeE"}) # from #3542 - check('type', "template " + check('type', "template {key}" "enable_if_not_array_t = std::enable_if_t::value, int>", - {2: "I0E21enable_if_not_array_t"}) + {2: "I0E21enable_if_not_array_t"}, + key='using') def test_initializers(): From 2c904181072510fe1c85b283e585de8da0731aa8 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 16 May 2020 12:40:20 +0200 Subject: [PATCH 16/40] C, fix rendering of rooted nested names Also, test doctree generation via astext(). --- CHANGES | 2 + sphinx/domains/c.py | 8 +++- tests/test_domain_c.py | 83 ++++++++++++++++++++++++++++-------------- 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/CHANGES b/CHANGES index 227d941ac..15b020074 100644 --- a/CHANGES +++ b/CHANGES @@ -106,6 +106,8 @@ Bugs fixed * #7646: handle errors on event handlers * C++, fix rendering and xrefs in nested names explicitly starting in global scope, e.g., ``::A::B``. +* C, fix rendering and xrefs in nested names explicitly starting + in global scope, e.g., ``.A.B``. Testing -------- diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 6e0dc2a54..164a87254 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -186,11 +186,17 @@ class ASTNestedName(ASTBase): # If lastIsName, then wrap all of the prefix in a desc_addname, # else append directly to signode. # TODO: also for C? - # NOTE: Breathe relies on the prefix being in the desc_addname node, + # NOTE: Breathe previously relied on the prefix being in the desc_addname node, # so it can remove it in inner declarations. dest = signode if mode == 'lastIsName': dest = addnodes.desc_addname() + if self.rooted: + prefix += '.' + if mode == 'lastIsName' and len(names) == 0: + signode += nodes.Text('.') + else: + dest += nodes.Text('.') for i in range(len(names)): ident = names[i] if not first: diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py index 237519fcc..cc9ce0b24 100644 --- a/tests/test_domain_c.py +++ b/tests/test_domain_c.py @@ -27,15 +27,29 @@ def parse(name, string): return ast -def _check(name, input, idDict, output): +def _check(name, input, idDict, output, key, asTextOutput): + if key is None: + key = name + key += ' ' + if name in ('function', 'member'): + inputActual = input + outputAst = output + outputAsText = output + else: + inputActual = input.format(key='') + outputAst = output.format(key='') + outputAsText = output.format(key=key) + if asTextOutput is not None: + outputAsText = asTextOutput + # first a simple check of the AST - ast = parse(name, input) + ast = parse(name, inputActual) res = str(ast) - if res != output: + if res != outputAst: print("") print("Input: ", input) print("Result: ", res) - print("Expected: ", output) + print("Expected: ", outputAst) raise DefinitionError("") rootSymbol = Symbol(None, None, None, None) symbol = rootSymbol.add_declaration(ast, docname="TestDoc") @@ -43,6 +57,13 @@ def _check(name, input, idDict, output): signode = addnodes.desc_signature(input, '') parentNode += signode ast.describe_signature(signode, 'lastIsName', symbol, options={}) + resAsText = parentNode.astext() + if resAsText != outputAsText: + print("") + print("Input: ", input) + print("astext(): ", resAsText) + print("Expected: ", outputAsText) + raise DefinitionError("") idExpected = [None] for i in range(1, _max_id + 1): @@ -75,14 +96,15 @@ def _check(name, input, idDict, output): raise DefinitionError("") -def check(name, input, idDict, output=None): +def check(name, input, idDict, output=None, key=None, asTextOutput=None): if output is None: output = input # First, check without semicolon - _check(name, input, idDict, output) + _check(name, input, idDict, output, key, asTextOutput) if name != 'macro': # Second, check with semicolon - _check(name, input + ' ;', idDict, output + ';') + _check(name, input + ' ;', idDict, output + ';', key, + asTextOutput + ';' if asTextOutput is not None else None) def test_expressions(): @@ -234,24 +256,24 @@ def test_expressions(): def test_type_definitions(): - check('type', "T", {1: "T"}) + check('type', "{key}T", {1: "T"}) - check('type', "bool *b", {1: 'b'}) - check('type', "bool *const b", {1: 'b'}) - check('type', "bool *const *b", {1: 'b'}) - check('type', "bool *volatile *b", {1: 'b'}) - check('type', "bool *restrict *b", {1: 'b'}) - check('type', "bool *volatile const b", {1: 'b'}) - check('type', "bool *volatile const b", {1: 'b'}) - check('type', "bool *volatile const *b", {1: 'b'}) - check('type', "bool b[]", {1: 'b'}) - check('type', "long long int foo", {1: 'foo'}) + check('type', "{key}bool *b", {1: 'b'}, key='typedef') + check('type', "{key}bool *const b", {1: 'b'}, key='typedef') + check('type', "{key}bool *const *b", {1: 'b'}, key='typedef') + check('type', "{key}bool *volatile *b", {1: 'b'}, key='typedef') + check('type', "{key}bool *restrict *b", {1: 'b'}, key='typedef') + check('type', "{key}bool *volatile const b", {1: 'b'}, key='typedef') + check('type', "{key}bool *volatile const b", {1: 'b'}, key='typedef') + check('type', "{key}bool *volatile const *b", {1: 'b'}, key='typedef') + check('type', "{key}bool b[]", {1: 'b'}, key='typedef') + check('type', "{key}long long int foo", {1: 'foo'}, key='typedef') # test decl specs on right - check('type', "bool const b", {1: 'b'}) + check('type', "{key}bool const b", {1: 'b'}, key='typedef') # from breathe#267 (named function parameters for function pointers - check('type', 'void (*gpio_callback_t)(struct device *port, uint32_t pin)', - {1: 'gpio_callback_t'}) + check('type', '{key}void (*gpio_callback_t)(struct device *port, uint32_t pin)', + {1: 'gpio_callback_t'}, key='typedef') def test_macro_definitions(): @@ -378,19 +400,26 @@ def test_function_definitions(): output='void f(int arr[static volatile const 42])') -def test_union_definitions(): - check('struct', 'A', {1: 'A'}) +class test_nested_name(): + check('struct', '{key}.A', {1: "A"}) + check('struct', '{key}.A.B', {1: "A.B"}) + check('function', 'void f(.A a)', {1: "f"}) + check('function', 'void f(.A.B a)', {1: "f"}) def test_union_definitions(): - check('union', 'A', {1: 'A'}) + check('struct', '{key}A', {1: 'A'}) + + +def test_union_definitions(): + check('union', '{key}A', {1: 'A'}) def test_enum_definitions(): - check('enum', 'A', {1: 'A'}) + check('enum', '{key}A', {1: 'A'}) - check('enumerator', 'A', {1: 'A'}) - check('enumerator', 'A = 42', {1: 'A'}) + check('enumerator', '{key}A', {1: 'A'}) + check('enumerator', '{key}A = 42', {1: 'A'}) def test_anon_definitions(): From 979472b5363fbb029fb3d845e19b3c91c778f2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar?= Date: Sat, 16 May 2020 13:36:56 +0200 Subject: [PATCH 17/40] Resolve with absolute path casting. --- sphinx/cmd/quickstart.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 72434c18b..cad3c65e5 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -11,7 +11,6 @@ import argparse import locale import os -import pathlib import re import sys import time @@ -358,7 +357,7 @@ def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir: d.setdefault('extensions', []) d['copyright'] = time.strftime('%Y') + ', ' + d['author'] - d["path"] = str(pathlib.Path(d['path']).resolve()) + d["path"] = os.path.abspath(d['path']) ensuredir(d['path']) srcdir = path.join(d['path'], 'source') if d['sep'] else d['path'] From fcfdc19624e91ae4c684aba359d19efd3f5790b0 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 15 May 2020 01:28:39 +0900 Subject: [PATCH 18/40] refactor: autodoc: Remove magic mock from singledispatch processing --- sphinx/ext/autodoc/__init__.py | 103 +++++++++++++-------------------- tests/test_ext_autodoc.py | 17 +++--- 2 files changed, 50 insertions(+), 70 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 203c21e8b..3aaf02dc6 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -16,7 +16,6 @@ import warnings from inspect import Parameter from types import ModuleType from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union -from unittest.mock import patch from docutils.statemachine import StringList @@ -421,8 +420,15 @@ class Documenter: directive = getattr(self, 'directivetype', self.objtype) name = self.format_name() sourcename = self.get_sourcename() - self.add_line('.. %s:%s:: %s%s' % (domain, directive, name, sig), - sourcename) + + # one signature per line, indented by column + prefix = '.. %s:%s:: ' % (domain, directive) + for i, sig_line in enumerate(sig.split("\n")): + self.add_line('%s%s%s' % (prefix, name, sig_line), + sourcename) + if i == 0: + prefix = " " * len(prefix) + if self.options.noindex: self.add_line(' :noindex:', sourcename) if self.objpath: @@ -1075,41 +1081,28 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ def add_directive_header(self, sig: str) -> None: sourcename = self.get_sourcename() - if inspect.is_singledispatch_function(self.object): - self.add_singledispatch_directive_header(sig) - else: - super().add_directive_header(sig) + super().add_directive_header(sig) if inspect.iscoroutinefunction(self.object): self.add_line(' :async:', sourcename) - def add_singledispatch_directive_header(self, sig: str) -> None: - sourcename = self.get_sourcename() + def format_signature(self, **kwargs: Any) -> str: + sig = super().format_signature(**kwargs) + sigs = [sig] - # intercept generated directive headers - # TODO: It is very hacky to use mock to intercept header generation - with patch.object(self, 'add_line') as add_line: - super().add_directive_header(sig) + if inspect.is_singledispatch_function(self.object): + # append signature of singledispatch'ed functions + for typ, func in self.object.registry.items(): + if typ is object: + pass # default implementation. skipped. + else: + self.annotate_to_first_argument(func, typ) - # output first line of header - self.add_line(*add_line.call_args_list[0][0]) + documenter = FunctionDocumenter(self.directive, '') + documenter.object = func + sigs.append(documenter.format_signature()) - # inserts signature of singledispatch'ed functions - for typ, func in self.object.registry.items(): - if typ is object: - pass # default implementation. skipped. - else: - self.annotate_to_first_argument(func, typ) - - documenter = FunctionDocumenter(self.directive, '') - documenter.object = func - self.add_line(' %s%s' % (self.format_name(), - documenter.format_signature()), - sourcename) - - # output remains of directive header - for call in add_line.call_args_list[1:]: - self.add_line(*call[0]) + return "\n".join(sigs) def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: """Annotate type hint to the first argument of function if needed.""" @@ -1487,11 +1480,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: return args def add_directive_header(self, sig: str) -> None: - meth = self.parent.__dict__.get(self.objpath[-1]) - if inspect.is_singledispatch_method(meth): - self.add_singledispatch_directive_header(sig) - else: - super().add_directive_header(sig) + super().add_directive_header(sig) sourcename = self.get_sourcename() obj = self.parent.__dict__.get(self.object_name, self.object) @@ -1509,36 +1498,26 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: def document_members(self, all_members: bool = False) -> None: pass - def add_singledispatch_directive_header(self, sig: str) -> None: - sourcename = self.get_sourcename() + def format_signature(self, **kwargs: Any) -> str: + sig = super().format_signature(**kwargs) + sigs = [sig] - # intercept generated directive headers - # TODO: It is very hacky to use mock to intercept header generation - with patch.object(self, 'add_line') as add_line: - super().add_directive_header(sig) - - # output first line of header - self.add_line(*add_line.call_args_list[0][0]) - - # inserts signature of singledispatch'ed functions meth = self.parent.__dict__.get(self.objpath[-1]) - for typ, func in meth.dispatcher.registry.items(): - if typ is object: - pass # default implementation. skipped. - else: - self.annotate_to_first_argument(func, typ) + if inspect.is_singledispatch_method(meth): + # append signature of singledispatch'ed functions + for typ, func in meth.dispatcher.registry.items(): + if typ is object: + pass # default implementation. skipped. + else: + self.annotate_to_first_argument(func, typ) - documenter = MethodDocumenter(self.directive, '') - documenter.parent = self.parent - documenter.object = func - documenter.objpath = self.objpath - self.add_line(' %s%s' % (self.format_name(), - documenter.format_signature()), - sourcename) + documenter = MethodDocumenter(self.directive, '') + documenter.parent = self.parent + documenter.object = func + documenter.objpath = [None] + sigs.append(documenter.format_signature()) - # output remains of directive header - for call in add_line.call_args_list[1:]: - self.add_line(*call[0]) + return "\n".join(sigs) def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: """Annotate type hint to the first argument of function if needed.""" diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index cecb171cd..88d7deb68 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -252,6 +252,7 @@ def test_get_doc(app): def getdocl(objtype, obj): inst = app.registry.documenters[objtype](directive, 'tmp') + inst.parent = object # dummy inst.object = obj inst.objpath = [obj.__name__] inst.doc_as_attr = False @@ -1658,8 +1659,8 @@ def test_singledispatch(app): '', '', '.. py:function:: func(arg, kwarg=None)', - ' func(arg: int, kwarg=None)', - ' func(arg: str, kwarg=None)', + ' func(arg: int, kwarg=None)', + ' func(arg: str, kwarg=None)', ' :module: target.singledispatch', '', ' A function for general use.', @@ -1674,8 +1675,8 @@ def test_singledispatch_autofunction(app): assert list(actual) == [ '', '.. py:function:: func(arg, kwarg=None)', - ' func(arg: int, kwarg=None)', - ' func(arg: str, kwarg=None)', + ' func(arg: int, kwarg=None)', + ' func(arg: str, kwarg=None)', ' :module: target.singledispatch', '', ' A function for general use.', @@ -1701,8 +1702,8 @@ def test_singledispatchmethod(app): '', '', ' .. py:method:: Foo.meth(arg, kwarg=None)', - ' Foo.meth(arg: int, kwarg=None)', - ' Foo.meth(arg: str, kwarg=None)', + ' Foo.meth(arg: int, kwarg=None)', + ' Foo.meth(arg: str, kwarg=None)', ' :module: target.singledispatchmethod', '', ' A method for general use.', @@ -1719,8 +1720,8 @@ def test_singledispatchmethod_automethod(app): assert list(actual) == [ '', '.. py:method:: Foo.meth(arg, kwarg=None)', - ' Foo.meth(arg: int, kwarg=None)', - ' Foo.meth(arg: str, kwarg=None)', + ' Foo.meth(arg: int, kwarg=None)', + ' Foo.meth(arg: str, kwarg=None)', ' :module: target.singledispatchmethod', '', ' A method for general use.', From 16ad0d10dd6ca5f534ef7ef92d5247e78eef2565 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 16 May 2020 22:58:58 +0900 Subject: [PATCH 19/40] Update CHANGES for PR #7653 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 15b020074..e4c5f05d9 100644 --- a/CHANGES +++ b/CHANGES @@ -98,6 +98,7 @@ Bugs fixed import the target module * #7535: sphinx-autogen: crashes when custom template uses inheritance * #7536: sphinx-autogen: crashes when template uses i18n feature +* #7653: sphinx-quickstart: Fix multiple directory creation for nested relpath * #2785: html: Bad alignment of equation links * #7581: napoleon: bad parsing of inline code in attribute docstrings * #7628: imgconverter: runs imagemagick once unnecessary for builders not From 4dad6d626259cf9337687a3ae168e6b30949594a Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 16 May 2020 16:56:53 +0200 Subject: [PATCH 20/40] C, enable tests of anon entities --- tests/test_domain_c.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py index cc9ce0b24..795e8ed37 100644 --- a/tests/test_domain_c.py +++ b/tests/test_domain_c.py @@ -423,12 +423,11 @@ def test_enum_definitions(): def test_anon_definitions(): - return # TODO - check('class', '@a', {3: "Ut1_a"}) - check('union', '@a', {3: "Ut1_a"}) - check('enum', '@a', {3: "Ut1_a"}) - check('class', '@1', {3: "Ut1_1"}) - check('class', '@a::A', {3: "NUt1_a1AE"}) + check('struct', '@a', {1: "@a"}, asTextOutput='struct [anonymous]') + check('union', '@a', {1: "@a"}, asTextOutput='union [anonymous]') + check('enum', '@a', {1: "@a"}, asTextOutput='enum [anonymous]') + check('struct', '@1', {1: "@1"}, asTextOutput='struct [anonymous]') + check('struct', '@a.A', {1: "@a.A"}, asTextOutput='struct [anonymous].A') def test_initializers(): From 198358149df693505ebae1564fb5e3a08dd167ce Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 May 2020 01:34:00 +0900 Subject: [PATCH 21/40] Fix #7676: autodoc: wrong value for :member-order: option is ignored silently --- CHANGES | 1 + sphinx/ext/autodoc/__init__.py | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index e4c5f05d9..52efa65c4 100644 --- a/CHANGES +++ b/CHANGES @@ -93,6 +93,7 @@ Bugs fixed * #7629: autodoc: autofunction emits an unfriendly warning if an invalid object specified * #7650: autodoc: undecorated signature is shown for decorated functions +* #7676: autodoc: wrong value for :member-order: option is ignored silently * #7551: autosummary: a nested class is indexed as non-nested class * #7661: autosummary: autosummary directive emits warnings twices if failed to import the target module diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 3aaf02dc6..bc249b0d3 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -15,7 +15,9 @@ import re import warnings from inspect import Parameter from types import ModuleType -from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union +from typing import ( + Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, Union +) from docutils.statemachine import StringList @@ -92,6 +94,16 @@ def inherited_members_option(arg: Any) -> Union[object, Set[str]]: return arg +def member_order_option(arg: Any) -> Optional[str]: + """Used to convert the :members: option to auto directives.""" + if arg is None: + return None + elif arg in ('alphabetical', 'bysource', 'groupwise'): + return arg + else: + raise ValueError(__('invalid value for member-order option: %s') % arg) + + SUPPRESS = object() @@ -817,7 +829,7 @@ class ModuleDocumenter(Documenter): 'noindex': bool_option, 'inherited-members': inherited_members_option, 'show-inheritance': bool_option, 'synopsis': identity, 'platform': identity, 'deprecated': bool_option, - 'member-order': identity, 'exclude-members': members_set_option, + 'member-order': member_order_option, 'exclude-members': members_set_option, 'private-members': bool_option, 'special-members': members_option, 'imported-members': bool_option, 'ignore-module-all': bool_option } # type: Dict[str, Callable] @@ -1150,7 +1162,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: option_spec = { 'members': members_option, 'undoc-members': bool_option, 'noindex': bool_option, 'inherited-members': inherited_members_option, - 'show-inheritance': bool_option, 'member-order': identity, + 'show-inheritance': bool_option, 'member-order': member_order_option, 'exclude-members': members_set_option, 'private-members': bool_option, 'special-members': members_option, } # type: Dict[str, Callable] From 38a21d7dacf6cf61587d8d86ad7a9a43c285d580 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 May 2020 01:30:58 +0900 Subject: [PATCH 22/40] Fix #7676: autodoc: typo in the default value of autodoc_member_order --- CHANGES | 1 + sphinx/ext/autodoc/__init__.py | 15 +++++++++++++-- tests/test_ext_autodoc.py | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index e4c5f05d9..22638f6aa 100644 --- a/CHANGES +++ b/CHANGES @@ -93,6 +93,7 @@ Bugs fixed * #7629: autodoc: autofunction emits an unfriendly warning if an invalid object specified * #7650: autodoc: undecorated signature is shown for decorated functions +* #7676: autodoc: typo in the default value of autodoc_member_order * #7551: autosummary: a nested class is indexed as non-nested class * #7661: autosummary: autosummary directive emits warnings twices if failed to import the target module diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 3aaf02dc6..08f83ebdf 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -21,7 +21,7 @@ from docutils.statemachine import StringList import sphinx from sphinx.application import Sphinx -from sphinx.config import ENUM +from sphinx.config import Config, ENUM from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.environment import BuildEnvironment from sphinx.ext.autodoc.importer import import_object, get_module_members, get_object_members @@ -1754,6 +1754,14 @@ def autodoc_attrgetter(app: Sphinx, obj: Any, name: str, *defargs: Any) -> Any: return safe_getattr(obj, name, *defargs) +def migrate_autodoc_member_order(app: Sphinx, config: Config) -> None: + if config.autodoc_member_order == 'alphabetic': + # RemovedInSphinx50Warning + logger.warning(__('autodoc_member_order now accepts "alphabetical" ' + 'instead of "alphabetic". Please update your setting.')) + config.autodoc_member_order = 'alphabetical' # type: ignore + + def setup(app: Sphinx) -> Dict[str, Any]: app.add_autodocumenter(ModuleDocumenter) app.add_autodocumenter(ClassDocumenter) @@ -1769,7 +1777,8 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_autodocumenter(SlotsAttributeDocumenter) app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init')) - app.add_config_value('autodoc_member_order', 'alphabetic', True) + app.add_config_value('autodoc_member_order', 'alphabetical', True, + ENUM('alphabetic', 'alphabetical', 'bysource', 'groupwise')) app.add_config_value('autodoc_default_options', {}, True) app.add_config_value('autodoc_docstring_signature', True, True) app.add_config_value('autodoc_mock_imports', [], True) @@ -1782,6 +1791,8 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_event('autodoc-process-signature') app.add_event('autodoc-skip-member') + app.connect('config-inited', migrate_autodoc_member_order) + app.setup_extension('sphinx.ext.autodoc.type_comment') app.setup_extension('sphinx.ext.autodoc.typehints') diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 88d7deb68..4ed4a9b05 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -59,7 +59,7 @@ def make_directive_bridge(env): platform = '', deprecated = False, members = [], - member_order = 'alphabetic', + member_order = 'alphabetical', exclude_members = set(), ignore_module_all = False, ) From 5ee475c8de2b6cb5c7edb3bd27ae981e7b0d6cfa Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 May 2020 13:40:30 +0900 Subject: [PATCH 23/40] Fix #7679: autodoc: Pass priority option to the config-inited handler --- sphinx/ext/autodoc/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 08f83ebdf..ae88e92d3 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1791,7 +1791,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_event('autodoc-process-signature') app.add_event('autodoc-skip-member') - app.connect('config-inited', migrate_autodoc_member_order) + app.connect('config-inited', migrate_autodoc_member_order, priority=800) app.setup_extension('sphinx.ext.autodoc.type_comment') app.setup_extension('sphinx.ext.autodoc.typehints') From c2ef1ad7e507c86442eae76e1ad7182383e13c8d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 May 2020 13:47:18 +0900 Subject: [PATCH 24/40] viewcode: Fix viewcode raises NoUri error on resolving phase except on HTML builders --- sphinx/ext/viewcode.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index dc24a1993..a2eeb7891 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -131,8 +131,10 @@ def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: Node ) -> Node: - # resolve our "viewcode" reference nodes -- they need special treatment - if node['reftype'] == 'viewcode': + if app.builder.format != 'html': + return None + elif node['reftype'] == 'viewcode': + # resolve our "viewcode" reference nodes -- they need special treatment return make_refnode(app.builder, node['refdoc'], node['reftarget'], node['refid'], contnode) From 3206e3154afc8d948ff9cdbc7bd22775bea839ba Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 May 2020 18:53:34 +0900 Subject: [PATCH 25/40] Add allowed_exceptions parameter to Sphinx.emit() (refs: #7683) It allows handlers to raise specified exceptions. --- CHANGES | 2 ++ sphinx/application.py | 20 +++++++++++++++----- sphinx/events.py | 14 ++++++++++---- tests/test_events.py | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 22638f6aa..0dd0a4f21 100644 --- a/CHANGES +++ b/CHANGES @@ -73,6 +73,8 @@ Features added :rst:dir:`py:exception:` and :rst:dir:`py:method:` directives * #7596: py domain: Change a type annotation for variables to a hyperlink * #7582: napoleon: a type for attribute are represented like type annotation +* #7683: Add ``allowed_exceptions`` parameter to ``Sphinx.emit()`` to allow + handlers to raise specified exceptions Bugs fixed ---------- diff --git a/sphinx/application.py b/sphinx/application.py index 8f06bf9cf..b02fb4d60 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -436,22 +436,32 @@ class Sphinx: logger.debug('[app] disconnecting event: [id=%s]', listener_id) self.events.disconnect(listener_id) - def emit(self, event: str, *args: Any) -> List: + def emit(self, event: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List: """Emit *event* and pass *arguments* to the callback functions. Return the return values of all callbacks as a list. Do not emit core Sphinx events in extensions! - """ - return self.events.emit(event, *args) - def emit_firstresult(self, event: str, *args: Any) -> Any: + .. versionchanged:: 3.1 + + Added *allowed_exceptions* to specify path-through exceptions + """ + return self.events.emit(event, *args, allowed_exceptions=allowed_exceptions) + + def emit_firstresult(self, event: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any: """Emit *event* and pass *arguments* to the callback functions. Return the result of the first callback that doesn't return ``None``. .. versionadded:: 0.5 + .. versionchanged:: 3.1 + + Added *allowed_exceptions* to specify path-through exceptions """ - return self.events.emit_firstresult(event, *args) + return self.events.emit_firstresult(event, *args, + allowed_exceptions=allowed_exceptions) # registering addon parts diff --git a/sphinx/events.py b/sphinx/events.py index 0f0f47b65..0911dfaaa 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -13,7 +13,7 @@ import warnings from collections import defaultdict from operator import attrgetter -from typing import Any, Callable, Dict, List, NamedTuple +from typing import Any, Callable, Dict, List, NamedTuple, Tuple from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.errors import ExtensionError, SphinxError @@ -22,6 +22,7 @@ from sphinx.util import logging if False: # For type annotation + from typing import Type # for python3.5.1 from sphinx.application import Sphinx @@ -88,7 +89,8 @@ class EventManager: if listener.id == listener_id: listeners.remove(listener) - def emit(self, name: str, *args: Any) -> List: + def emit(self, name: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List: """Emit a Sphinx event.""" try: logger.debug('[app] emitting event: %r%s', name, repr(args)[:100]) @@ -106,6 +108,9 @@ class EventManager: results.append(listener.handler(*args)) else: results.append(listener.handler(self.app, *args)) + except allowed_exceptions: + # pass through the errors specified as *allowed_exceptions* + raise except SphinxError: raise except Exception as exc: @@ -113,12 +118,13 @@ class EventManager: (listener.handler, name)) from exc return results - def emit_firstresult(self, name: str, *args: Any) -> Any: + def emit_firstresult(self, name: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any: """Emit a Sphinx event and returns first result. This returns the result of the first handler that doesn't return ``None``. """ - for result in self.emit(name, *args): + for result in self.emit(name, *args, allowed_exceptions=allowed_exceptions): if result is not None: return result return None diff --git a/tests/test_events.py b/tests/test_events.py index 4881588a4..4fbe03a17 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -8,6 +8,9 @@ :license: BSD, see LICENSE for details. """ +import pytest + +from sphinx.errors import ExtensionError from sphinx.events import EventManager @@ -22,3 +25,19 @@ def test_event_priority(): events.emit('builder-inited') assert result == [3, 1, 2, 5, 4] + + +def test_event_allowed_exceptions(): + def raise_error(app): + raise RuntimeError + + events = EventManager(object()) # pass an dummy object as an app + events.connect('builder-inited', raise_error, priority=500) + + # all errors are conveted to ExtensionError + with pytest.raises(ExtensionError): + events.emit('builder-inited') + + # Allow RuntimeError (pass-through) + with pytest.raises(RuntimeError): + events.emit('builder-inited', allowed_exceptions=(RuntimeError,)) From ff7545a19163e78bdd2bfeb8e9d8832e4582196a Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 17 May 2020 12:32:38 +0200 Subject: [PATCH 26/40] Allow NoUri from 'missing-reference' handlers. Also extend documentation of 'missing-reference'. --- doc/extdev/appapi.rst | 8 ++++++-- sphinx/errors.py | 3 ++- sphinx/transforms/post_transforms/__init__.py | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst index 961558600..d5b1a8a98 100644 --- a/doc/extdev/appapi.rst +++ b/doc/extdev/appapi.rst @@ -230,11 +230,15 @@ connect handlers to the events. Example: .. event:: missing-reference (app, env, node, contnode) - Emitted when a cross-reference to a Python module or object cannot be - resolved. If the event handler can resolve the reference, it should return a + Emitted when a cross-reference to an object cannot be resolved. + If the event handler can resolve the reference, it should return a new docutils node to be inserted in the document tree in place of the node *node*. Usually this node is a :class:`reference` node containing *contnode* as a child. + If the handler can not resolve the cross-reference, + it can either return ``None`` to let other handlers try, + or raise :class:`NoUri` to prevent other handlers in trying and suppress + a warning about this cross-reference being unresolved. :param env: The build environment (``app.builder.env``). :param node: The :class:`pending_xref` node to be resolved. Its attributes diff --git a/sphinx/errors.py b/sphinx/errors.py index a9d027cb8..d9a83712c 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -116,7 +116,8 @@ class PycodeError(Exception): class NoUri(Exception): - """Raised by builder.get_relative_uri() if there is no URI available.""" + """Raised by builder.get_relative_uri() or from missing-reference handlers + if there is no URI available.""" pass diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index 5bd9723e0..742da9d82 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -92,7 +92,8 @@ class ReferencesResolver(SphinxPostTransform): # no new node found? try the missing-reference event if newnode is None: newnode = self.app.emit_firstresult('missing-reference', self.env, - node, contnode) + node, contnode, + allowed_exceptions=(NoUri)) # still not found? warn if node wishes to be warned about or # we are in nit-picky mode if newnode is None: From 2070f836c53025f7684e72f6bb608031e0b3407f Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 17 May 2020 12:39:19 +0200 Subject: [PATCH 27/40] Remember Pythons tuple syntax --- sphinx/transforms/post_transforms/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index 742da9d82..4499e3376 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -93,7 +93,7 @@ class ReferencesResolver(SphinxPostTransform): if newnode is None: newnode = self.app.emit_firstresult('missing-reference', self.env, node, contnode, - allowed_exceptions=(NoUri)) + allowed_exceptions=(NoUri,)) # still not found? warn if node wishes to be warned about or # we are in nit-picky mode if newnode is None: From de4aca857c28f007a9a633a04a2e2e516c3af19a Mon Sep 17 00:00:00 2001 From: Daniel Fremont Date: Sun, 17 May 2020 09:07:11 -0700 Subject: [PATCH 28/40] revisions per comments from tk0miya --- doc/usage/extensions/autosummary.rst | 4 +++ sphinx/ext/autosummary/generate.py | 33 ++++++++++--------- .../templates/autosummary/module.rst | 2 +- .../autosummary_dummy_module.py | 4 +++ tests/roots/test-ext-autosummary/index.rst | 1 + tests/test_ext_autosummary.py | 9 ++++- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/doc/usage/extensions/autosummary.rst b/doc/usage/extensions/autosummary.rst index 49e327019..b5acab65d 100644 --- a/doc/usage/extensions/autosummary.rst +++ b/doc/usage/extensions/autosummary.rst @@ -288,6 +288,10 @@ The following variables available in the templates: List containing names of "public" attributes in the class/module. Only available for classes and modules. + .. versionchanged:: 3.1 + + Attributes of modules are supported. + .. data:: modules List containing names of "public" modules in the package. Only available for diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index a6d86445e..1471b5eb2 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -42,6 +42,7 @@ from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warnin from sphinx.ext.autodoc import Documenter from sphinx.ext.autosummary import import_by_name, get_documenter from sphinx.locale import __ +from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.registry import SphinxComponentRegistry from sphinx.util import logging from sphinx.util import rst @@ -218,6 +219,21 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, public.append(name) return public, items + def get_module_attrs(members: Any) -> Tuple[List[str], List[str]]: + """Find module attributes with docstrings.""" + attrs, public = [], [] + try: + analyzer = ModuleAnalyzer.for_module(name) + attr_docs = analyzer.find_attr_docs() + for namespace, attr_name in attr_docs: + if namespace == '' and attr_name in members: + attrs.append(attr_name) + if not attr_name.startswith('_'): + public.append(attr_name) + except PycodeError: + pass # give up if ModuleAnalyzer fails to parse code + return attrs, public + def get_modules(obj: Any) -> Tuple[List[str], List[str]]: items = [] # type: List[str] for _, modname, ispkg in pkgutil.iter_modules(obj.__path__): @@ -237,24 +253,11 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, get_members(obj, {'class'}, imported=imported_members) ns['exceptions'], ns['all_exceptions'] = \ get_members(obj, {'exception'}, imported=imported_members) + ns['attributes'], ns['all_attributes'] = \ + get_module_attrs(ns['members']) ispackage = hasattr(obj, '__path__') if ispackage and recursive: ns['modules'], ns['all_modules'] = get_modules(obj) - - # Find module attributes with docstrings - attrs, public = [], [] - from sphinx.pycode import ModuleAnalyzer, PycodeError - try: - analyzer = ModuleAnalyzer.for_module(name) - attr_docs = analyzer.find_attr_docs() - for _, attr_name in attr_docs: - if attr_name in ns['members']: - attrs.append(attr_name) - if not attr_name.startswith('_'): - public.append(attr_name) - except PycodeError as err: - pass - ns['attributes'], ns['all_attributes'] = attrs, public elif doc.objtype == 'class': ns['members'] = dir(obj) ns['inherited_members'] = \ diff --git a/sphinx/ext/autosummary/templates/autosummary/module.rst b/sphinx/ext/autosummary/templates/autosummary/module.rst index 8617e9814..3a93e872a 100644 --- a/sphinx/ext/autosummary/templates/autosummary/module.rst +++ b/sphinx/ext/autosummary/templates/autosummary/module.rst @@ -8,7 +8,7 @@ .. autosummary:: {% for item in attributes %} - {{item}} + {{ item }} {%- endfor %} {% endif %} {% endblock %} diff --git a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py index ffd381f51..0c54a1477 100644 --- a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py +++ b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py @@ -19,3 +19,7 @@ class Foo: def bar(x: Union[int, str], y: int = 1): pass + + +#: a module-level attribute +qux = 2 diff --git a/tests/roots/test-ext-autosummary/index.rst b/tests/roots/test-ext-autosummary/index.rst index bc3f80234..9f657bb73 100644 --- a/tests/roots/test-ext-autosummary/index.rst +++ b/tests/roots/test-ext-autosummary/index.rst @@ -11,4 +11,5 @@ autosummary_dummy_module.Foo autosummary_dummy_module.Foo.Bar autosummary_dummy_module.bar + autosummary_dummy_module.qux autosummary_importfail diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index aa075a9e6..166029ccb 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -203,16 +203,18 @@ def test_autosummary_generate(app, status, warning): [autosummary_table, nodes.table, nodes.tgroup, (nodes.colspec, nodes.colspec, [nodes.tbody, (nodes.row, + nodes.row, nodes.row, nodes.row, nodes.row)])]) assert_node(doctree[4][0], addnodes.toctree, caption="An autosummary") - assert len(doctree[3][0][0][2]) == 4 + assert len(doctree[3][0][0][2]) == 5 assert doctree[3][0][0][2][0].astext() == 'autosummary_dummy_module\n\n' assert doctree[3][0][0][2][1].astext() == 'autosummary_dummy_module.Foo()\n\n' assert doctree[3][0][0][2][2].astext() == 'autosummary_dummy_module.Foo.Bar\n\n' assert doctree[3][0][0][2][3].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n' + assert doctree[3][0][0][2][4].astext() == 'autosummary_dummy_module.qux\n\na module-level attribute' module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').read_text() assert (' .. autosummary::\n' @@ -237,6 +239,11 @@ def test_autosummary_generate(app, status, warning): '\n' '.. autoclass:: Foo.Bar\n' in FooBar) + qux = (app.srcdir / 'generated' / 'autosummary_dummy_module.qux.rst').read_text() + assert ('.. currentmodule:: autosummary_dummy_module\n' + '\n' + '.. autodata:: qux' in qux) + @pytest.mark.sphinx('dummy', testroot='ext-autosummary', confoverrides={'autosummary_generate_overwrite': False}) From aad103885f971273b7b97386bd8ab483195ada30 Mon Sep 17 00:00:00 2001 From: Daniel Fremont Date: Sun, 17 May 2020 09:16:29 -0700 Subject: [PATCH 29/40] got public/all attrs backwards --- sphinx/ext/autosummary/generate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 1471b5eb2..a57c73fb7 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -232,7 +232,7 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, public.append(attr_name) except PycodeError: pass # give up if ModuleAnalyzer fails to parse code - return attrs, public + return public, attrs def get_modules(obj: Any) -> Tuple[List[str], List[str]]: items = [] # type: List[str] From 3e68d59d1224407c1d37e0c583969568b9f2730e Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Wed, 20 May 2020 15:15:03 +0300 Subject: [PATCH 30/40] Add viewport meta tag for responsive layout Viewport meta tag is necessary to make layout responsive. Without it, the layout is rendered for desktop size and then scaled down, making text small and difficult to read. It also makes a site fail Google Lighthouse audits. --- sphinx/themes/basic/layout.html | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index 685e548fb..50feffd71 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -120,6 +120,7 @@ {%- else %} {%- endif %} + {{- metatags }} {%- block htmltitle %} {{ title|striptags|e }}{{ titlesuffix }} From b7e6c67ce8274815153434054f148f1e8dcb4e00 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 21 May 2020 00:35:06 +0900 Subject: [PATCH 31/40] Update CHANGES for PR #7695 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 0dd0a4f21..34960dc75 100644 --- a/CHANGES +++ b/CHANGES @@ -65,6 +65,7 @@ Features added * #7541: html theme: Add a "clearer" at the end of the "body" * #7542: html theme: Make admonition/topic/sidebar scrollable * #7543: html theme: Add top and bottom margins to tables +* #7695: html theme: Add viewport meta tag for basic theme * C and C++: allow semicolon in the end of declarations. * C++, parse parameterized noexcept specifiers. * #7294: C++, parse expressions with user-defined literals. From 35651e2508234ff6d71d2416dfe53e4fcf858586 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 21 May 2020 00:53:48 +0900 Subject: [PATCH 32/40] Update CHANGES for PR #7469 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 34960dc75..a548dd5ca 100644 --- a/CHANGES +++ b/CHANGES @@ -48,6 +48,7 @@ Features added * #7466: autosummary: headings in generated documents are not translated * #7490: autosummary: Add ``:caption:`` option to autosummary directive to set a caption to the toctree +* #7469: autosummary: Support module attributes * #248, #6040: autosummary: Add ``:recursive:`` option to autosummary directive to generate stub files recursively * #4030: autosummary: Add :confval:`autosummary_context` to add template From 752d3285d250bbaf673cff25e83f03f247502021 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 21 May 2020 00:56:32 +0900 Subject: [PATCH 33/40] Update docs (refs: #7469) --- doc/usage/extensions/autosummary.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/usage/extensions/autosummary.rst b/doc/usage/extensions/autosummary.rst index b5acab65d..38d18361e 100644 --- a/doc/usage/extensions/autosummary.rst +++ b/doc/usage/extensions/autosummary.rst @@ -290,7 +290,7 @@ The following variables available in the templates: .. versionchanged:: 3.1 - Attributes of modules are supported. + Attributes of modules are supported. .. data:: modules From 784d4cb36a2aca4bcb2c773db2506cc609a2a18a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 17 May 2020 23:07:41 +0900 Subject: [PATCH 34/40] Fix #7685: autosummary: imported members are listed unexpectedly --- CHANGES | 2 + sphinx/ext/autosummary/generate.py | 54 +++++++++++- .../autosummary_dummy_module.py | 20 ++++- tests/test_ext_autosummary.py | 82 ++++++++++++++++++- 4 files changed, 154 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index a548dd5ca..e301f1165 100644 --- a/CHANGES +++ b/CHANGES @@ -101,6 +101,8 @@ Bugs fixed * #7551: autosummary: a nested class is indexed as non-nested class * #7661: autosummary: autosummary directive emits warnings twices if failed to import the target module +* #7685: autosummary: The template variable "members" contains imported members + even if :confval:`autossummary_imported_members` is False * #7535: sphinx-autogen: crashes when custom template uses inheritance * #7536: sphinx-autogen: crashes when template uses i18n feature * #7653: sphinx-quickstart: Fix multiple directory creation for nested relpath diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index a57c73fb7..473ac3db6 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -18,6 +18,7 @@ """ import argparse +import inspect import locale import os import pkgutil @@ -176,6 +177,56 @@ class AutosummaryRenderer: # -- Generating output --------------------------------------------------------- +class ModuleScanner: + def __init__(self, app: Any, obj: Any) -> None: + self.app = app + self.object = obj + + def get_object_type(self, name: str, value: Any) -> str: + return get_documenter(self.app, value, self.object).objtype + + def is_skipped(self, name: str, value: Any, objtype: str) -> bool: + try: + return self.app.emit_firstresult('autodoc-skip-member', objtype, + name, value, False, {}) + except Exception as exc: + logger.warning(__('autosummary: failed to determine %r to be documented, ' + 'the following exception was raised:\n%s'), + name, exc, type='autosummary') + return False + + def scan(self, imported_members: bool) -> List[str]: + members = [] + for name in dir(self.object): + try: + value = safe_getattr(self.object, name) + except AttributeError: + value = None + + objtype = self.get_object_type(name, value) + if self.is_skipped(name, value, objtype): + continue + + try: + if inspect.ismodule(value): + imported = True + elif safe_getattr(value, '__module__') != self.object.__name__: + imported = True + else: + imported = False + except AttributeError: + imported = False + + if imported_members: + # list all members up + members.append(name) + elif imported is False: + # list not-imported members up + members.append(name) + + return members + + def generate_autosummary_content(name: str, obj: Any, parent: Any, template: AutosummaryRenderer, template_name: str, imported_members: bool, app: Any, @@ -246,7 +297,8 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, ns.update(context) if doc.objtype == 'module': - ns['members'] = dir(obj) + scanner = ModuleScanner(app, obj) + ns['members'] = scanner.scan(imported_members) ns['functions'], ns['all_functions'] = \ get_members(obj, {'function'}, imported=imported_members) ns['classes'], ns['all_classes'] = \ diff --git a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py index 0c54a1477..85981a0f8 100644 --- a/tests/roots/test-ext-autosummary/autosummary_dummy_module.py +++ b/tests/roots/test-ext-autosummary/autosummary_dummy_module.py @@ -1,4 +1,4 @@ -from os import * # NOQA +from os import path # NOQA from typing import Union @@ -17,7 +17,23 @@ class Foo: pass -def bar(x: Union[int, str], y: int = 1): +class _Baz: + pass + + +def bar(x: Union[int, str], y: int = 1) -> None: + pass + + +def _quux(): + pass + + +class Exc(Exception): + pass + + +class _Exc(Exception): pass diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 166029ccb..281ba141e 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -19,7 +19,10 @@ from sphinx import addnodes from sphinx.ext.autosummary import ( autosummary_table, autosummary_toc, mangle_signature, import_by_name, extract_summary ) -from sphinx.ext.autosummary.generate import AutosummaryEntry, generate_autosummary_docs, main as autogen_main +from sphinx.ext.autosummary.generate import ( + AutosummaryEntry, generate_autosummary_content, generate_autosummary_docs, + main as autogen_main +) from sphinx.testing.util import assert_node, etree_parse from sphinx.util.docutils import new_document from sphinx.util.osutil import cd @@ -189,6 +192,83 @@ def test_escaping(app, status, warning): assert str_content(title) == 'underscore_module_' +@pytest.mark.sphinx(testroot='ext-autosummary') +def test_autosummary_generate_content_for_module(app): + import autosummary_dummy_module + template = Mock() + + generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None, + template, None, False, app, False, {}) + assert template.render.call_args[0][0] == 'module' + + context = template.render.call_args[0][1] + assert context['members'] == ['Exc', 'Foo', '_Baz', '_Exc', '__builtins__', + '__cached__', '__doc__', '__file__', '__name__', + '__package__', '_quux', 'bar', 'qux'] + assert context['functions'] == ['bar'] + assert context['all_functions'] == ['_quux', 'bar'] + assert context['classes'] == ['Foo'] + assert context['all_classes'] == ['Foo', '_Baz'] + assert context['exceptions'] == ['Exc'] + assert context['all_exceptions'] == ['Exc', '_Exc'] + assert context['attributes'] == ['qux'] + assert context['all_attributes'] == ['qux'] + assert context['fullname'] == 'autosummary_dummy_module' + assert context['module'] == 'autosummary_dummy_module' + assert context['objname'] == '' + assert context['name'] == '' + assert context['objtype'] == 'module' + + +@pytest.mark.sphinx(testroot='ext-autosummary') +def test_autosummary_generate_content_for_module_skipped(app): + import autosummary_dummy_module + template = Mock() + + def skip_member(app, what, name, obj, skip, options): + if name in ('Foo', 'bar', 'Exc'): + return True + + app.connect('autodoc-skip-member', skip_member) + generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None, + template, None, False, app, False, {}) + context = template.render.call_args[0][1] + assert context['members'] == ['_Baz', '_Exc', '__builtins__', '__cached__', '__doc__', + '__file__', '__name__', '__package__', '_quux', 'qux'] + assert context['functions'] == [] + assert context['classes'] == [] + assert context['exceptions'] == [] + + +@pytest.mark.sphinx(testroot='ext-autosummary') +def test_autosummary_generate_content_for_module_imported_members(app): + import autosummary_dummy_module + template = Mock() + + generate_autosummary_content('autosummary_dummy_module', autosummary_dummy_module, None, + template, None, True, app, False, {}) + assert template.render.call_args[0][0] == 'module' + + context = template.render.call_args[0][1] + assert context['members'] == ['Exc', 'Foo', 'Union', '_Baz', '_Exc', '__builtins__', + '__cached__', '__doc__', '__file__', '__loader__', + '__name__', '__package__', '__spec__', '_quux', + 'bar', 'path', 'qux'] + assert context['functions'] == ['bar'] + assert context['all_functions'] == ['_quux', 'bar'] + assert context['classes'] == ['Foo'] + assert context['all_classes'] == ['Foo', '_Baz'] + assert context['exceptions'] == ['Exc'] + assert context['all_exceptions'] == ['Exc', '_Exc'] + assert context['attributes'] == ['qux'] + assert context['all_attributes'] == ['qux'] + assert context['fullname'] == 'autosummary_dummy_module' + assert context['module'] == 'autosummary_dummy_module' + assert context['objname'] == '' + assert context['name'] == '' + assert context['objtype'] == 'module' + + @pytest.mark.sphinx('dummy', testroot='ext-autosummary') def test_autosummary_generate(app, status, warning): app.builder.build_all() From 5e5bd748e6531d57e978fc7730cf6232bd2485e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Defferrard?= Date: Wed, 20 May 2020 22:30:58 +0200 Subject: [PATCH 35/40] remove repeted word in reStructuredText Primer --- doc/usage/restructuredtext/basics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/usage/restructuredtext/basics.rst b/doc/usage/restructuredtext/basics.rst index dffaf297c..8f596ed9a 100644 --- a/doc/usage/restructuredtext/basics.rst +++ b/doc/usage/restructuredtext/basics.rst @@ -159,7 +159,7 @@ Doctest blocks Doctest blocks (:duref:`ref `) are interactive Python sessions cut-and-pasted into docstrings. They do not require the :ref:`literal blocks ` syntax. The doctest block must end -with a blank line and should *not* end with with an unused prompt:: +with a blank line and should *not* end with an unused prompt:: >>> 1 + 1 2 From ebd48b90819c4a5bacbdf7566bd5a0cff17c3ae5 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Sat, 16 May 2020 12:25:42 +0100 Subject: [PATCH 36/40] Respect member-order="bysource" even when no analyzer is present This takes advantage of the fact that in Python 3.6 and up, the __dict__ attribute of classes and modules is insertion-ordered, which is usually a good approximation of "source order". Notably, this means that `..automodule:: some_c_extension_module` will document members in the order they were added to the module dict, which is likely what the user wants. --- sphinx/ext/autodoc/__init__.py | 37 +++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 08f83ebdf..ef4faf182 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -521,12 +521,12 @@ class Documenter: else: logger.warning(__('missing attribute %s in object %s') % (name, self.fullname), type='autodoc') - return False, sorted(selected) + return False, selected elif self.options.inherited_members: - return False, sorted((m.name, m.value) for m in members.values()) + return False, [(m.name, m.value) for m in members.values()] else: - return False, sorted((m.name, m.value) for m in members.values() - if m.directly_defined) + return False, [(m.name, m.value) for m in members.values() + if m.directly_defined] def filter_members(self, members: List[Tuple[str, Any]], want_all: bool ) -> List[Tuple[str, Any, bool]]: @@ -699,17 +699,26 @@ class Documenter: member_order = self.options.member_order or \ self.env.config.autodoc_member_order if member_order == 'groupwise': - # sort by group; relies on stable sort to keep items in the - # same group sorted alphabetically - memberdocumenters.sort(key=lambda e: e[0].member_order) - elif member_order == 'bysource' and self.analyzer: - # sort by source order, by virtue of the module analyzer - tagorder = self.analyzer.tagorder + # sort by group; alphabetically within groups + memberdocumenters.sort(key=lambda e: (e[0].member_order, e[0].name)) + elif member_order == 'bysource': + if self.analyzer: + # sort by source order, by virtue of the module analyzer + tagorder = self.analyzer.tagorder - def keyfunc(entry: Tuple[Documenter, bool]) -> int: - fullname = entry[0].name.split('::')[1] - return tagorder.get(fullname, len(tagorder)) - memberdocumenters.sort(key=keyfunc) + def keyfunc(entry: Tuple[Documenter, bool]) -> int: + fullname = entry[0].name.split('::')[1] + return tagorder.get(fullname, len(tagorder)) + memberdocumenters.sort(key=keyfunc) + else: + # Assume that member discovery order matches source order. + # This is a reasonable assumption in Python 3.6 and up, where + # module.__dict__ is insertion-ordered. + pass + elif member_order == 'alphabetical': + memberdocumenters.sort(key=lambda e: e[0].name) + else: + raise ValueError("Illegal member order {}".format(member_order)) for documenter, isattr in memberdocumenters: documenter.generate( From ce3455d80e2e3c99dcd79912b017f571b5ed4168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Thu, 21 May 2020 12:36:15 +0000 Subject: [PATCH 37/40] Fix typo in make.bat_t, https:// link --- sphinx/templates/quickstart/make.bat_t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 774585566..830cf656e 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -27,9 +27,9 @@ if "%1" == "help" ( 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. qthelp to make HTML files and a Qt help project echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub + echo. epub to make an EPUB echo. latex to make LaTeX files (you can set PAPER=a4 or PAPER=letter) echo. latexpdf to make LaTeX files and then PDFs out of them echo. text to make text files @@ -69,7 +69,7 @@ if errorlevel 9009 ( 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/ + echo.https://sphinx-doc.org/ exit /b 1 ) From 04698d525a92101d5ff6863cfd15b70e9f0533be Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 21 May 2020 22:58:47 +0900 Subject: [PATCH 38/40] refactor: autosectionlabel: Use accessors of std domain --- sphinx/ext/autosectionlabel.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sphinx/ext/autosectionlabel.py b/sphinx/ext/autosectionlabel.py index 9890cdf7d..4bb401791 100644 --- a/sphinx/ext/autosectionlabel.py +++ b/sphinx/ext/autosectionlabel.py @@ -15,6 +15,7 @@ from docutils import nodes from docutils.nodes import Node from sphinx.application import Sphinx +from sphinx.domains.std import StandardDomain from sphinx.locale import __ from sphinx.util import logging from sphinx.util.nodes import clean_astext @@ -33,8 +34,7 @@ def get_node_depth(node: Node) -> int: def register_sections_as_label(app: Sphinx, document: Node) -> None: - labels = app.env.domaindata['std']['labels'] - anonlabels = app.env.domaindata['std']['anonlabels'] + domain = cast(StandardDomain, app.env.get_domain('std')) for node in document.traverse(nodes.section): if (app.config.autosectionlabel_maxdepth and get_node_depth(node) >= app.config.autosectionlabel_maxdepth): @@ -49,13 +49,13 @@ def register_sections_as_label(app: Sphinx, document: Node) -> None: name = nodes.fully_normalize_name(ref_name) sectname = clean_astext(title) - if name in labels: + if name in domain.labels: logger.warning(__('duplicate label %s, other instance in %s'), - name, app.env.doc2path(labels[name][0]), + name, app.env.doc2path(domain.labels[name][0]), location=node, type='autosectionlabel', subtype=docname) - anonlabels[name] = docname, labelid - labels[name] = docname, labelid, sectname + domain.anonlabels[name] = docname, labelid + domain.labels[name] = docname, labelid, sectname def setup(app: Sphinx) -> Dict[str, Any]: From eb29926441ee13eeea333f09771f92d7e4d38a5f Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 21 May 2020 23:50:20 +0900 Subject: [PATCH 39/40] Fix #7696: html: Updated jQuery version from 3.4.1 to 3.5.1 --- CHANGES | 1 + .../{jquery-3.4.1.js => jquery-3.5.1.js} | 1238 ++++++++++------- sphinx/themes/basic/static/jquery.js | 4 +- tests/test_theming.py | 2 +- 4 files changed, 760 insertions(+), 485 deletions(-) rename sphinx/themes/basic/static/{jquery-3.4.1.js => jquery-3.5.1.js} (91%) diff --git a/CHANGES b/CHANGES index aef983eb6..4156c2909 100644 --- a/CHANGES +++ b/CHANGES @@ -18,6 +18,7 @@ Bugs fixed * #7567: autodoc: parametrized types are shown twice for generic types * #7637: autodoc: system defined TypeVars are shown in Python 3.9 +* #7696: html: Updated jQuery version from 3.4.1 to 3.5.1 for security reasons * #7611: md5 fails when OpenSSL FIPS is enabled * #7626: release package does not contain ``CODE_OF_CONDUCT`` diff --git a/sphinx/themes/basic/static/jquery-3.4.1.js b/sphinx/themes/basic/static/jquery-3.5.1.js similarity index 91% rename from sphinx/themes/basic/static/jquery-3.4.1.js rename to sphinx/themes/basic/static/jquery-3.5.1.js index 773ad95c5..50937333b 100644 --- a/sphinx/themes/basic/static/jquery-3.4.1.js +++ b/sphinx/themes/basic/static/jquery-3.5.1.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v3.4.1 + * jQuery JavaScript Library v3.5.1 * https://jquery.com/ * * Includes Sizzle.js @@ -9,7 +9,7 @@ * Released under the MIT license * https://jquery.org/license * - * Date: 2019-05-01T21:04Z + * Date: 2020-05-04T22:49Z */ ( function( global, factory ) { @@ -47,13 +47,16 @@ var arr = []; -var document = window.document; - var getProto = Object.getPrototypeOf; var slice = arr.slice; -var concat = arr.concat; +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + var push = arr.push; @@ -86,6 +89,8 @@ var isWindow = function isWindow( obj ) { }; +var document = window.document; + var preservedScriptAttributes = { @@ -142,7 +147,7 @@ function toType( obj ) { var - version = "3.4.1", + version = "3.5.1", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -150,11 +155,7 @@ var // 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.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + }; jQuery.fn = jQuery.prototype = { @@ -220,6 +221,18 @@ jQuery.fn = jQuery.prototype = { return this.eq( -1 ); }, + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); @@ -353,9 +366,10 @@ jQuery.extend( { return true; }, - // Evaluates a script in a global context - globalEval: function( code, options ) { - DOMEval( code, { nonce: options && options.nonce } ); + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); }, each: function( obj, callback ) { @@ -379,13 +393,6 @@ jQuery.extend( { return obj; }, - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - // results is for internal usage only makeArray: function( arr, results ) { var ret = results || []; @@ -472,7 +479,7 @@ jQuery.extend( { } // Flatten any nested arrays - return concat.apply( [], ret ); + return flat( ret ); }, // A global GUID counter for objects @@ -489,7 +496,7 @@ if ( typeof Symbol === "function" ) { // Populate the class2type map jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { +function( _i, name ) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); } ); @@ -511,17 +518,16 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.3.4 + * Sizzle CSS Selector Engine v2.3.5 * https://sizzlejs.com/ * * Copyright JS Foundation and other contributors * Released under the MIT license * https://js.foundation/ * - * Date: 2019-04-08 + * Date: 2020-03-14 */ -(function( window ) { - +( function( window ) { var i, support, Expr, @@ -561,59 +567,70 @@ var i, }, // Instance methods - hasOwn = ({}).hasOwnProperty, + hasOwn = ( {} ).hasOwnProperty, arr = [], pop = arr.pop, - push_native = arr.push, + pushNative = arr.push, push = arr.push, slice = arr.slice, + // 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 = list.length; for ( ; i < len; i++ ) { - if ( list[i] === elem ) { + if ( list[ i ] === elem ) { return i; } } return -1; }, - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", // Regular expressions // http://www.w3.org/TR/css3-selectors/#whitespace whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors 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 + - "*\\]", + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: // 1. quoted (capture 3; capture 4 or capture 5) "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) ".*" + ")\\)|)", // 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" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), rdescend = new RegExp( whitespace + "|>" ), rpseudo = new RegExp( pseudos ), @@ -625,14 +642,16 @@ var i, "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 + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, rhtml = /HTML$/i, @@ -648,18 +667,21 @@ var i, // 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; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair high < 0 ? - // BMP codepoint String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); }, @@ -675,7 +697,8 @@ var i, } // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; } // Other potentially-special ASCII characters get backslash-escaped @@ -700,18 +723,20 @@ var i, // Optimize for push.apply( _, NodeList ) try { push.apply( - (arr = slice.call( preferredDoc.childNodes )), + ( arr = slice.call( preferredDoc.childNodes ) ), preferredDoc.childNodes ); + // Support: Android<4.0 // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions arr[ preferredDoc.childNodes.length ].nodeType; } catch ( e ) { push = { apply: arr.length ? // Leverage slice if possible function( target, els ) { - push_native.apply( target, slice.call(els) ); + pushNative.apply( target, slice.call( els ) ); } : // Support: IE<9 @@ -719,8 +744,9 @@ try { function( target, els ) { var j = target.length, i = 0; + // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} + while ( ( target[ j++ ] = els[ i++ ] ) ) {} target.length = j - 1; } }; @@ -744,24 +770,21 @@ function Sizzle( selector, context, results, seed ) { // Try to shortcut find operations (as opposed to filters) in HTML documents if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } + 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 )) ) { + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { // ID selector - if ( (m = match[1]) ) { + if ( ( m = match[ 1 ] ) ) { // Document context if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { + if ( ( elem = context.getElementById( m ) ) ) { // Support: IE, Opera, Webkit // TODO: identify versions @@ -780,7 +803,7 @@ function Sizzle( selector, context, results, seed ) { // Support: IE, Opera, Webkit // TODO: identify versions // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && + if ( newContext && ( elem = newContext.getElementById( m ) ) && contains( context, elem ) && elem.id === m ) { @@ -790,12 +813,12 @@ function Sizzle( selector, context, results, seed ) { } // Type selector - } else if ( match[2] ) { + } else if ( match[ 2 ] ) { push.apply( results, context.getElementsByTagName( selector ) ); return results; // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && context.getElementsByClassName ) { push.apply( results, context.getElementsByClassName( m ) ); @@ -806,11 +829,11 @@ function Sizzle( selector, context, results, seed ) { // Take advantage of querySelectorAll if ( support.qsa && !nonnativeSelectorCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && // Support: IE 8 only // Exclude object elements - (nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) { + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { newSelector = selector; newContext = context; @@ -819,27 +842,36 @@ function Sizzle( selector, context, results, seed ) { // descendant combinators, which is not what we want. // In such cases, we work around the behavior by prefixing every selector in the // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && rdescend.test( selector ) ) { + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { - // 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) ); + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // 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] ); + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); } newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; } try { @@ -872,12 +904,14 @@ function createCache() { var keys = []; function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries delete cache[ keys.shift() ]; } - return (cache[ key + " " ] = value); + return ( cache[ key + " " ] = value ); } return cache; } @@ -896,17 +930,19 @@ function markFunction( fn ) { * @param {Function} fn Passed the created element and returns a boolean result */ function assert( fn ) { - var el = document.createElement("fieldset"); + var el = document.createElement( "fieldset" ); try { return !!fn( el ); - } catch (e) { + } catch ( e ) { return false; } finally { + // Remove from its parent by default if ( el.parentNode ) { el.parentNode.removeChild( el ); } + // release memory in IE el = null; } @@ -918,11 +954,11 @@ function assert( fn ) { * @param {Function} handler The method that will be applied */ function addHandle( attrs, handler ) { - var arr = attrs.split("|"), + var arr = attrs.split( "|" ), i = arr.length; while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; + Expr.attrHandle[ arr[ i ] ] = handler; } } @@ -944,7 +980,7 @@ function siblingCheck( a, b ) { // Check if b follows a if ( cur ) { - while ( (cur = cur.nextSibling) ) { + while ( ( cur = cur.nextSibling ) ) { if ( cur === b ) { return -1; } @@ -972,7 +1008,7 @@ function createInputPseudo( type ) { function createButtonPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; + return ( name === "input" || name === "button" ) && elem.type === type; }; } @@ -1015,7 +1051,7 @@ function createDisabledPseudo( disabled ) { // Where there is no isDisabled, check manually /* jshint -W018 */ elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; + inDisabledFieldset( elem ) === disabled; } return elem.disabled === disabled; @@ -1037,21 +1073,21 @@ function createDisabledPseudo( disabled ) { * @param {Function} fn */ function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { + return markFunction( function( argument ) { argument = +argument; - return markFunction(function( seed, matches ) { + return markFunction( function( seed, matches ) { var j, matchIndexes = fn( [], seed.length, argument ), i = matchIndexes.length; // Match elements found at the specified indexes while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); } } - }); - }); + } ); + } ); } /** @@ -1073,7 +1109,7 @@ support = Sizzle.support = {}; */ isXML = Sizzle.isXML = function( elem ) { var namespace = elem.namespaceURI, - docElem = (elem.ownerDocument || elem).documentElement; + docElem = ( elem.ownerDocument || elem ).documentElement; // Support: IE <=8 // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes @@ -1091,7 +1127,11 @@ setDocument = Sizzle.setDocument = function( node ) { doc = node ? node.ownerDocument || node : preferredDoc; // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { return document; } @@ -1100,10 +1140,14 @@ setDocument = Sizzle.setDocument = function( node ) { docElem = document.documentElement; documentIsHTML = !isXML( document ); - // Support: IE 9-11, Edge + // Support: IE 9 - 11+, Edge 12 - 18+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( preferredDoc !== document && - (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { // Support: IE 11, Edge if ( subWindow.addEventListener ) { @@ -1115,25 +1159,36 @@ setDocument = Sizzle.setDocument = function( node ) { } } + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + /* Attributes ---------------------------------------------------------------------- */ // Support: IE<8 // Verify that getAttribute really returns attributes and not properties // (excepting IE8 booleans) - support.attributes = assert(function( el ) { + support.attributes = assert( function( el ) { el.className = "i"; - return !el.getAttribute("className"); - }); + return !el.getAttribute( "className" ); + } ); /* getElement(s)By* ---------------------------------------------------------------------- */ // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( el ) { - el.appendChild( document.createComment("") ); - return !el.getElementsByTagName("*").length; - }); + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); // Support: IE<9 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); @@ -1142,38 +1197,38 @@ setDocument = Sizzle.setDocument = function( node ) { // Check if getElementById returns elements by name // The broken getElementById methods don't pick up programmatically-set names, // so use a roundabout getElementsByName test - support.getById = assert(function( el ) { + support.getById = assert( function( el ) { docElem.appendChild( el ).id = expando; return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); + } ); // ID filter and find if ( support.getById ) { - Expr.filter["ID"] = function( id ) { + Expr.filter[ "ID" ] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { - return elem.getAttribute("id") === attrId; + return elem.getAttribute( "id" ) === attrId; }; }; - Expr.find["ID"] = function( id, context ) { + Expr.find[ "ID" ] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var elem = context.getElementById( id ); return elem ? [ elem ] : []; } }; } else { - Expr.filter["ID"] = function( id ) { + Expr.filter[ "ID" ] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); + elem.getAttributeNode( "id" ); return node && node.value === attrId; }; }; // Support: IE 6 - 7 only // getElementById is not reliable as a find shortcut - Expr.find["ID"] = function( id, context ) { + Expr.find[ "ID" ] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var node, i, elems, elem = context.getElementById( id ); @@ -1181,7 +1236,7 @@ setDocument = Sizzle.setDocument = function( node ) { if ( elem ) { // Verify the id attribute - node = elem.getAttributeNode("id"); + node = elem.getAttributeNode( "id" ); if ( node && node.value === id ) { return [ elem ]; } @@ -1189,8 +1244,8 @@ setDocument = Sizzle.setDocument = function( node ) { // Fall back on getElementsByName elems = context.getElementsByName( id ); i = 0; - while ( (elem = elems[i++]) ) { - node = elem.getAttributeNode("id"); + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); if ( node && node.value === id ) { return [ elem ]; } @@ -1203,7 +1258,7 @@ setDocument = Sizzle.setDocument = function( node ) { } // Tag - Expr.find["TAG"] = support.getElementsByTagName ? + Expr.find[ "TAG" ] = support.getElementsByTagName ? function( tag, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( tag ); @@ -1218,12 +1273,13 @@ setDocument = Sizzle.setDocument = function( node ) { var elem, tmp = [], i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too results = context.getElementsByTagName( tag ); // Filter out possible comments if ( tag === "*" ) { - while ( (elem = results[i++]) ) { + while ( ( elem = results[ i++ ] ) ) { if ( elem.nodeType === 1 ) { tmp.push( elem ); } @@ -1235,7 +1291,7 @@ setDocument = Sizzle.setDocument = function( node ) { }; // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { return context.getElementsByClassName( className ); } @@ -1256,10 +1312,14 @@ setDocument = Sizzle.setDocument = function( node ) { // See https://bugs.jquery.com/ticket/13378 rbuggyQSA = []; - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + // Build QSA regex // Regex strategy adopted from Diego Perini - assert(function( el ) { + assert( function( el ) { + + var input; + // Select is set to empty string on purpose // This is to test IE's treatment of not explicitly // setting a boolean content attribute, @@ -1273,78 +1333,98 @@ setDocument = Sizzle.setDocument = function( node ) { // Nothing should be selected when empty strings follow ^= or $= or *= // The test attribute must be unknown in Opera but "safe" for WinRT // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll("[msallowcapture^='']").length ) { + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); } // Support: IE8 // Boolean attributes and "value" are not treated correctly - if ( !el.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("~="); + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); } // 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 ( !el.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); + 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(".#.+[+~]"); + rbuggyQSA.push( ".#.+[+~]" ); } - }); - assert(function( el ) { + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { el.innerHTML = "" + ""; // Support: Windows 8 Native Apps // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); + var input = document.createElement( "input" ); input.setAttribute( "type", "hidden" ); el.appendChild( input ).setAttribute( "name", "D" ); // Support: IE8 // Enforce case-sensitivity of name attribute - if ( el.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 ( el.querySelectorAll(":enabled").length !== 2 ) { + 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 ) { + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { rbuggyQSA.push( ":enabled", ":disabled" ); } + // Support: Opera 10 - 11 only // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); } - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { - assert(function( el ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9) support.disconnectedMatch = matches.call( el, "*" ); @@ -1353,11 +1433,11 @@ setDocument = Sizzle.setDocument = function( node ) { // Gecko does not error, returns false instead matches.call( el, "[s!='']:x" ); rbuggyMatches.push( "!=", pseudos ); - }); + } ); } - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); /* Contains ---------------------------------------------------------------------- */ @@ -1374,11 +1454,11 @@ setDocument = Sizzle.setDocument = function( node ) { adown.contains ? adown.contains( bup ) : a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); + ) ); } : function( a, b ) { if ( b ) { - while ( (b = b.parentNode) ) { + while ( ( b = b.parentNode ) ) { if ( b === a ) { return true; } @@ -1407,7 +1487,11 @@ setDocument = Sizzle.setDocument = function( node ) { } // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? a.compareDocumentPosition( b ) : // Otherwise we know they are disconnected @@ -1415,13 +1499,24 @@ setDocument = Sizzle.setDocument = function( node ) { // Disconnected nodes if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { return -1; } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { return 1; } @@ -1434,6 +1529,7 @@ setDocument = Sizzle.setDocument = function( node ) { return compare & 4 ? -1 : 1; } : function( a, b ) { + // Exit early if the nodes are identical if ( a === b ) { hasDuplicate = true; @@ -1449,8 +1545,14 @@ setDocument = Sizzle.setDocument = function( node ) { // Parentless nodes are either documents or disconnected if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ aup ? -1 : bup ? 1 : sortInput ? @@ -1464,26 +1566,32 @@ setDocument = Sizzle.setDocument = function( node ) { // Otherwise we need full lists of their ancestors for comparison cur = a; - while ( (cur = cur.parentNode) ) { + while ( ( cur = cur.parentNode ) ) { ap.unshift( cur ); } cur = b; - while ( (cur = cur.parentNode) ) { + while ( ( cur = cur.parentNode ) ) { bp.unshift( cur ); } // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { + while ( ap[ i ] === bp[ i ] ) { i++; } return i ? + // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : + siblingCheck( ap[ i ], bp[ i ] ) : // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ 0; }; @@ -1495,10 +1603,7 @@ Sizzle.matches = function( expr, elements ) { }; Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } + setDocument( elem ); if ( support.matchesSelector && documentIsHTML && !nonnativeSelectorCache[ expr + " " ] && @@ -1510,12 +1615,13 @@ Sizzle.matchesSelector = function( elem, expr ) { // IE 9's matchesSelector returns false on disconnected nodes if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { return ret; } - } catch (e) { + } catch ( e ) { nonnativeSelectorCache( expr, true ); } } @@ -1524,20 +1630,31 @@ Sizzle.matchesSelector = function( elem, expr ) { }; Sizzle.contains = function( context, elem ) { + // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { setDocument( context ); } return contains( context, elem ); }; Sizzle.attr = function( elem, name ) { + // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { setDocument( elem ); } var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? fn( elem, name, !documentIsHTML ) : @@ -1547,13 +1664,13 @@ Sizzle.attr = function( elem, name ) { val : support.attributes || !documentIsHTML ? elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? + ( val = elem.getAttributeNode( name ) ) && val.specified ? val.value : null; }; Sizzle.escape = function( sel ) { - return (sel + "").replace( rcssescape, fcssescape ); + return ( sel + "" ).replace( rcssescape, fcssescape ); }; Sizzle.error = function( msg ) { @@ -1576,7 +1693,7 @@ Sizzle.uniqueSort = function( results ) { results.sort( sortOrder ); if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { + while ( ( elem = results[ i++ ] ) ) { if ( elem === results[ i ] ) { j = duplicates.push( i ); } @@ -1604,17 +1721,21 @@ getText = Sizzle.getText = function( elem ) { nodeType = elem.nodeType; if ( !nodeType ) { + // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { + while ( ( node = elem[ i++ ] ) ) { + // Do not traverse comment nodes ret += getText( node ); } } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements // innerText usage removed for consistency of new lines (jQuery #11153) if ( typeof elem.textContent === "string" ) { return elem.textContent; } else { + // Traverse its children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { ret += getText( elem ); @@ -1623,6 +1744,7 @@ getText = Sizzle.getText = function( elem ) { } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } + // Do not include comment or processing instruction nodes return ret; @@ -1650,19 +1772,21 @@ Expr = Sizzle.selectors = { preFilter: { "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; } return match.slice( 0, 4 ); }, "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] 1 type (only|nth|...) 2 what (child|of-type) @@ -1673,22 +1797,25 @@ Expr = Sizzle.selectors = { 7 sign of y-component 8 y of y-component */ - match[1] = match[1].toLowerCase(); + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { - if ( match[1].slice( 0, 3 ) === "nth" ) { // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); } return match; @@ -1696,26 +1823,28 @@ Expr = Sizzle.selectors = { "PSEUDO": function( match ) { var excess, - unquoted = !match[6] && match[2]; + unquoted = !match[ 6 ] && match[ 2 ]; - if ( matchExpr["CHILD"].test( match[0] ) ) { + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { return null; } // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; // Strip excess characters from unquoted arguments } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && + ( excess = tokenize( unquoted, true ) ) && + // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); } // Return only captures needed by the pseudo filter method (type and argument) @@ -1728,7 +1857,9 @@ Expr = Sizzle.selectors = { "TAG": function( nodeNameSelector ) { var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); return nodeNameSelector === "*" ? - function() { return true; } : + function() { + return true; + } : function( elem ) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; @@ -1738,10 +1869,16 @@ Expr = Sizzle.selectors = { var pattern = classCache[ className + " " ]; return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); }, "ATTR": function( name, operator, check ) { @@ -1757,6 +1894,8 @@ Expr = Sizzle.selectors = { result += ""; + /* eslint-disable max-len */ + return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf( check ) === 0 : @@ -1765,10 +1904,12 @@ Expr = Sizzle.selectors = { operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : false; + /* eslint-enable max-len */ + }; }, - "CHILD": function( type, what, argument, first, last ) { + "CHILD": function( type, what, _argument, first, last ) { var simple = type.slice( 0, 3 ) !== "nth", forward = type.slice( -4 ) !== "last", ofType = what === "of-type"; @@ -1780,7 +1921,7 @@ Expr = Sizzle.selectors = { return !!elem.parentNode; } : - function( elem, context, xml ) { + function( elem, _context, xml ) { var cache, uniqueCache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, @@ -1794,7 +1935,7 @@ Expr = Sizzle.selectors = { if ( simple ) { while ( dir ) { node = elem; - while ( (node = node[ dir ]) ) { + while ( ( node = node[ dir ] ) ) { if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { @@ -1802,6 +1943,7 @@ Expr = Sizzle.selectors = { return false; } } + // Reverse direction for :only-* (if we haven't yet done so) start = dir = type === "only" && !start && "nextSibling"; } @@ -1817,22 +1959,22 @@ Expr = Sizzle.selectors = { // ...in a gzip-friendly way node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); + outerCache = node[ expando ] || ( node[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || - (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 ] || + while ( ( node = ++nodeIndex && node && node[ dir ] || // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { + ( diff = nodeIndex = 0 ) || start.pop() ) ) { // When found, cache indexes on `parent` and break if ( node.nodeType === 1 && ++diff && node === elem ) { @@ -1842,16 +1984,18 @@ Expr = Sizzle.selectors = { } } else { + // Use previously-cached element index if available if ( useCache ) { + // ...in a gzip-friendly way node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); + outerCache = node[ expando ] || ( node[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); + ( outerCache[ node.uniqueID ] = {} ); cache = uniqueCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; @@ -1861,9 +2005,10 @@ Expr = Sizzle.selectors = { // 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()) ) { + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { if ( ( ofType ? node.nodeName.toLowerCase() === name : @@ -1872,12 +2017,13 @@ Expr = Sizzle.selectors = { // Cache the index of each encountered element if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); + outerCache = node[ expando ] || + ( node[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); + ( outerCache[ node.uniqueID ] = {} ); uniqueCache[ type ] = [ dirruns, diff ]; } @@ -1898,6 +2044,7 @@ Expr = Sizzle.selectors = { }, "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive // http://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters @@ -1917,15 +2064,15 @@ Expr = Sizzle.selectors = { if ( fn.length > 1 ) { args = [ pseudo, pseudo, "", argument ]; return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { + markFunction( function( seed, matches ) { var idx, matched = fn( seed, argument ), i = matched.length; while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); } - }) : + } ) : function( elem ) { return fn( elem, 0, args ); }; @@ -1936,8 +2083,10 @@ Expr = Sizzle.selectors = { }, pseudos: { + // Potentially complex pseudos - "not": markFunction(function( selector ) { + "not": markFunction( function( selector ) { + // Trim the selector passed to compile // to avoid treating leading and trailing // spaces as combinators @@ -1946,39 +2095,40 @@ Expr = Sizzle.selectors = { matcher = compile( selector.replace( rtrim, "$1" ) ); return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { + markFunction( function( seed, matches, _context, xml ) { var elem, unmatched = matcher( seed, null, xml, [] ), i = seed.length; // Match elements unmatched by `matcher` while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); } } - }) : - function( elem, context, xml ) { - input[0] = elem; + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; matcher( input, null, xml, results ); + // Don't keep the element (issue #299) - input[0] = null; + input[ 0 ] = null; return !results.pop(); }; - }), + } ), - "has": markFunction(function( selector ) { + "has": markFunction( function( selector ) { return function( elem ) { return Sizzle( selector, elem ).length > 0; }; - }), + } ), - "contains": markFunction(function( text ) { + "contains": markFunction( function( text ) { text = text.replace( runescape, funescape ); return function( elem ) { return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; }; - }), + } ), // "Whether an element is represented by a :lang() selector // is based solely on the element's language value @@ -1988,25 +2138,26 @@ Expr = Sizzle.selectors = { // The identifier C does not have to be a valid language name." // http://www.w3.org/TR/selectors/#lang-pseudo "lang": markFunction( function( lang ) { + // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { + if ( !ridentifier.test( lang || "" ) ) { Sizzle.error( "unsupported lang: " + lang ); } lang = lang.replace( runescape, funescape ).toLowerCase(); return function( elem ) { var elemLang; do { - if ( (elemLang = documentIsHTML ? + if ( ( elemLang = documentIsHTML ? elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { elemLang = elemLang.toLowerCase(); return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); return false; }; - }), + } ), // Miscellaneous "target": function( elem ) { @@ -2019,7 +2170,9 @@ Expr = Sizzle.selectors = { }, "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); }, // Boolean properties @@ -2027,16 +2180,20 @@ Expr = Sizzle.selectors = { "disabled": createDisabledPseudo( true ), "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); }, "selected": function( elem ) { + // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions elem.parentNode.selectedIndex; } @@ -2045,6 +2202,7 @@ Expr = Sizzle.selectors = { // Contents "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), // but not by others (comment: 8; processing instruction: 7; etc.) @@ -2058,7 +2216,7 @@ Expr = Sizzle.selectors = { }, "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); + return !Expr.pseudos[ "empty" ]( elem ); }, // Element/input types @@ -2082,39 +2240,40 @@ Expr = Sizzle.selectors = { // Support: IE<8 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); }, // Position-in-collection - "first": createPositionalPseudo(function() { + "first": createPositionalPseudo( function() { return [ 0 ]; - }), + } ), - "last": createPositionalPseudo(function( matchIndexes, length ) { + "last": createPositionalPseudo( function( _matchIndexes, length ) { return [ length - 1 ]; - }), + } ), - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { return [ argument < 0 ? argument + length : argument ]; - }), + } ), - "even": createPositionalPseudo(function( matchIndexes, length ) { + "even": createPositionalPseudo( function( matchIndexes, length ) { var i = 0; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; - }), + } ), - "odd": createPositionalPseudo(function( matchIndexes, length ) { + "odd": createPositionalPseudo( function( matchIndexes, length ) { var i = 1; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; - }), + } ), - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument > length ? @@ -2124,19 +2283,19 @@ Expr = Sizzle.selectors = { matchIndexes.push( i ); } return matchIndexes; - }), + } ), - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; ++i < length; ) { matchIndexes.push( i ); } return matchIndexes; - }) + } ) } }; -Expr.pseudos["nth"] = Expr.pseudos["eq"]; +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; // Add button/input type pseudos for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { @@ -2167,37 +2326,39 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) { while ( soFar ) { // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { if ( match ) { + // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; + soFar = soFar.slice( match[ 0 ].length ) || soFar; } - groups.push( (tokens = []) ); + groups.push( ( tokens = [] ) ); } matched = false; // Combinators - if ( (match = rcombinators.exec( soFar )) ) { + if ( ( match = rcombinators.exec( soFar ) ) ) { matched = match.shift(); - tokens.push({ + tokens.push( { value: matched, + // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); + type: match[ 0 ].replace( rtrim, " " ) + } ); soFar = soFar.slice( matched.length ); } // Filters for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { matched = match.shift(); - tokens.push({ + tokens.push( { value: matched, type: type, matches: match - }); + } ); soFar = soFar.slice( matched.length ); } } @@ -2214,6 +2375,7 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) { soFar.length : soFar ? Sizzle.error( selector ) : + // Cache the tokens tokenCache( selector, groups ).slice( 0 ); }; @@ -2223,7 +2385,7 @@ function toSelector( tokens ) { len = tokens.length, selector = ""; for ( ; i < len; i++ ) { - selector += tokens[i].value; + selector += tokens[ i ].value; } return selector; } @@ -2236,9 +2398,10 @@ function addCombinator( matcher, combinator, base ) { doneName = done++; return combinator.first ? + // Check against closest ancestor/preceding element function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { + while ( ( elem = elem[ dir ] ) ) { if ( elem.nodeType === 1 || checkNonElements ) { return matcher( elem, context, xml ); } @@ -2253,7 +2416,7 @@ function addCombinator( matcher, combinator, base ) { // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching if ( xml ) { - while ( (elem = elem[ dir ]) ) { + while ( ( elem = elem[ dir ] ) ) { if ( elem.nodeType === 1 || checkNonElements ) { if ( matcher( elem, context, xml ) ) { return true; @@ -2261,27 +2424,29 @@ function addCombinator( matcher, combinator, base ) { } } } else { - while ( (elem = elem[ dir ]) ) { + while ( ( elem = elem[ dir ] ) ) { if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); if ( skip && skip === elem.nodeName.toLowerCase() ) { elem = elem[ dir ] || elem; - } else if ( (oldCache = uniqueCache[ key ]) && + } 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 ]); + return ( newCache[ 2 ] = oldCache[ 2 ] ); } else { + // Reuse newcache so results back-propagate to previous elements uniqueCache[ key ] = newCache; // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { return true; } } @@ -2297,20 +2462,20 @@ function elementMatcher( matchers ) { function( elem, context, xml ) { var i = matchers.length; while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { + if ( !matchers[ i ]( elem, context, xml ) ) { return false; } } return true; } : - matchers[0]; + matchers[ 0 ]; } function multipleContexts( selector, contexts, results ) { var i = 0, len = contexts.length; for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); + Sizzle( selector, contexts[ i ], results ); } return results; } @@ -2323,7 +2488,7 @@ function condense( unmatched, map, filter, context, xml ) { mapped = map != null; for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { + if ( ( elem = unmatched[ i ] ) ) { if ( !filter || filter( elem, context, xml ) ) { newUnmatched.push( elem ); if ( mapped ) { @@ -2343,14 +2508,18 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS if ( postFinder && !postFinder[ expando ] ) { postFinder = setMatcher( postFinder, postSelector ); } - return markFunction(function( seed, results, context, xml ) { + return markFunction( function( seed, results, context, xml ) { var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), // Prefilter to get matcher input, preserving a map for seed-results synchronization matcherIn = preFilter && ( seed || !selector ) ? @@ -2358,6 +2527,7 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS elems, matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, postFinder || ( seed ? preFilter : preexisting || postFilter ) ? @@ -2381,8 +2551,8 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS // Un-match failing elements by moving them back to matcherIn i = temp.length; while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); } } } @@ -2390,25 +2560,27 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS if ( seed ) { if ( postFinder || preFilter ) { if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts temp = []; i = matcherOut.length; while ( i-- ) { - if ( (elem = matcherOut[i]) ) { + if ( ( elem = matcherOut[ i ] ) ) { + // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); + temp.push( ( matcherIn[ i ] = elem ) ); } } - postFinder( null, (matcherOut = []), temp, xml ); + postFinder( null, ( matcherOut = [] ), temp, xml ); } // Move matched elements from seed to results to keep them synchronized i = matcherOut.length; while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { - seed[temp] = !(results[temp] = elem); + seed[ temp ] = !( results[ temp ] = elem ); } } } @@ -2426,14 +2598,14 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS push.apply( results, matcherOut ); } } - }); + } ); } function matcherFromTokens( tokens ) { var checkContext, matcher, j, len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], i = leadingRelative ? 1 : 0, // The foundational matcher ensures that elements are reachable from top-level context(s) @@ -2445,38 +2617,43 @@ function matcherFromTokens( tokens ) { }, implicitRelative, true ), matchers = [ function( elem, context, xml ) { var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? + ( 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++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); // Return special upon seeing a positional matcher if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling j = ++i; for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { + if ( Expr.relative[ tokens[ j ].type ] ) { break; } } return setMatcher( i > 1 && elementMatcher( matchers ), i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) ).replace( rtrim, "$1" ), matcher, i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), j < len && toSelector( tokens ) ); } @@ -2497,28 +2674,40 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { unmatched = seed && [], setMatched = [], contextBackup = outermostContext, + // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), len = elems.length; if ( outermost ) { - outermostContext = context === document || context || outermost; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; } // Add elements passing elementMatchers directly to results // Support: IE<9, Safari // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { if ( byElement && elem ) { j = 0; - if ( !context && elem.ownerDocument !== document ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { setDocument( elem ); xml = !documentIsHTML; } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { results.push( elem ); break; } @@ -2530,8 +2719,9 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { // Track unmatched elements for set filters if ( bySet ) { + // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { + if ( ( elem = !matcher && elem ) ) { matchedCount--; } @@ -2555,16 +2745,17 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { // numerically zero. if ( bySet && i !== matchedCount ) { j = 0; - while ( (matcher = setMatchers[j++]) ) { + while ( ( matcher = setMatchers[ j++ ] ) ) { matcher( unmatched, setMatched, context, xml ); } if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting if ( matchedCount > 0 ) { while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); } } } @@ -2605,13 +2796,14 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { cached = compilerCache[ selector + " " ]; if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element if ( !match ) { match = tokenize( selector ); } i = match.length; while ( i-- ) { - cached = matcherFromTokens( match[i] ); + cached = matcherFromTokens( match[ i ] ); if ( cached[ expando ] ) { setMatchers.push( cached ); } else { @@ -2620,7 +2812,10 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { } // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); // Save selector and tokenization cached.selector = selector; @@ -2640,7 +2835,7 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { select = Sizzle.select = function( selector, context, results, seed ) { var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); results = results || []; @@ -2649,11 +2844,12 @@ select = Sizzle.select = function( selector, context, results, seed ) { if ( match.length === 1 ) { // 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" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; if ( !context ) { return results; @@ -2666,20 +2862,22 @@ select = Sizzle.select = function( selector, context, results, seed ) { } // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; while ( i-- ) { - token = tokens[i]; + token = tokens[ i ]; // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { + if ( Expr.relative[ ( type = token.type ) ] ) { break; } - if ( (find = Expr.find[ type ]) ) { + if ( ( find = Expr.find[ type ] ) ) { + // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { // If seed is empty or no tokens remain, we can return early tokens.splice( i, 1 ); @@ -2710,7 +2908,7 @@ select = Sizzle.select = function( selector, context, results, seed ) { // One-time assignments // Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; // Support: Chrome 14-35+ // Always assume duplicates if they aren't passed to the comparison function @@ -2721,58 +2919,59 @@ 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( el ) { +support.sortDetached = assert( function( el ) { + // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; -}); + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); // Support: IE<8 // Prevent attribute/property "interpolation" // https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( el ) { +if ( !assert( function( el ) { el.innerHTML = ""; - return el.firstChild.getAttribute("href") === "#" ; -}) ) { + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { addHandle( "type|href|height|width", function( elem, name, isXML ) { if ( !isXML ) { return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); } - }); + } ); } // Support: IE<9 // Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( el ) { +if ( !support.attributes || !assert( function( el ) { el.innerHTML = ""; el.firstChild.setAttribute( "value", "" ); return el.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { return elem.defaultValue; } - }); + } ); } // Support: IE<9 // Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( el ) { - return el.getAttribute("disabled") == null; -}) ) { +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { addHandle( booleans, function( elem, name, isXML ) { var val; if ( !isXML ) { return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? + ( val = elem.getAttributeNode( name ) ) && val.specified ? val.value : - null; + null; } - }); + } ); } return Sizzle; -})( window ); +} )( window ); @@ -3141,7 +3340,7 @@ jQuery.each( { parents: function( elem ) { return dir( elem, "parentNode" ); }, - parentsUntil: function( elem, i, until ) { + parentsUntil: function( elem, _i, until ) { return dir( elem, "parentNode", until ); }, next: function( elem ) { @@ -3156,10 +3355,10 @@ jQuery.each( { prevAll: function( elem ) { return dir( elem, "previousSibling" ); }, - nextUntil: function( elem, i, until ) { + nextUntil: function( elem, _i, until ) { return dir( elem, "nextSibling", until ); }, - prevUntil: function( elem, i, until ) { + prevUntil: function( elem, _i, until ) { return dir( elem, "previousSibling", until ); }, siblings: function( elem ) { @@ -3169,7 +3368,13 @@ jQuery.each( { return siblings( elem.firstChild ); }, contents: function( elem ) { - if ( typeof elem.contentDocument !== "undefined" ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + return elem.contentDocument; } @@ -3512,7 +3717,7 @@ jQuery.extend( { var fns = arguments; return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { + jQuery.each( tuples, function( _i, tuple ) { // Map tuples (progress, done, fail) to arguments (done, fail, progress) var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; @@ -3965,7 +4170,7 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { // ...except when executing function values } else { bulk = fn; - fn = function( elem, key, value ) { + fn = function( elem, _key, value ) { return bulk.call( jQuery( elem ), value ); }; } @@ -4000,7 +4205,7 @@ var rmsPrefix = /^-ms-/, rdashAlpha = /-([a-z])/g; // Used by camelCase as callback to replace() -function fcamelCase( all, letter ) { +function fcamelCase( _all, letter ) { return letter.toUpperCase(); } @@ -4528,27 +4733,6 @@ var isHiddenWithinTree = function( elem, el ) { 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 ]; - } - - return ret; -}; - - function adjustCSS( elem, prop, valueParts, tween ) { @@ -4719,11 +4903,40 @@ var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); -// We have to close these tags to support XHTML (#13200) -var wrapMap = { +( 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 = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; // Support: IE <=9 only - option: [ 1, "" ], + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { // XHTML parsers do not magically insert elements in the // same way that tag soup parsers do. So we cannot shorten @@ -4736,12 +4949,14 @@ var wrapMap = { _default: [ 0, "", "" ] }; -// Support: IE <=9 only -wrapMap.optgroup = wrapMap.option; - wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + function getAll( context, tag ) { @@ -4874,32 +5089,6 @@ function buildFragment( elems, context, scripts, selection, ignored ) { } -( 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 = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); - - var rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, @@ -5008,8 +5197,8 @@ jQuery.event = { 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 ) { + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { return; } @@ -5033,7 +5222,7 @@ jQuery.event = { // Init the element's event structure and main handler, if this is the first if ( !( events = elemData.events ) ) { - events = elemData.events = {}; + events = elemData.events = Object.create( null ); } if ( !( eventHandle = elemData.handle ) ) { eventHandle = elemData.handle = function( e ) { @@ -5191,12 +5380,15 @@ jQuery.event = { dispatch: function( nativeEvent ) { - // Make a writable jQuery.Event from the native event object - var event = jQuery.event.fix( nativeEvent ); - var i, j, ret, matched, handleObj, handlerQueue, args = new Array( arguments.length ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event @@ -5771,13 +5963,6 @@ jQuery.fn.extend( { var - /* eslint-disable max-len */ - - // 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, - - /* eslint-enable */ - // Support: IE <=10 - 11, Edge 12 - 13 only // In IE/Edge using regex groups here causes severe slowdowns. // See https://connect.microsoft.com/IE/feedback/details/1736512/ @@ -5814,7 +5999,7 @@ function restoreScript( elem ) { } function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + var i, l, type, pdataOld, udataOld, udataCur, events; if ( dest.nodeType !== 1 ) { return; @@ -5822,13 +6007,11 @@ function cloneCopyEvent( src, dest ) { // 1. Copy private data: events, handlers, etc. if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); + pdataOld = dataPriv.get( src ); events = pdataOld.events; if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; + dataPriv.remove( dest, "handle events" ); for ( type in events ) { for ( i = 0, l = events[ type ].length; i < l; i++ ) { @@ -5864,7 +6047,7 @@ function fixInput( src, dest ) { function domManip( collection, args, callback, ignored ) { // Flatten any nested arrays - args = concat.apply( [], args ); + args = flat( args ); var fragment, first, scripts, hasScripts, node, doc, i = 0, @@ -5939,7 +6122,7 @@ function domManip( collection, args, callback, ignored ) { if ( jQuery._evalUrl && !node.noModule ) { jQuery._evalUrl( node.src, { nonce: node.nonce || node.getAttribute( "nonce" ) - } ); + }, doc ); } } else { DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); @@ -5976,7 +6159,7 @@ function remove( elem, selector, keepData ) { jQuery.extend( { htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); + return html; }, clone: function( elem, dataAndEvents, deepDataAndEvents ) { @@ -6238,6 +6421,27 @@ var getStyles = function( elem ) { return view.getComputedStyle( elem ); }; +var swap = function( elem, options, callback ) { + 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.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); @@ -6295,7 +6499,7 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); } var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableMarginLeftVal, + reliableTrDimensionsVal, reliableMarginLeftVal, container = document.createElement( "div" ), div = document.createElement( "div" ); @@ -6330,6 +6534,35 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); scrollboxSize: function() { computeStyleTests(); return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; } } ); } )(); @@ -6454,7 +6687,7 @@ var fontWeight: "400" }; -function setPositiveNumber( elem, value, subtract ) { +function setPositiveNumber( _elem, value, subtract ) { // Any relative (+/-) values have already been // normalized at this point @@ -6559,17 +6792,26 @@ function getWidthOrHeight( elem, dimension, extra ) { } - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - // Support: IE 9-11 only - // Also use offsetWidth/offsetHeight for when box sizing is unreliable - // We use getClientRects() to check for hidden/disconnected. - // In those cases, the computed value can be trusted to be border-box + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected elem.getClientRects().length ) { isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; @@ -6764,7 +7006,7 @@ jQuery.extend( { } } ); -jQuery.each( [ "height", "width" ], function( i, dimension ) { +jQuery.each( [ "height", "width" ], function( _i, dimension ) { jQuery.cssHooks[ dimension ] = { get: function( elem, computed, extra ) { if ( computed ) { @@ -7537,7 +7779,7 @@ jQuery.fn.extend( { clearQueue = type; type = undefined; } - if ( clearQueue && type !== false ) { + if ( clearQueue ) { this.queue( type || "fx", [] ); } @@ -7620,7 +7862,7 @@ jQuery.fn.extend( { } } ); -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" ? @@ -7841,7 +8083,7 @@ boolHook = { } }; -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { var getter = attrHandle[ name ] || jQuery.find.attr; attrHandle[ name ] = function( elem, name, isXML ) { @@ -8465,7 +8707,9 @@ jQuery.extend( jQuery.event, { special.bindType || type; // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && dataPriv.get( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); @@ -8576,7 +8820,10 @@ if ( !support.focusin ) { jQuery.event.special[ fix ] = { setup: function() { - var doc = this.ownerDocument || this, + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, attaches = dataPriv.access( doc, fix ); if ( !attaches ) { @@ -8585,7 +8832,7 @@ if ( !support.focusin ) { dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); }, teardown: function() { - var doc = this.ownerDocument || this, + var doc = this.ownerDocument || this.document || this, attaches = dataPriv.access( doc, fix ) - 1; if ( !attaches ) { @@ -8601,7 +8848,7 @@ if ( !support.focusin ) { } var location = window.location; -var nonce = Date.now(); +var nonce = { guid: Date.now() }; var rquery = ( /\?/ ); @@ -8733,7 +8980,7 @@ jQuery.fn.extend( { rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && ( this.checked || !rcheckableType.test( type ) ); } ) - .map( function( i, elem ) { + .map( function( _i, elem ) { var val = jQuery( this ).val(); if ( val == null ) { @@ -9346,7 +9593,8 @@ jQuery.extend( { // Add or update anti-cache param if needed if ( s.cache === false ) { cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; } // Put hash and anti-cache on the URL that will be requested (gh-1732) @@ -9479,6 +9727,11 @@ jQuery.extend( { response = ajaxHandleResponses( s, jqXHR, responses ); } + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + // Convert no matter what (that way responseXXX fields are always set) response = ajaxConvert( s, response, jqXHR, isSuccess ); @@ -9569,7 +9822,7 @@ jQuery.extend( { } } ); -jQuery.each( [ "get", "post" ], function( i, method ) { +jQuery.each( [ "get", "post" ], function( _i, method ) { jQuery[ method ] = function( url, data, callback, type ) { // Shift arguments if data argument was omitted @@ -9590,8 +9843,17 @@ jQuery.each( [ "get", "post" ], function( i, method ) { }; } ); +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); -jQuery._evalUrl = function( url, options ) { + +jQuery._evalUrl = function( url, options, doc ) { return jQuery.ajax( { url: url, @@ -9609,7 +9871,7 @@ jQuery._evalUrl = function( url, options ) { "text script": function() {} }, dataFilter: function( response ) { - jQuery.globalEval( response, options ); + jQuery.globalEval( response, options, doc ); } } ); }; @@ -9931,7 +10193,7 @@ var oldCallbacks = [], jQuery.ajaxSetup( { jsonp: "callback", jsonpCallback: function() { - var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); + var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) ); this[ callback ] = true; return callback; } @@ -10148,23 +10410,6 @@ jQuery.fn.load = function( url, params, callback ) { -// 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; @@ -10221,6 +10466,12 @@ jQuery.offset = { options.using.call( elem, props ); } else { + if ( typeof props.top === "number" ) { + props.top += "px"; + } + if ( typeof props.left === "number" ) { + props.left += "px"; + } curElem.css( props ); } } @@ -10371,7 +10622,7 @@ jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( // 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.each( [ "top", "left" ], function( _i, prop ) { jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, function( elem, computed ) { if ( computed ) { @@ -10434,25 +10685,19 @@ jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { } ); -jQuery.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( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); +jQuery.each( [ + "ajaxStart", + "ajaxStop", + "ajaxComplete", + "ajaxError", + "ajaxSuccess", + "ajaxSend" +], function( _i, type ) { + jQuery.fn[ type ] = function( fn ) { + return this.on( type, fn ); }; } ); -jQuery.fn.extend( { - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -} ); - @@ -10474,9 +10719,33 @@ jQuery.fn.extend( { return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); } } ); +jQuery.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( _i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + } ); + + + + +// Support: Android <=4.0 only +// Make sure we trim BOM and NBSP +var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + // Bind a function to a context, optionally partially applying any // arguments. // jQuery.proxy is deprecated to promote standards (specifically Function#bind) @@ -10539,6 +10808,11 @@ jQuery.isNumeric = function( obj ) { !isNaN( obj - parseFloat( obj ) ); }; +jQuery.trim = function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); +}; @@ -10587,7 +10861,7 @@ jQuery.noConflict = function( deep ) { // Expose jQuery and $ identifiers, even in AMD // (#7102#comment:10, https://github.com/jquery/jquery/pull/557) // and CommonJS for browser emulators (#13566) -if ( !noGlobal ) { +if ( typeof noGlobal === "undefined" ) { window.jQuery = window.$ = jQuery; } diff --git a/sphinx/themes/basic/static/jquery.js b/sphinx/themes/basic/static/jquery.js index a1c07fd80..b0614034a 100644 --- a/sphinx/themes/basic/static/jquery.js +++ b/sphinx/themes/basic/static/jquery.js @@ -1,2 +1,2 @@ -/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),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("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.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(e,n){k.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),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("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.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(e,n){S.fn[n]=function(e,t){return 0 Date: Fri, 22 May 2020 23:10:28 +0900 Subject: [PATCH 40/40] Update CHANGES for PR #7676 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index efc3f5c7e..bbdbd27b4 100644 --- a/CHANGES +++ b/CHANGES @@ -99,6 +99,7 @@ Bugs fixed * #7650: autodoc: undecorated signature is shown for decorated functions * #7676: autodoc: typo in the default value of autodoc_member_order * #7676: autodoc: wrong value for :member-order: option is ignored silently +* #7676: autodoc: member-order="bysource" does not work for C module * #7551: autosummary: a nested class is indexed as non-nested class * #7661: autosummary: autosummary directive emits warnings twices if failed to import the target module