From 93e858b7eacd36ef722e317cc123a3ae27945472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20=20Galaz?= Date: Thu, 5 Sep 2019 17:22:56 -0400 Subject: [PATCH 001/145] request initial state when subscribing to events (test+consumer) --- manager/subscription/consumers.py | 17 ++++++ .../subscription/tests/test_subscriptions.py | 55 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/manager/subscription/consumers.py b/manager/subscription/consumers.py index 3657f685..e6cd105e 100644 --- a/manager/subscription/consumers.py +++ b/manager/subscription/consumers.py @@ -76,6 +76,23 @@ async def handle_subscription_message(self, message): await self.send_json({ 'data': 'Successfully subscribed to %s-%s-%s-%s' % (category, csc, salindex, stream) }) + + # If subscribed to an event, send request for initial-state + if category == 'event': + await self.channel_layer.group_send( + 'initial_state-all-all-all', + { + 'type': 'subscription_all_data', + 'category': 'initial_state', + 'data': [{ + "csc": csc, + "salindex": salindex, + "stream": { + "event_name": stream + } + }] + } + ) return if option == 'unsubscribe': diff --git a/manager/subscription/tests/test_subscriptions.py b/manager/subscription/tests/test_subscriptions.py index 61e4ad08..b1402eef 100644 --- a/manager/subscription/tests/test_subscriptions.py +++ b/manager/subscription/tests/test_subscriptions.py @@ -320,3 +320,58 @@ async def test_receive_part_of_message_for_subscribed_groups_only(self): await communicator.send_json_to(subscription_msg) await communicator.receive_json_from() await communicator.disconnect() + + @pytest.mark.asyncio + @pytest.mark.django_db + async def test_request_initial_state_when_subscribing_to_event(self): + """ + Must send a request for initial_state to the Producer whenever + a client subscribes to events + """ + # Arrange + client_communicator = WebsocketCommunicator(application, self.url) + producer_communicator = WebsocketCommunicator(application, self.url) + await client_communicator.connect() + await producer_communicator.connect() + + # Act 1 (Subscribe producer) + await producer_communicator.send_json_to({ + 'option': 'subscribe', + 'category': 'initial_state', + 'csc': 'all', + 'salindex': 'all', + 'stream': 'all' + }) + await producer_communicator.receive_json_from() + + # Act 2 (Subscribe client) + for combination in self.combinations: + # initial state is only useful for events + if combination["category"] != "event": + continue + + msg = { + "option": "subscribe", + "csc": combination["csc"], + "salindex": combination["salindex"], + "stream": combination["stream"], + "category": combination["category"] + } + await client_communicator.send_json_to(msg) + producer_consumer_response = await producer_communicator.receive_json_from() + + # Assert + assert producer_consumer_response == { + 'category': 'initial_state', + 'data': [{ + 'csc': combination["csc"], + 'salindex': combination["salindex"], + 'stream': { + 'event_name': combination["stream"] + } + }] + + } + + await client_communicator.disconnect() + await producer_communicator.disconnect() From fdba57e38840b766784cadb040ec92f1e57e081a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20=20Galaz?= Date: Thu, 5 Sep 2019 17:31:58 -0400 Subject: [PATCH 002/145] fix workdir in dockerfile-dev --- Dockerfile-dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile-dev b/Dockerfile-dev index b14c852a..f9a0fe18 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -10,7 +10,7 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* # Set workdir and install python requirements -WORKDIR /usr/src/love +WORKDIR /usr/src/love/manager COPY manager/requirements.txt . RUN pip install -r requirements.txt From f6ec9b1bcaca61917cdfa0f23990ff055017c521 Mon Sep 17 00:00:00 2001 From: sfehlandt Date: Mon, 7 Oct 2019 13:05:24 -0300 Subject: [PATCH 003/145] Set local docker-compose to use postgres --- docker-compose.yml | 27 ++++++++++++++++++++++- manager/manager/settings.py | 43 +++++++++++++++++++++++-------------- manager/requirements.txt | 1 + 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0bfca3a8..4fc76fa4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,14 +2,39 @@ version: "3.7" services: + database: + container_name: manager-postgres-local + image: postgres:12.0 + environment: + - POSTGRES_DB=postgres + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + volumes: + - db_data_local:/var/lib/postgresql/data + manager: container_name: manager-local build: context: . dockerfile: Dockerfile-dev image: love-manager-image-mount + environment: + - DB_ENGINE=postgresql + - DB_NAME=postgres + - DB_USER=postgres + - DB_PASS=postgres + - DB_HOST=database + - DB_PORT=5432 + ports: + - "8000:8000" + depends_on: + - database + restart: always volumes: - .:/usr/src/love - command: "" + command: "sleep infinity" stdin_open: true tty: true + +volumes: + db_data_local: diff --git a/manager/manager/settings.py b/manager/manager/settings.py index 3a0ab783..dee60a1e 100644 --- a/manager/manager/settings.py +++ b/manager/manager/settings.py @@ -24,19 +24,41 @@ # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'tbder3gzppu)kl%(u3awhhg^^zu#j&!ceh@$n&v0d38sjx43s8' +SECRET_KEY = os.getenv('SECRET_KEY', 'tbder3gzppu)kl%(u3awhhg^^zu#j&!ceh@$n&v0d38sjx43s8') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +if os.environ.get('NO_DEBUG'): + DEBUG = False +else: + DEBUG = True + +# Database +# https://docs.djangoproject.com/en/2.1/ref/settings/#databases +if os.environ.get('DB_ENGINE') == 'postgresql': + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': os.getenv('DB_NAME', 'postgres'), + 'USER': os.getenv('DB_USER', 'postgres'), + 'HOST': os.getenv('DB_HOST', 'postgres'), + 'PORT': os.getenv('DB_PORT', '5432'), + 'PASSWORD': os.getenv('DB_PASS', 'postgres') + } + } +else: + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } + } ALLOWED_HOSTS = [ 'localhost', 'love-manager-mount', 'love-nginx-mount', 'manager', - 'love-manager', 'love-nginx', '10.0.100.1', '10.0.100.209', '127.0.0.1' + 'love-manager', 'love-nginx', '10.0.100.1', '10.0.100.209', '127.0.0.1', '0.0.0.0' ] - # Application definition - INSTALLED_APPS = [ 'django.contrib.auth', 'django.contrib.admin', @@ -90,17 +112,6 @@ WSGI_APPLICATION = 'manager.wsgi.application' -# Database -# https://docs.djangoproject.com/en/2.1/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - } -} - - # Password validation # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators diff --git a/manager/requirements.txt b/manager/requirements.txt index cd2f2165..10242f90 100644 --- a/manager/requirements.txt +++ b/manager/requirements.txt @@ -27,6 +27,7 @@ m2r==0.2.1 more-itertools==5.0.0 msgpack==0.6.0 pluggy==0.8.1 +psycopg2==2.8.3 py==1.7.0 pyasn1==0.4.4 pyasn1-modules==0.2.2 From f3408700945abfc1cb2e9cd174224c13ebb514f7 Mon Sep 17 00:00:00 2001 From: sfehlandt Date: Mon, 7 Oct 2019 13:19:26 -0300 Subject: [PATCH 004/145] Update README --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 18f3c6c4..8a5f821e 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,20 @@ All these variables are initialized with default variables defined in :code:`.en * `USER_USER_PASS`: password for the default `user` user, which has readonly permissions and cannot execute commands. * `CMD_USER_PASS`: password for the default `cmd` user, which has readonly permissions but can execute commands. * `LOVE_MANAGER_REDIS_HOST`: the location of the redis host that implements the `Channels Layer`. -* `REDIS_PASS`: the password that the LOVE-manager needs tio use to connect with `redis`. +* `REDIS_PASS`: the password that the LOVE-manager needs to use to connect with `redis`. * `PROCESS_CONNECTION_PASS`: the password that the LOVE-producer will use to establish a websocket connection with the LOVE-manager. +* `DB_ENGINE`: describe which database engine should be used. If its value is `postgresql` Postgres will be used, otherwise it will use Sqlite3. +* `DB_NAME`: defines the name of the Database. Only used if `DB_ENGINE=postgresql`. +* `DB_USER`: defines the user of the Database. Only used if `DB_ENGINE=postgresql`. +* `DB_PASS`: defines the password of the Database. Only used if `DB_ENGINE=postgresql`. +* `DB_HOST`: defines the host of the Database. Only used if `DB_ENGINE=postgresql`. +* `DB_PORT`: defines the port of the Database. Only used if `DB_ENGINE=postgresql`. +* `NO_DEBUG`: defines wether or not the LOVE-.manager will be run using Django's debug mode. If the variable is defined, then Debug mode will be off. +* `SECRET_KEY`: overrides Django's SECRET_KEY, if not defined the default value (public in this repo) will be used. * `AUTH_LDAP_SERVER_URI`: (deprecated) the location of the LDAP authentication server. No LDAP server is used if this variable is empty # Local load for development -We provide a docker image and a docker-compose file in order to load the LOVE-manager locally for development purposes, i.e. run tests and build documentation. +We provide a docker image and a docker-compose file in order to load the LOVE-manager with a Postgres database locally, for development purposes, such as run tests and build documentation. This docker-compose does not copy the code into the image, but instead it mounts the repository inside the image, this way you can edit the code from outside the docker container with no need to rebuild or restart. From 33d1033c3e8d06db4e545e46e62a298811e085b6 Mon Sep 17 00:00:00 2001 From: sfehlandt Date: Mon, 7 Oct 2019 14:47:54 -0300 Subject: [PATCH 005/145] Upgrade requirements --- manager/requirements.txt | 90 ++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/manager/requirements.txt b/manager/requirements.txt index 10242f90..652274d0 100644 --- a/manager/requirements.txt +++ b/manager/requirements.txt @@ -1,47 +1,77 @@ -aioredis==1.2.0 -asgiref==2.3.2 -asn1crypto==0.24.0 -async-timeout==2.0.1 +aioredis==1.3.0 +alabaster==0.7.12 +asgiref==3.2.2 +asn1crypto==1.0.1 +async-timeout==3.0.1 atomicwrites==1.3.0 -attrs==18.2.0 -autobahn==18.11.1 +attrs==19.2.0 +autobahn==19.10.1 Automat==0.7.0 -cffi==1.11.5 -channels==2.1.7 -channels-redis==2.3.3 +Babel==2.7.0 +certifi==2019.9.11 +cffi==1.12.3 +channels==2.3.0 +channels-redis==2.4.0 +chardet==3.0.4 constantly==15.1.0 -cryptography==2.4.2 -daphne==2.2.3 -Django==2.1.11 -django-auth-ldap==1.7.0 -django-cors-headers==2.4.0 -djangorestframework==3.9.1 +cryptography==2.7 +daphne==2.3.0 +Django==2.2.6 +django-auth-ldap==2.0.0 +django-cors-headers==3.1.1 django-webpack-loader==0.6.0 -flake8==3.7.7 +djangorestframework==3.10.3 +docutils==0.15.2 +entrypoints==0.3 +flake8==3.7.8 freezegun==0.3.12 -hiredis==0.2.0 -hyperlink==18.0.0 -idna==2.7 +hiredis==1.0.0 +hyperlink==19.0.0 +idna==2.8 +imagesize==1.1.0 +importlib-metadata==0.23 incremental==17.5.0 +Jinja2==2.10.3 m2r==0.2.1 -more-itertools==5.0.0 -msgpack==0.6.0 -pluggy==0.8.1 +MarkupSafe==1.1.1 +mccabe==0.6.1 +mistune==0.8.4 +more-itertools==7.2.0 +msgpack==0.6.2 +packaging==19.2 +pluggy==0.13.0 psycopg2==2.8.3 -py==1.7.0 -pyasn1==0.4.4 -pyasn1-modules==0.2.2 +py==1.8.0 +pyasn1==0.4.7 +pyasn1-modules==0.2.6 +pycodestyle==2.5.0 pycparser==2.19 +pyflakes==2.1.1 +Pygments==2.4.2 PyHamcrest==1.9.0 -pytest==4.2.0 +pyparsing==2.4.2 +pytest==5.2.1 pytest-asyncio==0.10.0 -pytest-django==3.4.7 +pytest-django==3.5.1 pytest-env==0.6.2 -python-ldap==3.1.0 -pytz==2018.7 +python-dateutil==2.8.0 +python-ldap==3.2.0 +pytz==2019.3 +requests==2.22.0 six==1.12.0 -Sphinx==2.1.2 +snowballstemmer==2.0.0 +Sphinx==2.2.0 sphinx-rtd-theme==0.4.3 +sphinxcontrib-applehelp==1.0.1 +sphinxcontrib-devhelp==1.0.1 +sphinxcontrib-htmlhelp==1.0.2 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.2 +sphinxcontrib-serializinghtml==1.1.3 +sqlparse==0.3.0 Twisted==19.7.0 txaio==18.8.1 +urllib3==1.25.6 +wcwidth==0.1.7 +zipp==0.6.0 zope.interface==4.6.0 From 94207af81227f47e8c63a1e3a4471efda09a091b Mon Sep 17 00:00:00 2001 From: sfehlandt Date: Mon, 7 Oct 2019 15:10:26 -0300 Subject: [PATCH 006/145] Fix tests --- manager/subscription/tests/test_commands.py | 8 ++++---- manager/subscription/tests/test_subscriptions.py | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/manager/subscription/tests/test_commands.py b/manager/subscription/tests/test_commands.py index cd742adb..5f788ccc 100644 --- a/manager/subscription/tests/test_commands.py +++ b/manager/subscription/tests/test_commands.py @@ -58,7 +58,7 @@ def build_messages(self, category, csc, salindex, streams): return response, response @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_authorized_user_can_send_command(self): """Test that an authorized user can send commands.""" # Arrange @@ -83,7 +83,7 @@ async def test_authorized_user_can_send_command(self): await communicator.disconnect() @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_unauthorized_user_cannot_send_command(self): """Test that an unauthorized user cannot send commands.""" # Arrange @@ -107,7 +107,7 @@ async def test_unauthorized_user_cannot_send_command(self): await communicator.disconnect() @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_authorized_user_gets_ack(self): """Test that commands get acknowledged.""" # Arrange @@ -177,4 +177,4 @@ async def test_authorized_user_gets_ack(self): print('\n\n\n') print(response) assert ack == response - await communicator.disconnect() \ No newline at end of file + await communicator.disconnect() diff --git a/manager/subscription/tests/test_subscriptions.py b/manager/subscription/tests/test_subscriptions.py index 60fbafb1..b2c638da 100644 --- a/manager/subscription/tests/test_subscriptions.py +++ b/manager/subscription/tests/test_subscriptions.py @@ -71,7 +71,7 @@ def build_messages(self, category, csc, salindex, streams): return response, response @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_join_and_leave_every_subscription(self): """Test that clients can join and then leave any subscription stream.""" # Arrange @@ -110,7 +110,7 @@ async def test_join_and_leave_every_subscription(self): await communicator.disconnect() @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_join_and_leave_all_subscription(self): """Test that clients can subscribe and leave all streams.""" # Arrange @@ -145,7 +145,7 @@ async def test_join_and_leave_all_subscription(self): await communicator.disconnect() @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_receive_messages_from_every_subscription(self): """Test that clients subscribed (individually) to every stream receive messages from all of them.""" # Arrange @@ -173,7 +173,7 @@ async def test_receive_messages_from_every_subscription(self): await communicator.disconnect() @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_receive_messages_from_all_subscription(self): """Test that clients subscribed to all streams receive messages from all of them.""" # Arrange @@ -204,7 +204,7 @@ async def test_receive_messages_from_all_subscription(self): await communicator.disconnect() @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_receive_message_for_subscribed_group_only(self): """Test that clients subscribed to some groups only receive messages from those.""" # Arrange @@ -240,7 +240,7 @@ async def test_receive_message_for_subscribed_group_only(self): await communicator.disconnect() @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_receive_message_for_subscribed_groups_only(self): """Test that clients subscribed to some groups only receive messages from those.""" # Arrange @@ -282,7 +282,7 @@ async def test_receive_message_for_subscribed_groups_only(self): await communicator.disconnect() @pytest.mark.asyncio - @pytest.mark.django_db + @pytest.mark.django_db(transaction=True) async def test_receive_part_of_message_for_subscribed_groups_only(self): """Test that clients subscribed to some groups only receive the corresponding part of incoming messages.""" # Arrange From a78b51a0fd69aebc298db7a188d7bf9d322dcdcd Mon Sep 17 00:00:00 2001 From: sfehlandt Date: Mon, 7 Oct 2019 15:11:56 -0300 Subject: [PATCH 007/145] Update docs --- docs/doctrees/environment.pickle | Bin 61171 -> 61184 bytes docs/doctrees/modules/readme_link.doctree | Bin 16335 -> 21726 bytes docs/html/.buildinfo | 2 +- docs/html/_static/basic.css | 11 +- .../{jquery-3.2.1.js => jquery-3.4.1.js} | 1339 +++++++++++------ docs/html/_static/jquery.js | 6 +- docs/html/modules/readme_link.html | 12 +- docs/html/searchindex.js | 2 +- 8 files changed, 862 insertions(+), 510 deletions(-) rename docs/html/_static/{jquery-3.2.1.js => jquery-3.4.1.js} (89%) diff --git a/docs/doctrees/environment.pickle b/docs/doctrees/environment.pickle index b5237180facb34f1b4fe66bbe998da41d3f3d09a..7876600de365a46b5fbf1dd946ff458176a6a0ab 100644 GIT binary patch delta 8679 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 delta 8625 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 RA5m@gD3JAuhH<|h`hSNST4n$M diff --git a/docs/doctrees/modules/readme_link.doctree b/docs/doctrees/modules/readme_link.doctree index 4e94af23cc244bc6eeea1b6d64748d63138c485b..0f398b1d9e120c39bb086a2136361d1381edbb20 100644 GIT binary patch delta 5057 zcmcgwdu&rx7^k-n=!QI0f~@N}Fx-o7Zfs0s3^uj~5bfp$jK^^IcD?Iu*Y%Fx-VKOQ zOfW&$5XLFu`w@)lmZb-1+ff@vc@x73Lj7tY5v=Q49^ zH`4maF6YPQSc2zUH}<$ao3?n|Jl~DhBA=-AMgm?D4NHMu3HgMm;1v`RiD7>rEFwjc z)sPRtxT=W0Dzv2!1)>TX5<;qo0t({!L0O6VBcie|#Pg^<)j`97P)J+lLUL3RBf|kD z25X{h4BVm4eW5^9tgT8&v-c(>SNXGvLy0oU8r;s!nng@y(&w5je&0CcY{jCuJsnNr zxkPHY(I^!JcY`z4D@ac8jX!l3#=59MS`=^o-_aX3ZOJv619!=00`R8b>51BI4p1GUKp!YC&3&Vu3ZBnU(}_vcl+W`uu$*nKWpsAR zVn}D&1i3s#b9quzPYqGeJs~#utz~Mtx8;E0WIx+pSI0xy@}Nca;ACksK$(0T_Bu=A zrA+|) zDy8pA7W#5PZ19^wUoOi5!<8AN?-xqn6-FO?2z>>B;cG_U9;%!6=FZMc`UV9>8I~iy z>7vkL&bZI(<8TClFb2R#A+Z=zO(>)$fNnSA3(k_54cw_-xWHGBKY}^JHaLHD;xWv{ zMGP(oYke zl&%80*yct~iN%n1!YMTY>=wpplg8 zz(N4A&PZT;TgM~>4$6^fBXECq0@>z90*S?tXL=}!31A;$1Rl&nU=ENCjxz|%WjTO2 zID-U^G6D}W0^vglbOMMWM&N0l_q6r2x;Jj$H2w$reuQ#UCycOj-Ac#-L-2(o#e=}6`IPIpU(dt1*|_b#R+c}R>z0`O$h zm7z~@k*b&|E2RdiF!(K~p=j#CRyL@5LxElt2*V(}-Xh|lT%Ohl6fr(sB)d|Nv1^m4 z1fC@NzC5q#Bu_UQlw!0(bT`<2aa~i0e=V9A7G+%bHBEu(7W~DkA?`~?6ZCdIvfpxvAo$U~YGFNW zpe<9q!4V5yTwTrmWC7}m9t*w#(}J&(<~3-Z555j<-0D|FMM(tTgwCOaDwPKffY(re z_^s;JiGb?>a1p-0rosLQ;<#hhUOiIc7W5%7 zg|=@Y1U+C>B0=n0(N6@`XIRv44S_ZUKh8*v(QyTWjhKH41sjF7u27gshRTQx^!auk(G5y!y(+l8v)dEdXV5YW< zYy^_OH93X1^G&A3ypUDB4Q>YfSf33PJBs+crT5V`<2?mW&`Y-SSFSSSDufod-Q;l;s*L>4J$2#Ft@zG5^J<3 zho6u1a11?Q&{20><~G4xotK dd:after { } dl.field-list { - display: flex; - flex-wrap: wrap; + display: grid; + grid-template-columns: fit-content(30%) auto; } dl.field-list > dt { - flex-basis: 20%; font-weight: bold; word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; } dl.field-list > dt:after { @@ -535,8 +536,8 @@ dl.field-list > dt:after { } dl.field-list > dd { - flex-basis: 70%; - padding-left: 1em; + padding-left: 0.5em; + margin-top: 0em; margin-left: 0em; margin-bottom: 0em; } diff --git a/docs/html/_static/jquery-3.2.1.js b/docs/html/_static/jquery-3.4.1.js similarity index 89% rename from docs/html/_static/jquery-3.2.1.js rename to docs/html/_static/jquery-3.4.1.js index d2d8ca47..773ad95c 100644 --- a/docs/html/_static/jquery-3.2.1.js +++ b/docs/html/_static/jquery-3.4.1.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v3.2.1 + * jQuery JavaScript Library v3.4.1 * https://jquery.com/ * * Includes Sizzle.js @@ -9,7 +9,7 @@ * Released under the MIT license * https://jquery.org/license * - * Date: 2017-03-20T18:59Z + * Date: 2019-05-01T21:04Z */ ( function( global, factory ) { @@ -71,16 +71,70 @@ var ObjectFunctionString = fnToString.call( Object ); var support = {}; +var isFunction = function isFunction( obj ) { + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; - function DOMEval( code, doc ) { + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { doc = doc || document; - var script = doc.createElement( "script" ); + var i, val, + script = doc.createElement( "script" ); script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } doc.head.appendChild( script ).parentNode.removeChild( script ); } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} /* global Symbol */ // Defining this global in .eslintrc.json would create a danger of using the global // unguarded in another place, it seems safer to define global only for this module @@ -88,7 +142,7 @@ var support = {}; var - version = "3.2.1", + version = "3.4.1", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -100,16 +154,7 @@ var // Support: Android <=4.0 only // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; jQuery.fn = jQuery.prototype = { @@ -209,7 +254,7 @@ jQuery.extend = jQuery.fn.extend = function() { } // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + if ( typeof target !== "object" && !isFunction( target ) ) { target = {}; } @@ -226,25 +271,28 @@ jQuery.extend = jQuery.fn.extend = function() { // Extend the base object for ( name in options ) { - src = target[ name ]; copy = options[ name ]; + // Prevent Object.prototype pollution // Prevent never-ending loop - if ( target === copy ) { + if ( name === "__proto__" || target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; - if ( copyIsArray ) { - copyIsArray = false; - clone = src && Array.isArray( src ) ? src : []; - + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; + clone = src; } + copyIsArray = false; // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); @@ -275,28 +323,6 @@ jQuery.extend( { noop: function() {}, - isFunction: function( obj ) { - return jQuery.type( obj ) === "function"; - }, - - isWindow: function( obj ) { - return obj != null && obj === obj.window; - }, - - isNumeric: function( obj ) { - - // As of jQuery 3.0, isNumeric is limited to - // strings and numbers (primitives or objects) - // that can be coerced to finite numbers (gh-2662) - var type = jQuery.type( obj ); - return ( type === "number" || type === "string" ) && - - // parseFloat NaNs numeric-cast false positives ("") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - !isNaN( obj - parseFloat( obj ) ); - }, - isPlainObject: function( obj ) { var proto, Ctor; @@ -319,9 +345,6 @@ jQuery.extend( { }, isEmptyObject: function( obj ) { - - /* eslint-disable no-unused-vars */ - // See https://github.com/eslint/eslint/issues/6125 var name; for ( name in obj ) { @@ -330,27 +353,9 @@ jQuery.extend( { return true; }, - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; - }, - // Evaluates a script in a global context - globalEval: function( code ) { - DOMEval( code ); - }, - - // Convert dashed to camelCase; used by the css and data modules - // Support: IE <=9 - 11, Edge 12 - 13 - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + globalEval: function( code, options ) { + DOMEval( code, { nonce: options && options.nonce } ); }, each: function( obj, callback ) { @@ -473,37 +478,6 @@ jQuery.extend( { // A global GUID counter for objects guid: 1, - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: Date.now, - // jQuery.support is not used in Core but other projects attach their // properties to it so it needs to exist. support: support @@ -526,9 +500,9 @@ function isArrayLike( obj ) { // hasOwn isn't used here due to false negatives // regarding Nodelist length in IE var length = !!obj && "length" in obj && obj.length, - type = jQuery.type( obj ); + type = toType( obj ); - if ( type === "function" || jQuery.isWindow( obj ) ) { + if ( isFunction( obj ) || isWindow( obj ) ) { return false; } @@ -537,14 +511,14 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.3.3 + * Sizzle CSS Selector Engine v2.3.4 * https://sizzlejs.com/ * - * Copyright jQuery Foundation and other contributors + * Copyright JS Foundation and other contributors * Released under the MIT license - * http://jquery.org/license + * https://js.foundation/ * - * Date: 2016-08-08 + * Date: 2019-04-08 */ (function( window ) { @@ -578,6 +552,7 @@ var i, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), + nonnativeSelectorCache = createCache(), sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; @@ -639,8 +614,7 @@ var i, rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + rdescend = new RegExp( whitespace + "|>" ), rpseudo = new RegExp( pseudos ), ridentifier = new RegExp( "^" + identifier + "$" ), @@ -661,6 +635,7 @@ var i, whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, + rhtml = /HTML$/i, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, @@ -715,9 +690,9 @@ var i, setDocument(); }, - disabledAncestor = addCombinator( + inDisabledFieldset = addCombinator( function( elem ) { - return elem.disabled === true && ("form" in elem || "label" in elem); + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; }, { dir: "parentNode", next: "legend" } ); @@ -830,18 +805,22 @@ function Sizzle( selector, context, results, seed ) { // Take advantage of querySelectorAll if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; + !nonnativeSelectorCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) && - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 + // Support: IE 8 only // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { + (nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // 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. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && rdescend.test( selector ) ) { // Capture the context ID, setting it first if necessary if ( (nid = context.getAttribute( "id" )) ) { @@ -863,17 +842,16 @@ function Sizzle( selector, context, results, seed ) { context; } - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); } } } @@ -1037,7 +1015,7 @@ function createDisabledPseudo( disabled ) { // Where there is no isDisabled, check manually /* jshint -W018 */ elem.isDisabled !== !disabled && - disabledAncestor( elem ) === disabled; + inDisabledFieldset( elem ) === disabled; } return elem.disabled === disabled; @@ -1094,10 +1072,13 @@ support = Sizzle.support = {}; * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; + var namespace = elem.namespaceURI, + docElem = (elem.ownerDocument || elem).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); }; /** @@ -1519,11 +1500,8 @@ Sizzle.matchesSelector = function( elem, expr ) { setDocument( elem ); } - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && + !nonnativeSelectorCache[ expr + " " ] && ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { @@ -1537,7 +1515,9 @@ Sizzle.matchesSelector = function( elem, expr ) { elem.document && elem.document.nodeType !== 11 ) { return ret; } - } catch (e) {} + } catch (e) { + nonnativeSelectorCache( expr, true ); + } } return Sizzle( expr, document, null, [ elem ] ).length > 0; @@ -1996,7 +1976,7 @@ Expr = Sizzle.selectors = { "contains": markFunction(function( text ) { text = text.replace( runescape, funescape ); return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; }; }), @@ -2135,7 +2115,11 @@ Expr = Sizzle.selectors = { }), "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; for ( ; --i >= 0; ) { matchIndexes.push( i ); } @@ -2848,11 +2832,9 @@ var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>| -var risSimple = /^.[^:#\[\.,]*$/; - // Implement the identical functionality for filter and not function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { + if ( isFunction( qualifier ) ) { return jQuery.grep( elements, function( elem, i ) { return !!qualifier.call( elem, i, elem ) !== not; } ); @@ -2872,16 +2854,8 @@ function winnow( elements, qualifier, not ) { } ); } - // Simple selector that can be filtered directly, removing non-Elements - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - // Complex selector, compare the two sets, removing non-Elements - qualifier = jQuery.filter( qualifier, elements ); - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; - } ); + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); } jQuery.filter = function( expr, elems, not ) { @@ -3002,7 +2976,7 @@ var rootjQuery, for ( match in context ) { // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { + if ( isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes @@ -3045,7 +3019,7 @@ var rootjQuery, // HANDLE: $(function) // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { + } else if ( isFunction( selector ) ) { return root.ready !== undefined ? root.ready( selector ) : @@ -3195,18 +3169,18 @@ jQuery.each( { return siblings( elem.firstChild ); }, contents: function( elem ) { - if ( nodeName( elem, "iframe" ) ) { - return elem.contentDocument; - } + if ( typeof elem.contentDocument !== "undefined" ) { + return elem.contentDocument; + } - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } - return jQuery.merge( [], elem.childNodes ); + return jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { @@ -3360,11 +3334,11 @@ jQuery.Callbacks = function( options ) { ( function add( args ) { jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { + if ( isFunction( arg ) ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } - } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + } else if ( arg && arg.length && toType( arg ) !== "string" ) { // Inspect recursively add( arg ); @@ -3479,11 +3453,11 @@ function adoptValue( value, resolve, reject, noValue ) { try { // Check for promise aspect first to privilege synchronous behavior - if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { + if ( value && isFunction( ( method = value.promise ) ) ) { method.call( value ).done( resolve ).fail( reject ); // Other thenables - } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { + } else if ( value && isFunction( ( method = value.then ) ) ) { method.call( value, resolve, reject ); // Other non-thenables @@ -3541,14 +3515,14 @@ jQuery.extend( { jQuery.each( tuples, function( i, tuple ) { // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; // deferred.progress(function() { bind to newDefer or newDefer.notify }) // deferred.done(function() { bind to newDefer or newDefer.resolve }) // deferred.fail(function() { bind to newDefer or newDefer.reject }) deferred[ tuple[ 1 ] ]( function() { var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { + if ( returned && isFunction( returned.promise ) ) { returned.promise() .progress( newDefer.notify ) .done( newDefer.resolve ) @@ -3602,7 +3576,7 @@ jQuery.extend( { returned.then; // Handle a returned thenable - if ( jQuery.isFunction( then ) ) { + if ( isFunction( then ) ) { // Special processors (notify) just wait for resolution if ( special ) { @@ -3698,7 +3672,7 @@ jQuery.extend( { resolve( 0, newDefer, - jQuery.isFunction( onProgress ) ? + isFunction( onProgress ) ? onProgress : Identity, newDefer.notifyWith @@ -3710,7 +3684,7 @@ jQuery.extend( { resolve( 0, newDefer, - jQuery.isFunction( onFulfilled ) ? + isFunction( onFulfilled ) ? onFulfilled : Identity ) @@ -3721,7 +3695,7 @@ jQuery.extend( { resolve( 0, newDefer, - jQuery.isFunction( onRejected ) ? + isFunction( onRejected ) ? onRejected : Thrower ) @@ -3761,8 +3735,15 @@ jQuery.extend( { // fulfilled_callbacks.disable tuples[ 3 - i ][ 2 ].disable, + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock ); } @@ -3832,7 +3813,7 @@ jQuery.extend( { // Use .then() to unwrap secondary thenables (cf. gh-3000) if ( master.state() === "pending" || - jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { return master.then(); } @@ -3960,7 +3941,7 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { bulk = key == null; // Sets many values - if ( jQuery.type( key ) === "object" ) { + if ( toType( key ) === "object" ) { chainable = true; for ( i in key ) { access( elems, fn, i, key[ i ], true, emptyGet, raw ); @@ -3970,7 +3951,7 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { } else if ( value !== undefined ) { chainable = true; - if ( !jQuery.isFunction( value ) ) { + if ( !isFunction( value ) ) { raw = true; } @@ -4012,6 +3993,23 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { return len ? fn( elems[ 0 ], key ) : emptyGet; }; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} var acceptData = function( owner ) { // Accepts only: @@ -4074,14 +4072,14 @@ Data.prototype = { // Handle: [ owner, key, value ] args // Always use camelCase key (gh-2257) if ( typeof data === "string" ) { - cache[ jQuery.camelCase( data ) ] = value; + cache[ camelCase( data ) ] = value; // Handle: [ owner, { properties } ] args } else { // Copy the properties one-by-one to the cache object for ( prop in data ) { - cache[ jQuery.camelCase( prop ) ] = data[ prop ]; + cache[ camelCase( prop ) ] = data[ prop ]; } } return cache; @@ -4091,7 +4089,7 @@ Data.prototype = { this.cache( owner ) : // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; }, access: function( owner, key, value ) { @@ -4139,9 +4137,9 @@ Data.prototype = { // If key is an array of keys... // We always set camelCase keys, so remove that. - key = key.map( jQuery.camelCase ); + key = key.map( camelCase ); } else { - key = jQuery.camelCase( key ); + key = camelCase( key ); // If a key with the spaces exists, use it. // Otherwise, create an array by matching non-whitespace @@ -4287,7 +4285,7 @@ jQuery.fn.extend( { if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice( 5 ) ); + name = camelCase( name.slice( 5 ) ); dataAttr( elem, name, data[ name ] ); } } @@ -4491,6 +4489,26 @@ var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } var isHiddenWithinTree = function( elem, el ) { // isHiddenWithinTree might be called from jQuery#filter function; @@ -4505,7 +4523,7 @@ var isHiddenWithinTree = function( elem, el ) { // Support: Firefox <=43 - 45 // Disconnected elements can have computed display: none, so first confirm that elem is // in the document. - jQuery.contains( elem.ownerDocument, elem ) && + isAttached( elem ) && jQuery.css( elem, "display" ) === "none"; }; @@ -4534,8 +4552,7 @@ var swap = function( elem, options, callback, args ) { function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, - scale = 1, + var adjusted, scale, maxIterations = 20, currentValue = tween ? function() { @@ -4548,35 +4565,39 @@ function adjustCSS( elem, prop, valueParts, tween ) { unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && rcssNum.exec( jQuery.css( elem, prop ) ); if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + // Trust units reported by jQuery.css unit = unit || initialInUnit[ 3 ]; - // Make sure we update the tween properties later on - valueParts = valueParts || []; - // Iteratively approximate from a nonzero starting point initialInUnit = +initial || 1; - do { - - // If previous iteration zeroed out, double until we get *something*. - // Use string for doubling so we don't accidentally see scale as unchanged below - scale = scale || ".5"; + while ( maxIterations-- ) { - // Adjust and apply - initialInUnit = initialInUnit / scale; + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; - // Update scale, tolerating zero or NaN from tween.cur() - // Break the loop if scale is unchanged or perfect, or if we've just had enough. - } while ( - scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations - ); + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; } if ( valueParts ) { @@ -4692,9 +4713,9 @@ jQuery.fn.extend( { } ); var rcheckableType = ( /^(?:checkbox|radio)$/i ); -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); -var rscriptType = ( /^$|\/(?:java|ecma)script/i ); +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); @@ -4764,7 +4785,7 @@ function setGlobalEval( elems, refElements ) { var rhtml = /<|&#?\w+;/; function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, contains, j, + var elem, tmp, tag, wrap, attached, j, fragment = context.createDocumentFragment(), nodes = [], i = 0, @@ -4776,7 +4797,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) { if ( elem || elem === 0 ) { // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { + if ( toType( elem ) === "object" ) { // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit @@ -4828,13 +4849,13 @@ function buildFragment( elems, context, scripts, selection, ignored ) { continue; } - contains = jQuery.contains( elem.ownerDocument, elem ); + attached = isAttached( elem ); // Append to fragment tmp = getAll( fragment.appendChild( elem ), "script" ); // Preserve script evaluation history - if ( contains ) { + if ( attached ) { setGlobalEval( tmp ); } @@ -4877,8 +4898,6 @@ function buildFragment( elems, context, scripts, selection, ignored ) { div.innerHTML = ""; support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; } )(); -var documentElement = document.documentElement; - var @@ -4894,8 +4913,19 @@ function returnFalse() { return false; } +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + // Support: IE <=9 only -// See #13393 for more info +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 function safeActiveElement() { try { return document.activeElement; @@ -5195,9 +5225,10 @@ jQuery.event = { while ( ( handleObj = matched.handlers[ j++ ] ) && !event.isImmediatePropagationStopped() ) { - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; @@ -5286,7 +5317,7 @@ jQuery.event = { enumerable: true, configurable: true, - get: jQuery.isFunction( hook ) ? + get: isFunction( hook ) ? function() { if ( this.originalEvent ) { return hook( this.originalEvent ); @@ -5321,39 +5352,51 @@ jQuery.event = { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, - focus: { + click: { - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); } + + // Return false to allow normal processing in the caller + return false; }, - delegateType: "focusout" - }, - click: { + trigger: function( data ) { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { - this.click(); - return false; + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); } + + // Return non-false to allow normal event-path propagation + return true; }, - // For cross-browser consistency, don't fire native .click() on links + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack _default: function( event ) { - return nodeName( event.target, "a" ); + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); } }, @@ -5370,6 +5413,93 @@ jQuery.event = { } }; +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + jQuery.removeEvent = function( elem, type, handle ) { // This "if" is needed for plain objects @@ -5421,7 +5551,7 @@ jQuery.Event = function( src, props ) { } // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); + this.timeStamp = src && src.timeStamp || Date.now(); // Mark it as fixed this[ jQuery.expando ] = true; @@ -5482,6 +5612,7 @@ jQuery.each( { shiftKey: true, view: true, "char": true, + code: true, charCode: true, key: true, keyCode: true, @@ -5528,6 +5659,33 @@ jQuery.each( { } }, jQuery.event.addProp ); +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + // Create mouseenter/leave events using mouseover/out and event-time checks // so that event delegation works in jQuery. // Do the same for pointerenter/pointerleave and pointerover/pointerout @@ -5620,14 +5778,13 @@ var /* eslint-enable */ - // Support: IE <=10 - 11, Edge 12 - 13 + // 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/ rnoInnerhtml = /\s*$/g; // Prefer a tbody over its parent table for containing new rows @@ -5635,7 +5792,7 @@ function manipulationTarget( elem, content ) { if ( nodeName( elem, "table" ) && nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - return jQuery( ">tbody", elem )[ 0 ] || elem; + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; } return elem; @@ -5647,10 +5804,8 @@ function disableScript( elem ) { return elem; } function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - - if ( match ) { - elem.type = match[ 1 ]; + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); } else { elem.removeAttribute( "type" ); } @@ -5716,15 +5871,15 @@ function domManip( collection, args, callback, ignored ) { l = collection.length, iNoClone = l - 1, value = args[ 0 ], - isFunction = jQuery.isFunction( value ); + valueIsFunction = isFunction( value ); // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || + if ( valueIsFunction || ( l > 1 && typeof value === "string" && !support.checkClone && rchecked.test( value ) ) ) { return collection.each( function( index ) { var self = collection.eq( index ); - if ( isFunction ) { + if ( valueIsFunction ) { args[ 0 ] = value.call( this, index, self.html() ); } domManip( self, args, callback, ignored ); @@ -5778,14 +5933,16 @@ function domManip( collection, args, callback, ignored ) { !dataPriv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) { - if ( node.src ) { + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + } ); } } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); } } } @@ -5807,7 +5964,7 @@ function remove( elem, selector, keepData ) { } if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + if ( keepData && isAttached( node ) ) { setGlobalEval( getAll( node, "script" ) ); } node.parentNode.removeChild( node ); @@ -5825,7 +5982,7 @@ jQuery.extend( { clone: function( elem, dataAndEvents, deepDataAndEvents ) { var i, l, srcElements, destElements, clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); + inPage = isAttached( elem ); // Fix IE cloning issues if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && @@ -6065,8 +6222,6 @@ jQuery.each( { return this.pushStack( ret ); }; } ); -var rmargin = ( /^margin/ ); - var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); var getStyles = function( elem ) { @@ -6083,6 +6238,8 @@ var getStyles = function( elem ) { return view.getComputedStyle( elem ); }; +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + ( function() { @@ -6096,25 +6253,35 @@ var getStyles = function( elem ) { return; } + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; div.style.cssText = - "box-sizing:border-box;" + - "position:relative;display:block;" + + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + "margin:auto;border:1px;padding:1px;" + - "top:1%;width:50%"; - div.innerHTML = ""; - documentElement.appendChild( container ); + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); var divStyle = window.getComputedStyle( div ); pixelPositionVal = divStyle.top !== "1%"; // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = divStyle.marginLeft === "2px"; - boxSizingReliableVal = divStyle.width === "4px"; + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; - // Support: Android 4.0 - 4.3 only + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 // Some styles come back with percentage values, even though they shouldn't - div.style.marginRight = "50%"; - pixelMarginRightVal = divStyle.marginRight === "4px"; + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; documentElement.removeChild( container ); @@ -6123,7 +6290,12 @@ var getStyles = function( elem ) { div = null; } - var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableMarginLeftVal, container = document.createElement( "div" ), div = document.createElement( "div" ); @@ -6138,26 +6310,26 @@ var getStyles = function( elem ) { div.cloneNode( true ).style.backgroundClip = ""; support.clearCloneStyle = div.style.backgroundClip === "content-box"; - container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + - "padding:0;margin-top:1px;position:absolute"; - container.appendChild( div ); - jQuery.extend( support, { - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, boxSizingReliable: function() { computeStyleTests(); return boxSizingReliableVal; }, - pixelMarginRight: function() { + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { computeStyleTests(); - return pixelMarginRightVal; + return pixelPositionVal; }, reliableMarginLeft: function() { computeStyleTests(); return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; } } ); } )(); @@ -6180,7 +6352,7 @@ function curCSS( elem, name, computed ) { if ( computed ) { ret = computed.getPropertyValue( name ) || computed[ name ]; - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + if ( ret === "" && !isAttached( elem ) ) { ret = jQuery.style( elem, name ); } @@ -6189,7 +6361,7 @@ function curCSS( elem, name, computed ) { // but width seems to be reliably pixels. // This is against the CSSOM draft spec: // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { // Remember the original values width = style.width; @@ -6236,30 +6408,13 @@ function addGetHookIf( conditionFn, hookFn ) { } -var +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }, - - cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style; - -// Return a css property mapped to a potentially vendor prefixed property +// Return a vendor-prefixed property or undefined function vendorPropName( name ) { - // Shortcut for names that are not vendor prefixed - if ( name in emptyStyle ) { - return name; - } - // Check for vendor prefixed names var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), i = cssPrefixes.length; @@ -6272,16 +6427,33 @@ function vendorPropName( name ) { } } -// Return a property mapped along what jQuery.cssProps suggests or to -// a vendor prefixed property. +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property function finalPropName( name ) { - var ret = jQuery.cssProps[ name ]; - if ( !ret ) { - ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; } - return ret; + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; } + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + function setPositiveNumber( elem, value, subtract ) { // Any relative (+/-) values have already been @@ -6294,87 +6466,137 @@ function setPositiveNumber( elem, value, subtract ) { value; } -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i, - val = 0; - - // If we already have the right measurement, avoid augmentation - if ( extra === ( isBorderBox ? "border" : "content" ) ) { - i = 4; +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; - // Otherwise initialize for horizontal or vertical properties - } else { - i = name === "width" ? 1 : 0; + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; } for ( ; i < 4; i += 2 ) { - // Both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); } - if ( isBorderBox ) { + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - // At this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" } else { - // At this point, extra isn't content, so add padding - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } - // At this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } } } - return val; + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; } -function getWidthOrHeight( elem, name, extra ) { +function getWidthOrHeight( elem, dimension, extra ) { // Start with computed style - var valueIsBorderBox, - styles = getStyles( elem ), - val = curCSS( elem, name, styles ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); - // Computed unit is not pixels. Stop here and return. + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. if ( rnumnonpx.test( val ) ) { - return val; + if ( !extra ) { + return val; + } + val = "auto"; } - // Check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && - ( support.boxSizingReliable() || val === elem.style[ name ] ); - // Fall back to offsetWidth/Height when value is "auto" + // Fall back to offsetWidth/offsetHeight when value is "auto" // This happens for inline elements with no explicit setting (gh-3571) - if ( val === "auto" ) { - val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + // 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 + if ( ( !support.boxSizingReliable() && isBorderBox || + val === "auto" || + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } } - // Normalize "", auto, and prepare for extra + // Normalize "" and auto val = parseFloat( val ) || 0; - // Use the active box-sizing model to add/subtract irrelevant styles + // Adjust for the element's box model return ( val + - augmentWidthOrHeight( + boxModelAdjustment( elem, - name, + dimension, extra || ( isBorderBox ? "border" : "content" ), valueIsBorderBox, - styles + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val ) ) + "px"; } @@ -6404,6 +6626,13 @@ jQuery.extend( { "flexGrow": true, "flexShrink": true, "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, "lineHeight": true, "opacity": true, "order": true, @@ -6415,9 +6644,7 @@ jQuery.extend( { // Add in properties whose names you wish to fix before // setting or getting the value - cssProps: { - "float": "cssFloat" - }, + cssProps: {}, // Get and set the style property on a DOM Node style: function( elem, name, value, extra ) { @@ -6429,7 +6656,7 @@ jQuery.extend( { // Make sure that we're working with the right name var ret, type, hooks, - origName = jQuery.camelCase( name ), + origName = camelCase( name ), isCustomProp = rcustomProp.test( name ), style = elem.style; @@ -6461,7 +6688,9 @@ jQuery.extend( { } // If a number was passed in, add the unit (except for certain CSS properties) - if ( type === "number" ) { + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); } @@ -6497,7 +6726,7 @@ jQuery.extend( { css: function( elem, name, extra, styles ) { var val, num, hooks, - origName = jQuery.camelCase( name ), + origName = camelCase( name ), isCustomProp = rcustomProp.test( name ); // Make sure that we're working with the right name. We don't @@ -6535,8 +6764,8 @@ jQuery.extend( { } } ); -jQuery.each( [ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { +jQuery.each( [ "height", "width" ], function( i, dimension ) { + jQuery.cssHooks[ dimension ] = { get: function( elem, computed, extra ) { if ( computed ) { @@ -6552,29 +6781,52 @@ jQuery.each( [ "height", "width" ], function( i, name ) { // in IE throws an error. ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); + return getWidthOrHeight( elem, dimension, extra ); } ) : - getWidthOrHeight( elem, name, extra ); + getWidthOrHeight( elem, dimension, extra ); } }, set: function( elem, value, extra ) { var matches, - styles = extra && getStyles( elem ), - subtract = extra && augmentWidthOrHeight( - elem, - name, - extra, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - styles + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 ); + } // Convert to pixels if value adjustment is needed if ( subtract && ( matches = rcssNum.exec( value ) ) && ( matches[ 3 ] || "px" ) !== "px" ) { - elem.style[ name ] = value; - value = jQuery.css( elem, name ); + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); } return setPositiveNumber( elem, value, subtract ); @@ -6618,7 +6870,7 @@ jQuery.each( { } }; - if ( !rmargin.test( prefix ) ) { + if ( prefix !== "margin" ) { jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; } } ); @@ -6728,9 +6980,9 @@ Tween.propHooks = { // Use .style if available and use plain properties where available. if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && - ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || - jQuery.cssHooks[ tween.prop ] ) ) { + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); } else { tween.elem[ tween.prop ] = tween.now; @@ -6789,7 +7041,7 @@ function createFxNow() { window.setTimeout( function() { fxNow = undefined; } ); - return ( fxNow = jQuery.now() ); + return ( fxNow = Date.now() ); } // Generate parameters to create a standard animation @@ -6893,9 +7145,10 @@ function defaultPrefilter( elem, props, opts ) { // Restrict "overflow" and "display" styles during box animations if ( isBox && elem.nodeType === 1 ) { - // Support: IE <=9 - 11, Edge 12 - 13 + // Support: IE <=9 - 11, Edge 12 - 15 // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; // Identify a display type, preferring old show/hide data over the CSS cascade @@ -7003,7 +7256,7 @@ function propFilter( props, specialEasing ) { // camelCase, specialEasing and expand cssHook pass for ( index in props ) { - name = jQuery.camelCase( index ); + name = camelCase( index ); easing = specialEasing[ name ]; value = props[ index ]; if ( Array.isArray( value ) ) { @@ -7128,9 +7381,9 @@ function Animation( elem, properties, options ) { for ( ; index < length; index++ ) { result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); if ( result ) { - if ( jQuery.isFunction( result.stop ) ) { + if ( isFunction( result.stop ) ) { jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - jQuery.proxy( result.stop, result ); + result.stop.bind( result ); } return result; } @@ -7138,7 +7391,7 @@ function Animation( elem, properties, options ) { jQuery.map( props, createTween, animation ); - if ( jQuery.isFunction( animation.opts.start ) ) { + if ( isFunction( animation.opts.start ) ) { animation.opts.start.call( elem, animation ); } @@ -7171,7 +7424,7 @@ jQuery.Animation = jQuery.extend( Animation, { }, tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { + if ( isFunction( props ) ) { callback = props; props = [ "*" ]; } else { @@ -7203,9 +7456,9 @@ jQuery.Animation = jQuery.extend( Animation, { jQuery.speed = function( speed, easing, fn ) { var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, + isFunction( speed ) && speed, duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing + easing: fn && easing || easing && !isFunction( easing ) && easing }; // Go to the end state if fx are off @@ -7232,7 +7485,7 @@ jQuery.speed = function( speed, easing, fn ) { opt.old = opt.complete; opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { + if ( isFunction( opt.old ) ) { opt.old.call( this ); } @@ -7396,7 +7649,7 @@ jQuery.fx.tick = function() { i = 0, timers = jQuery.timers; - fxNow = jQuery.now(); + fxNow = Date.now(); for ( ; i < timers.length; i++ ) { timer = timers[ i ]; @@ -7749,7 +8002,7 @@ jQuery.each( [ // Strip and collapse whitespace according to HTML spec - // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace function stripAndCollapse( value ) { var tokens = value.match( rnothtmlwhite ) || []; return tokens.join( " " ); @@ -7760,20 +8013,30 @@ function getClass( elem ) { return elem.getAttribute && elem.getAttribute( "class" ) || ""; } +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + jQuery.fn.extend( { addClass: function( value ) { var classes, elem, cur, curValue, clazz, j, finalValue, i = 0; - if ( jQuery.isFunction( value ) ) { + if ( isFunction( value ) ) { return this.each( function( j ) { jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); } ); } - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; + classes = classesToArray( value ); + if ( classes.length ) { while ( ( elem = this[ i++ ] ) ) { curValue = getClass( elem ); cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); @@ -7802,7 +8065,7 @@ jQuery.fn.extend( { var classes, elem, cur, curValue, clazz, j, finalValue, i = 0; - if ( jQuery.isFunction( value ) ) { + if ( isFunction( value ) ) { return this.each( function( j ) { jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); } ); @@ -7812,9 +8075,9 @@ jQuery.fn.extend( { return this.attr( "class", "" ); } - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; + classes = classesToArray( value ); + if ( classes.length ) { while ( ( elem = this[ i++ ] ) ) { curValue = getClass( elem ); @@ -7844,13 +8107,14 @@ jQuery.fn.extend( { }, toggleClass: function( value, stateVal ) { - var type = typeof value; + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); - if ( typeof stateVal === "boolean" && type === "string" ) { + if ( typeof stateVal === "boolean" && isValidValue ) { return stateVal ? this.addClass( value ) : this.removeClass( value ); } - if ( jQuery.isFunction( value ) ) { + if ( isFunction( value ) ) { return this.each( function( i ) { jQuery( this ).toggleClass( value.call( this, i, getClass( this ), stateVal ), @@ -7862,12 +8126,12 @@ jQuery.fn.extend( { return this.each( function() { var className, i, self, classNames; - if ( type === "string" ) { + if ( isValidValue ) { // Toggle individual class names i = 0; self = jQuery( this ); - classNames = value.match( rnothtmlwhite ) || []; + classNames = classesToArray( value ); while ( ( className = classNames[ i++ ] ) ) { @@ -7926,7 +8190,7 @@ var rreturn = /\r/g; jQuery.fn.extend( { val: function( value ) { - var hooks, ret, isFunction, + var hooks, ret, valueIsFunction, elem = this[ 0 ]; if ( !arguments.length ) { @@ -7955,7 +8219,7 @@ jQuery.fn.extend( { return; } - isFunction = jQuery.isFunction( value ); + valueIsFunction = isFunction( value ); return this.each( function( i ) { var val; @@ -7964,7 +8228,7 @@ jQuery.fn.extend( { return; } - if ( isFunction ) { + if ( valueIsFunction ) { val = value.call( this, i, jQuery( this ).val() ); } else { val = value; @@ -8106,18 +8370,24 @@ jQuery.each( [ "radio", "checkbox" ], function() { // Return jQuery for attributes-only inclusion -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; jQuery.extend( jQuery.event, { trigger: function( event, data, elem, onlyHandlers ) { - var i, cur, tmp, bubbleType, ontype, handle, special, + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, eventPath = [ elem || document ], type = hasOwn.call( event, "type" ) ? event.type : event, namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - cur = tmp = elem = elem || document; + cur = lastElement = tmp = elem = elem || document; // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { @@ -8169,7 +8439,7 @@ jQuery.extend( jQuery.event, { // Determine event propagation path in advance, per W3C events spec (#9951) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { bubbleType = special.delegateType || type; if ( !rfocusMorph.test( bubbleType + type ) ) { @@ -8189,7 +8459,7 @@ jQuery.extend( jQuery.event, { // Fire handlers on the event path i = 0; while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - + lastElement = cur; event.type = i > 1 ? bubbleType : special.bindType || type; @@ -8221,7 +8491,7 @@ jQuery.extend( jQuery.event, { // Call a native DOM method on the target with the same name as the event. // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; @@ -8232,7 +8502,17 @@ jQuery.extend( jQuery.event, { // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + jQuery.event.triggered = undefined; if ( tmp ) { @@ -8278,31 +8558,6 @@ jQuery.fn.extend( { } ); -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.fn.extend( { - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -} ); - - - - -support.focusin = "onfocusin" in window; - - // Support: Firefox <=44 // Firefox doesn't have focus(in | out) events // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 @@ -8346,7 +8601,7 @@ if ( !support.focusin ) { } var location = window.location; -var nonce = jQuery.now(); +var nonce = Date.now(); var rquery = ( /\?/ ); @@ -8404,7 +8659,7 @@ function buildParams( prefix, obj, traditional, add ) { } } ); - } else if ( !traditional && jQuery.type( obj ) === "object" ) { + } else if ( !traditional && toType( obj ) === "object" ) { // Serialize object item. for ( name in obj ) { @@ -8426,7 +8681,7 @@ jQuery.param = function( a, traditional ) { add = function( key, valueOrFunction ) { // If value is a function, invoke it and use its return value - var value = jQuery.isFunction( valueOrFunction ) ? + var value = isFunction( valueOrFunction ) ? valueOrFunction() : valueOrFunction; @@ -8434,6 +8689,10 @@ jQuery.param = function( a, traditional ) { encodeURIComponent( value == null ? "" : value ); }; + if ( a == null ) { + return ""; + } + // If an array was passed in, assume that it is an array of form elements. if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { @@ -8544,7 +8803,7 @@ function addToPrefiltersOrTransports( structure ) { i = 0, dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - if ( jQuery.isFunction( func ) ) { + if ( isFunction( func ) ) { // For each dataType in the dataTypeExpression while ( ( dataType = dataTypes[ i++ ] ) ) { @@ -8936,12 +9195,14 @@ jQuery.extend( { if ( !responseHeaders ) { responseHeaders = {}; while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); } } - match = responseHeaders[ key.toLowerCase() ]; + match = responseHeaders[ key.toLowerCase() + " " ]; } - return match == null ? null : match; + return match == null ? null : match.join( ", " ); }, // Raw string @@ -9016,7 +9277,7 @@ jQuery.extend( { if ( s.crossDomain == null ) { urlAnchor = document.createElement( "a" ); - // Support: IE <=8 - 11, Edge 12 - 13 + // Support: IE <=8 - 11, Edge 12 - 15 // IE throws exception on accessing the href property if url is malformed, // e.g. http://example.com:80x/ try { @@ -9074,8 +9335,8 @@ jQuery.extend( { // Remember the hash so we can put it back uncached = s.url.slice( cacheURL.length ); - // If data is available, append data to url - if ( s.data ) { + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; // #9682: remove data so that it's not used in an eventual retry @@ -9312,7 +9573,7 @@ jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { // Shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { + if ( isFunction( data ) ) { type = type || callback; callback = data; data = undefined; @@ -9330,7 +9591,7 @@ jQuery.each( [ "get", "post" ], function( i, method ) { } ); -jQuery._evalUrl = function( url ) { +jQuery._evalUrl = function( url, options ) { return jQuery.ajax( { url: url, @@ -9340,7 +9601,16 @@ jQuery._evalUrl = function( url ) { cache: true, async: false, global: false, - "throws": true + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options ); + } } ); }; @@ -9350,7 +9620,7 @@ jQuery.fn.extend( { var wrap; if ( this[ 0 ] ) { - if ( jQuery.isFunction( html ) ) { + if ( isFunction( html ) ) { html = html.call( this[ 0 ] ); } @@ -9376,7 +9646,7 @@ jQuery.fn.extend( { }, wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { + if ( isFunction( html ) ) { return this.each( function( i ) { jQuery( this ).wrapInner( html.call( this, i ) ); } ); @@ -9396,10 +9666,10 @@ jQuery.fn.extend( { }, wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); + var htmlIsFunction = isFunction( html ); return this.each( function( i ) { - jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); } ); }, @@ -9491,7 +9761,8 @@ jQuery.ajaxTransport( function( options ) { return function() { if ( callback ) { callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; if ( type === "abort" ) { xhr.abort(); @@ -9531,7 +9802,7 @@ jQuery.ajaxTransport( function( options ) { // Listen to events xhr.onload = callback(); - errorCallback = xhr.onerror = callback( "error" ); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); // Support: IE 9 only // Use onreadystatechange to replace onabort @@ -9622,24 +9893,21 @@ jQuery.ajaxPrefilter( "script", function( s ) { // Bind script tag hack transport jQuery.ajaxTransport( "script", function( s ) { - // This transport only deals with cross domain requests - if ( s.crossDomain ) { + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { var script, callback; return { send: function( _, complete ) { - script = jQuery( " + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

5.5. ui_framework package¶

+ +
+

5.5.2. Submodules¶

+
+
+

5.5.3. ui_framework.admin module¶

+

Defines the Django Admin model pages for this app .

+

Registers the models that will be available throgh the Djangpo Admin interface.

+

For more information see: +https://docs.djangoproject.com/en/2.2/ref/contrib/admin/

+
+
+

5.5.4. ui_framework.apps module¶

+

Django apps configuration for the ui_framework app.

+
+
+class ui_framework.apps.UiFrameworkConfig(app_name, app_module)¶
+

Bases: django.apps.config.AppConfig

+

General App config class. Currently defines the name of the app.

+
+
+name = 'ui_framework'¶
+
+ +
+ +
+
+

5.5.5. ui_framework.models module¶

+

Defines the Django models for this app.

+

For more information see: +https://docs.djangoproject.com/en/2.2/topics/db/models/

+
+
+class ui_framework.models.BaseModel(*args, **kwargs)¶
+

Bases: django.db.models.base.Model

+

Base Model for the models of this app.

+
+
+class Meta¶
+

Bases: object

+

Define attributes of the Meta class.

+
+
+abstract = False¶
+

Make this an abstract class in order to be used as an enhanced base model

+
+ +
+ +
+
+creation_timestamp¶
+

Creation timestamp, autogenerated upon creation

+
+ +
+
+get_next_by_creation_timestamp(*, field=<django.db.models.fields.DateTimeField: creation_timestamp>, is_next=True, **kwargs)¶
+
+ +
+
+get_next_by_update_timestamp(*, field=<django.db.models.fields.DateTimeField: update_timestamp>, is_next=True, **kwargs)¶
+
+ +
+
+get_previous_by_creation_timestamp(*, field=<django.db.models.fields.DateTimeField: creation_timestamp>, is_next=False, **kwargs)¶
+
+ +
+
+get_previous_by_update_timestamp(*, field=<django.db.models.fields.DateTimeField: update_timestamp>, is_next=False, **kwargs)¶
+
+ +
+
+update_timestamp¶
+

Update timestamp, autogenerated upon creation and autoupdated on every update

+
+ +
+ +
+
+class ui_framework.models.View(*args, **kwargs)¶
+

Bases: ui_framework.models.BaseModel

+

View Model.

+
+
+exception DoesNotExist¶
+

Bases: django.core.exceptions.ObjectDoesNotExist

+
+ +
+
+exception MultipleObjectsReturned¶
+

Bases: django.core.exceptions.MultipleObjectsReturned

+
+ +
+
+data¶
+

The data that constitutes the View, stored as a JSON

+
+ +
+
+get_next_by_creation_timestamp(*, field=<django.db.models.fields.DateTimeField: creation_timestamp>, is_next=True, **kwargs)¶
+
+ +
+
+get_next_by_update_timestamp(*, field=<django.db.models.fields.DateTimeField: update_timestamp>, is_next=True, **kwargs)¶
+
+ +
+
+get_previous_by_creation_timestamp(*, field=<django.db.models.fields.DateTimeField: creation_timestamp>, is_next=False, **kwargs)¶
+
+ +
+
+get_previous_by_update_timestamp(*, field=<django.db.models.fields.DateTimeField: update_timestamp>, is_next=False, **kwargs)¶
+
+ +
+
+id¶
+

A wrapper for a deferred-loading field. When the value is read from this +object the first time, the query is executed.

+
+ +
+
+name¶
+

The name of the View. e.g ‘My View’

+
+ +
+
+objects = <django.db.models.manager.Manager object>¶
+
+ +
+
+workspace_views¶
+

Accessor to the related objects manager on the reverse side of a +many-to-one relation.

+

In the example:

+
class Child(Model):
+    parent = ForeignKey(Parent, related_name='children')
+
+
+

Parent.children is a ReverseManyToOneDescriptor instance.

+

Most of the implementation is delegated to a dynamically defined manager +class built by create_forward_many_to_many_manager() defined below.

+
+ +
+
+workspaces¶
+

Accessor to the related objects manager on the forward and reverse sides of +a many-to-many relation.

+

In the example:

+
class Pizza(Model):
+    toppings = ManyToManyField(Topping, related_name='pizzas')
+
+
+

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor +instances.

+

Most of the implementation is delegated to a dynamically defined manager +class built by create_forward_many_to_many_manager() defined below.

+
+ +
+ +
+
+class ui_framework.models.Workspace(*args, **kwargs)¶
+

Bases: ui_framework.models.BaseModel

+

Workspace Model.

+
+
+exception DoesNotExist¶
+

Bases: django.core.exceptions.ObjectDoesNotExist

+
+ +
+
+exception MultipleObjectsReturned¶
+

Bases: django.core.exceptions.MultipleObjectsReturned

+
+ +
+
+get_next_by_creation_timestamp(*, field=<django.db.models.fields.DateTimeField: creation_timestamp>, is_next=True, **kwargs)¶
+
+ +
+
+get_next_by_update_timestamp(*, field=<django.db.models.fields.DateTimeField: update_timestamp>, is_next=True, **kwargs)¶
+
+ +
+
+get_previous_by_creation_timestamp(*, field=<django.db.models.fields.DateTimeField: creation_timestamp>, is_next=False, **kwargs)¶
+
+ +
+
+get_previous_by_update_timestamp(*, field=<django.db.models.fields.DateTimeField: update_timestamp>, is_next=False, **kwargs)¶
+
+ +
+
+get_sorted_views()¶
+

Return the views sorted by the sort_value of their corresponding WorkView.

+
+
list:

List of View objects associated to this Workspace

+
+
+
+ +
+
+static has_read_permission(request)¶
+
+ +
+
+id¶
+

A wrapper for a deferred-loading field. When the value is read from this +object the first time, the query is executed.

+
+ +
+
+name¶
+

The name of the Workspace. e.g ‘My Workspace’

+
+ +
+
+objects = <django.db.models.manager.Manager object>¶
+
+ +
+
+views¶
+

Accessor to the related objects manager on the forward and reverse sides of +a many-to-many relation.

+

In the example:

+
class Pizza(Model):
+    toppings = ManyToManyField(Topping, related_name='pizzas')
+
+
+

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor +instances.

+

Most of the implementation is delegated to a dynamically defined manager +class built by create_forward_many_to_many_manager() defined below.

+
+ +
+
+workspace_views¶
+

Accessor to the related objects manager on the reverse side of a +many-to-one relation.

+

In the example:

+
class Child(Model):
+    parent = ForeignKey(Parent, related_name='children')
+
+
+

Parent.children is a ReverseManyToOneDescriptor instance.

+

Most of the implementation is delegated to a dynamically defined manager +class built by create_forward_many_to_many_manager() defined below.

+
+ +
+ +
+
+class ui_framework.models.WorkspaceView(*args, **kwargs)¶
+

Bases: ui_framework.models.BaseModel

+

WorkspaceView Model, that relates a Works with a View.

+
+
+exception DoesNotExist¶
+

Bases: django.core.exceptions.ObjectDoesNotExist

+
+ +
+
+exception MultipleObjectsReturned¶
+

Bases: django.core.exceptions.MultipleObjectsReturned

+
+ +
+
+get_next_by_creation_timestamp(*, field=<django.db.models.fields.DateTimeField: creation_timestamp>, is_next=True, **kwargs)¶
+
+ +
+
+get_next_by_update_timestamp(*, field=<django.db.models.fields.DateTimeField: update_timestamp>, is_next=True, **kwargs)¶
+
+ +
+
+get_previous_by_creation_timestamp(*, field=<django.db.models.fields.DateTimeField: creation_timestamp>, is_next=False, **kwargs)¶
+
+ +
+
+get_previous_by_update_timestamp(*, field=<django.db.models.fields.DateTimeField: update_timestamp>, is_next=False, **kwargs)¶
+
+ +
+
+id¶
+

A wrapper for a deferred-loading field. When the value is read from this +object the first time, the query is executed.

+
+ +
+
+objects = <django.db.models.manager.Manager object>¶
+
+ +
+
+sort_value¶
+

Order of the View within the Workspace.

+
+ +
+
+view¶
+

The corresponding View

+
+ +
+
+view_id¶
+

A wrapper for a deferred-loading field. When the value is read from this +object the first time, the query is executed.

+
+ +
+
+view_name¶
+

The custom name for the View within the Workspace

+
+ +
+
+workspace¶
+

The corresponding Workspace

+
+ +
+
+workspace_id¶
+

A wrapper for a deferred-loading field. When the value is read from this +object the first time, the query is executed.

+
+ +
+ +
+
+

5.5.6. ui_framework.serializers module¶

+

Defines the serializer used by the REST API exposed by this app.

+
+
+class ui_framework.serializers.ViewSerializer(instance=None, data=<class 'rest_framework.fields.empty'>, **kwargs)¶
+

Bases: rest_framework.serializers.ModelSerializer

+

Serializer for the View model.

+
+
+class Meta¶
+

Bases: object

+

Meta class to map serializer’s fields with the model fields.

+
+
+fields = '__all__'¶
+
+ +
+
+model¶
+

alias of ui_framework.models.View

+
+ +
+ +
+ +
+
+class ui_framework.serializers.WorkspaceSerializer(instance=None, data=<class 'rest_framework.fields.empty'>, **kwargs)¶
+

Bases: rest_framework.serializers.ModelSerializer

+

Serializer for the Workspace model.

+
+
+class Meta¶
+

Bases: object

+

Meta class to map serializer’s fields with the model fields.

+
+
+fields = '__all__'¶
+
+ +
+
+model¶
+

alias of ui_framework.models.Workspace

+
+ +
+ +
+ +
+
+class ui_framework.serializers.WorkspaceViewSerializer(instance=None, data=<class 'rest_framework.fields.empty'>, **kwargs)¶
+

Bases: rest_framework.serializers.ModelSerializer

+

Serializer for the WorkspaceView model.

+
+
+class Meta¶
+

Bases: object

+

Meta class to map serializer’s fields with the model fields.

+
+
+fields = '__all__'¶
+
+ +
+
+model¶
+

alias of ui_framework.models.WorkspaceView

+
+ +
+ +
+ +
+
+

5.5.7. ui_framework.urls module¶

+

API app URL Configuration.

+
+
The urlpatterns list routes URLs to views. For more information please see:

https://docs.djangoproject.com/en/2.2/topics/http/urls/

+
+
+
+

5.5.7.1. Examples¶

+
+
Function views
    +
  1. Add an import: from my_app import views

  2. +
  3. Add a URL to urlpatterns: path(‘’, views.home, name=’home’)

  4. +
+
+
Class-based views
    +
  1. Add an import: from other_app.views import Home

  2. +
  3. Add a URL to urlpatterns: path(‘’, Home.as_view(), name=’home’)

  4. +
+
+
Including another URLconf
    +
  1. Import the include() function: from django.urls import include, path

  2. +
  3. Add a URL to urlpatterns: path(‘blog/’, include(‘blog.urls’))

  4. +
+
+
+
+
+
+

5.5.8. ui_framework.views module¶

+

Defines the views exposed by the REST API exposed by this app.

+
+
+class ui_framework.views.ViewViewSet(**kwargs)¶
+

Bases: rest_framework.viewsets.ModelViewSet

+

Define API endpoints for the View model.

+
+
+basename = None¶
+
+ +
+
+description = None¶
+
+ +
+
+detail = None¶
+
+ +
+
+name = None¶
+
+ +
+
+queryset = <QuerySet []>¶
+

Set of objects to be accessed by queries to this viewsets endpoints

+
+ +
+
+serializer_class¶
+

alias of ui_framework.serializers.ViewSerializer

+
+ +
+
+suffix = None¶
+
+ +
+ +
+
+class ui_framework.views.WorkspaceViewSet(**kwargs)¶
+

Bases: rest_framework.viewsets.ModelViewSet

+

Define API endpoints for the Workspace model.

+
+
+basename = None¶
+
+ +
+
+description = None¶
+
+ +
+
+detail = None¶
+
+ +
+
+name = None¶
+
+ +
+
+queryset = <QuerySet []>¶
+

Set of objects to be accessed by queries to this viewsets endpoints

+
+ +
+
+serializer_class¶
+

alias of ui_framework.serializers.WorkspaceSerializer

+
+ +
+
+suffix = None¶
+
+ +
+ +
+
+class ui_framework.views.WorkspaceViewViewSet(**kwargs)¶
+

Bases: rest_framework.viewsets.ModelViewSet

+

Define API endpoints for the WorkspaceView model.

+
+
+basename = None¶
+
+ +
+
+description = None¶
+
+ +
+
+detail = None¶
+
+ +
+
+name = None¶
+
+ +
+
+queryset = <QuerySet []>¶
+

Set of objects to be accessed by queries to this viewsets endpoints

+
+ +
+
+serializer_class¶
+

alias of ui_framework.serializers.WorkspaceViewSerializer

+
+ +
+
+suffix = None¶
+
+ +
+ +
+
+

5.5.9. Module contents¶

+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/html/apidoc/ui_framework.tests.html b/docs/html/apidoc/ui_framework.tests.html new file mode 100644 index 00000000..0b3ff363 --- /dev/null +++ b/docs/html/apidoc/ui_framework.tests.html @@ -0,0 +1,532 @@ + + + + + + + + + + + 5.5.1.1. ui_framework.tests package — LOVE-manager 0.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

5.5.1.1. ui_framework.tests package¶

+
+

5.5.1.1.1. Submodules¶

+
+
+

5.5.1.1.2. ui_framework.tests.tests_api module¶

+

Test the UI Framework API.

+
+
+class ui_framework.tests.tests_api.AuthorizedCrudTestCase(methodName='runTest')¶
+

Bases: ui_framework.tests.utils.BaseTestCase

+

Test that authorized users can use the CRUD API.

+
+
+setUp()¶
+

Set testcase. Inherits from utils.BaseTestCase.

+
+ +
+
+test_authorized_create_objects()¶
+

Test that authorized users can create objects through the API.

+
+ +
+
+test_authorized_delete_objects()¶
+

Test that authorized users can dalete objects through the API.

+
+ +
+
+test_authorized_list_objects()¶
+

Test that authorized users can retrieve the list of objects through the API.

+
+ +
+
+test_authorized_retrieve_objects()¶
+

Test that authorized users can retrieve objects through the API.

+
+ +
+
+test_authorized_update_objects()¶
+

Test that authorized users can update objects through the API.

+
+ +
+ +
+
+class ui_framework.tests.tests_api.UnauthenticatedCrudTestCase(methodName='runTest')¶
+

Bases: ui_framework.tests.utils.BaseTestCase

+

Test that unauthenticated users cannot use the CRUD API.

+
+
+setUp()¶
+

Set testcase. Inherits from utils.BaseTestCase.

+
+ +
+
+test_unauthenticated_create_objects()¶
+

Test that unauthenticated users cannot create objects through the API.

+
+ +
+
+test_unauthenticated_delete_objects()¶
+

Test that unauthenticated users cannot dalete objects through the API.

+
+ +
+
+test_unauthenticated_list_objects()¶
+

Test that unauthenticated users cannot retrieve the list of objects through the API.

+
+ +
+
+test_unauthenticated_retrieve_objects()¶
+

Test that unauthenticated users cannot retrieve objects through the API.

+
+ +
+
+test_unauthenticated_update_objects()¶
+

Test that unauthenticated users cannot update objects through the API.

+
+ +
+ +
+
+class ui_framework.tests.tests_api.UnauthorizedCrudTestCase(methodName='runTest')¶
+

Bases: ui_framework.tests.utils.BaseTestCase

+

Test that unauthorized users cannot use the CRUD API.

+
+
+setUp()¶
+

Set testcase. Inherits from utils.BaseTestCase.

+
+ +
+
+test_unauthorized_create_objects()¶
+

Test that unauthorized users cannot create objects through the API.

+
+ +
+
+test_unauthorized_delete_objects()¶
+

Test that unauthorized users cannot dalete objects through the API.

+
+ +
+
+test_unauthorized_list_objects()¶
+

Test that unauthorized users can still retrieve the list of objects through the API.

+
+ +
+
+test_unauthorized_retrieve_objects()¶
+

Test that unauthorized users can still retrieve objects through the API.

+
+ +
+
+test_unauthorized_update_objects()¶
+

Test that unauthorized users cannot update objects through the API.

+
+ +
+ +
+
+

5.5.1.1.3. ui_framework.tests.tests_models module¶

+

Test the models.

+
+
+class ui_framework.tests.tests_models.ViewModelTestCase(methodName='runTest')¶
+

Bases: django.test.testcases.TestCase

+

Test the view model.

+
+
+setUp()¶
+

Testcase setup.

+
+ +
+
+test_create_view()¶
+

Test that a view can be created in the database.

+
+ +
+
+test_delete_view()¶
+

Test that a view can be deleted from the database.

+
+ +
+
+test_retrieve_view()¶
+

Test that a view can be retrieved from the database.

+
+ +
+
+test_update_view()¶
+

Test that a view can be updated in the database.

+
+ +
+ +
+
+class ui_framework.tests.tests_models.WorkspaceAndViewsRelationsTestCase(methodName='runTest')¶
+

Bases: django.test.testcases.TestCase

+

Test the relationships vetween Workspace, View and WorkspaceView models.

+
+
+setUp()¶
+

Testcase setup.

+
+ +
+
+test_add_and_get_views_to_workspace()¶
+

Test that Views can be added/retrieved to/from a Workspace in the DB.

+
+ +
+
+test_get_workspaces_from_a_view()¶
+

Test that a View can retrieve its Workspaces from the DB.

+
+ +
+ +
+
+class ui_framework.tests.tests_models.WorkspaceModelTestCase(methodName='runTest')¶
+

Bases: django.test.testcases.TestCase

+

Test the workspace model.

+
+
+setUp()¶
+

Testcase setup.

+
+ +
+
+test_create_workspace()¶
+

Test that a workspace can be created in the database.

+
+ +
+
+test_delete_workspace()¶
+

Test that a workspace can be deleted from the database.

+
+ +
+
+test_retrieve_workspace()¶
+

Test that a workspace can be retrieved from the database.

+
+ +
+
+test_update_workspace()¶
+

Test that a workspace can be updated in the database.

+
+ +
+ +
+
+class ui_framework.tests.tests_models.WorkspaceViewModelTestCase(methodName='runTest')¶
+

Bases: django.test.testcases.TestCase

+

Test the workspace_view model.

+
+
+setUp()¶
+

Testcase setup.

+
+ +
+
+test_create_workspace_view()¶
+

Test that a workspace_view can be created in the database.

+
+ +
+
+test_delete_workspace_view()¶
+

Test that a workspace_view can be deleted from the database.

+
+ +
+
+test_retrieve_workspace_view()¶
+

Test that a workspace_view can be retrieved from the database.

+
+ +
+
+test_update_workspace_view()¶
+

Test that a workspace_view can be updated in the database.

+
+ +
+ +
+
+

5.5.1.1.4. ui_framework.tests.utils module¶

+

Utilities for testing purposes.

+
+
+class ui_framework.tests.utils.BaseTestCase(methodName='runTest')¶
+

Bases: django.test.testcases.TestCase

+

Base TestCase used to define a common setUp.

+
+
+setUp()¶
+

Set the base testcase.

+

We start with 3 workspaces and 4 views and we add view_i and view_i+1 to workspace_i

+
+ +
+ +
+
+ui_framework.tests.utils.get_dict(obj)¶
+

Return a dictionary with the fields of a given object.

+
+ +
+
+

5.5.1.1.5. Module contents¶

+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/html/genindex.html b/docs/html/genindex.html index 40f64739..7680a92a 100644 --- a/docs/html/genindex.html +++ b/docs/html/genindex.html @@ -153,6 +153,7 @@

Index

A + | B | C | D | E @@ -165,16 +166,20 @@

Index

| N | O | P + | Q | R | S | T | U | V + | W

A

+
+ +

B

+ + +
@@ -215,6 +244,8 @@

C

@@ -223,6 +254,26 @@

C

D

+ @@ -244,21 +295,73 @@

F

G

@@ -287,6 +392,12 @@

I

@@ -317,10 +428,10 @@

M

  • manager.settings (module)
  • - - + @@ -338,7 +455,21 @@

    N

    @@ -349,6 +480,12 @@

    O

    @@ -370,6 +507,20 @@

    P

    +

    Q

    + + +
    +

    R