aboutsummaryrefslogtreecommitdiffstats
path: root/web/src
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2014-12-09 18:18:14 +0100
committerMaximilian Hils <git@maximilianhils.com>2014-12-09 18:18:14 +0100
commit14a8d2f5b83a1ea28abbb490f6c94c43b4e1f960 (patch)
treec114643959a6223289e8287e9daaa1b65a377356 /web/src
parent096a3af273ccb309820351b466e62382f62a2c36 (diff)
downloadmitmproxy-14a8d2f5b83a1ea28abbb490f6c94c43b4e1f960.tar.gz
mitmproxy-14a8d2f5b83a1ea28abbb490f6c94c43b4e1f960.tar.bz2
mitmproxy-14a8d2f5b83a1ea28abbb490f6c94c43b4e1f960.zip
always use the app dispatcher
Diffstat (limited to 'web/src')
-rw-r--r--web/src/flows.json2012
-rw-r--r--web/src/js/actions.js35
-rw-r--r--web/src/js/app.js7
-rw-r--r--web/src/js/components/flowdetail.jsx.js2
-rw-r--r--web/src/js/components/mainview.jsx.js2
-rw-r--r--web/src/js/connection.js52
-rw-r--r--web/src/js/stores/flowstore.js69
-rw-r--r--web/src/vendor/bootstrap/bootstrap.css535
-rw-r--r--web/src/vendor/bootstrap/bootstrap.js566
-rw-r--r--web/src/vendor/bootstrap/glyphicons-halflings-regular.svg2
-rw-r--r--web/src/vendor/qunit/qunit.css33
-rw-r--r--web/src/vendor/qunit/qunit.js1364
-rw-r--r--web/src/vendor/react-bootstrap/react-bootstrap.js5346
-rw-r--r--web/src/vendor/react-router/react-router.js253
14 files changed, 1865 insertions, 8413 deletions
diff --git a/web/src/flows.json b/web/src/flows.json
deleted file mode 100644
index bdbfd5cc..00000000
--- a/web/src/flows.json
+++ /dev/null
@@ -1,2012 +0,0 @@
-[{
- "request": {
- "timestamp_end": 1410651311.107,
- "timestamp_start": 1410651311.106,
- "form_in": "relative",
- "headers": [
- [
- "Host",
- "news.ycombinator.com"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Cookie",
- "__cfduid=d0486ff404fe3beb320f15e958861aaea1410651010546"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Pragma",
- "no-cache"
- ],
- [
- "Cache-Control",
- "no-cache"
- ]
- ],
- "host": "news.ycombinator.com",
- "form_out": "relative",
- "path": "/",
- "method": "GET",
- "scheme": "https",
- "port": 443,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651311.055,
- "state": [],
- "timestamp_ssl_setup": 1410651311.096,
- "sni": "news.ycombinator.com",
- "timestamp_start": 1410651311.04,
- "address": {
- "use_ipv6": false,
- "address": [
- "news.ycombinator.com",
- 443
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63383
- ]
- },
- "ssl_established": true
- },
- "client_conn": {
- "timestamp_start": 1410651310.36,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63380
- ]
- },
- "timestamp_ssl_setup": 1410651311.105,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": true
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "cloudflare-nginx"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:35:08 GMT"
- ],
- [
- "Content-Type",
- "text/html; charset=utf-8"
- ],
- [
- "Transfer-Encoding",
- "chunked"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Vary",
- "Accept-Encoding"
- ],
- [
- "Cache-Control",
- "private"
- ],
- [
- "X-Frame-Options",
- "DENY"
- ],
- [
- "Cache-Control",
- "max-age=0"
- ],
- [
- "Strict-Transport-Security",
- "max-age=31556900; includeSubDomains"
- ],
- [
- "CF-RAY",
- "169828d0108e088d-FRA"
- ],
- [
- "Content-Encoding",
- "gzip"
- ]
- ],
- "timestamp_start": 1410651311.6,
- "msg": "OK",
- "timestamp_end": 1410651311.603,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651311.657,
- "timestamp_start": 1410651311.653,
- "form_in": "relative",
- "headers": [
- [
- "Host",
- "news.ycombinator.com"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "text/css,*/*;q=0.1"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "https://news.ycombinator.com/"
- ],
- [
- "Cookie",
- "__cfduid=d0486ff404fe3beb320f15e958861aaea1410651010546"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Pragma",
- "no-cache"
- ],
- [
- "Cache-Control",
- "no-cache"
- ]
- ],
- "host": "news.ycombinator.com",
- "form_out": "relative",
- "path": "/news.css?IZYAdhDe5bN6BGyHv1jq",
- "method": "GET",
- "scheme": "https",
- "port": 443,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651311.055,
- "state": [],
- "timestamp_ssl_setup": 1410651311.096,
- "sni": "news.ycombinator.com",
- "timestamp_start": 1410651311.04,
- "address": {
- "use_ipv6": false,
- "address": [
- "news.ycombinator.com",
- 443
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63383
- ]
- },
- "ssl_established": true
- },
- "client_conn": {
- "timestamp_start": 1410651310.36,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63380
- ]
- },
- "timestamp_ssl_setup": 1410651311.105,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": true
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "cloudflare-nginx"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:35:08 GMT"
- ],
- [
- "Content-Type",
- "text/css"
- ],
- [
- "Transfer-Encoding",
- "chunked"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Last-Modified",
- "Fri, 01 Aug 2014 04:27:14 GMT"
- ],
- [
- "Vary",
- "Accept-Encoding"
- ],
- [
- "Expires",
- "Mon, 29 Jul 2024 04:27:14 GMT"
- ],
- [
- "Cache-Control",
- "max-age=311575926"
- ],
- [
- "Cache-Control",
- "public"
- ],
- [
- "CF-RAY",
- "169828d38096088d-FRA"
- ],
- [
- "Content-Encoding",
- "gzip"
- ]
- ],
- "timestamp_start": 1410651312.167,
- "msg": "OK",
- "timestamp_end": 1410651312.17,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651312.362,
- "timestamp_start": 1410651312.359,
- "form_in": "relative",
- "headers": [
- [
- "Host",
- "news.ycombinator.com"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "image/png,image/*;q=0.8,*/*;q=0.5"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "https://news.ycombinator.com/"
- ],
- [
- "Cookie",
- "__cfduid=d0486ff404fe3beb320f15e958861aaea1410651010546"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Pragma",
- "no-cache"
- ],
- [
- "Cache-Control",
- "no-cache"
- ]
- ],
- "host": "news.ycombinator.com",
- "form_out": "relative",
- "path": "/s.gif",
- "method": "GET",
- "scheme": "https",
- "port": 443,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651312.303,
- "state": [],
- "timestamp_ssl_setup": 1410651312.349,
- "sni": "news.ycombinator.com",
- "timestamp_start": 1410651312.287,
- "address": {
- "use_ipv6": false,
- "address": [
- "news.ycombinator.com",
- 443
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63391
- ]
- },
- "ssl_established": true
- },
- "client_conn": {
- "timestamp_start": 1410651312.193,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63386
- ]
- },
- "timestamp_ssl_setup": 1410651312.358,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": true
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "cloudflare-nginx"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:35:08 GMT"
- ],
- [
- "Content-Type",
- "image/gif"
- ],
- [
- "Content-Length",
- "43"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Last-Modified",
- "Tue, 12 Mar 2013 09:06:31 GMT"
- ],
- [
- "ETag",
- "\"513ef017-2b\""
- ],
- [
- "Expires",
- "Fri, 31 Mar 2023 21:06:02 GMT"
- ],
- [
- "Cache-Control",
- "public, max-age=269645454"
- ],
- [
- "CF-Cache-Status",
- "HIT"
- ],
- [
- "Vary",
- "Accept-Encoding"
- ],
- [
- "Accept-Ranges",
- "bytes"
- ],
- [
- "CF-RAY",
- "169828d7e771088d-FRA"
- ]
- ],
- "timestamp_start": 1410651312.383,
- "msg": "OK",
- "timestamp_end": 1410651312.393,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651312.389,
- "timestamp_start": 1410651312.368,
- "form_in": "relative",
- "headers": [
- [
- "Host",
- "news.ycombinator.com"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "image/png,image/*;q=0.8,*/*;q=0.5"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "https://news.ycombinator.com/news.css?IZYAdhDe5bN6BGyHv1jq"
- ],
- [
- "Cookie",
- "__cfduid=d0486ff404fe3beb320f15e958861aaea1410651010546"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Pragma",
- "no-cache"
- ],
- [
- "Cache-Control",
- "no-cache"
- ]
- ],
- "host": "news.ycombinator.com",
- "form_out": "relative",
- "path": "/grayarrow.gif",
- "method": "GET",
- "scheme": "https",
- "port": 443,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651312.307,
- "state": [],
- "timestamp_ssl_setup": 1410651312.355,
- "sni": "news.ycombinator.com",
- "timestamp_start": 1410651312.291,
- "address": {
- "use_ipv6": false,
- "address": [
- "news.ycombinator.com",
- 443
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63393
- ]
- },
- "ssl_established": true
- },
- "client_conn": {
- "timestamp_start": 1410651312.2,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63387
- ]
- },
- "timestamp_ssl_setup": 1410651312.368,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": true
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "cloudflare-nginx"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:35:08 GMT"
- ],
- [
- "Content-Type",
- "image/gif"
- ],
- [
- "Content-Length",
- "111"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Last-Modified",
- "Tue, 12 Mar 2013 09:06:31 GMT"
- ],
- [
- "ETag",
- "\"513ef017-6f\""
- ],
- [
- "Expires",
- "Sat, 01 Apr 2023 05:56:11 GMT"
- ],
- [
- "Cache-Control",
- "public, max-age=269677263"
- ],
- [
- "CF-Cache-Status",
- "HIT"
- ],
- [
- "Vary",
- "Accept-Encoding"
- ],
- [
- "Accept-Ranges",
- "bytes"
- ],
- [
- "CF-RAY",
- "169828d81430088d-FRA"
- ]
- ],
- "timestamp_start": 1410651312.409,
- "msg": "OK",
- "timestamp_end": 1410651312.412,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651312.386,
- "timestamp_start": 1410651312.368,
- "form_in": "relative",
- "headers": [
- [
- "Host",
- "news.ycombinator.com"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "image/png,image/*;q=0.8,*/*;q=0.5"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "https://news.ycombinator.com/"
- ],
- [
- "Cookie",
- "__cfduid=d0486ff404fe3beb320f15e958861aaea1410651010546"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Pragma",
- "no-cache"
- ],
- [
- "Cache-Control",
- "no-cache"
- ]
- ],
- "host": "news.ycombinator.com",
- "form_out": "relative",
- "path": "/y18.gif",
- "method": "GET",
- "scheme": "https",
- "port": 443,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651312.303,
- "state": [],
- "timestamp_ssl_setup": 1410651312.355,
- "sni": "news.ycombinator.com",
- "timestamp_start": 1410651312.287,
- "address": {
- "use_ipv6": false,
- "address": [
- "news.ycombinator.com",
- 443
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63392
- ]
- },
- "ssl_established": true
- },
- "client_conn": {
- "timestamp_start": 1410651312.192,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63385
- ]
- },
- "timestamp_ssl_setup": 1410651312.368,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": true
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "cloudflare-nginx"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:35:08 GMT"
- ],
- [
- "Content-Type",
- "image/gif"
- ],
- [
- "Content-Length",
- "100"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Last-Modified",
- "Tue, 12 Mar 2013 09:06:31 GMT"
- ],
- [
- "ETag",
- "\"513ef017-64\""
- ],
- [
- "Expires",
- "Sat, 01 Apr 2023 04:28:54 GMT"
- ],
- [
- "Cache-Control",
- "public, max-age=269672026"
- ],
- [
- "CF-Cache-Status",
- "HIT"
- ],
- [
- "Vary",
- "Accept-Encoding"
- ],
- [
- "Accept-Ranges",
- "bytes"
- ],
- [
- "CF-RAY",
- "169828d8109a088d-FRA"
- ]
- ],
- "timestamp_start": 1410651312.413,
- "msg": "OK",
- "timestamp_end": 1410651312.416,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651373.965,
- "timestamp_start": 1410651373.963,
- "form_in": "absolute",
- "headers": [
- [
- "Host",
- "mitmproxy.org"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "host": "mitmproxy.org",
- "form_out": "relative",
- "path": "/",
- "method": "GET",
- "scheme": "http",
- "port": 80,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651374.189,
- "state": [],
- "timestamp_ssl_setup": null,
- "sni": null,
- "timestamp_start": 1410651373.985,
- "address": {
- "use_ipv6": false,
- "address": [
- "mitmproxy.org",
- 80
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63404
- ]
- },
- "ssl_established": false
- },
- "client_conn": {
- "timestamp_start": 1410651373.958,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63403
- ]
- },
- "timestamp_ssl_setup": null,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": false
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "nginx/1.1.19"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:36:10 GMT"
- ],
- [
- "Content-Type",
- "text/html"
- ],
- [
- "Last-Modified",
- "Wed, 26 Feb 2014 19:58:20 GMT"
- ],
- [
- "Transfer-Encoding",
- "chunked"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Vary",
- "Accept-Encoding"
- ],
- [
- "Content-Encoding",
- "gzip"
- ]
- ],
- "timestamp_start": 1410651374.365,
- "msg": "OK",
- "timestamp_end": 1410651374.366,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651374.391,
- "timestamp_start": 1410651374.387,
- "form_in": "absolute",
- "headers": [
- [
- "Host",
- "mitmproxy.org"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "text/css,*/*;q=0.1"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "http://mitmproxy.org/"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "host": "mitmproxy.org",
- "form_out": "relative",
- "path": "/01-bootstrap.min.css",
- "method": "GET",
- "scheme": "http",
- "port": 80,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651374.189,
- "state": [],
- "timestamp_ssl_setup": null,
- "sni": null,
- "timestamp_start": 1410651373.985,
- "address": {
- "use_ipv6": false,
- "address": [
- "mitmproxy.org",
- 80
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63404
- ]
- },
- "ssl_established": false
- },
- "client_conn": {
- "timestamp_start": 1410651373.958,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63403
- ]
- },
- "timestamp_ssl_setup": null,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": false
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "nginx/1.1.19"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:36:10 GMT"
- ],
- [
- "Content-Type",
- "text/css"
- ],
- [
- "Last-Modified",
- "Wed, 26 Feb 2014 19:58:20 GMT"
- ],
- [
- "Transfer-Encoding",
- "chunked"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Vary",
- "Accept-Encoding"
- ],
- [
- "Content-Encoding",
- "gzip"
- ]
- ],
- "timestamp_start": 1410651374.579,
- "msg": "OK",
- "timestamp_end": 1410651374.58,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651374.396,
- "timestamp_start": 1410651374.394,
- "form_in": "absolute",
- "headers": [
- [
- "Host",
- "mitmproxy.org"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "text/css,*/*;q=0.1"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "http://mitmproxy.org/"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "host": "mitmproxy.org",
- "form_out": "relative",
- "path": "/03-sitestyle.css",
- "method": "GET",
- "scheme": "http",
- "port": 80,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651374.567,
- "state": [],
- "timestamp_ssl_setup": null,
- "sni": null,
- "timestamp_start": 1410651374.401,
- "address": {
- "use_ipv6": false,
- "address": [
- "mitmproxy.org",
- 80
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63407
- ]
- },
- "ssl_established": false
- },
- "client_conn": {
- "timestamp_start": 1410651374.389,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63405
- ]
- },
- "timestamp_ssl_setup": null,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": false
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "nginx/1.1.19"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:36:11 GMT"
- ],
- [
- "Content-Type",
- "text/css"
- ],
- [
- "Content-Length",
- "124"
- ],
- [
- "Last-Modified",
- "Wed, 26 Feb 2014 19:58:20 GMT"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Accept-Ranges",
- "bytes"
- ]
- ],
- "timestamp_start": 1410651374.746,
- "msg": "OK",
- "timestamp_end": 1410651374.747,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651374.795,
- "timestamp_start": 1410651374.793,
- "form_in": "absolute",
- "headers": [
- [
- "Host",
- "www.google-analytics.com"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "*/*"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "http://mitmproxy.org/"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "host": "www.google-analytics.com",
- "form_out": "relative",
- "path": "/ga.js",
- "method": "GET",
- "scheme": "http",
- "port": 80,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651374.99,
- "state": [],
- "timestamp_ssl_setup": null,
- "sni": null,
- "timestamp_start": 1410651374.974,
- "address": {
- "use_ipv6": false,
- "address": [
- "www.google-analytics.com",
- 80
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63409
- ]
- },
- "ssl_established": false
- },
- "client_conn": {
- "timestamp_start": 1410651374.389,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63405
- ]
- },
- "timestamp_ssl_setup": null,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": false
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Date",
- "Sat, 13 Sep 2014 22:02:27 GMT"
- ],
- [
- "Expires",
- "Sun, 14 Sep 2014 00:02:27 GMT"
- ],
- [
- "Last-Modified",
- "Mon, 08 Sep 2014 18:50:13 GMT"
- ],
- [
- "X-Content-Type-Options",
- "nosniff"
- ],
- [
- "Content-Type",
- "text/javascript"
- ],
- [
- "Vary",
- "Accept-Encoding"
- ],
- [
- "Content-Encoding",
- "gzip"
- ],
- [
- "Server",
- "Golfe2"
- ],
- [
- "Content-Length",
- "16062"
- ],
- [
- "Age",
- "5624"
- ],
- [
- "Cache-Control",
- "public, max-age=7200"
- ],
- [
- "Alternate-Protocol",
- "80:quic,p=0.002"
- ]
- ],
- "timestamp_start": 1410651375.013,
- "msg": "OK",
- "timestamp_end": 1410651375.015,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651375.084,
- "timestamp_start": 1410651375.078,
- "form_in": "absolute",
- "headers": [
- [
- "Host",
- "www.google-analytics.com"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "image/png,image/*;q=0.8,*/*;q=0.5"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "http://mitmproxy.org/"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "host": "www.google-analytics.com",
- "form_out": "relative",
- "path": "/__utm.gif?utmwv=5.5.7&utms=1&utmn=1242429522&utmhn=mitmproxy.org&utmcs=UTF-8&utmsr=1536x864&utmvp=1091x742&utmsc=24-bit&utmul=de&utmje=1&utmfl=15.0%20r0&utmdt=mitmproxy%20-%20home&utmhid=812953117&utmr=-&utmp=%2F&utmht=1410651375077&utmac=UA-4150636-13&utmcc=__utma%3D30234659.1711188806.1410651375.1410651375.1410651375.1%3B%2B__utmz%3D30234659.1410651375.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmu=q~",
- "method": "GET",
- "scheme": "http",
- "port": 80,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651374.99,
- "state": [],
- "timestamp_ssl_setup": null,
- "sni": null,
- "timestamp_start": 1410651374.974,
- "address": {
- "use_ipv6": false,
- "address": [
- "www.google-analytics.com",
- 80
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63409
- ]
- },
- "ssl_established": false
- },
- "client_conn": {
- "timestamp_start": 1410651374.389,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63405
- ]
- },
- "timestamp_ssl_setup": null,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": false
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Pragma",
- "no-cache"
- ],
- [
- "Expires",
- "Wed, 19 Apr 2000 11:43:00 GMT"
- ],
- [
- "Last-Modified",
- "Wed, 21 Jan 2004 19:51:30 GMT"
- ],
- [
- "X-Content-Type-Options",
- "nosniff"
- ],
- [
- "Content-Type",
- "image/gif"
- ],
- [
- "Date",
- "Thu, 04 Sep 2014 18:39:58 GMT"
- ],
- [
- "Server",
- "Golfe2"
- ],
- [
- "Content-Length",
- "35"
- ],
- [
- "Age",
- "795373"
- ],
- [
- "Cache-Control",
- "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
- ],
- [
- "Alternate-Protocol",
- "80:quic,p=0.002"
- ]
- ],
- "timestamp_start": 1410651375.104,
- "msg": "OK",
- "timestamp_end": 1410651375.107,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651374.778,
- "timestamp_start": 1410651374.766,
- "form_in": "absolute",
- "headers": [
- [
- "Host",
- "mitmproxy.org"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "image/png,image/*;q=0.8,*/*;q=0.5"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "http://mitmproxy.org/"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "host": "mitmproxy.org",
- "form_out": "relative",
- "path": "/images/apple.png",
- "method": "GET",
- "scheme": "http",
- "port": 80,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651374.952,
- "state": [],
- "timestamp_ssl_setup": null,
- "sni": null,
- "timestamp_start": 1410651374.782,
- "address": {
- "use_ipv6": false,
- "address": [
- "mitmproxy.org",
- 80
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63408
- ]
- },
- "ssl_established": false
- },
- "client_conn": {
- "timestamp_start": 1410651374.39,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63406
- ]
- },
- "timestamp_ssl_setup": null,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": false
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "nginx/1.1.19"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:36:11 GMT"
- ],
- [
- "Content-Type",
- "image/png"
- ],
- [
- "Content-Length",
- "20532"
- ],
- [
- "Last-Modified",
- "Wed, 26 Feb 2014 19:58:20 GMT"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Accept-Ranges",
- "bytes"
- ]
- ],
- "timestamp_start": 1410651375.125,
- "msg": "OK",
- "timestamp_end": 1410651375.126,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651374.778,
- "timestamp_start": 1410651374.766,
- "form_in": "absolute",
- "headers": [
- [
- "Host",
- "mitmproxy.org"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "image/png,image/*;q=0.8,*/*;q=0.5"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Referer",
- "http://mitmproxy.org/"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "host": "mitmproxy.org",
- "form_out": "relative",
- "path": "/images/mitmproxy-small.png",
- "method": "GET",
- "scheme": "http",
- "port": 80,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651374.189,
- "state": [],
- "timestamp_ssl_setup": null,
- "sni": null,
- "timestamp_start": 1410651373.985,
- "address": {
- "use_ipv6": false,
- "address": [
- "mitmproxy.org",
- 80
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63404
- ]
- },
- "ssl_established": false
- },
- "client_conn": {
- "timestamp_start": 1410651373.958,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63403
- ]
- },
- "timestamp_ssl_setup": null,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": false
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 200,
- "headers": [
- [
- "Server",
- "nginx/1.1.19"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:36:11 GMT"
- ],
- [
- "Content-Type",
- "image/png"
- ],
- [
- "Content-Length",
- "170108"
- ],
- [
- "Last-Modified",
- "Wed, 26 Feb 2014 19:58:20 GMT"
- ],
- [
- "Connection",
- "keep-alive"
- ],
- [
- "Accept-Ranges",
- "bytes"
- ]
- ],
- "timestamp_start": 1410651374.953,
- "msg": "OK",
- "timestamp_end": 1410651374.954,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651376.078,
- "timestamp_start": 1410651376.075,
- "form_in": "absolute",
- "headers": [
- [
- "Host",
- "mitmproxy.org"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Cookie",
- "__utma=30234659.1711188806.1410651375.1410651375.1410651375.1; __utmb=30234659.1.10.1410651375; __utmc=30234659; __utmz=30234659.1410651375.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "host": "mitmproxy.org",
- "form_out": "relative",
- "path": "/favicon.ico",
- "method": "GET",
- "scheme": "http",
- "port": 80,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651374.189,
- "state": [],
- "timestamp_ssl_setup": null,
- "sni": null,
- "timestamp_start": 1410651373.985,
- "address": {
- "use_ipv6": false,
- "address": [
- "mitmproxy.org",
- 80
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63404
- ]
- },
- "ssl_established": false
- },
- "client_conn": {
- "timestamp_start": 1410651373.958,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63403
- ]
- },
- "timestamp_ssl_setup": null,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": false
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 404,
- "headers": [
- [
- "Server",
- "nginx/1.1.19"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:36:12 GMT"
- ],
- [
- "Content-Type",
- "text/html"
- ],
- [
- "Content-Length",
- "169"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "timestamp_start": 1410651376.254,
- "msg": "Not Found",
- "timestamp_end": 1410651376.255,
- "httpversion": [
- 1,
- 1
- ]
- }
-},
-{
- "request": {
- "timestamp_end": 1410651376.282,
- "timestamp_start": 1410651376.279,
- "form_in": "absolute",
- "headers": [
- [
- "Host",
- "mitmproxy.org"
- ],
- [
- "User-Agent",
- "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
- ],
- [
- "Accept",
- "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
- ],
- [
- "Accept-Language",
- "de,en-US;q=0.7,en;q=0.3"
- ],
- [
- "Accept-Encoding",
- "gzip, deflate"
- ],
- [
- "Cookie",
- "__utma=30234659.1711188806.1410651375.1410651375.1410651375.1; __utmb=30234659.1.10.1410651375; __utmc=30234659; __utmz=30234659.1410651375.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "host": "mitmproxy.org",
- "form_out": "relative",
- "path": "/favicon.ico",
- "method": "GET",
- "scheme": "http",
- "port": 80,
- "httpversion": [
- 1,
- 1
- ]
- },
- "server_conn": {
- "timestamp_tcp_setup": 1410651374.189,
- "state": [],
- "timestamp_ssl_setup": null,
- "sni": null,
- "timestamp_start": 1410651373.985,
- "address": {
- "use_ipv6": false,
- "address": [
- "mitmproxy.org",
- 80
- ]
- },
- "timestamp_end": null,
- "source_address": {
- "use_ipv6": false,
- "address": [
- "192.168.1.117",
- 63404
- ]
- },
- "ssl_established": false
- },
- "client_conn": {
- "timestamp_start": 1410651373.958,
- "address": {
- "use_ipv6": false,
- "address": [
- "127.0.0.1",
- 63403
- ]
- },
- "timestamp_ssl_setup": null,
- "timestamp_end": null,
- "clientcert": null,
- "ssl_established": false
- },
- "conntype": "http",
- "version": [
- 0,
- 11
- ],
- "error": null,
- "response": {
- "code": 404,
- "headers": [
- [
- "Server",
- "nginx/1.1.19"
- ],
- [
- "Date",
- "Sat, 13 Sep 2014 23:36:12 GMT"
- ],
- [
- "Content-Type",
- "text/html"
- ],
- [
- "Content-Length",
- "169"
- ],
- [
- "Connection",
- "keep-alive"
- ]
- ],
- "timestamp_start": 1410651376.461,
- "msg": "Not Found",
- "timestamp_end": 1410651376.462,
- "httpversion": [
- 1,
- 1
- ]
- }
-}] \ No newline at end of file
diff --git a/web/src/js/actions.js b/web/src/js/actions.js
index 3e7510ad..28bb58b8 100644
--- a/web/src/js/actions.js
+++ b/web/src/js/actions.js
@@ -1,13 +1,38 @@
var ActionTypes = {
- //Settings
+ // Connection
+ CONNECTION_OPEN: "connection_open",
+ CONNECTION_CLOSE: "connection_close",
+ CONNECTION_ERROR: "connection_error",
+
+ // Settings
UPDATE_SETTINGS: "update_settings",
- //EventLog
+ // EventLog
ADD_EVENT: "add_event",
- //Flow
+ // Flow
ADD_FLOW: "add_flow",
UPDATE_FLOW: "update_flow",
+ REMOVE_FLOW: "remove_flow",
+ RESET_FLOWS: "reset_flows",
+};
+
+var ConnectionActions = {
+ open: function () {
+ AppDispatcher.dispatchViewAction({
+ type: ActionTypes.CONNECTION_OPEN
+ });
+ },
+ close: function () {
+ AppDispatcher.dispatchViewAction({
+ type: ActionTypes.CONNECTION_CLOSE
+ });
+ },
+ error: function () {
+ AppDispatcher.dispatchViewAction({
+ type: ActionTypes.CONNECTION_ERROR
+ });
+ }
};
var SettingsActions = {
@@ -23,7 +48,7 @@ var SettingsActions = {
}
};
-var event_id = 0;
+var EventLogActions_event_id = 0;
var EventLogActions = {
add_event: function (message) {
AppDispatcher.dispatchViewAction({
@@ -31,7 +56,7 @@ var EventLogActions = {
data: {
message: message,
level: "web",
- id: "viewAction-" + event_id++
+ id: "viewAction-" + EventLogActions_event_id++
}
});
}
diff --git a/web/src/js/app.js b/web/src/js/app.js
index b5d50d34..5146cb46 100644
--- a/web/src/js/app.js
+++ b/web/src/js/app.js
@@ -1,10 +1,7 @@
$(function () {
+ window.ws = new Connection("/updates");
+
ReactRouter.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
- var UpdateConnection = new Connection("/updates");
- UpdateConnection.onmessage = function (message) {
- var m = JSON.parse(message.data);
- AppDispatcher.dispatchServerAction(m);
- };
}); \ No newline at end of file
diff --git a/web/src/js/components/flowdetail.jsx.js b/web/src/js/components/flowdetail.jsx.js
index 2bda5b80..6d46cd2e 100644
--- a/web/src/js/components/flowdetail.jsx.js
+++ b/web/src/js/components/flowdetail.jsx.js
@@ -306,7 +306,7 @@ var FlowDetail = React.createClass({
return tabs;
},
nextTab: function (i) {
- var tabs = this.getTabs();
+ var tabs = this.getTabs(this.props.flow);
var currentIndex = tabs.indexOf(this.getParams().detailTab);
// JS modulo operator doesn't correct negative numbers, make sure that we are positive.
var nextIndex = (currentIndex + i + tabs.length) % tabs.length;
diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js
index d5066b1a..c7c9ee9b 100644
--- a/web/src/js/components/mainview.jsx.js
+++ b/web/src/js/components/mainview.jsx.js
@@ -24,7 +24,7 @@ var MainView = React.createClass({
this.forceUpdate();
var selected = this.getSelected();
if(selected){
- this.refs.flowTable.scrollIntoView();
+ this.refs.flowTable.scrollIntoView(selected);
}
},
onUpdate: function (flow) {
diff --git a/web/src/js/connection.js b/web/src/js/connection.js
index d511270d..6ca353b3 100644
--- a/web/src/js/connection.js
+++ b/web/src/js/connection.js
@@ -1,38 +1,24 @@
function Connection(url) {
- if (url[0] != "/") {
- this.url = url;
- } else {
- this.url = location.origin.replace("http", "ws") + url;
+
+ if (url[0] === "/") {
+ url = location.origin.replace("http", "ws") + url;
}
- var ws = new WebSocket(this.url);
+
+ var ws = new WebSocket(url);
ws.onopen = function () {
- this.onopen.apply(this, arguments);
- }.bind(this);
- ws.onmessage = function () {
- this.onmessage.apply(this, arguments);
- }.bind(this);
+ ConnectionActions.open();
+ };
+ ws.onmessage = function (message) {
+ var m = JSON.parse(message.data);
+ AppDispatcher.dispatchServerAction(m);
+ };
ws.onerror = function () {
- this.onerror.apply(this, arguments);
- }.bind(this);
+ ConnectionActions.error();
+ EventLogActions.add_event("WebSocket connection error.");
+ };
ws.onclose = function () {
- this.onclose.apply(this, arguments);
- }.bind(this);
- this.ws = ws;
-}
-Connection.prototype.onopen = function (open) {
- console.debug("onopen", this, arguments);
-};
-Connection.prototype.onmessage = function (message) {
- console.warn("onmessage (not implemented)", this, message.data);
-};
-Connection.prototype.onerror = function (error) {
- EventLogActions.add_event("WebSocket Connection Error.");
- console.debug("onerror", this, arguments);
-};
-Connection.prototype.onclose = function (close) {
- EventLogActions.add_event("WebSocket Connection closed.");
- console.debug("onclose", this, arguments);
-};
-Connection.prototype.close = function () {
- this.ws.close();
-}; \ No newline at end of file
+ ConnectionActions.close();
+ EventLogActions.add_event("WebSocket connection closed.");
+ };
+ return ws;
+} \ No newline at end of file
diff --git a/web/src/js/stores/flowstore.js b/web/src/js/stores/flowstore.js
index 1034bd53..4110ea7f 100644
--- a/web/src/js/stores/flowstore.js
+++ b/web/src/js/stores/flowstore.js
@@ -1,4 +1,4 @@
-function FlowStore(endpoint) {
+function FlowStore() {
this._views = [];
this.reset();
}
@@ -43,21 +43,46 @@ _.extend(FlowStore.prototype, {
});
-function LiveFlowStore(endpoint) {
+function LiveFlowStore() {
FlowStore.call(this);
this.updates_before_fetch = undefined;
this._fetchxhr = false;
- this.endpoint = endpoint || "/flows";
- this.conn = new Connection(this.endpoint + "/updates");
- this.conn.onopen = this._onopen.bind(this);
- this.conn.onmessage = function (e) {
- var message = JSON.parse(e.data);
- this.handle_update(message.type, message.data);
- }.bind(this);
+
+ this.handle = this.handle.bind(this);
+ AppDispatcher.register(this.handle);
+
+ // Avoid double-fetch on startup.
+ if(!(window.ws && window.ws.readyState === WebSocket.CONNECTING)) {
+ this.fetch();
+ }
}
_.extend(LiveFlowStore.prototype, FlowStore.prototype, {
+ handle: function (event) {
+ switch (event.type) {
+ case ActionTypes.CONNECTION_OPEN:
+ case ActionTypes.RESET_FLOWS:
+ this.fetch();
+ break;
+ case ActionTypes.ADD_FLOW:
+ case ActionTypes.UPDATE_FLOW:
+ case ActionTypes.REMOVE_FLOW:
+ if (this.updates_before_fetch) {
+ console.log("defer update", type, data);
+ this.updates_before_fetch.push(event);
+ } else {
+ if(event.type === ActionTypes.ADD_FLOW){
+ this.add(event.data);
+ } else if (event.type === ActionTypes.UPDATE_FLOW){
+ this.update(event.data);
+ } else {
+ this.remove(event.data);
+ }
+ }
+ break;
+ }
+ },
close: function () {
- this.conn.close();
+ AppDispatcher.unregister(this.handle);
},
add: function (flow) {
// Make sure that deferred adds don't add an element twice.
@@ -65,32 +90,14 @@ _.extend(LiveFlowStore.prototype, FlowStore.prototype, {
FlowStore.prototype.add.call(this, flow);
}
},
- _onopen: function () {
- //Update stream openend, fetch list of flows.
- console.log("Update Connection opened, fetching flows...");
- this.fetch();
- },
fetch: function () {
+ console.log("fetch");
if (this._fetchxhr) {
this._fetchxhr.abort();
}
- this._fetchxhr = $.getJSON(this.endpoint, this.handle_fetch.bind(this));
+ this._fetchxhr = $.getJSON("/flows", this.handle_fetch.bind(this));
this.updates_before_fetch = []; // (JS: empty array is true)
},
- handle_update: function (type, data) {
- console.log("LiveFlowStore.handle_update", type, data);
-
- if (type === "reset") {
- return this.fetch();
- }
-
- if (this.updates_before_fetch) {
- console.log("defer update", type, data);
- this.updates_before_fetch.push(arguments);
- } else {
- this[type](data);
- }
- },
handle_fetch: function (data) {
this._fetchxhr = false;
console.log("Flows fetched.", this.updates_before_fetch);
@@ -98,7 +105,7 @@ _.extend(LiveFlowStore.prototype, FlowStore.prototype, {
var updates = this.updates_before_fetch;
this.updates_before_fetch = false;
for (var i = 0; i < updates.length; i++) {
- this.handle_update.apply(this, updates[i]);
+ this.handle(updates[i]);
}
},
});
diff --git a/web/src/vendor/bootstrap/bootstrap.css b/web/src/vendor/bootstrap/bootstrap.css
index 037dd056..c6f3d210 100644
--- a/web/src/vendor/bootstrap/bootstrap.css
+++ b/web/src/vendor/bootstrap/bootstrap.css
@@ -1,10 +1,10 @@
/*!
- * Bootstrap v3.2.0 (http://getbootstrap.com)
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
-/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
+/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
html {
font-family: sans-serif;
-webkit-text-size-adjust: 100%;
@@ -22,6 +22,7 @@ footer,
header,
hgroup,
main,
+menu,
nav,
section,
summary {
@@ -43,7 +44,7 @@ template {
display: none;
}
a {
- background: transparent;
+ background-color: transparent;
}
a:active,
a:hover {
@@ -187,8 +188,11 @@ td,
th {
padding: 0;
}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
@media print {
- * {
+ *,
+ *:before,
+ *:after {
color: #000 !important;
text-shadow: none !important;
background: transparent !important;
@@ -205,8 +209,8 @@ th {
abbr[title]:after {
content: " (" attr(title) ")";
}
- a[href^="javascript:"]:after,
- a[href^="#"]:after {
+ a[href^="#"]:after,
+ a[href^="javascript:"]:after {
content: "";
}
pre,
@@ -241,10 +245,6 @@ th {
.navbar {
display: none;
}
- .table td,
- .table th {
- background-color: #fff !important;
- }
.btn > .caret,
.dropup > .btn > .caret {
border-top-color: #000 !important;
@@ -255,6 +255,10 @@ th {
.table {
border-collapse: collapse !important;
}
+ .table td,
+ .table th {
+ background-color: #fff !important;
+ }
.table-bordered th,
.table-bordered td {
border: 1px solid #ddd !important;
@@ -284,7 +288,8 @@ th {
.glyphicon-plus:before {
content: "\2b";
}
-.glyphicon-euro:before {
+.glyphicon-euro:before,
+.glyphicon-eur:before {
content: "\20ac";
}
.glyphicon-minus:before {
@@ -910,12 +915,12 @@ textarea {
line-height: inherit;
}
a {
- color: #428bca;
+ color: #337ab7;
text-decoration: none;
}
a:hover,
a:focus {
- color: #2a6496;
+ color: #23527c;
text-decoration: underline;
}
a:focus {
@@ -935,7 +940,6 @@ img {
.carousel-inner > .item > img,
.carousel-inner > .item > a > img {
display: block;
- width: 100% \9;
max-width: 100%;
height: auto;
}
@@ -944,7 +948,6 @@ img {
}
.img-thumbnail {
display: inline-block;
- width: 100% \9;
max-width: 100%;
height: auto;
padding: 4px;
@@ -1117,9 +1120,6 @@ small,
.small {
font-size: 85%;
}
-cite {
- font-style: normal;
-}
mark,
.mark {
padding: .2em;
@@ -1153,10 +1153,10 @@ mark,
color: #777;
}
.text-primary {
- color: #428bca;
+ color: #337ab7;
}
a.text-primary:hover {
- color: #3071a9;
+ color: #286090;
}
.text-success {
color: #3c763d;
@@ -1184,10 +1184,10 @@ a.text-danger:hover {
}
.bg-primary {
color: #fff;
- background-color: #428bca;
+ background-color: #337ab7;
}
a.bg-primary:hover {
- background-color: #3071a9;
+ background-color: #286090;
}
.bg-success {
background-color: #dff0d8;
@@ -1328,10 +1328,6 @@ blockquote.pull-right small:after,
blockquote.pull-right .small:after {
content: '\00A0 \2014';
}
-blockquote:before,
-blockquote:after {
- content: "";
-}
address {
margin-bottom: 20px;
font-style: normal;
@@ -1362,6 +1358,7 @@ kbd {
kbd kbd {
padding: 0;
font-size: 100%;
+ font-weight: bold;
-webkit-box-shadow: none;
box-shadow: none;
}
@@ -2060,6 +2057,12 @@ pre code {
table {
background-color: transparent;
}
+caption {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ color: #777;
+ text-align: left;
+}
th {
text-align: left;
}
@@ -2120,12 +2123,10 @@ th {
.table-bordered > thead > tr > td {
border-bottom-width: 2px;
}
-.table-striped > tbody > tr:nth-child(odd) > td,
-.table-striped > tbody > tr:nth-child(odd) > th {
+.table-striped > tbody > tr:nth-child(odd) {
background-color: #f9f9f9;
}
-.table-hover > tbody > tr:hover > td,
-.table-hover > tbody > tr:hover > th {
+.table-hover > tbody > tr:hover {
background-color: #f5f5f5;
}
table col[class*="col-"] {
@@ -2244,13 +2245,15 @@ table th[class*="col-"] {
.table-hover > tbody > tr.danger:hover > th {
background-color: #ebcccc;
}
+.table-responsive {
+ min-height: .01%;
+ overflow-x: auto;
+}
@media screen and (max-width: 767px) {
.table-responsive {
width: 100%;
margin-bottom: 15px;
- overflow-x: auto;
overflow-y: hidden;
- -webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
border: 1px solid #ddd;
}
@@ -2375,14 +2378,14 @@ output {
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
}
.form-control::-moz-placeholder {
- color: #777;
+ color: #999;
opacity: 1;
}
.form-control:-ms-input-placeholder {
- color: #777;
+ color: #999;
}
.form-control::-webkit-input-placeholder {
- color: #777;
+ color: #999;
}
.form-control[disabled],
.form-control[readonly],
@@ -2397,24 +2400,25 @@ textarea.form-control {
input[type="search"] {
-webkit-appearance: none;
}
-input[type="date"],
-input[type="time"],
-input[type="datetime-local"],
-input[type="month"] {
- line-height: 34px;
- line-height: 1.42857143 \0;
-}
-input[type="date"].input-sm,
-input[type="time"].input-sm,
-input[type="datetime-local"].input-sm,
-input[type="month"].input-sm {
- line-height: 30px;
-}
-input[type="date"].input-lg,
-input[type="time"].input-lg,
-input[type="datetime-local"].input-lg,
-input[type="month"].input-lg {
- line-height: 46px;
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+ input[type="date"],
+ input[type="time"],
+ input[type="datetime-local"],
+ input[type="month"] {
+ line-height: 34px;
+ }
+ input[type="date"].input-sm,
+ input[type="time"].input-sm,
+ input[type="datetime-local"].input-sm,
+ input[type="month"].input-sm {
+ line-height: 30px;
+ }
+ input[type="date"].input-lg,
+ input[type="time"].input-lg,
+ input[type="datetime-local"].input-lg,
+ input[type="month"].input-lg {
+ line-height: 46px;
+ }
}
.form-group {
margin-bottom: 15px;
@@ -2423,12 +2427,12 @@ input[type="month"].input-lg {
.checkbox {
position: relative;
display: block;
- min-height: 20px;
margin-top: 10px;
margin-bottom: 10px;
}
.radio label,
.checkbox label {
+ min-height: 20px;
padding-left: 20px;
margin-bottom: 0;
font-weight: normal;
@@ -2491,35 +2495,41 @@ fieldset[disabled] .checkbox label {
padding-left: 0;
}
.input-sm,
-.form-horizontal .form-group-sm .form-control {
+.form-group-sm .form-control {
height: 30px;
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
-select.input-sm {
+select.input-sm,
+select.form-group-sm .form-control {
height: 30px;
line-height: 30px;
}
textarea.input-sm,
-select[multiple].input-sm {
+textarea.form-group-sm .form-control,
+select[multiple].input-sm,
+select[multiple].form-group-sm .form-control {
height: auto;
}
.input-lg,
-.form-horizontal .form-group-lg .form-control {
+.form-group-lg .form-control {
height: 46px;
padding: 10px 16px;
font-size: 18px;
line-height: 1.33;
border-radius: 6px;
}
-select.input-lg {
+select.input-lg,
+select.form-group-lg .form-control {
height: 46px;
line-height: 46px;
}
textarea.input-lg,
-select[multiple].input-lg {
+textarea.form-group-lg .form-control,
+select[multiple].input-lg,
+select[multiple].form-group-lg .form-control {
height: auto;
}
.has-feedback {
@@ -2530,7 +2540,7 @@ select[multiple].input-lg {
}
.form-control-feedback {
position: absolute;
- top: 25px;
+ top: 0;
right: 0;
z-index: 2;
display: block;
@@ -2538,6 +2548,7 @@ select[multiple].input-lg {
height: 34px;
line-height: 34px;
text-align: center;
+ pointer-events: none;
}
.input-lg + .form-control-feedback {
width: 46px;
@@ -2554,7 +2565,11 @@ select[multiple].input-lg {
.has-success .radio,
.has-success .checkbox,
.has-success .radio-inline,
-.has-success .checkbox-inline {
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
color: #3c763d;
}
.has-success .form-control {
@@ -2580,7 +2595,11 @@ select[multiple].input-lg {
.has-warning .radio,
.has-warning .checkbox,
.has-warning .radio-inline,
-.has-warning .checkbox-inline {
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
color: #8a6d3b;
}
.has-warning .form-control {
@@ -2606,7 +2625,11 @@ select[multiple].input-lg {
.has-error .radio,
.has-error .checkbox,
.has-error .radio-inline,
-.has-error .checkbox-inline {
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
color: #a94442;
}
.has-error .form-control {
@@ -2627,6 +2650,9 @@ select[multiple].input-lg {
.has-error .form-control-feedback {
color: #a94442;
}
+.has-feedback label ~ .form-control-feedback {
+ top: 25px;
+}
.has-feedback label.sr-only ~ .form-control-feedback {
top: 0;
}
@@ -2647,6 +2673,9 @@ select[multiple].input-lg {
width: auto;
vertical-align: middle;
}
+ .form-inline .form-control-static {
+ display: inline-block;
+ }
.form-inline .input-group {
display: inline-table;
vertical-align: middle;
@@ -2707,7 +2736,6 @@ select[multiple].input-lg {
}
}
.form-horizontal .has-feedback .form-control-feedback {
- top: 0;
right: 15px;
}
@media (min-width: 768px) {
@@ -2730,6 +2758,8 @@ select[multiple].input-lg {
text-align: center;
white-space: nowrap;
vertical-align: middle;
+ -ms-touch-action: manipulation;
+ touch-action: manipulation;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
@@ -2741,13 +2771,17 @@ select[multiple].input-lg {
}
.btn:focus,
.btn:active:focus,
-.btn.active:focus {
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.btn:hover,
-.btn:focus {
+.btn:focus,
+.btn.focus {
color: #333;
text-decoration: none;
}
@@ -2775,6 +2809,7 @@ fieldset[disabled] .btn {
}
.btn-default:hover,
.btn-default:focus,
+.btn-default.focus,
.btn-default:active,
.btn-default.active,
.open > .dropdown-toggle.btn-default {
@@ -2796,6 +2831,9 @@ fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
.btn-default.disabled:active,
.btn-default[disabled]:active,
fieldset[disabled] .btn-default:active,
@@ -2811,17 +2849,18 @@ fieldset[disabled] .btn-default.active {
}
.btn-primary {
color: #fff;
- background-color: #428bca;
- border-color: #357ebd;
+ background-color: #337ab7;
+ border-color: #2e6da4;
}
.btn-primary:hover,
.btn-primary:focus,
+.btn-primary.focus,
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
color: #fff;
- background-color: #3071a9;
- border-color: #285e8e;
+ background-color: #286090;
+ border-color: #204d74;
}
.btn-primary:active,
.btn-primary.active,
@@ -2837,17 +2876,20 @@ fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
.btn-primary.disabled:active,
.btn-primary[disabled]:active,
fieldset[disabled] .btn-primary:active,
.btn-primary.disabled.active,
.btn-primary[disabled].active,
fieldset[disabled] .btn-primary.active {
- background-color: #428bca;
- border-color: #357ebd;
+ background-color: #337ab7;
+ border-color: #2e6da4;
}
.btn-primary .badge {
- color: #428bca;
+ color: #337ab7;
background-color: #fff;
}
.btn-success {
@@ -2857,6 +2899,7 @@ fieldset[disabled] .btn-primary.active {
}
.btn-success:hover,
.btn-success:focus,
+.btn-success.focus,
.btn-success:active,
.btn-success.active,
.open > .dropdown-toggle.btn-success {
@@ -2878,6 +2921,9 @@ fieldset[disabled] .btn-success:hover,
.btn-success.disabled:focus,
.btn-success[disabled]:focus,
fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
.btn-success.disabled:active,
.btn-success[disabled]:active,
fieldset[disabled] .btn-success:active,
@@ -2898,6 +2944,7 @@ fieldset[disabled] .btn-success.active {
}
.btn-info:hover,
.btn-info:focus,
+.btn-info.focus,
.btn-info:active,
.btn-info.active,
.open > .dropdown-toggle.btn-info {
@@ -2919,6 +2966,9 @@ fieldset[disabled] .btn-info:hover,
.btn-info.disabled:focus,
.btn-info[disabled]:focus,
fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
.btn-info.disabled:active,
.btn-info[disabled]:active,
fieldset[disabled] .btn-info:active,
@@ -2939,6 +2989,7 @@ fieldset[disabled] .btn-info.active {
}
.btn-warning:hover,
.btn-warning:focus,
+.btn-warning.focus,
.btn-warning:active,
.btn-warning.active,
.open > .dropdown-toggle.btn-warning {
@@ -2960,6 +3011,9 @@ fieldset[disabled] .btn-warning:hover,
.btn-warning.disabled:focus,
.btn-warning[disabled]:focus,
fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
.btn-warning.disabled:active,
.btn-warning[disabled]:active,
fieldset[disabled] .btn-warning:active,
@@ -2980,6 +3034,7 @@ fieldset[disabled] .btn-warning.active {
}
.btn-danger:hover,
.btn-danger:focus,
+.btn-danger.focus,
.btn-danger:active,
.btn-danger.active,
.open > .dropdown-toggle.btn-danger {
@@ -3001,6 +3056,9 @@ fieldset[disabled] .btn-danger:hover,
.btn-danger.disabled:focus,
.btn-danger[disabled]:focus,
fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
.btn-danger.disabled:active,
.btn-danger[disabled]:active,
fieldset[disabled] .btn-danger:active,
@@ -3016,12 +3074,12 @@ fieldset[disabled] .btn-danger.active {
}
.btn-link {
font-weight: normal;
- color: #428bca;
- cursor: pointer;
+ color: #337ab7;
border-radius: 0;
}
.btn-link,
.btn-link:active,
+.btn-link.active,
.btn-link[disabled],
fieldset[disabled] .btn-link {
background-color: transparent;
@@ -3036,7 +3094,7 @@ fieldset[disabled] .btn-link {
}
.btn-link:hover,
.btn-link:focus {
- color: #2a6496;
+ color: #23527c;
text-decoration: underline;
background-color: transparent;
}
@@ -3091,9 +3149,11 @@ input[type="button"].btn-block {
}
.collapse {
display: none;
+ visibility: hidden;
}
.collapse.in {
display: block;
+ visibility: visible;
}
tr.collapse.in {
display: table-row;
@@ -3105,9 +3165,15 @@ tbody.collapse.in {
position: relative;
height: 0;
overflow: hidden;
- -webkit-transition: height .35s ease;
- -o-transition: height .35s ease;
- transition: height .35s ease;
+ -webkit-transition-timing-function: ease;
+ -o-transition-timing-function: ease;
+ transition-timing-function: ease;
+ -webkit-transition-duration: .35s;
+ -o-transition-duration: .35s;
+ transition-duration: .35s;
+ -webkit-transition-property: height, visibility;
+ -o-transition-property: height, visibility;
+ transition-property: height, visibility;
}
.caret {
display: inline-block;
@@ -3177,7 +3243,7 @@ tbody.collapse.in {
.dropdown-menu > .active > a:focus {
color: #fff;
text-decoration: none;
- background-color: #428bca;
+ background-color: #337ab7;
outline: 0;
}
.dropdown-menu > .disabled > a,
@@ -3270,10 +3336,6 @@ tbody.collapse.in {
.btn-group-vertical > .btn.active {
z-index: 2;
}
-.btn-group > .btn:focus,
-.btn-group-vertical > .btn:focus {
- outline: 0;
-}
.btn-group .btn + .btn,
.btn-group .btn + .btn-group,
.btn-group .btn-group + .btn,
@@ -3413,12 +3475,13 @@ tbody.collapse.in {
.btn-group-justified > .btn-group .dropdown-menu {
left: auto;
}
-[data-toggle="buttons"] > .btn > input[type="radio"],
-[data-toggle="buttons"] > .btn > input[type="checkbox"] {
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
position: absolute;
- z-index: -1;
- filter: alpha(opacity=0);
- opacity: 0;
+ clip: rect(0, 0, 0, 0);
+ pointer-events: none;
}
.input-group {
position: relative;
@@ -3607,7 +3670,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
.nav .open > a:hover,
.nav .open > a:focus {
background-color: #eee;
- border-color: #428bca;
+ border-color: #337ab7;
}
.nav .nav-divider {
height: 1px;
@@ -3700,7 +3763,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
.nav-pills > li.active > a:hover,
.nav-pills > li.active > a:focus {
color: #fff;
- background-color: #428bca;
+ background-color: #337ab7;
}
.nav-stacked > li {
float: none;
@@ -3757,9 +3820,11 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
}
.tab-content > .tab-pane {
display: none;
+ visibility: hidden;
}
.tab-content > .active {
display: block;
+ visibility: visible;
}
.nav-tabs .dropdown-menu {
margin-top: -1px;
@@ -3806,6 +3871,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
height: auto !important;
padding-bottom: 0;
overflow: visible !important;
+ visibility: visible !important;
}
.navbar-collapse.in {
overflow-y: visible;
@@ -3821,7 +3887,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
.navbar-fixed-bottom .navbar-collapse {
max-height: 340px;
}
-@media (max-width: 480px) and (orientation: landscape) {
+@media (max-device-width: 480px) and (orientation: landscape) {
.navbar-fixed-top .navbar-collapse,
.navbar-fixed-bottom .navbar-collapse {
max-height: 200px;
@@ -3858,9 +3924,6 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
right: 0;
left: 0;
z-index: 1030;
- -webkit-transform: translate3d(0, 0, 0);
- -o-transform: translate3d(0, 0, 0);
- transform: translate3d(0, 0, 0);
}
@media (min-width: 768px) {
.navbar-fixed-top,
@@ -3888,6 +3951,9 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
.navbar-brand:focus {
text-decoration: none;
}
+.navbar-brand > img {
+ display: block;
+}
@media (min-width: 768px) {
.navbar > .container .navbar-brand,
.navbar > .container-fluid .navbar-brand {
@@ -3966,17 +4032,6 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
padding-top: 15px;
padding-bottom: 15px;
}
- .navbar-nav.navbar-right:last-child {
- margin-right: -15px;
- }
-}
-@media (min-width: 768px) {
- .navbar-left {
- float: left !important;
- }
- .navbar-right {
- float: right !important;
- }
}
.navbar-form {
padding: 10px 15px;
@@ -4000,6 +4055,9 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
width: auto;
vertical-align: middle;
}
+ .navbar-form .form-control-static {
+ display: inline-block;
+ }
.navbar-form .input-group {
display: inline-table;
vertical-align: middle;
@@ -4040,6 +4098,9 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
.navbar-form .form-group {
margin-bottom: 5px;
}
+ .navbar-form .form-group:last-child {
+ margin-bottom: 0;
+ }
}
@media (min-width: 768px) {
.navbar-form {
@@ -4052,9 +4113,6 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
-webkit-box-shadow: none;
box-shadow: none;
}
- .navbar-form.navbar-right:last-child {
- margin-right: -15px;
- }
}
.navbar-nav > li > .dropdown-menu {
margin-top: 0;
@@ -4062,6 +4120,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
border-top-right-radius: 0;
}
.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
@@ -4087,7 +4147,16 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
margin-right: 15px;
margin-left: 15px;
}
- .navbar-text.navbar-right:last-child {
+}
+@media (min-width: 768px) {
+ .navbar-left {
+ float: left !important;
+ }
+ .navbar-right {
+ float: right !important;
+ margin-right: -15px;
+ }
+ .navbar-right ~ .navbar-right {
margin-right: 0;
}
}
@@ -4192,7 +4261,7 @@ fieldset[disabled] .navbar-default .btn-link:focus {
border-color: #080808;
}
.navbar-inverse .navbar-brand {
- color: #777;
+ color: #9d9d9d;
}
.navbar-inverse .navbar-brand:hover,
.navbar-inverse .navbar-brand:focus {
@@ -4200,10 +4269,10 @@ fieldset[disabled] .navbar-default .btn-link:focus {
background-color: transparent;
}
.navbar-inverse .navbar-text {
- color: #777;
+ color: #9d9d9d;
}
.navbar-inverse .navbar-nav > li > a {
- color: #777;
+ color: #9d9d9d;
}
.navbar-inverse .navbar-nav > li > a:hover,
.navbar-inverse .navbar-nav > li > a:focus {
@@ -4250,7 +4319,7 @@ fieldset[disabled] .navbar-default .btn-link:focus {
background-color: #080808;
}
.navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
- color: #777;
+ color: #9d9d9d;
}
.navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
.navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
@@ -4271,13 +4340,13 @@ fieldset[disabled] .navbar-default .btn-link:focus {
}
}
.navbar-inverse .navbar-link {
- color: #777;
+ color: #9d9d9d;
}
.navbar-inverse .navbar-link:hover {
color: #fff;
}
.navbar-inverse .btn-link {
- color: #777;
+ color: #9d9d9d;
}
.navbar-inverse .btn-link:hover,
.navbar-inverse .btn-link:focus {
@@ -4323,7 +4392,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus {
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
- color: #428bca;
+ color: #337ab7;
text-decoration: none;
background-color: #fff;
border: 1px solid #ddd;
@@ -4343,7 +4412,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus {
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
- color: #2a6496;
+ color: #23527c;
background-color: #eee;
border-color: #ddd;
}
@@ -4356,8 +4425,8 @@ fieldset[disabled] .navbar-inverse .btn-link:focus {
z-index: 2;
color: #fff;
cursor: default;
- background-color: #428bca;
- border-color: #428bca;
+ background-color: #337ab7;
+ border-color: #337ab7;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
@@ -4471,11 +4540,11 @@ a.label:focus {
background-color: #5e5e5e;
}
.label-primary {
- background-color: #428bca;
+ background-color: #337ab7;
}
.label-primary[href]:hover,
.label-primary[href]:focus {
- background-color: #3071a9;
+ background-color: #286090;
}
.label-success {
background-color: #5cb85c;
@@ -4536,16 +4605,22 @@ a.badge:focus {
text-decoration: none;
cursor: pointer;
}
-a.list-group-item.active > .badge,
+.list-group-item.active > .badge,
.nav-pills > .active > a > .badge {
- color: #428bca;
+ color: #337ab7;
background-color: #fff;
}
+.list-group-item > .badge {
+ float: right;
+}
+.list-group-item > .badge + .badge {
+ margin-right: 5px;
+}
.nav-pills > li > a > .badge {
margin-left: 3px;
}
.jumbotron {
- padding: 30px;
+ padding: 30px 15px;
margin-bottom: 30px;
color: inherit;
background-color: #eee;
@@ -4562,7 +4637,8 @@ a.list-group-item.active > .badge,
.jumbotron > hr {
border-top-color: #d5d5d5;
}
-.container .jumbotron {
+.container .jumbotron,
+.container-fluid .jumbotron {
border-radius: 6px;
}
.jumbotron .container {
@@ -4570,10 +4646,10 @@ a.list-group-item.active > .badge,
}
@media screen and (min-width: 768px) {
.jumbotron {
- padding-top: 48px;
- padding-bottom: 48px;
+ padding: 48px 0;
}
- .container .jumbotron {
+ .container .jumbotron,
+ .container-fluid .jumbotron {
padding-right: 60px;
padding-left: 60px;
}
@@ -4590,9 +4666,9 @@ a.list-group-item.active > .badge,
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
- -webkit-transition: all .2s ease-in-out;
- -o-transition: all .2s ease-in-out;
- transition: all .2s ease-in-out;
+ -webkit-transition: border .2s ease-in-out;
+ -o-transition: border .2s ease-in-out;
+ transition: border .2s ease-in-out;
}
.thumbnail > img,
.thumbnail a > img {
@@ -4602,7 +4678,7 @@ a.list-group-item.active > .badge,
a.thumbnail:hover,
a.thumbnail:focus,
a.thumbnail.active {
- border-color: #428bca;
+ border-color: #337ab7;
}
.thumbnail .caption {
padding: 9px;
@@ -4724,7 +4800,7 @@ a.thumbnail.active {
line-height: 20px;
color: #fff;
text-align: center;
- background-color: #428bca;
+ background-color: #337ab7;
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
-webkit-transition: width .6s ease;
@@ -4745,18 +4821,6 @@ a.thumbnail.active {
-o-animation: progress-bar-stripes 2s linear infinite;
animation: progress-bar-stripes 2s linear infinite;
}
-.progress-bar[aria-valuenow="1"],
-.progress-bar[aria-valuenow="2"] {
- min-width: 30px;
-}
-.progress-bar[aria-valuenow="0"] {
- min-width: 30px;
- color: #777;
- background-color: transparent;
- background-image: none;
- -webkit-box-shadow: none;
- box-shadow: none;
-}
.progress-bar-success {
background-color: #5cb85c;
}
@@ -4789,29 +4853,35 @@ a.thumbnail.active {
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
-.media,
-.media-body {
- overflow: hidden;
- zoom: 1;
-}
-.media,
-.media .media {
+.media {
margin-top: 15px;
}
.media:first-child {
margin-top: 0;
}
-.media-object {
- display: block;
-}
-.media-heading {
- margin: 0 0 5px;
+.media-right,
+.media > .pull-right {
+ padding-left: 10px;
}
+.media-left,
.media > .pull-left {
- margin-right: 10px;
+ padding-right: 10px;
}
-.media > .pull-right {
- margin-left: 10px;
+.media-left,
+.media-right,
+.media-body {
+ display: table-cell;
+ vertical-align: top;
+}
+.media-middle {
+ vertical-align: middle;
+}
+.media-bottom {
+ vertical-align: bottom;
+}
+.media-heading {
+ margin-top: 0;
+ margin-bottom: 5px;
}
.media-list {
padding-left: 0;
@@ -4838,12 +4908,6 @@ a.thumbnail.active {
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
}
-.list-group-item > .badge {
- float: right;
-}
-.list-group-item > .badge + .badge {
- margin-right: 5px;
-}
a.list-group-item {
color: #555;
}
@@ -4860,6 +4924,7 @@ a.list-group-item:focus {
.list-group-item.disabled:hover,
.list-group-item.disabled:focus {
color: #777;
+ cursor: not-allowed;
background-color: #eee;
}
.list-group-item.disabled .list-group-item-heading,
@@ -4877,8 +4942,8 @@ a.list-group-item:focus {
.list-group-item.active:focus {
z-index: 2;
color: #fff;
- background-color: #428bca;
- border-color: #428bca;
+ background-color: #337ab7;
+ border-color: #337ab7;
}
.list-group-item.active .list-group-item-heading,
.list-group-item.active:hover .list-group-item-heading,
@@ -4894,7 +4959,7 @@ a.list-group-item:focus {
.list-group-item.active .list-group-item-text,
.list-group-item.active:hover .list-group-item-text,
.list-group-item.active:focus .list-group-item-text {
- color: #e1edf7;
+ color: #c7ddef;
}
.list-group-item-success {
color: #3c763d;
@@ -5028,19 +5093,23 @@ a.list-group-item-danger.active:focus {
border-bottom-right-radius: 3px;
border-bottom-left-radius: 3px;
}
-.panel > .list-group {
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
margin-bottom: 0;
}
-.panel > .list-group .list-group-item {
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
border-width: 1px 0;
border-radius: 0;
}
-.panel > .list-group:first-child .list-group-item:first-child {
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
border-top: 0;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
-.panel > .list-group:last-child .list-group-item:last-child {
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
border-bottom: 0;
border-bottom-right-radius: 3px;
border-bottom-left-radius: 3px;
@@ -5056,11 +5125,24 @@ a.list-group-item-danger.active:focus {
.panel > .panel-collapse > .table {
margin-bottom: 0;
}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+ padding-right: 15px;
+ padding-left: 15px;
+}
.panel > .table:first-child,
.panel > .table-responsive:first-child > .table:first-child {
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
@@ -5086,6 +5168,13 @@ a.list-group-item-danger.active:focus {
border-bottom-right-radius: 3px;
border-bottom-left-radius: 3px;
}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
@@ -5107,7 +5196,9 @@ a.list-group-item-danger.active:focus {
border-bottom-right-radius: 3px;
}
.panel > .panel-body + .table,
-.panel > .panel-body + .table-responsive {
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
border-top: 1px solid #ddd;
}
.panel > .table > tbody:first-child > tr:first-child th,
@@ -5183,7 +5274,8 @@ a.list-group-item-danger.active:focus {
.panel-group .panel-heading {
border-bottom: 0;
}
-.panel-group .panel-heading + .panel-collapse > .panel-body {
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
border-top: 1px solid #ddd;
}
.panel-group .panel-footer {
@@ -5211,22 +5303,22 @@ a.list-group-item-danger.active:focus {
border-bottom-color: #ddd;
}
.panel-primary {
- border-color: #428bca;
+ border-color: #337ab7;
}
.panel-primary > .panel-heading {
color: #fff;
- background-color: #428bca;
- border-color: #428bca;
+ background-color: #337ab7;
+ border-color: #337ab7;
}
.panel-primary > .panel-heading + .panel-collapse > .panel-body {
- border-top-color: #428bca;
+ border-top-color: #337ab7;
}
.panel-primary > .panel-heading .badge {
- color: #428bca;
+ color: #337ab7;
background-color: #fff;
}
.panel-primary > .panel-footer + .panel-collapse > .panel-body {
- border-bottom-color: #428bca;
+ border-bottom-color: #337ab7;
}
.panel-success {
border-color: #d6e9c6;
@@ -5310,7 +5402,8 @@ a.list-group-item-danger.active:focus {
.embed-responsive .embed-responsive-item,
.embed-responsive iframe,
.embed-responsive embed,
-.embed-responsive object {
+.embed-responsive object,
+.embed-responsive video {
position: absolute;
top: 0;
bottom: 0;
@@ -5381,7 +5474,7 @@ button.close {
right: 0;
bottom: 0;
left: 0;
- z-index: 1050;
+ z-index: 1040;
display: none;
overflow: hidden;
-webkit-overflow-scrolling: touch;
@@ -5391,14 +5484,16 @@ button.close {
-webkit-transition: -webkit-transform .3s ease-out;
-o-transition: -o-transform .3s ease-out;
transition: transform .3s ease-out;
- -webkit-transform: translate3d(0, -25%, 0);
- -o-transform: translate3d(0, -25%, 0);
- transform: translate3d(0, -25%, 0);
+ -webkit-transform: translate(0, -25%);
+ -ms-transform: translate(0, -25%);
+ -o-transform: translate(0, -25%);
+ transform: translate(0, -25%);
}
.modal.in .modal-dialog {
- -webkit-transform: translate3d(0, 0, 0);
- -o-transform: translate3d(0, 0, 0);
- transform: translate3d(0, 0, 0);
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
}
.modal-open .modal {
overflow-x: hidden;
@@ -5422,12 +5517,10 @@ button.close {
box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
}
.modal-backdrop {
- position: fixed;
+ position: absolute;
top: 0;
right: 0;
- bottom: 0;
left: 0;
- z-index: 1040;
background-color: #000;
}
.modal-backdrop.fade {
@@ -5498,7 +5591,9 @@ button.close {
position: absolute;
z-index: 1070;
display: block;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 12px;
+ font-weight: normal;
line-height: 1.4;
visibility: visible;
filter: alpha(opacity=0);
@@ -5548,14 +5643,16 @@ button.close {
border-top-color: #000;
}
.tooltip.top-left .tooltip-arrow {
+ right: 5px;
bottom: 0;
- left: 5px;
+ margin-bottom: -5px;
border-width: 5px 5px 0;
border-top-color: #000;
}
.tooltip.top-right .tooltip-arrow {
- right: 5px;
bottom: 0;
+ left: 5px;
+ margin-bottom: -5px;
border-width: 5px 5px 0;
border-top-color: #000;
}
@@ -5582,13 +5679,15 @@ button.close {
}
.tooltip.bottom-left .tooltip-arrow {
top: 0;
- left: 5px;
+ right: 5px;
+ margin-top: -5px;
border-width: 0 5px 5px;
border-bottom-color: #000;
}
.tooltip.bottom-right .tooltip-arrow {
top: 0;
- right: 5px;
+ left: 5px;
+ margin-top: -5px;
border-width: 0 5px 5px;
border-bottom-color: #000;
}
@@ -5600,6 +5699,10 @@ button.close {
display: none;
max-width: 276px;
padding: 1px;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1.42857143;
text-align: left;
white-space: normal;
background-color: #fff;
@@ -5627,8 +5730,6 @@ button.close {
padding: 8px 14px;
margin: 0;
font-size: 14px;
- font-weight: normal;
- line-height: 18px;
background-color: #f7f7f7;
border-bottom: 1px solid #ebebeb;
border-radius: 5px 5px 0 0;
@@ -5731,6 +5832,37 @@ button.close {
.carousel-inner > .item > a > img {
line-height: 1;
}
+@media all and (transform-3d), (-webkit-transform-3d) {
+ .carousel-inner > .item {
+ -webkit-transition: -webkit-transform .6s ease-in-out;
+ -o-transition: -o-transform .6s ease-in-out;
+ transition: transform .6s ease-in-out;
+
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ -webkit-perspective: 1000;
+ perspective: 1000;
+ }
+ .carousel-inner > .item.next,
+ .carousel-inner > .item.active.right {
+ left: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+ .carousel-inner > .item.prev,
+ .carousel-inner > .item.active.left {
+ left: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+ .carousel-inner > .item.next.left,
+ .carousel-inner > .item.prev.right,
+ .carousel-inner > .item.active {
+ left: 0;
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
.carousel-inner > .active,
.carousel-inner > .next,
.carousel-inner > .prev {
@@ -5986,9 +6118,6 @@ button.close {
}
.affix {
position: fixed;
- -webkit-transform: translate3d(0, 0, 0);
- -o-transform: translate3d(0, 0, 0);
- transform: translate3d(0, 0, 0);
}
@-ms-viewport {
width: device-width;
diff --git a/web/src/vendor/bootstrap/bootstrap.js b/web/src/vendor/bootstrap/bootstrap.js
index 53da1c77..b6ac8d99 100644
--- a/web/src/vendor/bootstrap/bootstrap.js
+++ b/web/src/vendor/bootstrap/bootstrap.js
@@ -1,13 +1,22 @@
/*!
- * Bootstrap v3.2.0 (http://getbootstrap.com)
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
-if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') }
+if (typeof jQuery === 'undefined') {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery')
+}
+
++function ($) {
+ var version = $.fn.jquery.split(' ')[0].split('.')
+ if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
+ }
+}(jQuery);
/* ========================================================================
- * Bootstrap: transition.js v3.2.0
+ * Bootstrap: transition.js v3.3.1
* http://getbootstrap.com/javascript/#transitions
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -67,7 +76,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}(jQuery);
/* ========================================================================
- * Bootstrap: alert.js v3.2.0
+ * Bootstrap: alert.js v3.3.1
* http://getbootstrap.com/javascript/#alerts
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -86,7 +95,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$(el).on('click', dismiss, this.close)
}
- Alert.VERSION = '3.2.0'
+ Alert.VERSION = '3.3.1'
+
+ Alert.TRANSITION_DURATION = 150
Alert.prototype.close = function (e) {
var $this = $(this)
@@ -102,7 +113,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (e) e.preventDefault()
if (!$parent.length) {
- $parent = $this.hasClass('alert') ? $this : $this.parent()
+ $parent = $this.closest('.alert')
}
$parent.trigger(e = $.Event('close.bs.alert'))
@@ -119,7 +130,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$.support.transition && $parent.hasClass('fade') ?
$parent
.one('bsTransitionEnd', removeElement)
- .emulateTransitionEnd(150) :
+ .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
removeElement()
}
@@ -160,7 +171,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}(jQuery);
/* ========================================================================
- * Bootstrap: button.js v3.2.0
+ * Bootstrap: button.js v3.3.1
* http://getbootstrap.com/javascript/#buttons
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -180,7 +191,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.isLoading = false
}
- Button.VERSION = '3.2.0'
+ Button.VERSION = '3.3.1'
Button.DEFAULTS = {
loadingText: 'loading...'
@@ -196,10 +207,10 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (data.resetText == null) $el.data('resetText', $el[val]())
- $el[val](data[state] == null ? this.options[state] : data[state])
-
// push to event loop to allow forms to submit
setTimeout($.proxy(function () {
+ $el[val](data[state] == null ? this.options[state] : data[state])
+
if (state == 'loadingText') {
this.isLoading = true
$el.addClass(d).attr(d, d)
@@ -221,6 +232,8 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
else $parent.find('.active').removeClass('active')
}
if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
+ } else {
+ this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
}
if (changed) this.$element.toggleClass('active')
@@ -261,17 +274,21 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// BUTTON DATA-API
// ===============
- $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
- var $btn = $(e.target)
- if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
- Plugin.call($btn, 'toggle')
- e.preventDefault()
- })
+ $(document)
+ .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+ var $btn = $(e.target)
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+ Plugin.call($btn, 'toggle')
+ e.preventDefault()
+ })
+ .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+ $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
+ })
}(jQuery);
/* ========================================================================
- * Bootstrap: carousel.js v3.2.0
+ * Bootstrap: carousel.js v3.3.1
* http://getbootstrap.com/javascript/#carousel
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -286,7 +303,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// =========================
var Carousel = function (element, options) {
- this.$element = $(element).on('keydown.bs.carousel', $.proxy(this.keydown, this))
+ this.$element = $(element)
this.$indicators = this.$element.find('.carousel-indicators')
this.options = options
this.paused =
@@ -295,20 +312,26 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.$active =
this.$items = null
- this.options.pause == 'hover' && this.$element
+ this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
+
+ this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
.on('mouseenter.bs.carousel', $.proxy(this.pause, this))
.on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
}
- Carousel.VERSION = '3.2.0'
+ Carousel.VERSION = '3.3.1'
+
+ Carousel.TRANSITION_DURATION = 600
Carousel.DEFAULTS = {
interval: 5000,
pause: 'hover',
- wrap: true
+ wrap: true,
+ keyboard: true
}
Carousel.prototype.keydown = function (e) {
+ if (/input|textarea/i.test(e.target.tagName)) return
switch (e.which) {
case 37: this.prev(); break
case 39: this.next(); break
@@ -335,6 +358,13 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
return this.$items.index(item || this.$active)
}
+ Carousel.prototype.getItemForDirection = function (direction, active) {
+ var delta = direction == 'prev' ? -1 : 1
+ var activeIndex = this.getItemIndex(active)
+ var itemIndex = (activeIndex + delta) % this.$items.length
+ return this.$items.eq(itemIndex)
+ }
+
Carousel.prototype.to = function (pos) {
var that = this
var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
@@ -344,7 +374,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
if (activeIndex == pos) return this.pause().cycle()
- return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
+ return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
}
Carousel.prototype.pause = function (e) {
@@ -372,7 +402,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
Carousel.prototype.slide = function (type, next) {
var $active = this.$element.find('.item.active')
- var $next = next || $active[type]()
+ var $next = next || this.getItemForDirection(type, $active)
var isCycling = this.interval
var direction = type == 'next' ? 'left' : 'right'
var fallback = type == 'next' ? 'first' : 'last'
@@ -418,7 +448,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
that.$element.trigger(slidEvent)
}, 0)
})
- .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
+ .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
} else {
$active.removeClass('active')
$next.addClass('active')
@@ -467,7 +497,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// CAROUSEL DATA-API
// =================
- $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
+ var clickHandler = function (e) {
var href
var $this = $(this)
var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
@@ -483,7 +513,11 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}
e.preventDefault()
- })
+ }
+
+ $(document)
+ .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
+ .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
$(window).on('load', function () {
$('[data-ride="carousel"]').each(function () {
@@ -495,7 +529,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}(jQuery);
/* ========================================================================
- * Bootstrap: collapse.js v3.2.0
+ * Bootstrap: collapse.js v3.3.1
* http://getbootstrap.com/javascript/#collapse
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -512,16 +546,25 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var Collapse = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Collapse.DEFAULTS, options)
+ this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]')
this.transitioning = null
- if (this.options.parent) this.$parent = $(this.options.parent)
+ if (this.options.parent) {
+ this.$parent = this.getParent()
+ } else {
+ this.addAriaAndCollapsedClass(this.$element, this.$trigger)
+ }
+
if (this.options.toggle) this.toggle()
}
- Collapse.VERSION = '3.2.0'
+ Collapse.VERSION = '3.3.1'
+
+ Collapse.TRANSITION_DURATION = 350
Collapse.DEFAULTS = {
- toggle: true
+ toggle: true,
+ trigger: '[data-toggle="collapse"]'
}
Collapse.prototype.dimension = function () {
@@ -532,17 +575,21 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
Collapse.prototype.show = function () {
if (this.transitioning || this.$element.hasClass('in')) return
+ var activesData
+ var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing')
+
+ if (actives && actives.length) {
+ activesData = actives.data('bs.collapse')
+ if (activesData && activesData.transitioning) return
+ }
+
var startEvent = $.Event('show.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
- var actives = this.$parent && this.$parent.find('> .panel > .in')
-
if (actives && actives.length) {
- var hasData = actives.data('bs.collapse')
- if (hasData && hasData.transitioning) return
Plugin.call(actives, 'hide')
- hasData || actives.data('bs.collapse', null)
+ activesData || actives.data('bs.collapse', null)
}
var dimension = this.dimension()
@@ -550,6 +597,11 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.$element
.removeClass('collapse')
.addClass('collapsing')[dimension](0)
+ .attr('aria-expanded', true)
+
+ this.$trigger
+ .removeClass('collapsed')
+ .attr('aria-expanded', true)
this.transitioning = 1
@@ -568,7 +620,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.$element
.one('bsTransitionEnd', $.proxy(complete, this))
- .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
}
Collapse.prototype.hide = function () {
@@ -584,17 +636,21 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.$element
.addClass('collapsing')
- .removeClass('collapse')
- .removeClass('in')
+ .removeClass('collapse in')
+ .attr('aria-expanded', false)
+
+ this.$trigger
+ .addClass('collapsed')
+ .attr('aria-expanded', false)
this.transitioning = 1
var complete = function () {
this.transitioning = 0
this.$element
- .trigger('hidden.bs.collapse')
.removeClass('collapsing')
.addClass('collapse')
+ .trigger('hidden.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
@@ -602,13 +658,40 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.$element
[dimension](0)
.one('bsTransitionEnd', $.proxy(complete, this))
- .emulateTransitionEnd(350)
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
}
Collapse.prototype.toggle = function () {
this[this.$element.hasClass('in') ? 'hide' : 'show']()
}
+ Collapse.prototype.getParent = function () {
+ return $(this.options.parent)
+ .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
+ .each($.proxy(function (i, element) {
+ var $element = $(element)
+ this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
+ }, this))
+ .end()
+ }
+
+ Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
+ var isOpen = $element.hasClass('in')
+
+ $element.attr('aria-expanded', isOpen)
+ $trigger
+ .toggleClass('collapsed', !isOpen)
+ .attr('aria-expanded', isOpen)
+ }
+
+ function getTargetFromTrigger($trigger) {
+ var href
+ var target = $trigger.attr('data-target')
+ || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
+
+ return $(target)
+ }
+
// COLLAPSE PLUGIN DEFINITION
// ==========================
@@ -619,7 +702,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var data = $this.data('bs.collapse')
var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
- if (!data && options.toggle && option == 'show') option = !option
+ if (!data && options.toggle && option == 'show') options.toggle = false
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
if (typeof option == 'string') data[option]()
})
@@ -644,21 +727,13 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// =================
$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
- var href
var $this = $(this)
- var target = $this.attr('data-target')
- || e.preventDefault()
- || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
- var $target = $(target)
- var data = $target.data('bs.collapse')
- var option = data ? 'toggle' : $this.data()
- var parent = $this.attr('data-parent')
- var $parent = parent && $(parent)
- if (!data || !data.transitioning) {
- if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
- $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
- }
+ if (!$this.attr('data-target')) e.preventDefault()
+
+ var $target = getTargetFromTrigger($this)
+ var data = $target.data('bs.collapse')
+ var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })
Plugin.call($target, option)
})
@@ -666,7 +741,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}(jQuery);
/* ========================================================================
- * Bootstrap: dropdown.js v3.2.0
+ * Bootstrap: dropdown.js v3.3.1
* http://getbootstrap.com/javascript/#dropdowns
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -686,7 +761,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$(element).on('click.bs.dropdown', this.toggle)
}
- Dropdown.VERSION = '3.2.0'
+ Dropdown.VERSION = '3.3.1'
Dropdown.prototype.toggle = function (e) {
var $this = $(this)
@@ -709,7 +784,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (e.isDefaultPrevented()) return
- $this.trigger('focus')
+ $this
+ .trigger('focus')
+ .attr('aria-expanded', 'true')
$parent
.toggleClass('open')
@@ -720,7 +797,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}
Dropdown.prototype.keydown = function (e) {
- if (!/(38|40|27)/.test(e.keyCode)) return
+ if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
var $this = $(this)
@@ -732,7 +809,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
- if (!isActive || (isActive && e.keyCode == 27)) {
+ if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
if (e.which == 27) $parent.find(toggle).trigger('focus')
return $this.trigger('click')
}
@@ -742,10 +819,10 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (!$items.length) return
- var index = $items.index($items.filter(':focus'))
+ var index = $items.index(e.target)
- if (e.keyCode == 38 && index > 0) index-- // up
- if (e.keyCode == 40 && index < $items.length - 1) index++ // down
+ if (e.which == 38 && index > 0) index-- // up
+ if (e.which == 40 && index < $items.length - 1) index++ // down
if (!~index) index = 0
$items.eq(index).trigger('focus')
@@ -755,11 +832,17 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (e && e.which === 3) return
$(backdrop).remove()
$(toggle).each(function () {
- var $parent = getParent($(this))
+ var $this = $(this)
+ var $parent = getParent($this)
var relatedTarget = { relatedTarget: this }
+
if (!$parent.hasClass('open')) return
+
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+
if (e.isDefaultPrevented()) return
+
+ $this.attr('aria-expanded', 'false')
$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
})
}
@@ -813,12 +896,14 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
.on('click.bs.dropdown.data-api', clearMenus)
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
- .on('keydown.bs.dropdown.data-api', toggle + ', [role="menu"], [role="listbox"]', Dropdown.prototype.keydown)
+ .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
+ .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
+ .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
}(jQuery);
/* ========================================================================
- * Bootstrap: modal.js v3.2.0
+ * Bootstrap: modal.js v3.3.1
* http://getbootstrap.com/javascript/#modals
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -849,7 +934,10 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}
}
- Modal.VERSION = '3.2.0'
+ Modal.VERSION = '3.3.1'
+
+ Modal.TRANSITION_DURATION = 300
+ Modal.BACKDROP_TRANSITION_DURATION = 150
Modal.DEFAULTS = {
backdrop: true,
@@ -872,10 +960,11 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.isShown = true
this.checkScrollbar()
+ this.setScrollbar()
this.$body.addClass('modal-open')
- this.setScrollbar()
this.escape()
+ this.resize()
this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
@@ -890,6 +979,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
.show()
.scrollTop(0)
+ if (that.options.backdrop) that.adjustBackdrop()
+ that.adjustDialog()
+
if (transition) {
that.$element[0].offsetWidth // force reflow
}
@@ -907,7 +999,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
.one('bsTransitionEnd', function () {
that.$element.trigger('focus').trigger(e)
})
- .emulateTransitionEnd(300) :
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
that.$element.trigger('focus').trigger(e)
})
}
@@ -923,10 +1015,8 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.isShown = false
- this.$body.removeClass('modal-open')
-
- this.resetScrollbar()
this.escape()
+ this.resize()
$(document).off('focusin.bs.modal')
@@ -938,7 +1028,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$.support.transition && this.$element.hasClass('fade') ?
this.$element
.one('bsTransitionEnd', $.proxy(this.hideModal, this))
- .emulateTransitionEnd(300) :
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
this.hideModal()
}
@@ -954,11 +1044,19 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
Modal.prototype.escape = function () {
if (this.isShown && this.options.keyboard) {
- this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
+ this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
e.which == 27 && this.hide()
}, this))
} else if (!this.isShown) {
- this.$element.off('keyup.dismiss.bs.modal')
+ this.$element.off('keydown.dismiss.bs.modal')
+ }
+ }
+
+ Modal.prototype.resize = function () {
+ if (this.isShown) {
+ $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
+ } else {
+ $(window).off('resize.bs.modal')
}
}
@@ -966,6 +1064,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var that = this
this.$element.hide()
this.backdrop(function () {
+ that.$body.removeClass('modal-open')
+ that.resetAdjustments()
+ that.resetScrollbar()
that.$element.trigger('hidden.bs.modal')
})
}
@@ -983,14 +1084,13 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var doAnimate = $.support.transition && animate
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
- .appendTo(this.$body)
-
- this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
- if (e.target !== e.currentTarget) return
- this.options.backdrop == 'static'
- ? this.$element[0].focus.call(this.$element[0])
- : this.hide.call(this)
- }, this))
+ .prependTo(this.$element)
+ .on('click.dismiss.bs.modal', $.proxy(function (e) {
+ if (e.target !== e.currentTarget) return
+ this.options.backdrop == 'static'
+ ? this.$element[0].focus.call(this.$element[0])
+ : this.hide.call(this)
+ }, this))
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
@@ -1001,7 +1101,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
doAnimate ?
this.$backdrop
.one('bsTransitionEnd', callback)
- .emulateTransitionEnd(150) :
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
callback()
} else if (!this.isShown && this.$backdrop) {
@@ -1014,7 +1114,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$.support.transition && this.$element.hasClass('fade') ?
this.$backdrop
.one('bsTransitionEnd', callbackRemove)
- .emulateTransitionEnd(150) :
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
callbackRemove()
} else if (callback) {
@@ -1022,14 +1122,43 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}
}
+ // these following methods are used to handle overflowing modals
+
+ Modal.prototype.handleUpdate = function () {
+ if (this.options.backdrop) this.adjustBackdrop()
+ this.adjustDialog()
+ }
+
+ Modal.prototype.adjustBackdrop = function () {
+ this.$backdrop
+ .css('height', 0)
+ .css('height', this.$element[0].scrollHeight)
+ }
+
+ Modal.prototype.adjustDialog = function () {
+ var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
+
+ this.$element.css({
+ paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
+ paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
+ })
+ }
+
+ Modal.prototype.resetAdjustments = function () {
+ this.$element.css({
+ paddingLeft: '',
+ paddingRight: ''
+ })
+ }
+
Modal.prototype.checkScrollbar = function () {
- if (document.body.clientWidth >= window.innerWidth) return
- this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
+ this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight
+ this.scrollbarWidth = this.measureScrollbar()
}
Modal.prototype.setScrollbar = function () {
var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
- if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
+ if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
}
Modal.prototype.resetScrollbar = function () {
@@ -1099,7 +1228,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}(jQuery);
/* ========================================================================
- * Bootstrap: tooltip.js v3.2.0
+ * Bootstrap: tooltip.js v3.3.1
* http://getbootstrap.com/javascript/#tooltip
* Inspired by the original jQuery.tipsy by Jason Frame
* ========================================================================
@@ -1125,7 +1254,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.init('tooltip', element, options)
}
- Tooltip.VERSION = '3.2.0'
+ Tooltip.VERSION = '3.3.1'
+
+ Tooltip.TRANSITION_DURATION = 150
Tooltip.DEFAULTS = {
animation: true,
@@ -1203,6 +1334,11 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget).data('bs.' + this.type)
+ if (self && self.$tip && self.$tip.is(':visible')) {
+ self.hoverState = 'in'
+ return
+ }
+
if (!self) {
self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
$(obj.currentTarget).data('bs.' + this.type, self)
@@ -1245,7 +1381,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (this.hasContent() && this.enabled) {
this.$element.trigger(e)
- var inDom = $.contains(document.documentElement, this.$element[0])
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
if (e.isDefaultPrevented() || !inDom) return
var that = this
@@ -1281,13 +1417,13 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (autoPlace) {
var orgPlacement = placement
- var $parent = this.$element.parent()
- var parentDim = this.getPosition($parent)
+ var $container = this.options.container ? $(this.options.container) : this.$element.parent()
+ var containerDim = this.getPosition($container)
- placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' :
- placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' :
- placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' :
- placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' :
+ placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
+ placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
+ placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
placement
$tip
@@ -1300,14 +1436,17 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.applyPlacement(calculatedOffset, placement)
var complete = function () {
+ var prevHoverState = that.hoverState
that.$element.trigger('shown.bs.' + that.type)
that.hoverState = null
+
+ if (prevHoverState == 'out') that.leave(that)
}
$.support.transition && this.$tip.hasClass('fade') ?
$tip
.one('bsTransitionEnd', complete)
- .emulateTransitionEnd(150) :
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
complete()
}
}
@@ -1354,16 +1493,18 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (delta.left) offset.left += delta.left
else offset.top += delta.top
- var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
- var arrowPosition = delta.left ? 'left' : 'top'
- var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
+ var isVertical = /top|bottom/.test(placement)
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
$tip.offset(offset)
- this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
}
- Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
- this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
+ Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {
+ this.arrow()
+ .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
+ .css(isHorizontal ? 'top' : 'left', '')
}
Tooltip.prototype.setContent = function () {
@@ -1374,16 +1515,17 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$tip.removeClass('fade in top bottom left right')
}
- Tooltip.prototype.hide = function () {
+ Tooltip.prototype.hide = function (callback) {
var that = this
var $tip = this.tip()
var e = $.Event('hide.bs.' + this.type)
- this.$element.removeAttr('aria-describedby')
-
function complete() {
if (that.hoverState != 'in') $tip.detach()
- that.$element.trigger('hidden.bs.' + that.type)
+ that.$element
+ .removeAttr('aria-describedby')
+ .trigger('hidden.bs.' + that.type)
+ callback && callback()
}
this.$element.trigger(e)
@@ -1395,7 +1537,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$.support.transition && this.$tip.hasClass('fade') ?
$tip
.one('bsTransitionEnd', complete)
- .emulateTransitionEnd(150) :
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
complete()
this.hoverState = null
@@ -1416,13 +1558,20 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
Tooltip.prototype.getPosition = function ($element) {
$element = $element || this.$element
+
var el = $element[0]
var isBody = el.tagName == 'BODY'
- return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
- scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
- width: isBody ? $(window).width() : $element.outerWidth(),
- height: isBody ? $(window).height() : $element.outerHeight()
- }, isBody ? { top: 0, left: 0 } : $element.offset())
+
+ var elRect = el.getBoundingClientRect()
+ if (elRect.width == null) {
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
+ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
+ }
+ var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
+ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
+
+ return $.extend({}, elRect, scroll, outerDims, elOffset)
}
Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
@@ -1486,14 +1635,6 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
}
- Tooltip.prototype.validate = function () {
- if (!this.$element[0].parentNode) {
- this.hide()
- this.$element = null
- this.options = null
- }
- }
-
Tooltip.prototype.enable = function () {
this.enabled = true
}
@@ -1520,8 +1661,11 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}
Tooltip.prototype.destroy = function () {
+ var that = this
clearTimeout(this.timeout)
- this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+ this.hide(function () {
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
+ })
}
@@ -1530,12 +1674,18 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
function Plugin(option) {
return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.tooltip')
- var options = typeof option == 'object' && option
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+ var selector = options && options.selector
if (!data && option == 'destroy') return
- if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+ if (selector) {
+ if (!data) $this.data('bs.tooltip', (data = {}))
+ if (!data[selector]) data[selector] = new Tooltip(this, options)
+ } else {
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+ }
if (typeof option == 'string') data[option]()
})
}
@@ -1557,7 +1707,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}(jQuery);
/* ========================================================================
- * Bootstrap: popover.js v3.2.0
+ * Bootstrap: popover.js v3.3.1
* http://getbootstrap.com/javascript/#popovers
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -1577,7 +1727,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
- Popover.VERSION = '3.2.0'
+ Popover.VERSION = '3.3.1'
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
placement: 'right',
@@ -1604,7 +1754,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var content = this.getContent()
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
- $tip.find('.popover-content').empty()[ // we use append for html objects to maintain js events
+ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
](content)
@@ -1644,12 +1794,18 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
function Plugin(option) {
return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.popover')
- var options = typeof option == 'object' && option
+ var $this = $(this)
+ var data = $this.data('bs.popover')
+ var options = typeof option == 'object' && option
+ var selector = options && options.selector
if (!data && option == 'destroy') return
- if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+ if (selector) {
+ if (!data) $this.data('bs.popover', (data = {}))
+ if (!data[selector]) data[selector] = new Popover(this, options)
+ } else {
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+ }
if (typeof option == 'string') data[option]()
})
}
@@ -1671,7 +1827,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}(jQuery);
/* ========================================================================
- * Bootstrap: scrollspy.js v3.2.0
+ * Bootstrap: scrollspy.js v3.3.1
* http://getbootstrap.com/javascript/#scrollspy
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -1702,7 +1858,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.process()
}
- ScrollSpy.VERSION = '3.2.0'
+ ScrollSpy.VERSION = '3.3.1'
ScrollSpy.DEFAULTS = {
offset: 10
@@ -1763,8 +1919,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
}
- if (activeTarget && scrollTop <= offsets[0]) {
- return activeTarget != (i = targets[0]) && this.activate(i)
+ if (activeTarget && scrollTop < offsets[0]) {
+ this.activeTarget = null
+ return this.clear()
}
for (i = offsets.length; i--;) {
@@ -1778,9 +1935,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
ScrollSpy.prototype.activate = function (target) {
this.activeTarget = target
- $(this.selector)
- .parentsUntil(this.options.target, '.active')
- .removeClass('active')
+ this.clear()
var selector = this.selector +
'[data-target="' + target + '"],' +
@@ -1799,6 +1954,12 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
active.trigger('activate.bs.scrollspy')
}
+ ScrollSpy.prototype.clear = function () {
+ $(this.selector)
+ .parentsUntil(this.options.target, '.active')
+ .removeClass('active')
+ }
+
// SCROLLSPY PLUGIN DEFINITION
// ===========================
@@ -1842,7 +2003,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}(jQuery);
/* ========================================================================
- * Bootstrap: tab.js v3.2.0
+ * Bootstrap: tab.js v3.3.1
* http://getbootstrap.com/javascript/#tabs
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -1860,7 +2021,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.element = $(element)
}
- Tab.VERSION = '3.2.0'
+ Tab.VERSION = '3.3.1'
+
+ Tab.TRANSITION_DURATION = 150
Tab.prototype.show = function () {
var $this = this.element
@@ -1874,22 +2037,30 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if ($this.parent('li').hasClass('active')) return
- var previous = $ul.find('.active:last a')[0]
- var e = $.Event('show.bs.tab', {
- relatedTarget: previous
+ var $previous = $ul.find('.active:last a')
+ var hideEvent = $.Event('hide.bs.tab', {
+ relatedTarget: $this[0]
+ })
+ var showEvent = $.Event('show.bs.tab', {
+ relatedTarget: $previous[0]
})
- $this.trigger(e)
+ $previous.trigger(hideEvent)
+ $this.trigger(showEvent)
- if (e.isDefaultPrevented()) return
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
var $target = $(selector)
this.activate($this.closest('li'), $ul)
this.activate($target, $target.parent(), function () {
+ $previous.trigger({
+ type: 'hidden.bs.tab',
+ relatedTarget: $this[0]
+ })
$this.trigger({
type: 'shown.bs.tab',
- relatedTarget: previous
+ relatedTarget: $previous[0]
})
})
}
@@ -1898,15 +2069,21 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var $active = container.find('> .active')
var transition = callback
&& $.support.transition
- && $active.hasClass('fade')
+ && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
function next() {
$active
.removeClass('active')
.find('> .dropdown-menu > .active')
- .removeClass('active')
+ .removeClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', false)
- element.addClass('active')
+ element
+ .addClass('active')
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
if (transition) {
element[0].offsetWidth // reflow for transition
@@ -1916,16 +2093,21 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}
if (element.parent('.dropdown-menu')) {
- element.closest('li.dropdown').addClass('active')
+ element
+ .closest('li.dropdown')
+ .addClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
}
callback && callback()
}
- transition ?
+ $active.length && transition ?
$active
.one('bsTransitionEnd', next)
- .emulateTransitionEnd(150) :
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
next()
$active.removeClass('in')
@@ -1963,15 +2145,19 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// TAB DATA-API
// ============
- $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+ var clickHandler = function (e) {
e.preventDefault()
Plugin.call($(this), 'show')
- })
+ }
+
+ $(document)
+ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
+ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
}(jQuery);
/* ========================================================================
- * Bootstrap: affix.js v3.2.0
+ * Bootstrap: affix.js v3.3.1
* http://getbootstrap.com/javascript/#affix
* ========================================================================
* Copyright 2011-2014 Twitter, Inc.
@@ -2000,7 +2186,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.checkPosition()
}
- Affix.VERSION = '3.2.0'
+ Affix.VERSION = '3.3.1'
Affix.RESET = 'affix affix-top affix-bottom'
@@ -2009,6 +2195,28 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
target: window
}
+ Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
+ var scrollTop = this.$target.scrollTop()
+ var position = this.$element.offset()
+ var targetHeight = this.$target.height()
+
+ if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
+
+ if (this.affixed == 'bottom') {
+ if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
+ return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
+ }
+
+ var initializing = this.affixed == null
+ var colliderTop = initializing ? scrollTop : position.top
+ var colliderHeight = initializing ? targetHeight : height
+
+ if (offsetTop != null && colliderTop <= offsetTop) return 'top'
+ if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
+
+ return false
+ }
+
Affix.prototype.getPinnedOffset = function () {
if (this.pinnedOffset) return this.pinnedOffset
this.$element.removeClass(Affix.RESET).addClass('affix')
@@ -2024,42 +2232,40 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
Affix.prototype.checkPosition = function () {
if (!this.$element.is(':visible')) return
- var scrollHeight = $(document).height()
- var scrollTop = this.$target.scrollTop()
- var position = this.$element.offset()
+ var height = this.$element.height()
var offset = this.options.offset
var offsetTop = offset.top
var offsetBottom = offset.bottom
+ var scrollHeight = $('body').height()
if (typeof offset != 'object') offsetBottom = offsetTop = offset
if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
- var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false :
- offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
- offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false
+ var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
- if (this.affixed === affix) return
- if (this.unpin != null) this.$element.css('top', '')
+ if (this.affixed != affix) {
+ if (this.unpin != null) this.$element.css('top', '')
- var affixType = 'affix' + (affix ? '-' + affix : '')
- var e = $.Event(affixType + '.bs.affix')
+ var affixType = 'affix' + (affix ? '-' + affix : '')
+ var e = $.Event(affixType + '.bs.affix')
- this.$element.trigger(e)
+ this.$element.trigger(e)
- if (e.isDefaultPrevented()) return
+ if (e.isDefaultPrevented()) return
- this.affixed = affix
- this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+ this.affixed = affix
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
- this.$element
- .removeClass(Affix.RESET)
- .addClass(affixType)
- .trigger($.Event(affixType.replace('affix', 'affixed')))
+ this.$element
+ .removeClass(Affix.RESET)
+ .addClass(affixType)
+ .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
+ }
if (affix == 'bottom') {
this.$element.offset({
- top: scrollHeight - this.$element.height() - offsetBottom
+ top: scrollHeight - height - offsetBottom
})
}
}
@@ -2104,8 +2310,8 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
data.offset = data.offset || {}
- if (data.offsetBottom) data.offset.bottom = data.offsetBottom
- if (data.offsetTop) data.offset.top = data.offsetTop
+ if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
+ if (data.offsetTop != null) data.offset.top = data.offsetTop
Plugin.call($spy, data)
})
diff --git a/web/src/vendor/bootstrap/glyphicons-halflings-regular.svg b/web/src/vendor/bootstrap/glyphicons-halflings-regular.svg
index e3e2dc73..25691af8 100644
--- a/web/src/vendor/bootstrap/glyphicons-halflings-regular.svg
+++ b/web/src/vendor/bootstrap/glyphicons-halflings-regular.svg
@@ -226,4 +226,4 @@
<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
</font>
-</defs></svg> \ No newline at end of file
+</defs></svg> \ No newline at end of file
diff --git a/web/src/vendor/qunit/qunit.css b/web/src/vendor/qunit/qunit.css
index 9437b4b6..385a1ce0 100644
--- a/web/src/vendor/qunit/qunit.css
+++ b/web/src/vendor/qunit/qunit.css
@@ -1,12 +1,12 @@
/*!
- * QUnit 1.15.0
+ * QUnit 1.16.0
* http://qunitjs.com/
*
- * Copyright 2014 jQuery Foundation and other contributors
+ * Copyright 2006, 2014 jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2014-08-08T16:00Z
+ * Date: 2014-12-03T16:32Z
*/
/** Font Family and Sizes */
@@ -91,6 +91,14 @@
list-style-position: inside;
}
+#qunit-tests > li {
+ display: none;
+}
+
+#qunit-tests li.pass, #qunit-tests li.running, #qunit-tests li.fail {
+ display: list-item;
+}
+
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
@@ -99,6 +107,10 @@
cursor: pointer;
}
+#qunit-tests li.skipped strong {
+ cursor: default;
+}
+
#qunit-tests li a {
padding: 0.5em;
color: #C2CCD1;
@@ -211,6 +223,21 @@
#qunit-banner.qunit-fail { background-color: #EE5757; }
+/*** Skipped tests */
+
+#qunit-tests .skipped {
+ background-color: #EBECE9;
+}
+
+#qunit-tests .qunit-skipped-label {
+ background-color: #F4FF77;
+ display: inline-block;
+ font-style: normal;
+ color: #366097;
+ line-height: 1.8em;
+ padding: 0 0.5em;
+ margin: -0.4em 0.4em -0.4em 0;
+}
/** Result */
diff --git a/web/src/vendor/qunit/qunit.js b/web/src/vendor/qunit/qunit.js
index 474cfe55..82020d40 100644
--- a/web/src/vendor/qunit/qunit.js
+++ b/web/src/vendor/qunit/qunit.js
@@ -1,12 +1,12 @@
/*!
- * QUnit 1.15.0
+ * QUnit 1.16.0
* http://qunitjs.com/
*
- * Copyright 2014 jQuery Foundation and other contributors
+ * Copyright 2006, 2014 jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2014-08-08T16:00Z
+ * Date: 2014-12-03T16:32Z
*/
(function( window ) {
@@ -14,6 +14,7 @@
var QUnit,
config,
onErrorFnPrev,
+ loggingCallbacks = {},
fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ),
toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty,
@@ -22,11 +23,13 @@ var QUnit,
now = Date.now || function() {
return new Date().getTime();
},
+ globalStartCalled = false,
+ runStarted = false,
setTimeout = window.setTimeout,
clearTimeout = window.clearTimeout,
defined = {
- document: typeof window.document !== "undefined",
- setTimeout: typeof window.setTimeout !== "undefined",
+ document: window.document !== undefined,
+ setTimeout: window.setTimeout !== undefined,
sessionStorage: (function() {
var x = "qunit-test-string";
try {
@@ -86,132 +89,7 @@ var QUnit,
return vals;
};
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[ name ] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test;
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- test = new Test({
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- start: function( count ) {
- var message;
-
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
-
- // Set the starting time when the first test is run
- QUnit.config.started = QUnit.config.started || now();
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
-
- message = "Called start() while already started (QUnit.config.semaphore was 0 already)";
-
- if ( config.current ) {
- QUnit.pushFailure( message, sourceFromStacktrace( 2 ) );
- } else {
- throw new Error( message );
- }
-
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13 );
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// We use the prototype to distinguish between properties that should
-// be exposed as globals (and in exports) and those that shouldn't
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
-
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
+QUnit = {};
/**
* Config object: Maintain internal state
@@ -246,23 +124,39 @@ config = {
// when enabled, the id is set to `true` as a `QUnit.config` property
urlConfig: [
{
+ id: "hidepassed",
+ label: "Hide passed tests",
+ tooltip: "Only show tests and assertions that fail. Stored as query-strings."
+ },
+ {
id: "noglobals",
label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
+ tooltip: "Enabling this will test if any test introduces new properties on the " +
+ "`window` object. Stored as query-strings."
},
{
id: "notrycatch",
label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
+ tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " +
+ "exceptions in IE reasonable. Stored as query-strings."
}
],
// Set of all modules.
- modules: {},
+ modules: [],
+
+ // The first unnamed module
+ currentModule: {
+ name: "",
+ tests: []
+ },
callbacks: {}
};
+// Push a loose unnamed module to the modules collection
+config.modules.push( config.currentModule );
+
// Initialize more QUnit.config and QUnit.urlParams
(function() {
var i, current,
@@ -291,17 +185,13 @@ config = {
// String search anywhere in moduleName+testName
config.filter = urlParams.filter;
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = [];
- if ( urlParams.testNumber ) {
+ config.testId = [];
+ if ( urlParams.testId ) {
- // Ensure that urlParams.testNumber is an array
- urlParams.testNumber = [].concat( urlParams.testNumber );
- for ( i = 0; i < urlParams.testNumber.length; i++ ) {
- current = urlParams.testNumber[ i ];
- config.testNumber.push( parseInt( current, 10 ) );
+ // Ensure that urlParams.testId is an array
+ urlParams.testId = [].concat( urlParams.testId );
+ for ( i = 0; i < urlParams.testId.length; i++ ) {
+ config.testId.push( urlParams.testId[ i ] );
}
}
@@ -309,8 +199,130 @@ config = {
QUnit.isLocal = location.protocol === "file:";
}());
+// Root QUnit object.
+// `QUnit` initialized at top of scope
extend( QUnit, {
+ // call on start of module test to prepend name to all tests
+ module: function( name, testEnvironment ) {
+ var currentModule = {
+ name: name,
+ testEnvironment: testEnvironment,
+ tests: []
+ };
+
+ // DEPRECATED: handles setup/teardown functions,
+ // beforeEach and afterEach should be used instead
+ if ( testEnvironment && testEnvironment.setup ) {
+ testEnvironment.beforeEach = testEnvironment.setup;
+ delete testEnvironment.setup;
+ }
+ if ( testEnvironment && testEnvironment.teardown ) {
+ testEnvironment.afterEach = testEnvironment.teardown;
+ delete testEnvironment.teardown;
+ }
+
+ config.modules.push( currentModule );
+ config.currentModule = currentModule;
+ },
+
+ // DEPRECATED: QUnit.asyncTest() will be removed in QUnit 2.0.
+ asyncTest: function( testName, expected, callback ) {
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = null;
+ }
+
+ QUnit.test( testName, expected, callback, true );
+ },
+
+ test: function( testName, expected, callback, async ) {
+ var test;
+
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = null;
+ }
+
+ test = new Test({
+ testName: testName,
+ expected: expected,
+ async: async,
+ callback: callback
+ });
+
+ test.queue();
+ },
+
+ skip: function( testName ) {
+ var test = new Test({
+ testName: testName,
+ skip: true
+ });
+
+ test.queue();
+ },
+
+ // DEPRECATED: The functionality of QUnit.start() will be altered in QUnit 2.0.
+ // In QUnit 2.0, invoking it will ONLY affect the `QUnit.config.autostart` blocking behavior.
+ start: function( count ) {
+ var globalStartAlreadyCalled = globalStartCalled;
+
+ if ( !config.current ) {
+ globalStartCalled = true;
+
+ if ( runStarted ) {
+ throw new Error( "Called start() outside of a test context while already started" );
+ } else if ( globalStartAlreadyCalled || count > 1 ) {
+ throw new Error( "Called start() outside of a test context too many times" );
+ } else if ( config.autostart ) {
+ throw new Error( "Called start() outside of a test context when " +
+ "QUnit.config.autostart was true" );
+ } else if ( !config.pageLoaded ) {
+
+ // The page isn't completely loaded yet, so bail out and let `QUnit.load` handle it
+ config.autostart = true;
+ return;
+ }
+ } else {
+
+ // If a test is running, adjust its semaphore
+ config.current.semaphore -= count || 1;
+
+ // Don't start until equal number of stop-calls
+ if ( config.current.semaphore > 0 ) {
+ return;
+ }
+
+ // throw an Error if start is called more often than stop
+ if ( config.current.semaphore < 0 ) {
+ config.current.semaphore = 0;
+
+ QUnit.pushFailure(
+ "Called start() while already started (test's semaphore was 0 already)",
+ sourceFromStacktrace( 2 )
+ );
+ return;
+ }
+ }
+
+ resumeProcessing();
+ },
+
+ // DEPRECATED: QUnit.stop() will be removed in QUnit 2.0.
+ stop: function( count ) {
+
+ // If there isn't a test running, don't allow QUnit.stop() to be called
+ if ( !config.current ) {
+ throw new Error( "Called stop() outside of a test context" );
+ }
+
+ // If a test is running, adjust its semaphore
+ config.current.semaphore += count || 1;
+
+ pauseProcessing();
+ },
+
config: config,
// Safe object type checking
@@ -358,71 +370,76 @@ extend( QUnit, {
for ( key in params ) {
if ( hasOwn.call( params, key ) ) {
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
+ querystring += encodeURIComponent( key );
+ if ( params[ key ] !== true ) {
+ querystring += "=" + encodeURIComponent( params[ key ] );
+ }
+ querystring += "&";
}
}
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
+ return location.protocol + "//" + location.host +
+ location.pathname + querystring.slice( 0, -1 );
},
- extend: extend
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
+ extend: extend,
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
+ load: function() {
+ config.pageLoaded = true;
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
+ // Initialize the configuration options
+ extend( config, {
+ stats: { all: 0, bad: 0 },
+ moduleStats: { all: 0, bad: 0 },
+ started: 0,
+ updateRate: 1000,
+ autostart: true,
+ filter: ""
+ }, true );
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
+ config.blocking = false;
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
+ if ( config.autostart ) {
+ resumeProcessing();
+ }
+ }
+});
- // testDone: { name, failed, passed, total, runtime }
- testDone: registerLoggingCallback( "testDone" ),
+// Register logging callbacks
+(function() {
+ var i, l, key,
+ callbacks = [ "begin", "done", "log", "testStart", "testDone",
+ "moduleStart", "moduleDone" ];
+
+ function registerLoggingCallback( key ) {
+ var loggingCallback = function( callback ) {
+ if ( QUnit.objectType( callback ) !== "function" ) {
+ throw new Error(
+ "QUnit logging methods require a callback function as their first parameters."
+ );
+ }
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
+ config.callbacks[ key ].push( callback );
+ };
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
+ // DEPRECATED: This will be removed on QUnit 2.0.0+
+ // Stores the registered functions allowing restoring
+ // at verifyLoggingCallbacks() if modified
+ loggingCallbacks[ key ] = loggingCallback;
-QUnit.load = function() {
- runLoggingCallbacks( "begin", {
- totalTests: Test.count
- });
+ return loggingCallback;
+ }
- // Initialize the configuration options
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: 0,
- updateRate: 1000,
- autostart: true,
- filter: "",
- semaphore: 1
- }, true );
+ for ( i = 0, l = callbacks.length; i < l; i++ ) {
+ key = callbacks[ i ];
- config.blocking = false;
+ // Initialize key collection of logging callback
+ if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) {
+ config.callbacks[ key ] = [];
+ }
- if ( config.autostart ) {
- QUnit.start();
+ QUnit[ key ] = registerLoggingCallback( key );
}
-};
+})();
// `onErrorFnPrev` initialized at top of scope
// Preserve other handlers
@@ -448,7 +465,7 @@ window.onerror = function( error, filePath, linerNr ) {
} else {
QUnit.test( "global failure", extend(function() {
QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
+ }, { validTest: true } ) );
}
return false;
}
@@ -457,21 +474,25 @@ window.onerror = function( error, filePath, linerNr ) {
};
function done() {
+ var runtime, passed;
+
config.autorun = true;
// Log the last module results
if ( config.previousModule ) {
runLoggingCallbacks( "moduleDone", {
- name: config.previousModule,
+ name: config.previousModule.name,
+ tests: config.previousModule.tests,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
+ total: config.moduleStats.all,
+ runtime: now() - config.moduleStats.started
});
}
delete config.previousModule;
- var runtime = now() - config.started,
- passed = config.stats.all - config.stats.bad;
+ runtime = now() - config.started;
+ passed = config.stats.all - config.stats.bad;
runLoggingCallbacks( "done", {
failed: config.stats.bad,
@@ -481,47 +502,6 @@ function done() {
});
}
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = ( test.module + ": " + test.testName ).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber.length > 0 ) {
- if ( inArray( test.testNumber, config.testNumber ) < 0 ) {
- return false;
- }
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
// Doesn't support IE6 to IE9
// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
function extractStacktrace( e, offset ) {
@@ -565,15 +545,27 @@ function extractStacktrace( e, offset ) {
return e.sourceURL + ":" + e.line;
}
}
+
function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
+ var e = new Error();
+ if ( !e.stack ) {
+ try {
+ throw e;
+ } catch ( err ) {
+ // This should already be true in most browsers
+ e = err;
+ }
}
+ return extractStacktrace( e, offset );
}
function synchronize( callback, last ) {
+ if ( QUnit.objectType( callback ) === "array" ) {
+ while ( callback.length ) {
+ synchronize( callback.shift() );
+ }
+ return;
+ }
config.queue.push( callback );
if ( config.autorun && !config.blocking ) {
@@ -589,7 +581,13 @@ function process( last ) {
config.depth = config.depth ? config.depth + 1 : 1;
while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( now() - start ) < config.updateRate ) ) {
+ if ( !defined.setTimeout || config.updateRate <= 0 ||
+ ( ( now() - start ) < config.updateRate ) ) {
+ if ( config.current ) {
+
+ // Reset async tracking for each phase of the Test lifecycle
+ config.current.usedAsync = false;
+ }
config.queue.shift()();
} else {
setTimeout( next, 13 );
@@ -602,6 +600,79 @@ function process( last ) {
}
}
+function begin() {
+ var i, l,
+ modulesLog = [];
+
+ // If the test run hasn't officially begun yet
+ if ( !config.started ) {
+
+ // Record the time of the test run's beginning
+ config.started = now();
+
+ verifyLoggingCallbacks();
+
+ // Delete the loose unnamed module if unused.
+ if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) {
+ config.modules.shift();
+ }
+
+ // Avoid unnecessary information by not logging modules' test environments
+ for ( i = 0, l = config.modules.length; i < l; i++ ) {
+ modulesLog.push({
+ name: config.modules[ i ].name,
+ tests: config.modules[ i ].tests
+ });
+ }
+
+ // The test run is officially beginning now
+ runLoggingCallbacks( "begin", {
+ totalTests: Test.count,
+ modules: modulesLog
+ });
+ }
+
+ config.blocking = false;
+ process( true );
+}
+
+function resumeProcessing() {
+ runStarted = true;
+
+ // A slight delay to allow this iteration of the event loop to finish (more assertions, etc.)
+ if ( defined.setTimeout ) {
+ setTimeout(function() {
+ if ( config.current && config.current.semaphore > 0 ) {
+ return;
+ }
+ if ( config.timeout ) {
+ clearTimeout( config.timeout );
+ }
+
+ begin();
+ }, 13 );
+ } else {
+ begin();
+ }
+}
+
+function pauseProcessing() {
+ config.blocking = true;
+
+ if ( config.testTimeout && defined.setTimeout ) {
+ clearTimeout( config.timeout );
+ config.timeout = setTimeout(function() {
+ if ( config.current ) {
+ config.current.semaphore = 0;
+ QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) );
+ } else {
+ throw new Error( "Test timed out" );
+ }
+ resumeProcessing();
+ }, config.testTimeout );
+ }
+}
+
function saveGlobal() {
config.pollution = [];
@@ -671,18 +742,6 @@ function extend( a, b, undefOnly ) {
return a;
}
-function registerLoggingCallback( key ) {
-
- // Initialize key collection of logging callback
- if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) {
- config.callbacks[ key ] = [];
- }
-
- return function( callback ) {
- config.callbacks[ key ].push( callback );
- };
-}
-
function runLoggingCallbacks( key, args ) {
var i, l, callbacks;
@@ -692,6 +751,34 @@ function runLoggingCallbacks( key, args ) {
}
}
+// DEPRECATED: This will be removed on 2.0.0+
+// This function verifies if the loggingCallbacks were modified by the user
+// If so, it will restore it, assign the given callback and print a console warning
+function verifyLoggingCallbacks() {
+ var loggingCallback, userCallback;
+
+ for ( loggingCallback in loggingCallbacks ) {
+ if ( QUnit[ loggingCallback ] !== loggingCallbacks[ loggingCallback ] ) {
+
+ userCallback = QUnit[ loggingCallback ];
+
+ // Restore the callback function
+ QUnit[ loggingCallback ] = loggingCallbacks[ loggingCallback ];
+
+ // Assign the deprecated given callback
+ QUnit[ loggingCallback ]( userCallback );
+
+ if ( window.console && window.console.warn ) {
+ window.console.warn(
+ "QUnit." + loggingCallback + " was replaced with a new value.\n" +
+ "Please, check out the documentation on how to apply logging callbacks.\n" +
+ "Reference: http://api.qunitjs.com/category/callbacks/"
+ );
+ }
+ }
+ }
+}
+
// from jquery.js
function inArray( elem, array ) {
if ( array.indexOf ) {
@@ -708,16 +795,46 @@ function inArray( elem, array ) {
}
function Test( settings ) {
+ var i, l;
+
+ ++Test.count;
+
extend( this, settings );
- this.assert = new Assert( this );
this.assertions = [];
- this.testNumber = ++Test.count;
+ this.semaphore = 0;
+ this.usedAsync = false;
+ this.module = config.currentModule;
+ this.stack = sourceFromStacktrace( 3 );
+
+ // Register unique strings
+ for ( i = 0, l = this.module.tests; i < l.length; i++ ) {
+ if ( this.module.tests[ i ].name === this.testName ) {
+ this.testName += " ";
+ }
+ }
+
+ this.testId = generateHash( this.module.name, this.testName );
+
+ this.module.tests.push({
+ name: this.testName,
+ testId: this.testId
+ });
+
+ if ( settings.skip ) {
+
+ // Skipped tests will fully ignore any sent callback
+ this.callback = function() {};
+ this.async = false;
+ this.expected = 0;
+ } else {
+ this.assert = new Assert( this );
+ }
}
Test.count = 0;
Test.prototype = {
- setup: function() {
+ before: function() {
if (
// Emit moduleStart when we're switching from one module to another
@@ -731,47 +848,43 @@ Test.prototype = {
) {
if ( hasOwn.call( config, "previousModule" ) ) {
runLoggingCallbacks( "moduleDone", {
- name: config.previousModule,
+ name: config.previousModule.name,
+ tests: config.previousModule.tests,
failed: config.moduleStats.bad,
passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
+ total: config.moduleStats.all,
+ runtime: now() - config.moduleStats.started
});
}
config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
+ config.moduleStats = { all: 0, bad: 0, started: now() };
runLoggingCallbacks( "moduleStart", {
- name: this.module
+ name: this.module.name,
+ tests: this.module.tests
});
}
config.current = this;
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
+ this.testEnvironment = extend( {}, this.module.testEnvironment );
+ delete this.testEnvironment.beforeEach;
+ delete this.testEnvironment.afterEach;
this.started = now();
runLoggingCallbacks( "testStart", {
name: this.testName,
- module: this.module,
- testNumber: this.testNumber
+ module: this.module.name,
+ testId: this.testId
});
if ( !config.pollution ) {
saveGlobal();
}
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment, this.assert );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment, this.assert );
- } catch ( e ) {
- this.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- }
},
+
run: function() {
+ var promise;
+
config.current = this;
if ( this.async ) {
@@ -781,18 +894,17 @@ Test.prototype = {
this.callbackStarted = now();
if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, this.assert );
- this.callbackRuntime = now() - this.callbackStarted;
+ promise = this.callback.call( this.testEnvironment, this.assert );
+ this.resolvePromise( promise );
return;
}
try {
- this.callback.call( this.testEnvironment, this.assert );
- this.callbackRuntime = now() - this.callbackStarted;
+ promise = this.callback.call( this.testEnvironment, this.assert );
+ this.resolvePromise( promise );
} catch ( e ) {
- this.callbackRuntime = now() - this.callbackStarted;
-
- this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
+ this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " +
+ this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
// else next test will carry the responsibility
saveGlobal();
@@ -803,31 +915,59 @@ Test.prototype = {
}
}
},
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = now() - this.callbackStarted;
+
+ after: function() {
+ checkPollution();
+ },
+
+ queueHook: function( hook, hookName ) {
+ var promise,
+ test = this;
+ return function runHook() {
+ config.current = test;
+ if ( config.notrycatch ) {
+ promise = hook.call( test.testEnvironment, test.assert );
+ test.resolvePromise( promise, hookName );
+ return;
}
- this.testEnvironment.teardown.call( this.testEnvironment, this.assert );
- return;
- } else {
try {
- this.testEnvironment.teardown.call( this.testEnvironment, this.assert );
- } catch ( e ) {
- this.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
+ promise = hook.call( test.testEnvironment, test.assert );
+ test.resolvePromise( promise, hookName );
+ } catch ( error ) {
+ test.pushFailure( hookName + " failed on " + test.testName + ": " +
+ ( error.message || error ), extractStacktrace( error, 0 ) );
}
+ };
+ },
+
+ // Currently only used for module level hooks, can be used to add global level ones
+ hooks: function( handler ) {
+ var hooks = [];
+
+ // Hooks are ignored on skipped tests
+ if ( this.skip ) {
+ return hooks;
}
- checkPollution();
+
+ if ( this.module.testEnvironment &&
+ QUnit.objectType( this.module.testEnvironment[ handler ] ) === "function" ) {
+ hooks.push( this.queueHook( this.module.testEnvironment[ handler ], handler ) );
+ }
+
+ return hooks;
},
+
finish: function() {
config.current = this;
if ( config.requireExpects && this.expected === null ) {
- this.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
+ this.pushFailure( "Expected number of assertions to be defined, but expect() was " +
+ "not called.", this.stack );
} else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- this.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
+ this.pushFailure( "Expected " + this.expected + " assertions, but " +
+ this.assertions.length + " were run", this.stack );
} else if ( this.expected === null && !this.assertions.length ) {
- this.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
+ this.pushFailure( "Expected at least one assertion, but none were run - call " +
+ "expect(0) to accept zero assertions.", this.stack );
}
var i,
@@ -847,7 +987,8 @@ Test.prototype = {
runLoggingCallbacks( "testDone", {
name: this.testName,
- module: this.module,
+ module: this.module.name,
+ skipped: !!this.skip,
failed: bad,
passed: this.assertions.length - bad,
total: this.assertions.length,
@@ -855,12 +996,17 @@ Test.prototype = {
// HTML Reporter use
assertions: this.assertions,
- testNumber: this.testNumber,
+ testId: this.testId,
// DEPRECATED: this property will be removed in 2.0.0, use runtime instead
duration: this.runtime
});
+ // QUnit.reset() is deprecated and will be replaced for a new
+ // fixture reset function on QUnit 2.0/2.1.
+ // It's still called here for backwards compatibility handling
+ QUnit.reset();
+
config.current = undefined;
},
@@ -868,26 +1014,39 @@ Test.prototype = {
var bad,
test = this;
+ if ( !this.valid() ) {
+ return;
+ }
+
function run() {
+
// each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
+ synchronize([
+ function() {
+ test.before();
+ },
+
+ test.hooks( "beforeEach" ),
+
+ function() {
+ test.run();
+ },
+
+ test.hooks( "afterEach" ).reverse(),
+
+ function() {
+ test.after();
+ },
+ function() {
+ test.finish();
+ }
+ ]);
}
// `bad` initialized at top of scope
// defer when previous test run passed, if storage is available
bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
+ +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName );
if ( bad ) {
run();
@@ -899,13 +1058,14 @@ Test.prototype = {
push: function( result, actual, expected, message ) {
var source,
details = {
- module: this.module,
+ module: this.module.name,
name: this.testName,
result: result,
message: message,
actual: actual,
expected: expected,
- testNumber: this.testNumber
+ testId: this.testId,
+ runtime: now() - this.started
};
if ( !result ) {
@@ -926,16 +1086,18 @@ Test.prototype = {
pushFailure: function( message, source, actual ) {
if ( !this instanceof Test ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace( 2 ) );
+ throw new Error( "pushFailure() assertion outside test context, was " +
+ sourceFromStacktrace( 2 ) );
}
var details = {
- module: this.module,
+ module: this.module.name,
name: this.testName,
result: false,
message: message || "error",
actual: actual || null,
- testNumber: this.testNumber
+ testId: this.testId,
+ runtime: now() - this.started
};
if ( source ) {
@@ -948,20 +1110,132 @@ Test.prototype = {
result: false,
message: message
});
+ },
+
+ resolvePromise: function( promise, phase ) {
+ var then, message,
+ test = this;
+ if ( promise != null ) {
+ then = promise.then;
+ if ( QUnit.objectType( then ) === "function" ) {
+ QUnit.stop();
+ then.call(
+ promise,
+ QUnit.start,
+ function( error ) {
+ message = "Promise rejected " +
+ ( !phase ? "during" : phase.replace( /Each$/, "" ) ) +
+ " " + test.testName + ": " + ( error.message || error );
+ test.pushFailure( message, extractStacktrace( error, 0 ) );
+
+ // else next test will carry the responsibility
+ saveGlobal();
+
+ // Unblock
+ QUnit.start();
+ }
+ );
+ }
+ }
+ },
+
+ valid: function() {
+ var include,
+ filter = config.filter && config.filter.toLowerCase(),
+ module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(),
+ fullName = ( this.module.name + ": " + this.testName ).toLowerCase();
+
+ // Internally-generated tests are always valid
+ if ( this.callback && this.callback.validTest ) {
+ return true;
+ }
+
+ if ( config.testId.length > 0 && inArray( this.testId, config.testId ) < 0 ) {
+ return false;
+ }
+
+ if ( module && ( !this.module.name || this.module.name.toLowerCase() !== module ) ) {
+ return false;
+ }
+
+ if ( !filter ) {
+ return true;
+ }
+
+ include = filter.charAt( 0 ) !== "!";
+ if ( !include ) {
+ filter = filter.slice( 1 );
+ }
+
+ // If the filter matches, we need to honour include
+ if ( fullName.indexOf( filter ) !== -1 ) {
+ return include;
+ }
+
+ // Otherwise, do the opposite
+ return !include;
+ }
+
+};
+
+// Resets the test setup. Useful for tests that modify the DOM.
+/*
+DEPRECATED: Use multiple tests instead of resetting inside a test.
+Use testStart or testDone for custom cleanup.
+This method will throw an error in 2.0, and will be removed in 2.1
+*/
+QUnit.reset = function() {
+
+ // Return on non-browser environments
+ // This is necessary to not break on node tests
+ if ( typeof window === "undefined" ) {
+ return;
+ }
+
+ var fixture = defined.document && document.getElementById &&
+ document.getElementById( "qunit-fixture" );
+
+ if ( fixture ) {
+ fixture.innerHTML = config.fixture;
}
};
QUnit.pushFailure = function() {
if ( !QUnit.config.current ) {
- throw new Error( "pushFailure() assertion outside test context, in " + sourceFromStacktrace( 2 ) );
+ throw new Error( "pushFailure() assertion outside test context, in " +
+ sourceFromStacktrace( 2 ) );
}
// Gets current test obj
- var currentTest = QUnit.config.current.assert.test;
+ var currentTest = QUnit.config.current;
return currentTest.pushFailure.apply( currentTest, arguments );
};
+// Based on Java's String.hashCode, a simple but not
+// rigorously collision resistant hashing function
+function generateHash( module, testName ) {
+ var hex,
+ i = 0,
+ hash = 0,
+ str = module + "\x1C" + testName,
+ len = str.length;
+
+ for ( ; i < len; i++ ) {
+ hash = ( ( hash << 5 ) - hash ) + str.charCodeAt( i );
+ hash |= 0;
+ }
+
+ // Convert the possibly negative integer hash code into an 8 character hex string, which isn't
+ // strictly necessary but increases user understanding that the id is a SHA-like hash
+ hex = ( 0x100000000 + hash ).toString( 16 );
+ if ( hex.length < 8 ) {
+ hex = "0000000" + hex;
+ }
+
+ return hex.slice( -8 );
+}
+
function Assert( testContext ) {
this.test = testContext;
}
@@ -969,7 +1243,8 @@ function Assert( testContext ) {
// Assert helpers
QUnit.assert = Assert.prototype = {
- // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through.
+ // Specify the number of expected assertions to guarantee that failed test
+ // (no assertions are run at all) don't slip through.
expect: function( asserts ) {
if ( arguments.length === 1 ) {
this.test.expected = asserts;
@@ -978,20 +1253,51 @@ QUnit.assert = Assert.prototype = {
}
},
+ // Increment this Test's semaphore counter, then return a single-use function that
+ // decrements that counter a maximum of once.
+ async: function() {
+ var test = this.test,
+ popped = false;
+
+ test.semaphore += 1;
+ test.usedAsync = true;
+ pauseProcessing();
+
+ return function done() {
+ if ( !popped ) {
+ test.semaphore -= 1;
+ popped = true;
+ resumeProcessing();
+ } else {
+ test.pushFailure( "Called the callback returned from `assert.async` more than once",
+ sourceFromStacktrace( 2 ) );
+ }
+ };
+ },
+
// Exports test.push() to the user API
- push: function() {
- var assert = this;
+ push: function( /* result, actual, expected, message */ ) {
+ var assert = this,
+ currentTest = ( assert instanceof Assert && assert.test ) || QUnit.config.current;
// Backwards compatibility fix.
// Allows the direct use of global exported assertions and QUnit.assert.*
// Although, it's use is not recommended as it can leak assertions
// to other tests from async tests, because we only get a reference to the current test,
// not exactly the test where assertion were intended to be called.
- if ( !QUnit.config.current ) {
+ if ( !currentTest ) {
throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) );
}
+
+ if ( currentTest.usedAsync === true && currentTest.semaphore === 0 ) {
+ currentTest.pushFailure( "Assertion after the final `assert.async` was resolved",
+ sourceFromStacktrace( 2 ) );
+
+ // Allow this assertion to continue running anyway...
+ }
+
if ( !( assert instanceof Assert ) ) {
- assert = QUnit.config.current.assert;
+ assert = currentTest.assert;
}
return assert.test.push.apply( assert.test, arguments );
},
@@ -1005,11 +1311,7 @@ QUnit.assert = Assert.prototype = {
ok: function( result, message ) {
message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " +
QUnit.dump.parse( result ) );
- if ( !!result ) {
- this.push( true, result, true, message );
- } else {
- this.test.pushFailure( message, null, result );
- }
+ this.push( !!result, result, true, message );
},
/**
@@ -1017,7 +1319,7 @@ QUnit.assert = Assert.prototype = {
* Prints out both actual and expected values.
* @name equal
* @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
+ * @example equal( format( "{0} bytes.", 2), "2 bytes.", "replaces {0} with next argument" );
*/
equal: function( actual, expected, message ) {
/*jshint eqeqeq:false */
@@ -1143,6 +1445,13 @@ QUnit.assert = Assert.prototype = {
}
};
+// Provide an alternative to assert.throws(), for enviroments that consider throws a reserved word
+// Known to us are: Closure Compiler, Narwhal
+(function() {
+ /*jshint sub:true */
+ Assert.prototype.raises = Assert.prototype[ "throws" ];
+}());
+
// Test for equality any JavaScript type.
// Author: Philippe Rathé <prathe@gmail.com>
QUnit.equiv = (function() {
@@ -1356,7 +1665,8 @@ QUnit.equiv = (function() {
}
// apply transition with (1..n) arguments
- }( args[ 0 ], args[ 1 ] ) ) && innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) );
+ }( args[ 0 ], args[ 1 ] ) ) &&
+ innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) );
};
return innerEquiv;
@@ -1386,6 +1696,11 @@ QUnit.dump = (function() {
function array( arr, stack ) {
var i = arr.length,
ret = new Array( i );
+
+ if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
+ return "[object Array]";
+ }
+
this.up();
while ( i-- ) {
ret[ i ] = this.parse( arr[ i ], undefined, stack );
@@ -1396,25 +1711,28 @@ QUnit.dump = (function() {
var reName = /^function (\w+)/,
dump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf( obj ) ];
- type = typeof parser;
- inStack = inArray( obj, stack );
+ // objType is used mostly internally, you can fix a (custom) type in advance
+ parse: function( obj, objType, stack ) {
+ stack = stack || [];
+ var res, parser, parserType,
+ inStack = inArray( obj, stack );
if ( inStack !== -1 ) {
return "recursion(" + ( inStack - stack.length ) + ")";
}
- if ( type === "function" ) {
+
+ objType = objType || this.typeOf( obj );
+ parser = this.parsers[ objType ];
+ parserType = typeof parser;
+
+ if ( parserType === "function" ) {
stack.push( obj );
res = parser.call( this, obj, stack );
stack.pop();
return res;
}
- return ( type === "string" ) ? parser : this.parsers.error;
+ return ( parserType === "string" ) ? parser : this.parsers.error;
},
typeOf: function( obj ) {
var type;
@@ -1428,7 +1746,9 @@ QUnit.dump = (function() {
type = "date";
} else if ( QUnit.is( "function", obj ) ) {
type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
+ } else if ( obj.setInterval !== undefined &&
+ obj.document !== undefined &&
+ obj.nodeType === undefined ) {
type = "window";
} else if ( obj.nodeType === 9 ) {
type = "document";
@@ -1440,7 +1760,9 @@ QUnit.dump = (function() {
toString.call( obj ) === "[object Array]" ||
// NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null && typeof obj[ 0 ] === "undefined" ) ) )
+ ( typeof obj.length === "number" && obj.item !== undefined &&
+ ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null &&
+ obj[ 0 ] === undefined ) ) )
) {
type = "array";
} else if ( obj.constructor === Error.prototype.constructor ) {
@@ -1451,7 +1773,7 @@ QUnit.dump = (function() {
return type;
},
separator: function() {
- return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&nbsp;" : " ";
+ return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&#160;" : " ";
},
// extra can be a number, shortcut for increasing-calling-decreasing
indent: function( extra ) {
@@ -1460,7 +1782,7 @@ QUnit.dump = (function() {
}
var chr = this.indentChar;
if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, "&nbsp;" );
+ chr = chr.replace( /\t/g, " " ).replace( / /g, "&#160;" );
}
return new Array( this.depth + ( extra || 0 ) ).join( chr );
},
@@ -1479,6 +1801,8 @@ QUnit.dump = (function() {
join: join,
//
depth: 1,
+ maxDepth: 5,
+
// This is the list of parsers, to modify them, use dump.setParser
parsers: {
window: "[Window]",
@@ -1491,6 +1815,7 @@ QUnit.dump = (function() {
"undefined": "undefined",
"function": function( fn ) {
var ret = "function",
+
// functions never have name in IE
name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ];
@@ -1506,8 +1831,13 @@ QUnit.dump = (function() {
nodelist: array,
"arguments": array,
object: function( map, stack ) {
- /*jshint forin:false */
- var ret = [], keys, key, val, i, nonEnumerableProperties;
+ var keys, key, val, i, nonEnumerableProperties,
+ ret = [];
+
+ if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
+ return "[object Object]";
+ }
+
dump.up();
keys = [];
for ( key in map ) {
@@ -1526,7 +1856,8 @@ QUnit.dump = (function() {
for ( i = 0; i < keys.length; i++ ) {
key = keys[ i ];
val = map[ key ];
- ret.push( dump.parse( key, "key" ) + ": " + dump.parse( val, undefined, stack ) );
+ ret.push( dump.parse( key, "key" ) + ": " +
+ dump.parse( val, undefined, stack ) );
}
dump.down();
return join( "{", ret, "}" );
@@ -1543,10 +1874,12 @@ QUnit.dump = (function() {
for ( i = 0, len = attrs.length; i < len; i++ ) {
val = attrs[ i ].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
+ // IE6 includes all attributes in .attributes, even ones not explicitly
+ // set. Those have values like undefined, null, 0, false, "" or
+ // "inherit".
if ( val && val !== "inherit" ) {
- ret += " " + attrs[ i ].nodeName + "=" + dump.parse( val, "attribute" );
+ ret += " " + attrs[ i ].nodeName + "=" +
+ dump.parse( val, "attribute" );
}
}
}
@@ -1653,17 +1986,23 @@ if ( typeof window !== "undefined" ) {
window.QUnit = QUnit;
}
-// For CommonJS environments, export everything
+// For nodejs
if ( typeof module !== "undefined" && module.exports ) {
module.exports = QUnit;
}
+// For CommonJS with exports, but without module.exports, like Rhino
+if ( typeof exports !== "undefined" ) {
+ exports.QUnit = QUnit;
+}
+
// Get a reference to the global object, like window in browsers
}( (function() {
return this;
})() ));
/*istanbul ignore next */
+// jscs:disable maximumLineLength
/*
* Javascript Diff Algorithm
* By John Resig (http://ejohn.org/)
@@ -1810,6 +2149,7 @@ QUnit.diff = (function() {
return str;
};
}());
+// jscs:enable
(function() {
@@ -1828,7 +2168,6 @@ QUnit.init = function() {
config.autorun = false;
config.filter = "";
config.queue = [];
- config.semaphore = 1;
// Return on non-browser environments
// This is necessary to not break on node tests
@@ -1867,27 +2206,7 @@ QUnit.init = function() {
result.id = "qunit-testresult";
result.className = "result";
tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...<br/>&nbsp;";
- }
-};
-
-// Resets the test setup. Useful for tests that modify the DOM.
-/*
-DEPRECATED: Use multiple tests instead of resetting inside a test.
-Use testStart or testDone for custom cleanup.
-This method will throw an error in 2.0, and will be removed in 2.1
-*/
-QUnit.reset = function() {
-
- // Return on non-browser environments
- // This is necessary to not break on node tests
- if ( typeof window === "undefined" ) {
- return;
- }
-
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
+ result.innerHTML = "Running...<br />&#160;";
}
};
@@ -1899,7 +2218,7 @@ if ( typeof window === "undefined" ) {
var config = QUnit.config,
hasOwn = Object.prototype.hasOwnProperty,
defined = {
- document: typeof window.document !== "undefined",
+ document: window.document !== undefined,
sessionStorage: (function() {
var x = "qunit-test-string";
try {
@@ -1910,7 +2229,8 @@ var config = QUnit.config,
return false;
}
}())
- };
+ },
+ modulesList = [];
/**
* Escape text for attribute or text content.
@@ -2026,7 +2346,7 @@ function getUrlConfigHtml() {
"' name='" + escaped + "' type='checkbox'" +
( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) +
( config[ val.id ] ? " checked='checked'" : "" ) +
- " title='" + escapedTooltip + "'><label for='qunit-urlconfig-" + escaped +
+ " title='" + escapedTooltip + "' /><label for='qunit-urlconfig-" + escaped +
"' title='" + escapedTooltip + "'>" + val.label + "</label>";
} else {
urlConfigHtml += "<label for='qunit-urlconfig-" + escaped +
@@ -2064,6 +2384,38 @@ function getUrlConfigHtml() {
return urlConfigHtml;
}
+// Handle "click" events on toolbar checkboxes and "change" for select menus.
+// Updates the URL with the new state of `config.urlConfig` values.
+function toolbarChanged() {
+ var updatedUrl, value,
+ field = this,
+ params = {};
+
+ // Detect if field is a select menu or a checkbox
+ if ( "selectedIndex" in field ) {
+ value = field.options[ field.selectedIndex ].value || undefined;
+ } else {
+ value = field.checked ? ( field.defaultValue || true ) : undefined;
+ }
+
+ params[ field.name ] = value;
+ updatedUrl = QUnit.url( params );
+
+ if ( "hidepassed" === field.name && "replaceState" in window.history ) {
+ config[ field.name ] = value || false;
+ if ( value ) {
+ addClass( id( "qunit-tests" ), "hidepass" );
+ } else {
+ removeClass( id( "qunit-tests" ), "hidepass" );
+ }
+
+ // It is not necessary to refresh the whole page
+ window.history.replaceState( null, "", updatedUrl );
+ } else {
+ window.location = updatedUrl;
+ }
+}
+
function toolbarUrlConfigContainer() {
var urlConfigContainer = document.createElement( "span" );
@@ -2072,61 +2424,34 @@ function toolbarUrlConfigContainer() {
// For oldIE support:
// * Add handlers to the individual elements instead of the container
// * Use "click" instead of "change" for checkboxes
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ?
- target.defaultValue || true :
- undefined;
- window.location = QUnit.url( params );
- });
- addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.options[ target.selectedIndex ].value || undefined;
- window.location = QUnit.url( params );
- });
+ addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", toolbarChanged );
+ addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", toolbarChanged );
return urlConfigContainer;
}
-function getModuleNames() {
+function toolbarModuleFilterHtml() {
var i,
- moduleNames = [];
+ moduleFilterHtml = "";
- for ( i in config.modules ) {
- if ( config.modules.hasOwnProperty( i ) ) {
- moduleNames.push( i );
- }
+ if ( !modulesList.length ) {
+ return false;
}
- moduleNames.sort(function( a, b ) {
+ modulesList.sort(function( a, b ) {
return a.localeCompare( b );
});
- return moduleNames;
-}
-
-function toolbarModuleFilterHtml() {
- var i,
- moduleFilterHtml = "",
- moduleNames = getModuleNames();
-
- if ( moduleNames.length <= 1 ) {
- return false;
- }
-
moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label>" +
"<select id='qunit-modulefilter' name='modulefilter'><option value='' " +
- ( config.module === undefined ? "selected='selected'" : "" ) +
+ ( QUnit.urlParams.module === undefined ? "selected='selected'" : "" ) +
">< All Modules ></option>";
- for ( i = 0; i < moduleNames.length; i++ ) {
+ for ( i = 0; i < modulesList.length; i++ ) {
moduleFilterHtml += "<option value='" +
- escapeText( encodeURIComponent( moduleNames[ i ] ) ) + "' " +
- ( config.module === moduleNames[ i ] ? "selected='selected'" : "" ) +
- ">" + escapeText( moduleNames[ i ] ) + "</option>";
+ escapeText( encodeURIComponent( modulesList[ i ] ) ) + "' " +
+ ( QUnit.urlParams.module === modulesList[ i ] ? "selected='selected'" : "" ) +
+ ">" + escapeText( modulesList[ i ] ) + "</option>";
}
moduleFilterHtml += "</select>";
@@ -2134,7 +2459,8 @@ function toolbarModuleFilterHtml() {
}
function toolbarModuleFilter() {
- var moduleFilter = document.createElement( "span" ),
+ var toolbar = id( "qunit-testrunner-toolbar" ),
+ moduleFilter = document.createElement( "span" ),
moduleFilterHtml = toolbarModuleFilterHtml();
if ( !moduleFilterHtml ) {
@@ -2146,73 +2472,25 @@ function toolbarModuleFilter() {
addEvent( moduleFilter.lastChild, "change", function() {
var selectBox = moduleFilter.getElementsByTagName( "select" )[ 0 ],
- selectedModule = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value );
+ selection = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value );
window.location = QUnit.url({
- module: ( selectedModule === "" ) ? undefined : selectedModule,
+ module: ( selection === "" ) ? undefined : selection,
// Remove any existing filters
filter: undefined,
- testNumber: undefined
+ testId: undefined
});
});
- return moduleFilter;
-}
-
-function toolbarFilter() {
- var testList = id( "qunit-tests" ),
- filter = document.createElement( "input" );
-
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- if ( filter.checked ) {
- addClass( testList, "hidepass" );
- if ( defined.sessionStorage ) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- }
- } else {
- removeClass( testList, "hidepass" );
- if ( defined.sessionStorage ) {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage &&
- sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
-
- addClass( testList, "hidepass" );
- }
-
- return filter;
-}
-
-function toolbarLabel() {
- var label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
-
- return label;
+ toolbar.appendChild( moduleFilter );
}
function appendToolbar() {
- var moduleFilter,
- toolbar = id( "qunit-testrunner-toolbar" );
+ var toolbar = id( "qunit-testrunner-toolbar" );
if ( toolbar ) {
- toolbar.appendChild( toolbarFilter() );
- toolbar.appendChild( toolbarLabel() );
toolbar.appendChild( toolbarUrlConfigContainer() );
-
- moduleFilter = toolbarModuleFilter();
- if ( moduleFilter ) {
- toolbar.appendChild( moduleFilter );
- }
}
}
@@ -2222,7 +2500,7 @@ function appendBanner() {
if ( banner ) {
banner.className = "";
banner.innerHTML = "<a href='" +
- QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) +
+ QUnit.url({ filter: undefined, module: undefined, testId: undefined }) +
"'>" + banner.innerHTML + "</a> ";
}
}
@@ -2241,7 +2519,7 @@ function appendTestResults() {
result.id = "qunit-testresult";
result.className = "result";
tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...<br>&nbsp;";
+ result.innerHTML = "Running...<br />&#160;";
}
}
@@ -2259,24 +2537,80 @@ function appendUserAgent() {
}
}
+function appendTestsList( modules ) {
+ var i, l, x, z, test, moduleObj;
+
+ for ( i = 0, l = modules.length; i < l; i++ ) {
+ moduleObj = modules[ i ];
+
+ if ( moduleObj.name ) {
+ modulesList.push( moduleObj.name );
+ }
+
+ for ( x = 0, z = moduleObj.tests.length; x < z; x++ ) {
+ test = moduleObj.tests[ x ];
+
+ appendTest( test.name, test.testId, moduleObj.name );
+ }
+ }
+}
+
+function appendTest( name, testId, moduleName ) {
+ var title, rerunTrigger, testBlock, assertList,
+ tests = id( "qunit-tests" );
+
+ if ( !tests ) {
+ return;
+ }
+
+ title = document.createElement( "strong" );
+ title.innerHTML = getNameHtml( name, moduleName );
+
+ rerunTrigger = document.createElement( "a" );
+ rerunTrigger.innerHTML = "Rerun";
+ rerunTrigger.href = QUnit.url({ testId: testId });
+
+ testBlock = document.createElement( "li" );
+ testBlock.appendChild( title );
+ testBlock.appendChild( rerunTrigger );
+ testBlock.id = "qunit-test-output-" + testId;
+
+ assertList = document.createElement( "ol" );
+ assertList.className = "qunit-assert-list";
+
+ testBlock.appendChild( assertList );
+
+ tests.appendChild( testBlock );
+}
+
// HTML Reporter initialization and load
-QUnit.begin(function() {
+QUnit.begin(function( details ) {
var qunit = id( "qunit" );
- if ( qunit ) {
- qunit.innerHTML =
+ // Fixture is the only one necessary to run without the #qunit element
+ storeFixture();
+
+ if ( !qunit ) {
+ return;
+ }
+
+ qunit.innerHTML =
"<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
"<h2 id='qunit-banner'></h2>" +
"<div id='qunit-testrunner-toolbar'></div>" +
"<h2 id='qunit-userAgent'></h2>" +
"<ol id='qunit-tests'></ol>";
- }
appendBanner();
appendTestResults();
appendUserAgent();
appendToolbar();
- storeFixture();
+ appendTestsList( details.modules );
+ toolbarModuleFilter();
+
+ if ( config.hidepassed ) {
+ addClass( qunit.lastChild, "hidepass" );
+ }
});
QUnit.done(function( details ) {
@@ -2286,7 +2620,7 @@ QUnit.done(function( details ) {
html = [
"Tests completed in ",
details.runtime,
- " milliseconds.<br>",
+ " milliseconds.<br />",
"<span class='passed'>",
details.passed,
"</span> assertions of <span class='total'>",
@@ -2343,35 +2677,20 @@ function getNameHtml( name, module ) {
}
QUnit.testStart(function( details ) {
- var a, b, li, running, assertList,
- name = getNameHtml( details.name, details.module ),
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = name;
+ var running, testBlock;
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: details.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = "qunit-test-output" + details.testNumber;
-
- assertList = document.createElement( "ol" );
- assertList.className = "qunit-assert-list";
-
- li.appendChild( assertList );
+ testBlock = id( "qunit-test-output-" + details.testId );
+ if ( testBlock ) {
+ testBlock.className = "running";
+ } else {
- tests.appendChild( li );
+ // Report later registered tests
+ appendTest( details.name, details.testId, details.module );
}
running = id( "qunit-testresult" );
if ( running ) {
- running.innerHTML = "Running: <br>" + name;
+ running.innerHTML = "Running: <br />" + getNameHtml( details.name, details.module );
}
});
@@ -2379,7 +2698,7 @@ QUnit.testStart(function( details ) {
QUnit.log(function( details ) {
var assertList, assertLi,
message, expected, actual,
- testItem = id( "qunit-test-output" + details.testNumber );
+ testItem = id( "qunit-test-output-" + details.testId );
if ( !testItem ) {
return;
@@ -2387,6 +2706,7 @@ QUnit.log(function( details ) {
message = escapeText( details.message ) || ( details.result ? "okay" : "failed" );
message = "<span class='test-message'>" + message + "</span>";
+ message += "<span class='runtime'>@ " + details.runtime + " ms</span>";
// pushFailure doesn't provide details.expected
// when it calls, it's implicit to also not show expected and diff stuff
@@ -2430,19 +2750,15 @@ QUnit.log(function( details ) {
QUnit.testDone(function( details ) {
var testTitle, time, testItem, assertList,
- good, bad, testCounts,
+ good, bad, testCounts, skipped,
tests = id( "qunit-tests" );
- // QUnit.reset() is deprecated and will be replaced for a new
- // fixture reset function on QUnit 2.0/2.1.
- // It's still called here for backwards compatibility handling
- QUnit.reset();
-
if ( !tests ) {
return;
}
- testItem = id( "qunit-test-output" + details.testNumber );
+ testItem = id( "qunit-test-output-" + details.testId );
+
assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
good = details.passed;
@@ -2471,20 +2787,28 @@ QUnit.testDone(function( details ) {
testTitle.innerHTML += " <b class='counts'>(" + testCounts +
details.assertions.length + ")</b>";
- addEvent( testTitle, "click", function() {
- toggleClass( assertList, "qunit-collapsed" );
- });
-
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = details.runtime + " ms";
+ if ( details.skipped ) {
+ addClass( testItem, "skipped" );
+ skipped = document.createElement( "em" );
+ skipped.className = "qunit-skipped-label";
+ skipped.innerHTML = "skipped";
+ testItem.insertBefore( skipped, testTitle );
+ } else {
+ addEvent( testTitle, "click", function() {
+ toggleClass( assertList, "qunit-collapsed" );
+ });
- testItem.className = bad ? "fail" : "pass";
+ testItem.className = bad ? "fail" : "pass";
- testItem.insertBefore( time, assertList );
+ time = document.createElement( "span" );
+ time.className = "runtime";
+ time.innerHTML = details.runtime + " ms";
+ testItem.insertBefore( time, assertList );
+ }
});
if ( !defined.document || document.readyState === "complete" ) {
+ config.pageLoaded = true;
config.autorun = true;
}
diff --git a/web/src/vendor/react-bootstrap/react-bootstrap.js b/web/src/vendor/react-bootstrap/react-bootstrap.js
deleted file mode 100644
index b803cae8..00000000
--- a/web/src/vendor/react-bootstrap/react-bootstrap.js
+++ /dev/null
@@ -1,5346 +0,0 @@
-(function (root, factory) {
- if (typeof define === 'function' && define.amd) {
- // AMD.
- define(['react'], factory);
- } else {
- // Browser globals
- root.ReactBootstrap = factory(root.React);
- }
-}(this, function (React) {
-
-/**
- * almond 0.1.2 Copyright (c) 2011, The Dojo Foundation All Rights Reserved.
- * Available via the MIT or new BSD license.
- * see: http://github.com/jrburke/almond for details
- */
-//Going sloppy to avoid 'use strict' string cost, but strict practices should
-//be followed.
-/*jslint sloppy: true */
-/*global setTimeout: false */
-
-var requirejs, require, define;
-(function (undef) {
- var defined = {},
- waiting = {},
- config = {},
- defining = {},
- aps = [].slice,
- main, req;
-
- /**
- * Given a relative module name, like ./something, normalize it to
- * a real name that can be mapped to a path.
- * @param {String} name the relative name
- * @param {String} baseName a real name that the name arg is relative
- * to.
- * @returns {String} normalized name
- */
- function normalize(name, baseName) {
- var baseParts = baseName && baseName.split("/"),
- map = config.map,
- starMap = (map && map['*']) || {},
- nameParts, nameSegment, mapValue, foundMap,
- foundI, foundStarMap, starI, i, j, part;
-
- //Adjust any relative paths.
- if (name && name.charAt(0) === ".") {
- //If have a base name, try to normalize against it,
- //otherwise, assume it is a top-level require that will
- //be relative to baseUrl in the end.
- if (baseName) {
- //Convert baseName to array, and lop off the last part,
- //so that . matches that "directory" and not name of the baseName's
- //module. For instance, baseName of "one/two/three", maps to
- //"one/two/three.js", but we want the directory, "one/two" for
- //this normalization.
- baseParts = baseParts.slice(0, baseParts.length - 1);
-
- name = baseParts.concat(name.split("/"));
-
- //start trimDots
- for (i = 0; (part = name[i]); i++) {
- if (part === ".") {
- name.splice(i, 1);
- i -= 1;
- } else if (part === "..") {
- if (i === 1 && (name[2] === '..' || name[0] === '..')) {
- //End of the line. Keep at least one non-dot
- //path segment at the front so it can be mapped
- //correctly to disk. Otherwise, there is likely
- //no path mapping for a path starting with '..'.
- //This can still fail, but catches the most reasonable
- //uses of ..
- return true;
- } else if (i > 0) {
- name.splice(i - 1, 2);
- i -= 2;
- }
- }
- }
- //end trimDots
-
- name = name.join("/");
- }
- }
-
- //Apply map config if available.
- if ((baseParts || starMap) && map) {
- nameParts = name.split('/');
-
- for (i = nameParts.length; i > 0; i -= 1) {
- nameSegment = nameParts.slice(0, i).join("/");
-
- if (baseParts) {
- //Find the longest baseName segment match in the config.
- //So, do joins on the biggest to smallest lengths of baseParts.
- for (j = baseParts.length; j > 0; j -= 1) {
- mapValue = map[baseParts.slice(0, j).join('/')];
-
- //baseName segment has config, find if it has one for
- //this name.
- if (mapValue) {
- mapValue = mapValue[nameSegment];
- if (mapValue) {
- //Match, update name to the new value.
- foundMap = mapValue;
- foundI = i;
- break;
- }
- }
- }
- }
-
- if (foundMap) {
- break;
- }
-
- //Check for a star map match, but just hold on to it,
- //if there is a shorter segment match later in a matching
- //config, then favor over this star map.
- if (!foundStarMap && starMap && starMap[nameSegment]) {
- foundStarMap = starMap[nameSegment];
- starI = i;
- }
- }
-
- if (!foundMap && foundStarMap) {
- foundMap = foundStarMap;
- foundI = starI;
- }
-
- if (foundMap) {
- nameParts.splice(0, foundI, foundMap);
- name = nameParts.join('/');
- }
- }
-
- return name;
- }
-
- function makeRequire(relName, forceSync) {
- return function () {
- //A version of a require function that passes a moduleName
- //value for items that may need to
- //look up paths relative to the moduleName
- return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync]));
- };
- }
-
- function makeNormalize(relName) {
- return function (name) {
- return normalize(name, relName);
- };
- }
-
- function makeLoad(depName) {
- return function (value) {
- defined[depName] = value;
- };
- }
-
- function callDep(name) {
- if (waiting.hasOwnProperty(name)) {
- var args = waiting[name];
- delete waiting[name];
- defining[name] = true;
- main.apply(undef, args);
- }
-
- if (!defined.hasOwnProperty(name)) {
- throw new Error('No ' + name);
- }
- return defined[name];
- }
-
- /**
- * Makes a name map, normalizing the name, and using a plugin
- * for normalization if necessary. Grabs a ref to plugin
- * too, as an optimization.
- */
- function makeMap(name, relName) {
- var prefix, plugin,
- index = name.indexOf('!');
-
- if (index !== -1) {
- prefix = normalize(name.slice(0, index), relName);
- name = name.slice(index + 1);
- plugin = callDep(prefix);
-
- //Normalize according
- if (plugin && plugin.normalize) {
- name = plugin.normalize(name, makeNormalize(relName));
- } else {
- name = normalize(name, relName);
- }
- } else {
- name = normalize(name, relName);
- }
-
- //Using ridiculous property names for space reasons
- return {
- f: prefix ? prefix + '!' + name : name, //fullName
- n: name,
- p: plugin
- };
- }
-
- function makeConfig(name) {
- return function () {
- return (config && config.config && config.config[name]) || {};
- };
- }
-
- main = function (name, deps, callback, relName) {
- var args = [],
- usingExports,
- cjsModule, depName, ret, map, i;
-
- //Use name if no relName
- relName = relName || name;
-
- //Call the callback to define the module, if necessary.
- if (typeof callback === 'function') {
-
- //Pull out the defined dependencies and pass the ordered
- //values to the callback.
- //Default to [require, exports, module] if no deps
- deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
- for (i = 0; i < deps.length; i++) {
- map = makeMap(deps[i], relName);
- depName = map.f;
-
- //Fast path CommonJS standard dependencies.
- if (depName === "require") {
- args[i] = makeRequire(name);
- } else if (depName === "exports") {
- //CommonJS module spec 1.1
- args[i] = defined[name] = {};
- usingExports = true;
- } else if (depName === "module") {
- //CommonJS module spec 1.1
- cjsModule = args[i] = {
- id: name,
- uri: '',
- exports: defined[name],
- config: makeConfig(name)
- };
- } else if (defined.hasOwnProperty(depName) || waiting.hasOwnProperty(depName)) {
- args[i] = callDep(depName);
- } else if (map.p) {
- map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
- args[i] = defined[depName];
- } else if (!defining[depName]) {
- throw new Error(name + ' missing ' + depName);
- }
- }
-
- ret = callback.apply(defined[name], args);
-
- if (name) {
- //If setting exports via "module" is in play,
- //favor that over return value and exports. After that,
- //favor a non-undefined return value over exports use.
- if (cjsModule && cjsModule.exports !== undef &&
- cjsModule.exports !== defined[name]) {
- defined[name] = cjsModule.exports;
- } else if (ret !== undef || !usingExports) {
- //Use the return value from the function.
- defined[name] = ret;
- }
- }
- } else if (name) {
- //May just be an object definition for the module. Only
- //worry about defining if have a module name.
- defined[name] = callback;
- }
- };
-
- requirejs = require = req = function (deps, callback, relName, forceSync) {
- if (typeof deps === "string") {
- //Just return the module wanted. In this scenario, the
- //deps arg is the module name, and second arg (if passed)
- //is just the relName.
- //Normalize module name, if it contains . or ..
- return callDep(makeMap(deps, callback).f);
- } else if (!deps.splice) {
- //deps is a config object, not an array.
- config = deps;
- if (callback.splice) {
- //callback is an array, which means it is a dependency list.
- //Adjust args if there are dependencies
- deps = callback;
- callback = relName;
- relName = null;
- } else {
- deps = undef;
- }
- }
-
- //Support require(['a'])
- callback = callback || function () {};
-
- //Simulate async callback;
- if (forceSync) {
- main(undef, deps, callback, relName);
- } else {
- setTimeout(function () {
- main(undef, deps, callback, relName);
- }, 15);
- }
-
- return req;
- };
-
- /**
- * Just drops the config on the floor, but returns req in case
- * the config return value is used.
- */
- req.config = function (cfg) {
- config = cfg;
- return req;
- };
-
- define = function (name, deps, callback) {
-
- //This module may not have dependencies
- if (!deps.splice) {
- //deps is not an array, so probably means
- //an object literal or factory function for
- //the value. Adjust args.
- callback = deps;
- deps = [];
- }
-
- waiting[name] = [name, deps, callback];
- };
-
- define.amd = {
- jQuery: true
- };
-}());
-
-define("almond", function(){});
-
-define('utils/classSet',['require','exports','module'],function (require, exports, module) {/**
- * React classSet
- *
- * Copyright 2013-2014 Facebook, Inc.
- * @licence https://github.com/facebook/react/blob/0.11-stable/LICENSE
- *
- * This file is unmodified from:
- * https://github.com/facebook/react/blob/0.11-stable/src/vendor/stubs/cx.js
- *
- */
-
-/**
- * This function is used to mark string literals representing CSS class names
- * so that they can be transformed statically. This allows for modularization
- * and minification of CSS class names.
- *
- * In static_upstream, this function is actually implemented, but it should
- * eventually be replaced with something more descriptive, and the transform
- * that is used in the main stack should be ported for use elsewhere.
- *
- * @param string|object className to modularize, or an object of key/values.
- * In the object case, the values are conditions that
- * determine if the className keys should be included.
- * @param [string ...] Variable list of classNames in the string case.
- * @return string Renderable space-separated CSS className.
- */
-function cx(classNames) {
- if (typeof classNames == 'object') {
- return Object.keys(classNames).filter(function(className) {
- return classNames[className];
- }).join(' ');
- } else {
- return Array.prototype.join.call(arguments, ' ');
- }
-}
-
-module.exports = cx;
-});
-
-define('utils/merge',['require','exports','module'],function (require, exports, module) {/**
- * Merge helper
- *
- * TODO: to be replaced with ES6's `Object.assign()` for React 0.12
- */
-
-/**
- * Shallow merges two structures by mutating the first parameter.
- *
- * @param {object} one Object to be merged into.
- * @param {?object} two Optional object with properties to merge from.
- */
-function mergeInto(one, two) {
- if (two != null) {
- for (var key in two) {
- if (!two.hasOwnProperty(key)) {
- continue;
- }
- one[key] = two[key];
- }
- }
-}
-
-/**
- * Shallow merges two structures into a return value, without mutating either.
- *
- * @param {?object} one Optional object with properties to merge from.
- * @param {?object} two Optional object with properties to merge from.
- * @return {object} The shallow extension of one by two.
- */
-function merge(one, two) {
- var result = {};
- mergeInto(result, one);
- mergeInto(result, two);
- return result;
-}
-
-module.exports = merge;
-});
-
-define('utils/cloneWithProps',['require','exports','module','react','./merge'],function (require, exports, module) {/**
- * React cloneWithProps
- *
- * Copyright 2013-2014 Facebook, Inc.
- * @licence https://github.com/facebook/react/blob/0.11-stable/LICENSE
- *
- * This file contains modified versions of:
- * https://github.com/facebook/react/blob/0.11-stable/src/utils/cloneWithProps.js
- * https://github.com/facebook/react/blob/0.11-stable/src/core/ReactPropTransferer.js
- * https://github.com/facebook/react/blob/0.11-stable/src/utils/joinClasses.js
- *
- * TODO: This should be replaced as soon as cloneWithProps is available via
- * the core React package or a separate package.
- * @see https://github.com/facebook/react/issues/1906
- *
- */
-
-var React = require('react');
-var merge = require('./merge');
-
-/**
- * Combines multiple className strings into one.
- * http://jsperf.com/joinclasses-args-vs-array
- *
- * @param {...?string} classes
- * @return {string}
- */
-function joinClasses(className/*, ... */) {
- if (!className) {
- className = '';
- }
- var nextClass;
- var argLength = arguments.length;
- if (argLength > 1) {
- for (var ii = 1; ii < argLength; ii++) {
- nextClass = arguments[ii];
- nextClass && (className += ' ' + nextClass);
- }
- }
- return className;
-}
-
-/**
- * Creates a transfer strategy that will merge prop values using the supplied
- * `mergeStrategy`. If a prop was previously unset, this just sets it.
- *
- * @param {function} mergeStrategy
- * @return {function}
- */
-function createTransferStrategy(mergeStrategy) {
- return function(props, key, value) {
- if (!props.hasOwnProperty(key)) {
- props[key] = value;
- } else {
- props[key] = mergeStrategy(props[key], value);
- }
- };
-}
-
-var transferStrategyMerge = createTransferStrategy(function(a, b) {
- // `merge` overrides the first object's (`props[key]` above) keys using the
- // second object's (`value`) keys. An object's style's existing `propA` would
- // get overridden. Flip the order here.
- return merge(b, a);
-});
-
-function emptyFunction() {}
-
-/**
- * Transfer strategies dictate how props are transferred by `transferPropsTo`.
- * NOTE: if you add any more exceptions to this list you should be sure to
- * update `cloneWithProps()` accordingly.
- */
-var TransferStrategies = {
- /**
- * Never transfer `children`.
- */
- children: emptyFunction,
- /**
- * Transfer the `className` prop by merging them.
- */
- className: createTransferStrategy(joinClasses),
- /**
- * Never transfer the `key` prop.
- */
- key: emptyFunction,
- /**
- * Never transfer the `ref` prop.
- */
- ref: emptyFunction,
- /**
- * Transfer the `style` prop (which is an object) by merging them.
- */
- style: transferStrategyMerge
-};
-
-/**
- * Mutates the first argument by transferring the properties from the second
- * argument.
- *
- * @param {object} props
- * @param {object} newProps
- * @return {object}
- */
-function transferInto(props, newProps) {
- for (var thisKey in newProps) {
- if (!newProps.hasOwnProperty(thisKey)) {
- continue;
- }
-
- var transferStrategy = TransferStrategies[thisKey];
-
- if (transferStrategy && TransferStrategies.hasOwnProperty(thisKey)) {
- transferStrategy(props, thisKey, newProps[thisKey]);
- } else if (!props.hasOwnProperty(thisKey)) {
- props[thisKey] = newProps[thisKey];
- }
- }
- return props;
-}
-
-/**
- * Merge two props objects using TransferStrategies.
- *
- * @param {object} oldProps original props (they take precedence)
- * @param {object} newProps new props to merge in
- * @return {object} a new object containing both sets of props merged.
- */
-function mergeProps(oldProps, newProps) {
- return transferInto(merge(oldProps), newProps);
-}
-
-var ReactPropTransferer = {
- mergeProps: mergeProps
-};
-
-var CHILDREN_PROP = 'children';
-
-/**
- * Sometimes you want to change the props of a child passed to you. Usually
- * this is to add a CSS class.
- *
- * @param {object} child child component you'd like to clone
- * @param {object} props props you'd like to modify. They will be merged
- * as if you used `transferPropsTo()`.
- * @return {object} a clone of child with props merged in.
- */
-function cloneWithProps(child, props) {
- var newProps = ReactPropTransferer.mergeProps(props, child.props);
-
- // Use `child.props.children` if it is provided.
- if (!newProps.hasOwnProperty(CHILDREN_PROP) &&
- child.props.hasOwnProperty(CHILDREN_PROP)) {
- newProps.children = child.props.children;
- }
-
- // Huge hack to support both the 0.10 API and the new way of doing things
- // TODO: remove when support for 0.10 is no longer needed
- if (React.version.indexOf('0.10.') === 0) {
- return child.constructor.ConvenienceConstructor(newProps);
- }
-
-
- // The current API doesn't retain _owner and _context, which is why this
- // doesn't use ReactDescriptor.cloneAndReplaceProps.
- return child.constructor(newProps);
-}
-
-module.exports = cloneWithProps;
-});
-
-define('constants',['require','exports','module'],function (require, exports, module) {module.exports = {
- CLASSES: {
- 'alert': 'alert',
- 'button': 'btn',
- 'button-group': 'btn-group',
- 'button-toolbar': 'btn-toolbar',
- 'column': 'col',
- 'input-group': 'input-group',
- 'form': 'form',
- 'glyphicon': 'glyphicon',
- 'label': 'label',
- 'list-group-item': 'list-group-item',
- 'panel': 'panel',
- 'panel-group': 'panel-group',
- 'progress-bar': 'progress-bar',
- 'nav': 'nav',
- 'navbar': 'navbar',
- 'modal': 'modal',
- 'row': 'row',
- 'well': 'well'
- },
- STYLES: {
- 'default': 'default',
- 'primary': 'primary',
- 'success': 'success',
- 'info': 'info',
- 'warning': 'warning',
- 'danger': 'danger',
- 'link': 'link',
- 'inline': 'inline',
- 'tabs': 'tabs',
- 'pills': 'pills'
- },
- SIZES: {
- 'large': 'lg',
- 'medium': 'md',
- 'small': 'sm',
- 'xsmall': 'xs'
- },
- GLYPHS: [
- 'asterisk',
- 'plus',
- 'euro',
- 'minus',
- 'cloud',
- 'envelope',
- 'pencil',
- 'glass',
- 'music',
- 'search',
- 'heart',
- 'star',
- 'star-empty',
- 'user',
- 'film',
- 'th-large',
- 'th',
- 'th-list',
- 'ok',
- 'remove',
- 'zoom-in',
- 'zoom-out',
- 'off',
- 'signal',
- 'cog',
- 'trash',
- 'home',
- 'file',
- 'time',
- 'road',
- 'download-alt',
- 'download',
- 'upload',
- 'inbox',
- 'play-circle',
- 'repeat',
- 'refresh',
- 'list-alt',
- 'lock',
- 'flag',
- 'headphones',
- 'volume-off',
- 'volume-down',
- 'volume-up',
- 'qrcode',
- 'barcode',
- 'tag',
- 'tags',
- 'book',
- 'bookmark',
- 'print',
- 'camera',
- 'font',
- 'bold',
- 'italic',
- 'text-height',
- 'text-width',
- 'align-left',
- 'align-center',
- 'align-right',
- 'align-justify',
- 'list',
- 'indent-left',
- 'indent-right',
- 'facetime-video',
- 'picture',
- 'map-marker',
- 'adjust',
- 'tint',
- 'edit',
- 'share',
- 'check',
- 'move',
- 'step-backward',
- 'fast-backward',
- 'backward',
- 'play',
- 'pause',
- 'stop',
- 'forward',
- 'fast-forward',
- 'step-forward',
- 'eject',
- 'chevron-left',
- 'chevron-right',
- 'plus-sign',
- 'minus-sign',
- 'remove-sign',
- 'ok-sign',
- 'question-sign',
- 'info-sign',
- 'screenshot',
- 'remove-circle',
- 'ok-circle',
- 'ban-circle',
- 'arrow-left',
- 'arrow-right',
- 'arrow-up',
- 'arrow-down',
- 'share-alt',
- 'resize-full',
- 'resize-small',
- 'exclamation-sign',
- 'gift',
- 'leaf',
- 'fire',
- 'eye-open',
- 'eye-close',
- 'warning-sign',
- 'plane',
- 'calendar',
- 'random',
- 'comment',
- 'magnet',
- 'chevron-up',
- 'chevron-down',
- 'retweet',
- 'shopping-cart',
- 'folder-close',
- 'folder-open',
- 'resize-vertical',
- 'resize-horizontal',
- 'hdd',
- 'bullhorn',
- 'bell',
- 'certificate',
- 'thumbs-up',
- 'thumbs-down',
- 'hand-right',
- 'hand-left',
- 'hand-up',
- 'hand-down',
- 'circle-arrow-right',
- 'circle-arrow-left',
- 'circle-arrow-up',
- 'circle-arrow-down',
- 'globe',
- 'wrench',
- 'tasks',
- 'filter',
- 'briefcase',
- 'fullscreen',
- 'dashboard',
- 'paperclip',
- 'heart-empty',
- 'link',
- 'phone',
- 'pushpin',
- 'usd',
- 'gbp',
- 'sort',
- 'sort-by-alphabet',
- 'sort-by-alphabet-alt',
- 'sort-by-order',
- 'sort-by-order-alt',
- 'sort-by-attributes',
- 'sort-by-attributes-alt',
- 'unchecked',
- 'expand',
- 'collapse-down',
- 'collapse-up',
- 'log-in',
- 'flash',
- 'log-out',
- 'new-window',
- 'record',
- 'save',
- 'open',
- 'saved',
- 'import',
- 'export',
- 'send',
- 'floppy-disk',
- 'floppy-saved',
- 'floppy-remove',
- 'floppy-save',
- 'floppy-open',
- 'credit-card',
- 'transfer',
- 'cutlery',
- 'header',
- 'compressed',
- 'earphone',
- 'phone-alt',
- 'tower',
- 'stats',
- 'sd-video',
- 'hd-video',
- 'subtitles',
- 'sound-stereo',
- 'sound-dolby',
- 'sound-5-1',
- 'sound-6-1',
- 'sound-7-1',
- 'copyright-mark',
- 'registration-mark',
- 'cloud-download',
- 'cloud-upload',
- 'tree-conifer',
- 'tree-deciduous'
- ]
-};
-
-});
-
-define('BootstrapMixin',['require','exports','module','react','./constants'],function (require, exports, module) {var React = require('react');
-var constants = require('./constants');
-
-var BootstrapMixin = {
- propTypes: {
- bsClass: React.PropTypes.oneOf(Object.keys(constants.CLASSES)),
- bsStyle: React.PropTypes.oneOf(Object.keys(constants.STYLES)),
- bsSize: React.PropTypes.oneOf(Object.keys(constants.SIZES))
- },
-
- getBsClassSet: function () {
- var classes = {};
-
- var bsClass = this.props.bsClass && constants.CLASSES[this.props.bsClass];
- if (bsClass) {
- classes[bsClass] = true;
-
- var prefix = bsClass + '-';
-
- var bsSize = this.props.bsSize && constants.SIZES[this.props.bsSize];
- if (bsSize) {
- classes[prefix + bsSize] = true;
- }
-
- var bsStyle = this.props.bsStyle && constants.STYLES[this.props.bsStyle];
- if (this.props.bsStyle) {
- classes[prefix + bsStyle] = true;
- }
- }
-
- return classes;
- }
-};
-
-module.exports = BootstrapMixin;
-});
-
-define('utils/ValidComponentChildren',['require','exports','module','react'],function (require, exports, module) {var React = require('react');
-
-/**
- * Maps children that are typically specified as `props.children`,
- * but only iterates over children that are "valid components".
- *
- * The mapFunction provided index will be normalised to the components mapped,
- * so an invalid component would not increase the index.
- *
- * @param {?*} children Children tree container.
- * @param {function(*, int)} mapFunction.
- * @param {*} mapContext Context for mapFunction.
- * @return {object} Object containing the ordered map of results.
- */
-function mapValidComponents(children, func, context) {
- var index = 0;
-
- return React.Children.map(children, function (child) {
- if (React.isValidComponent(child)) {
- var lastIndex = index;
- index++;
- return func.call(context, child, lastIndex);
- }
-
- return child;
- });
-}
-
-/**
- * Iterates through children that are typically specified as `props.children`,
- * but only iterates over children that are "valid components".
- *
- * The provided forEachFunc(child, index) will be called for each
- * leaf child with the index reflecting the position relative to "valid components".
- *
- * @param {?*} children Children tree container.
- * @param {function(*, int)} forEachFunc.
- * @param {*} forEachContext Context for forEachContext.
- */
-function forEachValidComponents(children, func, context) {
- var index = 0;
-
- return React.Children.forEach(children, function (child) {
- if (React.isValidComponent(child)) {
- func.call(context, child, index);
- index++;
- }
- });
-}
-
-/**
- * Count the number of "valid components" in the Children container.
- *
- * @param {?*} children Children tree container.
- * @returns {number}
- */
-function numberOfValidComponents(children) {
- var count = 0;
-
- React.Children.forEach(children, function (child) {
- if (React.isValidComponent(child)) { count++; }
- });
-
- return count;
-}
-
-/**
- * Determine if the Child container has one or more "valid components".
- *
- * @param {?*} children Children tree container.
- * @returns {boolean}
- */
-function hasValidComponent(children) {
- var hasValid = false;
-
- React.Children.forEach(children, function (child) {
- if (!hasValid && React.isValidComponent(child)) {
- hasValid = true;
- }
- });
-
- return hasValid;
-}
-
-module.exports = {
- map: mapValidComponents,
- forEach: forEachValidComponents,
- numberOf: numberOfValidComponents,
- hasValidComponent: hasValidComponent
-};
-});
-
-define('PanelGroup',['require','exports','module','react','./utils/classSet','./utils/cloneWithProps','./BootstrapMixin','./utils/ValidComponentChildren'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var BootstrapMixin = require('./BootstrapMixin');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-
-var PanelGroup = React.createClass({displayName: 'PanelGroup',
- mixins: [BootstrapMixin],
-
- propTypes: {
- collapsable: React.PropTypes.bool,
- activeKey: React.PropTypes.any,
- defaultActiveKey: React.PropTypes.any,
- onSelect: React.PropTypes.func
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'panel-group'
- };
- },
-
- getInitialState: function () {
- var defaultActiveKey = this.props.defaultActiveKey;
-
- return {
- activeKey: defaultActiveKey
- };
- },
-
- render: function () {
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(this.getBsClassSet()), onSelect:null},
- ValidComponentChildren.map(this.props.children, this.renderPanel)
- )
- );
- },
-
- renderPanel: function (child) {
- var activeKey =
- this.props.activeKey != null ? this.props.activeKey : this.state.activeKey;
-
- var props = {
- bsStyle: child.props.bsStyle || this.props.bsStyle,
- key: child.props.key,
- ref: child.props.ref
- };
-
- if (this.props.accordion) {
- props.collapsable = true;
- props.expanded = (child.props.key === activeKey);
- props.onSelect = this.handleSelect;
- }
-
- return cloneWithProps(
- child,
- props
- );
- },
-
- shouldComponentUpdate: function() {
- // Defer any updates to this component during the `onSelect` handler.
- return !this._isChanging;
- },
-
- handleSelect: function (key) {
- if (this.props.onSelect) {
- this._isChanging = true;
- this.props.onSelect(key);
- this._isChanging = false;
- }
-
- if (this.state.activeKey === key) {
- key = null;
- }
-
- this.setState({
- activeKey: key
- });
- }
-});
-
-module.exports = PanelGroup;
-});
-
-define('Accordion',['require','exports','module','react','./PanelGroup'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var PanelGroup = require('./PanelGroup');
-
-var Accordion = React.createClass({displayName: 'Accordion',
- render: function () {
- return this.transferPropsTo(
- PanelGroup( {accordion:true},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Accordion;
-});
-
-define('utils/domUtils',['require','exports','module'],function (require, exports, module) {
-/**
- * Shortcut to compute element style
- *
- * @param {HTMLElement} elem
- * @returns {CssStyle}
- */
-function getComputedStyles(elem) {
- return elem.ownerDocument.defaultView.getComputedStyle(elem, null);
-}
-
-/**
- * Get elements offset
- *
- * TODO: REMOVE JQUERY!
- *
- * @param {HTMLElement} DOMNode
- * @returns {{top: number, left: number}}
- */
-function getOffset(DOMNode) {
- if (window.jQuery) {
- return window.jQuery(DOMNode).offset();
- }
-
- var docElem = document.documentElement;
- var box = { top: 0, left: 0 };
-
- // If we don't have gBCR, just use 0,0 rather than error
- // BlackBerry 5, iOS 3 (original iPhone)
- if ( typeof DOMNode.getBoundingClientRect !== 'undefined' ) {
- box = DOMNode.getBoundingClientRect();
- }
-
- return {
- top: box.top + window.pageYOffset - docElem.clientTop,
- left: box.left + window.pageXOffset - docElem.clientLeft
- };
-}
-
-/**
- * Get elements position
- *
- * TODO: REMOVE JQUERY!
- *
- * @param {HTMLElement} elem
- * @param {HTMLElement?} offsetParent
- * @returns {{top: number, left: number}}
- */
-function getPosition(elem, offsetParent) {
- if (window.jQuery) {
- return window.jQuery(elem).position();
- }
-
- var offset,
- parentOffset = {top: 0, left: 0};
-
- // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
- if (getComputedStyles(elem).position === 'fixed' ) {
- // We assume that getBoundingClientRect is available when computed position is fixed
- offset = elem.getBoundingClientRect();
-
- } else {
- if (!offsetParent) {
- // Get *real* offsetParent
- offsetParent = offsetParent(elem);
- }
-
- // Get correct offsets
- offset = getOffset(elem);
- if ( offsetParent.nodeName !== 'HTML') {
- parentOffset = getOffset(offsetParent);
- }
-
- // Add offsetParent borders
- parentOffset.top += parseInt(getComputedStyles(offsetParent).borderTopWidth, 10);
- parentOffset.left += parseInt(getComputedStyles(offsetParent).borderLeftWidth, 10);
- }
-
- // Subtract parent offsets and element margins
- return {
- top: offset.top - parentOffset.top - parseInt(getComputedStyles(elem).marginTop, 10),
- left: offset.left - parentOffset.left - parseInt(getComputedStyles(elem).marginLeft, 10)
- };
-}
-
-/**
- * Get parent element
- *
- * @param {HTMLElement?} elem
- * @returns {HTMLElement}
- */
-function offsetParent(elem) {
- var docElem = document.documentElement;
- var offsetParent = elem.offsetParent || docElem;
-
- while ( offsetParent && ( offsetParent.nodeName !== 'HTML' &&
- getComputedStyles(offsetParent).position === 'static' ) ) {
- offsetParent = offsetParent.offsetParent;
- }
-
- return offsetParent || docElem;
-}
-
-module.exports = {
- getComputedStyles: getComputedStyles,
- getOffset: getOffset,
- getPosition: getPosition,
- offsetParent: offsetParent
-};
-});
-
-define('utils/EventListener',['require','exports','module'],function (require, exports, module) {/**
- * React EventListener.listen
- *
- * Copyright 2013-2014 Facebook, Inc.
- * @licence https://github.com/facebook/react/blob/0.11-stable/LICENSE
- *
- * This file contains a modified version of:
- * https://github.com/facebook/react/blob/0.11-stable/src/vendor/stubs/EventListener.js
- *
- * TODO: remove in favour of solution provided by:
- * https://github.com/facebook/react/issues/285
- */
-
-/**
- * Does not take into account specific nature of platform.
- */
-var EventListener = {
- /**
- * Listen to DOM events during the bubble phase.
- *
- * @param {DOMEventTarget} target DOM element to register listener on.
- * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
- * @param {function} callback Callback function.
- * @return {object} Object with a `remove` method.
- */
- listen: function(target, eventType, callback) {
- if (target.addEventListener) {
- target.addEventListener(eventType, callback, false);
- return {
- remove: function() {
- target.removeEventListener(eventType, callback, false);
- }
- };
- } else if (target.attachEvent) {
- target.attachEvent('on' + eventType, callback);
- return {
- remove: function() {
- target.detachEvent('on' + eventType, callback);
- }
- };
- }
- }
-};
-
-module.exports = EventListener;
-
-});
-
-define('AffixMixin',['require','exports','module','react','./utils/domUtils','./utils/EventListener'],function (require, exports, module) {/* global window, document */
-
-var React = require('react');
-var domUtils = require('./utils/domUtils');
-var EventListener = require('./utils/EventListener');
-
-var AffixMixin = {
- propTypes: {
- offset: React.PropTypes.number,
- offsetTop: React.PropTypes.number,
- offsetBottom: React.PropTypes.number
- },
-
- getInitialState: function () {
- return {
- affixClass: 'affix-top'
- };
- },
-
- getPinnedOffset: function (DOMNode) {
- if (this.pinnedOffset) {
- return this.pinnedOffset;
- }
-
- DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, '');
- DOMNode.className += DOMNode.className.length ? ' affix' : 'affix';
-
- this.pinnedOffset = domUtils.getOffset(DOMNode).top - window.pageYOffset;
-
- return this.pinnedOffset;
- },
-
- checkPosition: function () {
- var DOMNode, scrollHeight, scrollTop, position, offsetTop, offsetBottom,
- affix, affixType, affixPositionTop;
-
- // TODO: or not visible
- if (!this.isMounted()) {
- return;
- }
-
- DOMNode = this.getDOMNode();
- scrollHeight = document.documentElement.offsetHeight;
- scrollTop = window.pageYOffset;
- position = domUtils.getOffset(DOMNode);
- offsetTop;
- offsetBottom;
-
- if (this.affixed === 'top') {
- position.top += scrollTop;
- }
-
- offsetTop = this.props.offsetTop != null ?
- this.props.offsetTop : this.props.offset;
- offsetBottom = this.props.offsetBottom != null ?
- this.props.offsetBottom : this.props.offset;
-
- if (offsetTop == null && offsetBottom == null) {
- return;
- }
- if (offsetTop == null) {
- offsetTop = 0;
- }
- if (offsetBottom == null) {
- offsetBottom = 0;
- }
-
- if (this.unpin != null && (scrollTop + this.unpin <= position.top)) {
- affix = false;
- } else if (offsetBottom != null && (position.top + DOMNode.offsetHeight >= scrollHeight - offsetBottom)) {
- affix = 'bottom';
- } else if (offsetTop != null && (scrollTop <= offsetTop)) {
- affix = 'top';
- } else {
- affix = false;
- }
-
- if (this.affixed === affix) {
- return;
- }
-
- if (this.unpin != null) {
- DOMNode.style.top = '';
- }
-
- affixType = 'affix' + (affix ? '-' + affix : '');
-
- this.affixed = affix;
- this.unpin = affix === 'bottom' ?
- this.getPinnedOffset(DOMNode) : null;
-
- if (affix === 'bottom') {
- DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, 'affix-bottom');
- affixPositionTop = scrollHeight - offsetBottom - DOMNode.offsetHeight - domUtils.getOffset(DOMNode).top;
- }
-
- this.setState({
- affixClass: affixType,
- affixPositionTop: affixPositionTop
- });
- },
-
- checkPositionWithEventLoop: function () {
- setTimeout(this.checkPosition, 0);
- },
-
- componentDidMount: function () {
- this._onWindowScrollListener =
- EventListener.listen(window, 'scroll', this.checkPosition);
- this._onDocumentClickListener =
- EventListener.listen(document, 'click', this.checkPositionWithEventLoop);
- },
-
- componentWillUnmount: function () {
- if (this._onWindowScrollListener) {
- this._onWindowScrollListener.remove();
- }
-
- if (this._onDocumentClickListener) {
- this._onDocumentClickListener.remove();
- }
- },
-
- componentDidUpdate: function (prevProps, prevState) {
- if (prevState.affixClass === this.state.affixClass) {
- this.checkPositionWithEventLoop();
- }
- }
-};
-
-module.exports = AffixMixin;
-});
-
-define('Affix',['require','exports','module','react','./AffixMixin','./utils/domUtils'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var AffixMixin = require('./AffixMixin');
-var domUtils = require('./utils/domUtils');
-
-var Affix = React.createClass({displayName: 'Affix',
- statics: {
- domUtils: domUtils
- },
-
- mixins: [AffixMixin],
-
- render: function () {
- var holderStyle = {top: this.state.affixPositionTop};
- return this.transferPropsTo(
- React.DOM.div( {className:this.state.affixClass, style:holderStyle},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Affix;
-});
-
-define('Alert',['require','exports','module','react','./utils/classSet','./BootstrapMixin'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-
-
-var Alert = React.createClass({displayName: 'Alert',
- mixins: [BootstrapMixin],
-
- propTypes: {
- onDismiss: React.PropTypes.func,
- dismissAfter: React.PropTypes.number
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'alert',
- bsStyle: 'info'
- };
- },
-
- renderDismissButton: function () {
- return (
- React.DOM.button(
- {type:"button",
- className:"close",
- onClick:this.props.onDismiss,
- 'aria-hidden':"true"},
- " × "
- )
- );
- },
-
- render: function () {
- var classes = this.getBsClassSet();
- var isDismissable = !!this.props.onDismiss;
-
- classes['alert-dismissable'] = isDismissable;
-
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(classes)},
- isDismissable ? this.renderDismissButton() : null,
- this.props.children
- )
- );
- },
-
- componentDidMount: function() {
- if (this.props.dismissAfter && this.props.onDismiss) {
- this.dismissTimer = setTimeout(this.props.onDismiss, this.props.dismissAfter);
- }
- },
-
- componentWillUnmount: function() {
- clearTimeout(this.dismissTimer);
- }
-});
-
-module.exports = Alert;
-});
-
-define('Badge',['require','exports','module','react','./utils/ValidComponentChildren','./utils/classSet'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-var classSet = require('./utils/classSet');
-
-var Badge = React.createClass({displayName: 'Badge',
- propTypes: {
- pullRight: React.PropTypes.bool,
- },
-
- render: function () {
- var classes = {
- 'pull-right': this.props.pullRight,
- 'badge': ValidComponentChildren.hasValidComponent(this.props.children)
- };
- return this.transferPropsTo(
- React.DOM.span( {className:classSet(classes)},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Badge;
-
-});
-
-define('utils/CustomPropTypes',['require','exports','module','react'],function (require, exports, module) {var React = require('react');
-
-var ANONYMOUS = '<<anonymous>>';
-
-var CustomPropTypes = {
- /**
- * Checks whether a prop is a valid React class
- *
- * @param props
- * @param propName
- * @param componentName
- * @returns {Error|undefined}
- */
- componentClass: createComponentClassChecker(),
-
- /**
- * Checks whether a prop provides a DOM element
- *
- * The element can be provided in two forms:
- * - Directly passed
- * - Or passed an object which has a `getDOMNode` method which will return the required DOM element
- *
- * @param props
- * @param propName
- * @param componentName
- * @returns {Error|undefined}
- */
- mountable: createMountableChecker()
-};
-
-/**
- * Create chain-able isRequired validator
- *
- * Largely copied directly from:
- * https://github.com/facebook/react/blob/0.11-stable/src/core/ReactPropTypes.js#L94
- */
-function createChainableTypeChecker(validate) {
- function checkType(isRequired, props, propName, componentName) {
- componentName = componentName || ANONYMOUS;
- if (props[propName] == null) {
- if (isRequired) {
- return new Error(
- 'Required prop `' + propName + '` was not specified in ' +
- '`' + componentName + '`.'
- );
- }
- } else {
- return validate(props, propName, componentName);
- }
- }
-
- var chainedCheckType = checkType.bind(null, false);
- chainedCheckType.isRequired = checkType.bind(null, true);
-
- return chainedCheckType;
-}
-
-function createComponentClassChecker() {
- function validate(props, propName, componentName) {
- if (!React.isValidClass(props[propName])) {
- return new Error(
- 'Invalid prop `' + propName + '` supplied to ' +
- '`' + componentName + '`, expected a valid React class.'
- );
- }
- }
-
- return createChainableTypeChecker(validate);
-}
-
-function createMountableChecker() {
- function validate(props, propName, componentName) {
- if (typeof props[propName] !== 'object' ||
- typeof props[propName].getDOMNode !== 'function' && props[propName].nodeType !== 1) {
- return new Error(
- 'Invalid prop `' + propName + '` supplied to ' +
- '`' + componentName + '`, expected a DOM element or an object that has a `getDOMNode` method'
- );
- }
- }
-
- return createChainableTypeChecker(validate);
-}
-
-module.exports = CustomPropTypes;
-});
-
-define('Button',['require','exports','module','react','./utils/classSet','./BootstrapMixin','./utils/CustomPropTypes'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-var CustomPropTypes = require('./utils/CustomPropTypes');
-
-var Button = React.createClass({displayName: 'Button',
- mixins: [BootstrapMixin],
-
- propTypes: {
- active: React.PropTypes.bool,
- disabled: React.PropTypes.bool,
- block: React.PropTypes.bool,
- navItem: React.PropTypes.bool,
- navDropdown: React.PropTypes.bool,
- componentClass: CustomPropTypes.componentClass
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'button',
- bsStyle: 'default',
- type: 'button'
- };
- },
-
- render: function () {
- var classes = this.props.navDropdown ? {} : this.getBsClassSet();
- var renderFuncName;
-
- classes['active'] = this.props.active;
- classes['btn-block'] = this.props.block;
-
- if (this.props.navItem) {
- return this.renderNavItem(classes);
- }
-
- renderFuncName = this.props.href || this.props.navDropdown ?
- 'renderAnchor' : 'renderButton';
-
- return this[renderFuncName](classes);
- },
-
- renderAnchor: function (classes) {
- var component = this.props.componentClass || React.DOM.a;
- var href = this.props.href || '#';
- classes['disabled'] = this.props.disabled;
-
- return this.transferPropsTo(
- component(
- {href:href,
- className:classSet(classes),
- role:"button"},
- this.props.children
- )
- );
- },
-
- renderButton: function (classes) {
- var component = this.props.componentClass || React.DOM.button;
-
- return this.transferPropsTo(
- component(
- {className:classSet(classes)},
- this.props.children
- )
- );
- },
-
- renderNavItem: function (classes) {
- var liClasses = {
- active: this.props.active
- };
-
- return (
- React.DOM.li( {className:classSet(liClasses)},
- this.renderAnchor(classes)
- )
- );
- }
-});
-
-module.exports = Button;
-
-});
-
-define('ButtonGroup',['require','exports','module','react','./utils/classSet','./BootstrapMixin','./Button'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-var Button = require('./Button');
-
-var ButtonGroup = React.createClass({displayName: 'ButtonGroup',
- mixins: [BootstrapMixin],
-
- propTypes: {
- vertical: React.PropTypes.bool,
- justified: React.PropTypes.bool
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'button-group'
- };
- },
-
- render: function () {
- var classes = this.getBsClassSet();
- classes['btn-group'] = !this.props.vertical;
- classes['btn-group-vertical'] = this.props.vertical;
- classes['btn-group-justified'] = this.props.justified;
-
- return this.transferPropsTo(
- React.DOM.div(
- {className:classSet(classes)},
- this.props.children
- )
- );
- }
-});
-
-module.exports = ButtonGroup;
-});
-
-define('ButtonToolbar',['require','exports','module','react','./utils/classSet','./BootstrapMixin','./Button'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-var Button = require('./Button');
-
-var ButtonToolbar = React.createClass({displayName: 'ButtonToolbar',
- mixins: [BootstrapMixin],
-
- getDefaultProps: function () {
- return {
- bsClass: 'button-toolbar'
- };
- },
-
- render: function () {
- var classes = this.getBsClassSet();
-
- return this.transferPropsTo(
- React.DOM.div(
- {role:"toolbar",
- className:classSet(classes)},
- this.props.children
- )
- );
- }
-});
-
-module.exports = ButtonToolbar;
-});
-
-define('Carousel',['require','exports','module','react','./utils/classSet','./utils/cloneWithProps','./BootstrapMixin','./utils/ValidComponentChildren'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var BootstrapMixin = require('./BootstrapMixin');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-
-var Carousel = React.createClass({displayName: 'Carousel',
- mixins: [BootstrapMixin],
-
- propTypes: {
- slide: React.PropTypes.bool,
- indicators: React.PropTypes.bool,
- controls: React.PropTypes.bool,
- pauseOnHover: React.PropTypes.bool,
- wrap: React.PropTypes.bool,
- onSelect: React.PropTypes.func,
- onSlideEnd: React.PropTypes.func,
- activeIndex: React.PropTypes.number,
- defaultActiveIndex: React.PropTypes.number,
- direction: React.PropTypes.oneOf(['prev', 'next'])
- },
-
- getDefaultProps: function () {
- return {
- slide: true,
- interval: 5000,
- pauseOnHover: true,
- wrap: true,
- indicators: true,
- controls: true
- };
- },
-
- getInitialState: function () {
- return {
- activeIndex: this.props.defaultActiveIndex == null ?
- 0 : this.props.defaultActiveIndex,
- previousActiveIndex: null,
- direction: null
- };
- },
-
- getDirection: function (prevIndex, index) {
- if (prevIndex === index) {
- return null;
- }
-
- return prevIndex > index ?
- 'prev' : 'next';
- },
-
- componentWillReceiveProps: function (nextProps) {
- var activeIndex = this.getActiveIndex();
-
- if (nextProps.activeIndex != null && nextProps.activeIndex !== activeIndex) {
- clearTimeout(this.timeout);
- this.setState({
- previousActiveIndex: activeIndex,
- direction: nextProps.direction != null ?
- nextProps.direction : this.getDirection(activeIndex, nextProps.activeIndex)
- });
- }
- },
-
- componentDidMount: function () {
- this.waitForNext();
- },
-
- componentWillUnmount: function() {
- clearTimeout(this.timeout);
- },
-
- next: function (e) {
- if (e) {
- e.preventDefault();
- }
-
- var index = this.getActiveIndex() + 1;
- var count = ValidComponentChildren.numberOf(this.props.children);
-
- if (index > count - 1) {
- if (!this.props.wrap) {
- return;
- }
- index = 0;
- }
-
- this.handleSelect(index, 'next');
- },
-
- prev: function (e) {
- if (e) {
- e.preventDefault();
- }
-
- var index = this.getActiveIndex() - 1;
-
- if (index < 0) {
- if (!this.props.wrap) {
- return;
- }
- index = ValidComponentChildren.numberOf(this.props.children) - 1;
- }
-
- this.handleSelect(index, 'prev');
- },
-
- pause: function () {
- this.isPaused = true;
- clearTimeout(this.timeout);
- },
-
- play: function () {
- this.isPaused = false;
- this.waitForNext();
- },
-
- waitForNext: function () {
- if (!this.isPaused && this.props.slide && this.props.interval &&
- this.props.activeIndex == null) {
- this.timeout = setTimeout(this.next, this.props.interval);
- }
- },
-
- handleMouseOver: function () {
- if (this.props.pauseOnHover) {
- this.pause();
- }
- },
-
- handleMouseOut: function () {
- if (this.isPaused) {
- this.play();
- }
- },
-
- render: function () {
- var classes = {
- carousel: true,
- slide: this.props.slide
- };
-
- return this.transferPropsTo(
- React.DOM.div(
- {className:classSet(classes),
- onMouseOver:this.handleMouseOver,
- onMouseOut:this.handleMouseOut},
- this.props.indicators ? this.renderIndicators() : null,
- React.DOM.div( {className:"carousel-inner", ref:"inner"},
- ValidComponentChildren.map(this.props.children, this.renderItem)
- ),
- this.props.controls ? this.renderControls() : null
- )
- );
- },
-
- renderPrev: function () {
- return (
- React.DOM.a( {className:"left carousel-control", href:"#prev", key:0, onClick:this.prev},
- React.DOM.span( {className:"glyphicon glyphicon-chevron-left"} )
- )
- );
- },
-
- renderNext: function () {
- return (
- React.DOM.a( {className:"right carousel-control", href:"#next", key:1, onClick:this.next},
- React.DOM.span( {className:"glyphicon glyphicon-chevron-right"})
- )
- );
- },
-
- renderControls: function () {
- if (this.props.wrap) {
- var activeIndex = this.getActiveIndex();
- var count = ValidComponentChildren.numberOf(this.props.children);
-
- return [
- (activeIndex !== 0) ? this.renderPrev() : null,
- (activeIndex !== count - 1) ? this.renderNext() : null
- ];
- }
-
- return [
- this.renderPrev(),
- this.renderNext()
- ];
- },
-
- renderIndicator: function (child, index) {
- var className = (index === this.getActiveIndex()) ?
- 'active' : null;
-
- return (
- React.DOM.li(
- {key:index,
- className:className,
- onClick:this.handleSelect.bind(this, index, null)} )
- );
- },
-
- renderIndicators: function () {
- var indicators = [];
- ValidComponentChildren
- .forEach(this.props.children, function(child, index) {
- indicators.push(
- this.renderIndicator(child, index),
-
- // Force whitespace between indicator elements, bootstrap
- // requires this for correct spacing of elements.
- ' '
- );
- }, this);
-
- return (
- React.DOM.ol( {className:"carousel-indicators"},
- indicators
- )
- );
- },
-
- getActiveIndex: function () {
- return this.props.activeIndex != null ? this.props.activeIndex : this.state.activeIndex;
- },
-
- handleItemAnimateOutEnd: function () {
- this.setState({
- previousActiveIndex: null,
- direction: null
- }, function() {
- this.waitForNext();
-
- if (this.props.onSlideEnd) {
- this.props.onSlideEnd();
- }
- });
- },
-
- renderItem: function (child, index) {
- var activeIndex = this.getActiveIndex();
- var isActive = (index === activeIndex);
- var isPreviousActive = this.state.previousActiveIndex != null &&
- this.state.previousActiveIndex === index && this.props.slide;
-
- return cloneWithProps(
- child,
- {
- active: isActive,
- ref: child.props.ref,
- key: child.props.key != null ?
- child.props.key : index,
- index: index,
- animateOut: isPreviousActive,
- animateIn: isActive && this.state.previousActiveIndex != null && this.props.slide,
- direction: this.state.direction,
- onAnimateOutEnd: isPreviousActive ? this.handleItemAnimateOutEnd: null
- }
- );
- },
-
- handleSelect: function (index, direction) {
- clearTimeout(this.timeout);
-
- var previousActiveIndex = this.getActiveIndex();
- direction = direction || this.getDirection(previousActiveIndex, index);
-
- if (this.props.onSelect) {
- this.props.onSelect(index, direction);
- }
-
- if (this.props.activeIndex == null && index !== previousActiveIndex) {
- if (this.state.previousActiveIndex != null) {
- // If currently animating don't activate the new index.
- // TODO: look into queuing this canceled call and
- // animating after the current animation has ended.
- return;
- }
-
- this.setState({
- activeIndex: index,
- previousActiveIndex: previousActiveIndex,
- direction: direction
- });
- }
- }
-});
-
-module.exports = Carousel;
-});
-
-define('utils/TransitionEvents',['require','exports','module'],function (require, exports, module) {/**
- * React TransitionEvents
- *
- * Copyright 2013-2014 Facebook, Inc.
- * @licence https://github.com/facebook/react/blob/0.11-stable/LICENSE
- *
- * This file contains a modified version of:
- * https://github.com/facebook/react/blob/0.11-stable/src/addons/transitions/ReactTransitionEvents.js
- *
- */
-
-var canUseDOM = !!(
- typeof window !== 'undefined' &&
- window.document &&
- window.document.createElement
- );
-
-/**
- * EVENT_NAME_MAP is used to determine which event fired when a
- * transition/animation ends, based on the style property used to
- * define that event.
- */
-var EVENT_NAME_MAP = {
- transitionend: {
- 'transition': 'transitionend',
- 'WebkitTransition': 'webkitTransitionEnd',
- 'MozTransition': 'mozTransitionEnd',
- 'OTransition': 'oTransitionEnd',
- 'msTransition': 'MSTransitionEnd'
- },
-
- animationend: {
- 'animation': 'animationend',
- 'WebkitAnimation': 'webkitAnimationEnd',
- 'MozAnimation': 'mozAnimationEnd',
- 'OAnimation': 'oAnimationEnd',
- 'msAnimation': 'MSAnimationEnd'
- }
-};
-
-var endEvents = [];
-
-function detectEvents() {
- var testEl = document.createElement('div');
- var style = testEl.style;
-
- // On some platforms, in particular some releases of Android 4.x,
- // the un-prefixed "animation" and "transition" properties are defined on the
- // style object but the events that fire will still be prefixed, so we need
- // to check if the un-prefixed events are useable, and if not remove them
- // from the map
- if (!('AnimationEvent' in window)) {
- delete EVENT_NAME_MAP.animationend.animation;
- }
-
- if (!('TransitionEvent' in window)) {
- delete EVENT_NAME_MAP.transitionend.transition;
- }
-
- for (var baseEventName in EVENT_NAME_MAP) {
- var baseEvents = EVENT_NAME_MAP[baseEventName];
- for (var styleName in baseEvents) {
- if (styleName in style) {
- endEvents.push(baseEvents[styleName]);
- break;
- }
- }
- }
-}
-
-if (canUseDOM) {
- detectEvents();
-}
-
-// We use the raw {add|remove}EventListener() call because EventListener
-// does not know how to remove event listeners and we really should
-// clean up. Also, these events are not triggered in older browsers
-// so we should be A-OK here.
-
-function addEventListener(node, eventName, eventListener) {
- node.addEventListener(eventName, eventListener, false);
-}
-
-function removeEventListener(node, eventName, eventListener) {
- node.removeEventListener(eventName, eventListener, false);
-}
-
-var ReactTransitionEvents = {
- addEndEventListener: function(node, eventListener) {
- if (endEvents.length === 0) {
- // If CSS transitions are not supported, trigger an "end animation"
- // event immediately.
- window.setTimeout(eventListener, 0);
- return;
- }
- endEvents.forEach(function(endEvent) {
- addEventListener(node, endEvent, eventListener);
- });
- },
-
- removeEndEventListener: function(node, eventListener) {
- if (endEvents.length === 0) {
- return;
- }
- endEvents.forEach(function(endEvent) {
- removeEventListener(node, endEvent, eventListener);
- });
- }
-};
-
-module.exports = ReactTransitionEvents;
-
-});
-
-define('CarouselItem',['require','exports','module','react','./utils/classSet','./utils/TransitionEvents'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var TransitionEvents = require('./utils/TransitionEvents');
-
-var CarouselItem = React.createClass({displayName: 'CarouselItem',
- propTypes: {
- direction: React.PropTypes.oneOf(['prev', 'next']),
- onAnimateOutEnd: React.PropTypes.func,
- active: React.PropTypes.bool,
- caption: React.PropTypes.renderable
- },
-
- getInitialState: function () {
- return {
- direction: null
- };
- },
-
- getDefaultProps: function () {
- return {
- animation: true
- };
- },
-
- handleAnimateOutEnd: function () {
- if (this.props.onAnimateOutEnd && this.isMounted()) {
- this.props.onAnimateOutEnd(this.props.index);
- }
- },
-
- componentWillReceiveProps: function (nextProps) {
- if (this.props.active !== nextProps.active) {
- this.setState({
- direction: null
- });
- }
- },
-
- componentDidUpdate: function (prevProps) {
- if (!this.props.active && prevProps.active) {
- TransitionEvents.addEndEventListener(
- this.getDOMNode(),
- this.handleAnimateOutEnd
- );
- }
-
- if (this.props.active !== prevProps.active) {
- setTimeout(this.startAnimation, 20);
- }
- },
-
- startAnimation: function () {
- if (!this.isMounted()) {
- return;
- }
-
- this.setState({
- direction: this.props.direction === 'prev' ?
- 'right' : 'left'
- });
- },
-
- render: function () {
- var classes = {
- item: true,
- active: (this.props.active && !this.props.animateIn) || this.props.animateOut,
- next: this.props.active && this.props.animateIn && this.props.direction === 'next',
- prev: this.props.active && this.props.animateIn && this.props.direction === 'prev'
- };
-
- if (this.state.direction && (this.props.animateIn || this.props.animateOut)) {
- classes[this.state.direction] = true;
- }
-
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(classes)},
- this.props.children,
- this.props.caption ? this.renderCaption() : null
- )
- );
- },
-
- renderCaption: function () {
- return (
- React.DOM.div( {className:"carousel-caption"},
- this.props.caption
- )
- );
- }
-});
-
-module.exports = CarouselItem;
-});
-
-define('Col',['require','exports','module','react','./utils/classSet','./utils/CustomPropTypes','./constants'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var CustomPropTypes = require('./utils/CustomPropTypes');
-var constants = require('./constants');
-
-
-var Col = React.createClass({displayName: 'Col',
- propTypes: {
- xs: React.PropTypes.number,
- sm: React.PropTypes.number,
- md: React.PropTypes.number,
- lg: React.PropTypes.number,
- xsOffset: React.PropTypes.number,
- smOffset: React.PropTypes.number,
- mdOffset: React.PropTypes.number,
- lgOffset: React.PropTypes.number,
- xsPush: React.PropTypes.number,
- smPush: React.PropTypes.number,
- mdPush: React.PropTypes.number,
- lgPush: React.PropTypes.number,
- xsPull: React.PropTypes.number,
- smPull: React.PropTypes.number,
- mdPull: React.PropTypes.number,
- lgPull: React.PropTypes.number,
- componentClass: CustomPropTypes.componentClass.isRequired
- },
-
- getDefaultProps: function () {
- return {
- componentClass: React.DOM.div
- };
- },
-
- render: function () {
- var componentClass = this.props.componentClass;
- var classes = {};
-
- Object.keys(constants.SIZES).forEach(function (key) {
- var size = constants.SIZES[key];
- var prop = size;
- var classPart = size + '-';
-
- if (this.props[prop]) {
- classes['col-' + classPart + this.props[prop]] = true;
- }
-
- prop = size + 'Offset';
- classPart = size + '-offset-';
- if (this.props[prop]) {
- classes['col-' + classPart + this.props[prop]] = true;
- }
-
- prop = size + 'Push';
- classPart = size + '-push-';
- if (this.props[prop]) {
- classes['col-' + classPart + this.props[prop]] = true;
- }
-
- prop = size + 'Pull';
- classPart = size + '-pull-';
- if (this.props[prop]) {
- classes['col-' + classPart + this.props[prop]] = true;
- }
- }, this);
-
- return this.transferPropsTo(
- componentClass( {className:classSet(classes)},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Col;
-});
-
-define('CollapsableMixin',['require','exports','module','react','./utils/TransitionEvents'],function (require, exports, module) {var React = require('react');
-var TransitionEvents = require('./utils/TransitionEvents');
-
-var CollapsableMixin = {
-
- propTypes: {
- collapsable: React.PropTypes.bool,
- defaultExpanded: React.PropTypes.bool,
- expanded: React.PropTypes.bool
- },
-
- getInitialState: function () {
- return {
- expanded: this.props.defaultExpanded != null ? this.props.defaultExpanded : null,
- collapsing: false
- };
- },
-
- handleTransitionEnd: function () {
- this._collapseEnd = true;
- this.setState({
- collapsing: false
- });
- },
-
- componentWillReceiveProps: function (newProps) {
- if (this.props.collapsable && newProps.expanded !== this.props.expanded) {
- this._collapseEnd = false;
- this.setState({
- collapsing: true
- });
- }
- },
-
- _addEndTransitionListener: function () {
- var node = this.getCollapsableDOMNode();
-
- if (node) {
- TransitionEvents.addEndEventListener(
- node,
- this.handleTransitionEnd
- );
- }
- },
-
- _removeEndTransitionListener: function () {
- var node = this.getCollapsableDOMNode();
-
- if (node) {
- TransitionEvents.addEndEventListener(
- node,
- this.handleTransitionEnd
- );
- }
- },
-
- componentDidMount: function () {
- this._afterRender();
- },
-
- componentWillUnmount: function () {
- this._removeEndTransitionListener();
- },
-
- componentWillUpdate: function (nextProps) {
- var dimension = (typeof this.getCollapsableDimension === 'function') ?
- this.getCollapsableDimension() : 'height';
- var node = this.getCollapsableDOMNode();
-
- this._removeEndTransitionListener();
- if (node && nextProps.expanded !== this.props.expanded && this.props.expanded) {
- node.style[dimension] = this.getCollapsableDimensionValue() + 'px';
- }
- },
-
- componentDidUpdate: function (prevProps, prevState) {
- if (this.state.collapsing !== prevState.collapsing) {
- this._afterRender();
- }
- },
-
- _afterRender: function () {
- if (!this.props.collapsable) {
- return;
- }
-
- this._addEndTransitionListener();
- setTimeout(this._updateDimensionAfterRender, 0);
- },
-
- _updateDimensionAfterRender: function () {
- var dimension = (typeof this.getCollapsableDimension === 'function') ?
- this.getCollapsableDimension() : 'height';
- var node = this.getCollapsableDOMNode();
-
- if (node) {
- if(this.isExpanded() && !this.state.collapsing) {
- node.style[dimension] = 'auto';
- } else {
- node.style[dimension] = this.isExpanded() ?
- this.getCollapsableDimensionValue() + 'px' : '0px';
- }
- }
- },
-
- isExpanded: function () {
- return (this.props.expanded != null) ?
- this.props.expanded : this.state.expanded;
- },
-
- getCollapsableClassSet: function (className) {
- var classes = {};
-
- if (typeof className === 'string') {
- className.split(' ').forEach(function (className) {
- if (className) {
- classes[className] = true;
- }
- });
- }
-
- classes.collapsing = this.state.collapsing;
- classes.collapse = !this.state.collapsing;
- classes['in'] = this.isExpanded() && !this.state.collapsing;
-
- return classes;
- }
-};
-
-module.exports = CollapsableMixin;
-});
-
-define('utils/createChainedFunction',['require','exports','module'],function (require, exports, module) {/**
- * Safe chained function
- *
- * Will only create a new function if needed,
- * otherwise will pass back existing functions or null.
- *
- * @param {function} one
- * @param {function} two
- * @returns {function|null}
- */
-function createChainedFunction(one, two) {
- var hasOne = typeof one === 'function';
- var hasTwo = typeof two === 'function';
-
- if (!hasOne && !hasTwo) { return null; }
- if (!hasOne) { return two; }
- if (!hasTwo) { return one; }
-
- return function chainedFunction() {
- one.apply(this, arguments);
- two.apply(this, arguments);
- };
-}
-
-module.exports = createChainedFunction;
-});
-
-define('DropdownStateMixin',['require','exports','module','react','./utils/EventListener'],function (require, exports, module) {var React = require('react');
-var EventListener = require('./utils/EventListener');
-
-/**
- * Checks whether a node is within
- * a root nodes tree
- *
- * @param {DOMElement} node
- * @param {DOMElement} root
- * @returns {boolean}
- */
-function isNodeInRoot(node, root) {
- while (node) {
- if (node === root) {
- return true;
- }
- node = node.parentNode;
- }
-
- return false;
-}
-
-var DropdownStateMixin = {
- getInitialState: function () {
- return {
- open: false
- };
- },
-
- setDropdownState: function (newState, onStateChangeComplete) {
- if (newState) {
- this.bindRootCloseHandlers();
- } else {
- this.unbindRootCloseHandlers();
- }
-
- this.setState({
- open: newState
- }, onStateChangeComplete);
- },
-
- handleDocumentKeyUp: function (e) {
- if (e.keyCode === 27) {
- this.setDropdownState(false);
- }
- },
-
- handleDocumentClick: function (e) {
- // If the click originated from within this component
- // don't do anything.
- if (isNodeInRoot(e.target, this.getDOMNode())) {
- return;
- }
-
- this.setDropdownState(false);
- },
-
- bindRootCloseHandlers: function () {
- this._onDocumentClickListener =
- EventListener.listen(document, 'click', this.handleDocumentClick);
- this._onDocumentKeyupListener =
- EventListener.listen(document, 'keyup', this.handleDocumentKeyUp);
- },
-
- unbindRootCloseHandlers: function () {
- if (this._onDocumentClickListener) {
- this._onDocumentClickListener.remove();
- }
-
- if (this._onDocumentKeyupListener) {
- this._onDocumentKeyupListener.remove();
- }
- },
-
- componentWillUnmount: function () {
- this.unbindRootCloseHandlers();
- }
-};
-
-module.exports = DropdownStateMixin;
-});
-
-define('DropdownMenu',['require','exports','module','react','./utils/classSet','./utils/cloneWithProps','./utils/createChainedFunction','./utils/ValidComponentChildren'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var createChainedFunction = require('./utils/createChainedFunction');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-
-var DropdownMenu = React.createClass({displayName: 'DropdownMenu',
- propTypes: {
- pullRight: React.PropTypes.bool,
- onSelect: React.PropTypes.func
- },
-
- render: function () {
- var classes = {
- 'dropdown-menu': true,
- 'dropdown-menu-right': this.props.pullRight
- };
-
- return this.transferPropsTo(
- React.DOM.ul(
- {className:classSet(classes),
- role:"menu"},
- ValidComponentChildren.map(this.props.children, this.renderMenuItem)
- )
- );
- },
-
- renderMenuItem: function (child) {
- return cloneWithProps(
- child,
- {
- // Capture onSelect events
- onSelect: createChainedFunction(child.props.onSelect, this.props.onSelect),
-
- // Force special props to be transferred
- key: child.props.key,
- ref: child.props.ref
- }
- );
- }
-});
-
-module.exports = DropdownMenu;
-});
-
-define('DropdownButton',['require','exports','module','react','./utils/classSet','./utils/cloneWithProps','./utils/createChainedFunction','./BootstrapMixin','./DropdownStateMixin','./Button','./ButtonGroup','./DropdownMenu','./utils/ValidComponentChildren'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var createChainedFunction = require('./utils/createChainedFunction');
-var BootstrapMixin = require('./BootstrapMixin');
-var DropdownStateMixin = require('./DropdownStateMixin');
-var Button = require('./Button');
-var ButtonGroup = require('./ButtonGroup');
-var DropdownMenu = require('./DropdownMenu');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-
-
-var DropdownButton = React.createClass({displayName: 'DropdownButton',
- mixins: [BootstrapMixin, DropdownStateMixin],
-
- propTypes: {
- pullRight: React.PropTypes.bool,
- dropup: React.PropTypes.bool,
- title: React.PropTypes.renderable,
- href: React.PropTypes.string,
- onClick: React.PropTypes.func,
- onSelect: React.PropTypes.func,
- navItem: React.PropTypes.bool
- },
-
- render: function () {
- var className = 'dropdown-toggle';
-
- var renderMethod = this.props.navItem ?
- 'renderNavItem' : 'renderButtonGroup';
-
- return this[renderMethod]([
- this.transferPropsTo(Button(
- {ref:"dropdownButton",
- className:className,
- onClick:this.handleDropdownClick,
- key:0,
- navDropdown:this.props.navItem,
- navItem:null,
- title:null,
- pullRight:null,
- dropup:null},
- this.props.title,' ',
- React.DOM.span( {className:"caret"} )
- )),
- DropdownMenu(
- {ref:"menu",
- 'aria-labelledby':this.props.id,
- pullRight:this.props.pullRight,
- key:1},
- ValidComponentChildren.map(this.props.children, this.renderMenuItem)
- )
- ]);
- },
-
- renderButtonGroup: function (children) {
- var groupClasses = {
- 'open': this.state.open,
- 'dropup': this.props.dropup
- };
-
- return (
- ButtonGroup(
- {bsSize:this.props.bsSize,
- className:classSet(groupClasses)},
- children
- )
- );
- },
-
- renderNavItem: function (children) {
- var classes = {
- 'dropdown': true,
- 'open': this.state.open,
- 'dropup': this.props.dropup
- };
-
- return (
- React.DOM.li( {className:classSet(classes)},
- children
- )
- );
- },
-
- renderMenuItem: function (child) {
- // Only handle the option selection if an onSelect prop has been set on the
- // component or it's child, this allows a user not to pass an onSelect
- // handler and have the browser preform the default action.
- var handleOptionSelect = this.props.onSelect || child.props.onSelect ?
- this.handleOptionSelect : null;
-
- return cloneWithProps(
- child,
- {
- // Capture onSelect events
- onSelect: createChainedFunction(child.props.onSelect, handleOptionSelect),
-
- // Force special props to be transferred
- key: child.props.key,
- ref: child.props.ref
- }
- );
- },
-
- handleDropdownClick: function (e) {
- e.preventDefault();
-
- this.setDropdownState(!this.state.open);
- },
-
- handleOptionSelect: function (key) {
- if (this.props.onSelect) {
- this.props.onSelect(key);
- }
-
- this.setDropdownState(false);
- }
-});
-
-module.exports = DropdownButton;
-});
-
-define('FadeMixin',['require','exports','module','react'],function (require, exports, module) {var React = require('react');
-
-// TODO: listen for onTransitionEnd to remove el
-module.exports = {
- _fadeIn: function () {
- var els;
-
- if (this.isMounted()) {
- els = this.getDOMNode().querySelectorAll('.fade');
- if (els.length) {
- Array.prototype.forEach.call(els, function (el) {
- el.className += ' in';
- });
- }
- }
- },
-
- _fadeOut: function () {
- var els = this._fadeOutEl.querySelectorAll('.fade.in');
-
- if (els.length) {
- Array.prototype.forEach.call(els, function (el) {
- el.className = el.className.replace(/\bin\b/, '');
- });
- }
-
- setTimeout(this._handleFadeOutEnd, 300);
- },
-
- _handleFadeOutEnd: function () {
- if (this._fadeOutEl && this._fadeOutEl.parentNode) {
- this._fadeOutEl.parentNode.removeChild(this._fadeOutEl);
- }
- },
-
- componentDidMount: function () {
- if (document.querySelectorAll) {
- // Firefox needs delay for transition to be triggered
- setTimeout(this._fadeIn, 20);
- }
- },
-
- componentWillUnmount: function () {
- var els = this.getDOMNode().querySelectorAll('.fade');
- if (els.length) {
- this._fadeOutEl = document.createElement('div');
- document.body.appendChild(this._fadeOutEl);
- this._fadeOutEl.appendChild(this.getDOMNode().cloneNode(true));
- // Firefox needs delay for transition to be triggered
- setTimeout(this._fadeOut, 20);
- }
- }
-};
-
-});
-
-define('Glyphicon',['require','exports','module','react','./utils/classSet','./BootstrapMixin','./constants'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-var constants = require('./constants');
-
-var Glyphicon = React.createClass({displayName: 'Glyphicon',
- mixins: [BootstrapMixin],
-
- propTypes: {
- glyph: React.PropTypes.oneOf(constants.GLYPHS).isRequired
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'glyphicon'
- };
- },
-
- render: function () {
- var classes = this.getBsClassSet();
-
- classes['glyphicon-' + this.props.glyph] = true;
-
- return this.transferPropsTo(
- React.DOM.span( {className:classSet(classes)},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Glyphicon;
-});
-
-define('Grid',['require','exports','module','react','./utils/CustomPropTypes'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var CustomPropTypes = require('./utils/CustomPropTypes');
-
-
-var Grid = React.createClass({displayName: 'Grid',
- propTypes: {
- fluid: React.PropTypes.bool,
- componentClass: CustomPropTypes.componentClass.isRequired
- },
-
- getDefaultProps: function () {
- return {
- componentClass: React.DOM.div
- };
- },
-
- render: function () {
- var componentClass = this.props.componentClass;
-
- return this.transferPropsTo(
- componentClass( {className:this.props.fluid ? 'container-fluid' : 'container'},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Grid;
-});
-
-define('Input',['require','exports','module','react','./utils/classSet','./Button'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var Button = require('./Button');
-
-var Input = React.createClass({displayName: 'Input',
- propTypes: {
- type: React.PropTypes.string,
- label: React.PropTypes.renderable,
- help: React.PropTypes.renderable,
- addonBefore: React.PropTypes.renderable,
- addonAfter: React.PropTypes.renderable,
- bsStyle: function(props) {
- if (props.type === 'submit') {
- // Return early if `type=submit` as the `Button` component
- // it transfers these props to has its own propType checks.
- return;
- }
-
- return React.PropTypes.oneOf(['success', 'warning', 'error']).apply(null, arguments);
- },
- hasFeedback: React.PropTypes.bool,
- groupClassName: React.PropTypes.string,
- wrapperClassName: React.PropTypes.string,
- labelClassName: React.PropTypes.string
- },
-
- getInputDOMNode: function () {
- return this.refs.input.getDOMNode();
- },
-
- getValue: function () {
- if (this.props.type === 'static') {
- return this.props.value;
- }
- else if (this.props.type) {
- return this.getInputDOMNode().value;
- }
- else {
- throw Error('Cannot use getValue without specifying input type.');
- }
- },
-
- getChecked: function () {
- return this.getInputDOMNode().checked;
- },
-
- isCheckboxOrRadio: function () {
- return this.props.type === 'radio' || this.props.type === 'checkbox';
- },
-
- renderInput: function () {
- var input = null;
-
- if (!this.props.type) {
- return this.props.children
- }
-
- switch (this.props.type) {
- case 'select':
- input = (
- React.DOM.select( {className:"form-control", ref:"input", key:"input"},
- this.props.children
- )
- );
- break;
- case 'textarea':
- input = React.DOM.textarea( {className:"form-control", ref:"input", key:"input"} );
- break;
- case 'static':
- input = (
- React.DOM.p( {className:"form-control-static", ref:"input", key:"input"},
- this.props.value
- )
- );
- break;
- case 'submit':
- input = this.transferPropsTo(
- Button( {componentClass:React.DOM.input} )
- );
- break;
- default:
- var className = this.isCheckboxOrRadio() ? '' : 'form-control';
- input = React.DOM.input( {className:className, ref:"input", key:"input"} );
- }
-
- return this.transferPropsTo(input);
- },
-
- renderInputGroup: function (children) {
- var addonBefore = this.props.addonBefore ? (
- React.DOM.span( {className:"input-group-addon", key:"addonBefore"},
- this.props.addonBefore
- )
- ) : null;
-
- var addonAfter = this.props.addonAfter ? (
- React.DOM.span( {className:"input-group-addon", key:"addonAfter"},
- this.props.addonAfter
- )
- ) : null;
-
- return addonBefore || addonAfter ? (
- React.DOM.div( {className:"input-group", key:"input-group"},
- addonBefore,
- children,
- addonAfter
- )
- ) : children;
- },
-
- renderIcon: function () {
- var classes = {
- 'glyphicon': true,
- 'form-control-feedback': true,
- 'glyphicon-ok': this.props.bsStyle === 'success',
- 'glyphicon-warning-sign': this.props.bsStyle === 'warning',
- 'glyphicon-remove': this.props.bsStyle === 'error'
- };
-
- return this.props.hasFeedback ? (
- React.DOM.span( {className:classSet(classes), key:"icon"} )
- ) : null;
- },
-
- renderHelp: function () {
- return this.props.help ? (
- React.DOM.span( {className:"help-block", key:"help"},
- this.props.help
- )
- ) : null;
- },
-
- renderCheckboxandRadioWrapper: function (children) {
- var classes = {
- 'checkbox': this.props.type === 'checkbox',
- 'radio': this.props.type === 'radio'
- };
-
- return (
- React.DOM.div( {className:classSet(classes), key:"checkboxRadioWrapper"},
- children
- )
- );
- },
-
- renderWrapper: function (children) {
- return this.props.wrapperClassName ? (
- React.DOM.div( {className:this.props.wrapperClassName, key:"wrapper"},
- children
- )
- ) : children;
- },
-
- renderLabel: function (children) {
- var classes = {
- 'control-label': !this.isCheckboxOrRadio()
- };
- classes[this.props.labelClassName] = this.props.labelClassName;
-
- return this.props.label ? (
- React.DOM.label( {htmlFor:this.props.id, className:classSet(classes), key:"label"},
- children,
- this.props.label
- )
- ) : children;
- },
-
- renderFormGroup: function (children) {
- var classes = {
- 'form-group': true,
- 'has-feedback': this.props.hasFeedback,
- 'has-success': this.props.bsStyle === 'success',
- 'has-warning': this.props.bsStyle === 'warning',
- 'has-error': this.props.bsStyle === 'error'
- };
- classes[this.props.groupClassName] = this.props.groupClassName;
-
- return (
- React.DOM.div( {className:classSet(classes)},
- children
- )
- );
- },
-
- render: function () {
- if (this.isCheckboxOrRadio()) {
- return this.renderFormGroup(
- this.renderWrapper([
- this.renderCheckboxandRadioWrapper(
- this.renderLabel(
- this.renderInput()
- )
- ),
- this.renderHelp()
- ])
- );
- }
- else {
- return this.renderFormGroup([
- this.renderLabel(),
- this.renderWrapper([
- this.renderInputGroup(
- this.renderInput()
- ),
- this.renderIcon(),
- this.renderHelp()
- ])
- ]);
- }
- }
-});
-
-module.exports = Input;
-
-});
-
-define('Interpolate',['require','exports','module','react','./utils/merge','./utils/ValidComponentChildren'],function (require, exports, module) {// https://www.npmjs.org/package/react-interpolate-component
-
-
-var React = require('react');
-var merge = require('./utils/merge');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-
-var REGEXP = /\%\((.+?)\)s/;
-
-var Interpolate = React.createClass({
- displayName: 'Interpolate',
-
- propTypes: {
- format: React.PropTypes.string
- },
-
- getDefaultProps: function() {
- return { component: React.DOM.span };
- },
-
- render: function() {
- var format = ValidComponentChildren.hasValidComponent(this.props.children) ? this.props.children : this.props.format;
- var parent = this.props.component;
- var unsafe = this.props.unsafe === true;
- var props = merge(this.props);
-
- delete props.children;
- delete props.format;
- delete props.component;
- delete props.unsafe;
-
- if (unsafe) {
- var content = format.split(REGEXP).reduce(function(memo, match, index) {
- var html;
-
- if (index % 2 === 0) {
- html = match;
- } else {
- html = props[match];
- delete props[match];
- }
-
- if (React.isValidComponent(html)) {
- throw new Error('cannot interpolate a React component into unsafe text');
- }
-
- memo += html;
-
- return memo;
- }, '');
-
- props.dangerouslySetInnerHTML = { __html: content };
-
- return parent(props);
- } else {
- var args = format.split(REGEXP).reduce(function(memo, match, index) {
- var child;
-
- if (index % 2 === 0) {
- if (match.length === 0) {
- return memo;
- }
-
- child = match;
- } else {
- child = props[match];
- delete props[match];
- }
-
- memo.push(child);
-
- return memo;
- }, [props]);
-
- return parent.apply(null, args);
- }
- }
-});
-
-module.exports = Interpolate;
-
-});
-
-define('Jumbotron',['require','exports','module','react'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-
-var Jumbotron = React.createClass({displayName: 'Jumbotron',
-
- render: function () {
- return this.transferPropsTo(
- React.DOM.div( {className:"jumbotron"},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Jumbotron;
-});
-
-define('Label',['require','exports','module','react','./utils/classSet','./BootstrapMixin'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-
-var Label = React.createClass({displayName: 'Label',
- mixins: [BootstrapMixin],
-
- getDefaultProps: function () {
- return {
- bsClass: 'label',
- bsStyle: 'default'
- };
- },
-
- render: function () {
- var classes = this.getBsClassSet();
-
- return this.transferPropsTo(
- React.DOM.span( {className:classSet(classes)},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Label;
-});
-
-define('ListGroup',['require','exports','module','react','./utils/classSet','./utils/cloneWithProps','./utils/ValidComponentChildren','./utils/createChainedFunction'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-var createChainedFunction = require('./utils/createChainedFunction');
-
-var ListGroup = React.createClass({displayName: 'ListGroup',
- propTypes: {
- onClick: React.PropTypes.func
- },
-
- render: function () {
- return (
- React.DOM.div( {className:"list-group"},
- ValidComponentChildren.map(this.props.children, this.renderListItem)
- )
- );
- },
-
- renderListItem: function (child) {
- return cloneWithProps(child, {
- onClick: createChainedFunction(child.props.onClick, this.props.onClick),
- ref: child.props.ref,
- key: child.props.key
- });
- }
-});
-
-module.exports = ListGroup;
-
-});
-
-define('ListGroupItem',['require','exports','module','react','./BootstrapMixin','./utils/classSet','./utils/cloneWithProps','./utils/ValidComponentChildren'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var BootstrapMixin = require('./BootstrapMixin');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-
-var ListGroupItem = React.createClass({displayName: 'ListGroupItem',
- mixins: [BootstrapMixin],
-
- propTypes: {
- bsStyle: React.PropTypes.oneOf(['danger','info','success','warning']),
- active: React.PropTypes.any,
- disabled: React.PropTypes.any,
- header: React.PropTypes.renderable,
- onClick: React.PropTypes.func
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'list-group-item'
- };
- },
-
- render: function () {
- var classes = this.getBsClassSet();
-
- classes['active'] = this.props.active;
- classes['disabled'] = this.props.disabled;
-
- if (this.props.href || this.props.onClick) {
- return this.renderAnchor(classes);
- } else {
- return this.renderSpan(classes);
- }
- },
-
- renderSpan: function (classes) {
- return this.transferPropsTo(
- React.DOM.span( {className:classSet(classes)},
- this.props.header ? this.renderStructuredContent() : this.props.children
- )
- );
- },
-
- renderAnchor: function (classes) {
- return this.transferPropsTo(
- React.DOM.a(
- {className:classSet(classes),
- onClick:this.handleClick},
- this.props.header ? this.renderStructuredContent() : this.props.children
- )
- );
- },
-
- renderStructuredContent: function () {
- var header;
- if (React.isValidComponent(this.props.header)) {
- header = cloneWithProps(this.props.header, {
- className: 'list-group-item-heading'
- });
- } else {
- header = (
- React.DOM.h4( {className:"list-group-item-heading"},
- this.props.header
- )
- );
- }
-
- var content = (
- React.DOM.p( {className:"list-group-item-text"},
- this.props.children
- )
- );
-
- return {
- header: header,
- content: content
- };
- },
-
- handleClick: function (e) {
- if (this.props.onClick) {
- e.preventDefault();
- this.props.onClick(this.props.key, this.props.href);
- }
- }
-});
-
-module.exports = ListGroupItem;
-
-});
-
-define('MenuItem',['require','exports','module','react','./utils/classSet'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-
-var MenuItem = React.createClass({displayName: 'MenuItem',
- propTypes: {
- header: React.PropTypes.bool,
- divider: React.PropTypes.bool,
- href: React.PropTypes.string,
- title: React.PropTypes.string,
- onSelect: React.PropTypes.func
- },
-
- getDefaultProps: function () {
- return {
- href: '#'
- };
- },
-
- handleClick: function (e) {
- if (this.props.onSelect) {
- e.preventDefault();
- this.props.onSelect(this.props.key);
- }
- },
-
- renderAnchor: function () {
- return (
- React.DOM.a( {onClick:this.handleClick, href:this.props.href, title:this.props.title, tabIndex:"-1"},
- this.props.children
- )
- );
- },
-
- render: function () {
- var classes = {
- 'dropdown-header': this.props.header,
- 'divider': this.props.divider
- };
-
- var children = null;
- if (this.props.header) {
- children = this.props.children;
- } else if (!this.props.divider) {
- children = this.renderAnchor();
- }
-
- return this.transferPropsTo(
- React.DOM.li( {role:"presentation", title:null, href:null, className:classSet(classes)},
- children
- )
- );
- }
-});
-
-module.exports = MenuItem;
-});
-
-define('Modal',['require','exports','module','react','./utils/classSet','./BootstrapMixin','./FadeMixin','./utils/EventListener'],function (require, exports, module) {/** @jsx React.DOM */
-/* global document:false */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-var FadeMixin = require('./FadeMixin');
-var EventListener = require('./utils/EventListener');
-
-
-// TODO:
-// - aria-labelledby
-// - Add `modal-body` div if only one child passed in that doesn't already have it
-// - Tests
-
-var Modal = React.createClass({displayName: 'Modal',
- mixins: [BootstrapMixin, FadeMixin],
-
- propTypes: {
- title: React.PropTypes.renderable,
- backdrop: React.PropTypes.oneOf(['static', true, false]),
- keyboard: React.PropTypes.bool,
- closeButton: React.PropTypes.bool,
- animation: React.PropTypes.bool,
- onRequestHide: React.PropTypes.func.isRequired
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'modal',
- backdrop: true,
- keyboard: true,
- animation: true,
- closeButton: true
- };
- },
-
- render: function () {
- var modalStyle = {display: 'block'};
- var dialogClasses = this.getBsClassSet();
- delete dialogClasses.modal;
- dialogClasses['modal-dialog'] = true;
-
- var classes = {
- modal: true,
- fade: this.props.animation,
- 'in': !this.props.animation || !document.querySelectorAll
- };
-
- var modal = this.transferPropsTo(
- React.DOM.div(
- {title:null,
- tabIndex:"-1",
- role:"dialog",
- style:modalStyle,
- className:classSet(classes),
- onClick:this.props.backdrop === true ? this.handleBackdropClick : null,
- ref:"modal"},
- React.DOM.div( {className:classSet(dialogClasses)},
- React.DOM.div( {className:"modal-content"},
- this.props.title ? this.renderHeader() : null,
- this.props.children
- )
- )
- )
- );
-
- return this.props.backdrop ?
- this.renderBackdrop(modal) : modal;
- },
-
- renderBackdrop: function (modal) {
- var classes = {
- 'modal-backdrop': true,
- 'fade': this.props.animation
- };
-
- classes['in'] = !this.props.animation || !document.querySelectorAll;
-
- var onClick = this.props.backdrop === true ?
- this.handleBackdropClick : null;
-
- return (
- React.DOM.div(null,
- React.DOM.div( {className:classSet(classes), ref:"backdrop", onClick:onClick} ),
- modal
- )
- );
- },
-
- renderHeader: function () {
- var closeButton;
- if (this.props.closeButton) {
- closeButton = (
- React.DOM.button( {type:"button", className:"close", 'aria-hidden':"true", onClick:this.props.onRequestHide}, "×")
- );
- }
-
- return (
- React.DOM.div( {className:"modal-header"},
- closeButton,
- this.renderTitle()
- )
- );
- },
-
- renderTitle: function () {
- return (
- React.isValidComponent(this.props.title) ?
- this.props.title : React.DOM.h4( {className:"modal-title"}, this.props.title)
- );
- },
-
- iosClickHack: function () {
- // IOS only allows click events to be delegated to the document on elements
- // it considers 'clickable' - anchors, buttons, etc. We fake a click handler on the
- // DOM nodes themselves. Remove if handled by React: https://github.com/facebook/react/issues/1169
- this.refs.modal.getDOMNode().onclick = function () {};
- this.refs.backdrop.getDOMNode().onclick = function () {};
- },
-
- componentDidMount: function () {
- this._onDocumentKeyupListener =
- EventListener.listen(document, 'keyup', this.handleDocumentKeyUp);
-
- if (this.props.backdrop) {
- this.iosClickHack();
- }
- },
-
- componentDidUpdate: function (prevProps) {
- if (this.props.backdrop && this.props.backdrop !== prevProps.backdrop) {
- this.iosClickHack();
- }
- },
-
- componentWillUnmount: function () {
- this._onDocumentKeyupListener.remove();
- },
-
- handleBackdropClick: function (e) {
- if (e.target !== e.currentTarget) {
- return;
- }
-
- this.props.onRequestHide();
- },
-
- handleDocumentKeyUp: function (e) {
- if (this.props.keyboard && e.keyCode === 27) {
- this.props.onRequestHide();
- }
- }
-});
-
-module.exports = Modal;
-
-});
-
-define('Nav',['require','exports','module','react','./BootstrapMixin','./CollapsableMixin','./utils/classSet','./utils/domUtils','./utils/cloneWithProps','./utils/ValidComponentChildren','./utils/createChainedFunction'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var BootstrapMixin = require('./BootstrapMixin');
-var CollapsableMixin = require('./CollapsableMixin');
-var classSet = require('./utils/classSet');
-var domUtils = require('./utils/domUtils');
-var cloneWithProps = require('./utils/cloneWithProps');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-var createChainedFunction = require('./utils/createChainedFunction');
-
-
-var Nav = React.createClass({displayName: 'Nav',
- mixins: [BootstrapMixin, CollapsableMixin],
-
- propTypes: {
- bsStyle: React.PropTypes.oneOf(['tabs','pills']),
- stacked: React.PropTypes.bool,
- justified: React.PropTypes.bool,
- onSelect: React.PropTypes.func,
- collapsable: React.PropTypes.bool,
- expanded: React.PropTypes.bool,
- navbar: React.PropTypes.bool
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'nav'
- };
- },
-
- getCollapsableDOMNode: function () {
- return this.getDOMNode();
- },
-
- getCollapsableDimensionValue: function () {
- var node = this.refs.ul.getDOMNode(),
- height = node.offsetHeight,
- computedStyles = domUtils.getComputedStyles(node);
-
- return height + parseInt(computedStyles.marginTop, 10) + parseInt(computedStyles.marginBottom, 10);
- },
-
- render: function () {
- var classes = this.props.collapsable ? this.getCollapsableClassSet() : {};
-
- classes['navbar-collapse'] = this.props.collapsable;
-
- if (this.props.navbar && !this.props.collapsable) {
- return this.transferPropsTo(this.renderUl());
- }
-
- return this.transferPropsTo(
- React.DOM.nav( {className:classSet(classes)},
- this.renderUl()
- )
- );
- },
-
- renderUl: function () {
- var classes = this.getBsClassSet();
-
- classes['nav-stacked'] = this.props.stacked;
- classes['nav-justified'] = this.props.justified;
- classes['navbar-nav'] = this.props.navbar;
- classes['pull-right'] = this.props.pullRight;
-
- return (
- React.DOM.ul( {className:classSet(classes), ref:"ul"},
- ValidComponentChildren.map(this.props.children, this.renderNavItem)
- )
- );
- },
-
- getChildActiveProp: function (child) {
- if (child.props.active) {
- return true;
- }
- if (this.props.activeKey != null) {
- if (child.props.key === this.props.activeKey) {
- return true;
- }
- }
- if (this.props.activeHref != null) {
- if (child.props.href === this.props.activeHref) {
- return true;
- }
- }
-
- return child.props.active;
- },
-
- renderNavItem: function (child) {
- return cloneWithProps(
- child,
- {
- active: this.getChildActiveProp(child),
- activeKey: this.props.activeKey,
- activeHref: this.props.activeHref,
- onSelect: createChainedFunction(child.props.onSelect, this.props.onSelect),
- ref: child.props.ref,
- key: child.props.key,
- navItem: true
- }
- );
- }
-});
-
-module.exports = Nav;
-
-});
-
-define('Navbar',['require','exports','module','react','./BootstrapMixin','./utils/CustomPropTypes','./utils/classSet','./utils/cloneWithProps','./utils/ValidComponentChildren','./utils/createChainedFunction','./Nav'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var BootstrapMixin = require('./BootstrapMixin');
-var CustomPropTypes = require('./utils/CustomPropTypes');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-var createChainedFunction = require('./utils/createChainedFunction');
-var Nav = require('./Nav');
-
-
-var Navbar = React.createClass({displayName: 'Navbar',
- mixins: [BootstrapMixin],
-
- propTypes: {
- fixedTop: React.PropTypes.bool,
- fixedBottom: React.PropTypes.bool,
- staticTop: React.PropTypes.bool,
- inverse: React.PropTypes.bool,
- fluid: React.PropTypes.bool,
- role: React.PropTypes.string,
- componentClass: CustomPropTypes.componentClass.isRequired,
- brand: React.PropTypes.renderable,
- toggleButton: React.PropTypes.renderable,
- onToggle: React.PropTypes.func,
- navExpanded: React.PropTypes.bool,
- defaultNavExpanded: React.PropTypes.bool
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'navbar',
- bsStyle: 'default',
- role: 'navigation',
- componentClass: React.DOM.nav
- };
- },
-
- getInitialState: function () {
- return {
- navExpanded: this.props.defaultNavExpanded
- };
- },
-
- shouldComponentUpdate: function() {
- // Defer any updates to this component during the `onSelect` handler.
- return !this._isChanging;
- },
-
- handleToggle: function () {
- if (this.props.onToggle) {
- this._isChanging = true;
- this.props.onToggle();
- this._isChanging = false;
- }
-
- this.setState({
- navOpen: !this.state.navOpen
- });
- },
-
- isNavOpen: function () {
- return this.props.navOpen != null ? this.props.navOpen : this.state.navOpen;
- },
-
- render: function () {
- var classes = this.getBsClassSet();
- var componentClass = this.props.componentClass;
-
- classes['navbar-fixed-top'] = this.props.fixedTop;
- classes['navbar-fixed-bottom'] = this.props.fixedBottom;
- classes['navbar-static-top'] = this.props.staticTop;
- classes['navbar-inverse'] = this.props.inverse;
-
- return this.transferPropsTo(
- componentClass( {className:classSet(classes)},
- React.DOM.div( {className:this.props.fluid ? 'container-fluid' : 'container'},
- (this.props.brand || this.props.toggleButton || this.props.toggleNavKey) ? this.renderHeader() : null,
- ValidComponentChildren.map(this.props.children, this.renderChild)
- )
- )
- );
- },
-
- renderChild: function (child) {
- return cloneWithProps(child, {
- navbar: true,
- collapsable: this.props.toggleNavKey != null && this.props.toggleNavKey === child.props.key,
- expanded: this.props.toggleNavKey != null && this.props.toggleNavKey === child.props.key && this.isNavOpen(),
- key: child.props.key,
- ref: child.props.ref
- });
- },
-
- renderHeader: function () {
- var brand;
-
- if (this.props.brand) {
- brand = React.isValidComponent(this.props.brand) ?
- cloneWithProps(this.props.brand, {
- className: 'navbar-brand'
- }) : React.DOM.span( {className:"navbar-brand"}, this.props.brand);
- }
-
- return (
- React.DOM.div( {className:"navbar-header"},
- brand,
- (this.props.toggleButton || this.props.toggleNavKey != null) ? this.renderToggleButton() : null
- )
- );
- },
-
- renderToggleButton: function () {
- var children;
-
- if (React.isValidComponent(this.props.toggleButton)) {
- return cloneWithProps(this.props.toggleButton, {
- className: 'navbar-toggle',
- onClick: createChainedFunction(this.handleToggle, this.props.toggleButton.props.onClick)
- });
- }
-
- children = (this.props.toggleButton != null) ?
- this.props.toggleButton : [
- React.DOM.span( {className:"sr-only", key:0}, "Toggle navigation"),
- React.DOM.span( {className:"icon-bar", key:1}),
- React.DOM.span( {className:"icon-bar", key:2}),
- React.DOM.span( {className:"icon-bar", key:3})
- ];
-
- return (
- React.DOM.button( {className:"navbar-toggle", type:"button", onClick:this.handleToggle},
- children
- )
- );
- }
-});
-
-module.exports = Navbar;
-
-});
-
-define('NavItem',['require','exports','module','react','./utils/classSet','./BootstrapMixin'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-
-var NavItem = React.createClass({displayName: 'NavItem',
- mixins: [BootstrapMixin],
-
- propTypes: {
- onSelect: React.PropTypes.func,
- active: React.PropTypes.bool,
- disabled: React.PropTypes.bool,
- href: React.PropTypes.string,
- title: React.PropTypes.string
- },
-
- getDefaultProps: function () {
- return {
- href: '#'
- };
- },
-
- render: function () {
- var classes = {
- 'active': this.props.active,
- 'disabled': this.props.disabled
- };
-
- return this.transferPropsTo(
- React.DOM.li( {className:classSet(classes)},
- React.DOM.a(
- {href:this.props.href,
- title:this.props.title,
- onClick:this.handleClick,
- ref:"anchor"},
- this.props.children
- )
- )
- );
- },
-
- handleClick: function (e) {
- if (this.props.onSelect) {
- e.preventDefault();
-
- if (!this.props.disabled) {
- this.props.onSelect(this.props.key,this.props.href);
- }
- }
- }
-});
-
-module.exports = NavItem;
-});
-
-define('OverlayMixin',['require','exports','module','react','./utils/CustomPropTypes'],function (require, exports, module) {var React = require('react');
-var CustomPropTypes = require('./utils/CustomPropTypes');
-
-module.exports = {
- propTypes: {
- container: CustomPropTypes.mountable
- },
-
- getDefaultProps: function () {
- return {
- container: {
- // Provide `getDOMNode` fn mocking a React component API. The `document.body`
- // reference needs to be contained within this function so that it is not accessed
- // in environments where it would not be defined, e.g. nodejs. Equally this is needed
- // before the body is defined where `document.body === null`, this ensures
- // `document.body` is only accessed after componentDidMount.
- getDOMNode: function getDOMNode() {
- return document.body;
- }
- }
- };
- },
-
- componentWillUnmount: function () {
- this._unrenderOverlay();
- if (this._overlayTarget) {
- this.getContainerDOMNode()
- .removeChild(this._overlayTarget);
- this._overlayTarget = null;
- }
- },
-
- componentDidUpdate: function () {
- this._renderOverlay();
- },
-
- componentDidMount: function () {
- this._renderOverlay();
- },
-
- _mountOverlayTarget: function () {
- this._overlayTarget = document.createElement('div');
- this.getContainerDOMNode()
- .appendChild(this._overlayTarget);
- },
-
- _renderOverlay: function () {
- if (!this._overlayTarget) {
- this._mountOverlayTarget();
- }
-
- // Save reference to help testing
- this._overlayInstance = React.renderComponent(this.renderOverlay(), this._overlayTarget);
- },
-
- _unrenderOverlay: function () {
- React.unmountComponentAtNode(this._overlayTarget);
- this._overlayInstance = null;
- },
-
- getOverlayDOMNode: function () {
- if (!this.isMounted()) {
- throw new Error('getOverlayDOMNode(): A component must be mounted to have a DOM node.');
- }
-
- return this._overlayInstance.getDOMNode();
- },
-
- getContainerDOMNode: function () {
- return this.props.container.getDOMNode ?
- this.props.container.getDOMNode() : this.props.container;
- }
-};
-
-});
-
-define('ModalTrigger',['require','exports','module','react','./OverlayMixin','./utils/cloneWithProps','./utils/createChainedFunction'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var OverlayMixin = require('./OverlayMixin');
-var cloneWithProps = require('./utils/cloneWithProps');
-var createChainedFunction = require('./utils/createChainedFunction');
-
-var ModalTrigger = React.createClass({displayName: 'ModalTrigger',
- mixins: [OverlayMixin],
-
- propTypes: {
- modal: React.PropTypes.renderable.isRequired
- },
-
- getInitialState: function () {
- return {
- isOverlayShown: false
- };
- },
-
- show: function () {
- this.setState({
- isOverlayShown: true
- });
- },
-
- hide: function () {
- this.setState({
- isOverlayShown: false
- });
- },
-
- toggle: function () {
- this.setState({
- isOverlayShown: !this.state.isOverlayShown
- });
- },
-
- renderOverlay: function () {
- if (!this.state.isOverlayShown) {
- return React.DOM.span(null );
- }
-
- return cloneWithProps(
- this.props.modal,
- {
- onRequestHide: this.hide
- }
- );
- },
-
- render: function () {
- var child = React.Children.only(this.props.children);
- return cloneWithProps(
- child,
- {
- onClick: createChainedFunction(child.props.onClick, this.toggle)
- }
- );
- }
-});
-
-module.exports = ModalTrigger;
-});
-
-define('OverlayTrigger',['require','exports','module','react','./OverlayMixin','./utils/domUtils','./utils/cloneWithProps','./utils/createChainedFunction','./utils/merge'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var OverlayMixin = require('./OverlayMixin');
-var domUtils = require('./utils/domUtils');
-var cloneWithProps = require('./utils/cloneWithProps');
-var createChainedFunction = require('./utils/createChainedFunction');
-var merge = require('./utils/merge');
-
-/**
- * Check if value one is inside or equal to the of value
- *
- * @param {string} one
- * @param {string|array} of
- * @returns {boolean}
- */
-function isOneOf(one, of) {
- if (Array.isArray(of)) {
- return of.indexOf(one) >= 0;
- }
- return one === of;
-}
-
-var OverlayTrigger = React.createClass({displayName: 'OverlayTrigger',
- mixins: [OverlayMixin],
-
- propTypes: {
- trigger: React.PropTypes.oneOfType([
- React.PropTypes.oneOf(['manual', 'click', 'hover', 'focus']),
- React.PropTypes.arrayOf(React.PropTypes.oneOf(['click', 'hover', 'focus']))
- ]),
- placement: React.PropTypes.oneOf(['top','right', 'bottom', 'left']),
- delay: React.PropTypes.number,
- delayShow: React.PropTypes.number,
- delayHide: React.PropTypes.number,
- defaultOverlayShown: React.PropTypes.bool,
- overlay: React.PropTypes.renderable.isRequired
- },
-
- getDefaultProps: function () {
- return {
- placement: 'right',
- trigger: ['hover', 'focus']
- };
- },
-
- getInitialState: function () {
- return {
- isOverlayShown: this.props.defaultOverlayShown == null ?
- false : this.props.defaultOverlayShown,
- overlayLeft: null,
- overlayTop: null
- };
- },
-
- show: function () {
- this.setState({
- isOverlayShown: true
- }, function() {
- this.updateOverlayPosition();
- });
- },
-
- hide: function () {
- this.setState({
- isOverlayShown: false
- });
- },
-
- toggle: function () {
- this.state.isOverlayShown ?
- this.hide() : this.show();
- },
-
- renderOverlay: function () {
- if (!this.state.isOverlayShown) {
- return React.DOM.span(null );
- }
-
- return cloneWithProps(
- this.props.overlay,
- {
- onRequestHide: this.hide,
- placement: this.props.placement,
- positionLeft: this.state.overlayLeft,
- positionTop: this.state.overlayTop
- }
- );
- },
-
- render: function () {
- if (this.props.trigger === 'manual') {
- return React.Children.only(this.props.children);
- }
-
- var props = {};
-
- if (isOneOf('click', this.props.trigger)) {
- props.onClick = createChainedFunction(this.toggle, this.props.onClick);
- }
-
- if (isOneOf('hover', this.props.trigger)) {
- props.onMouseOver = createChainedFunction(this.handleDelayedShow, this.props.onMouseOver);
- props.onMouseOut = createChainedFunction(this.handleDelayedHide, this.props.onMouseOut);
- }
-
- if (isOneOf('focus', this.props.trigger)) {
- props.onFocus = createChainedFunction(this.handleDelayedShow, this.props.onFocus);
- props.onBlur = createChainedFunction(this.handleDelayedHide, this.props.onBlur);
- }
-
- return cloneWithProps(
- React.Children.only(this.props.children),
- props
- );
- },
-
- componentWillUnmount: function() {
- clearTimeout(this._hoverDelay);
- },
-
- handleDelayedShow: function () {
- if (this._hoverDelay != null) {
- clearTimeout(this._hoverDelay);
- this._hoverDelay = null;
- return;
- }
-
- var delay = this.props.delayShow != null ?
- this.props.delayShow : this.props.delay;
-
- if (!delay) {
- this.show();
- return;
- }
-
- this._hoverDelay = setTimeout(function() {
- this._hoverDelay = null;
- this.show();
- }.bind(this), delay);
- },
-
- handleDelayedHide: function () {
- if (this._hoverDelay != null) {
- clearTimeout(this._hoverDelay);
- this._hoverDelay = null;
- return;
- }
-
- var delay = this.props.delayHide != null ?
- this.props.delayHide : this.props.delay;
-
- if (!delay) {
- this.hide();
- return;
- }
-
- this._hoverDelay = setTimeout(function() {
- this._hoverDelay = null;
- this.hide();
- }.bind(this), delay);
- },
-
- updateOverlayPosition: function () {
- if (!this.isMounted()) {
- return;
- }
-
- var pos = this.calcOverlayPosition();
-
- this.setState({
- overlayLeft: pos.left,
- overlayTop: pos.top
- });
- },
-
- calcOverlayPosition: function () {
- var childOffset = this.getPosition();
-
- var overlayNode = this.getOverlayDOMNode();
- var overlayHeight = overlayNode.offsetHeight;
- var overlayWidth = overlayNode.offsetWidth;
-
- switch (this.props.placement) {
- case 'right':
- return {
- top: childOffset.top + childOffset.height / 2 - overlayHeight / 2,
- left: childOffset.left + childOffset.width
- };
- case 'left':
- return {
- top: childOffset.top + childOffset.height / 2 - overlayHeight / 2,
- left: childOffset.left - overlayWidth
- };
- case 'top':
- return {
- top: childOffset.top - overlayHeight,
- left: childOffset.left + childOffset.width / 2 - overlayWidth / 2
- };
- case 'bottom':
- return {
- top: childOffset.top + childOffset.height,
- left: childOffset.left + childOffset.width / 2 - overlayWidth / 2
- };
- default:
- throw new Error('calcOverlayPosition(): No such placement of "' + this.props.placement + '" found.');
- }
- },
-
- getPosition: function () {
- var node = this.getDOMNode();
- var container = this.getContainerDOMNode();
-
- var offset = container.tagName == 'BODY' ?
- domUtils.getOffset(node) : domUtils.getPosition(node, container);
-
- return merge(offset, {
- height: node.offsetHeight,
- width: node.offsetWidth
- });
- }
-});
-
-module.exports = OverlayTrigger;
-});
-
-define('PageHeader',['require','exports','module','react'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-
-var PageHeader = React.createClass({displayName: 'PageHeader',
-
- render: function () {
- return this.transferPropsTo(
- React.DOM.div( {className:"page-header"},
- React.DOM.h1(null, this.props.children)
- )
- );
- }
-});
-
-module.exports = PageHeader;
-});
-
-define('Panel',['require','exports','module','react','./utils/classSet','./utils/cloneWithProps','./BootstrapMixin','./CollapsableMixin'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var BootstrapMixin = require('./BootstrapMixin');
-var CollapsableMixin = require('./CollapsableMixin');
-
-var Panel = React.createClass({displayName: 'Panel',
- mixins: [BootstrapMixin, CollapsableMixin],
-
- propTypes: {
- onSelect: React.PropTypes.func,
- header: React.PropTypes.renderable,
- footer: React.PropTypes.renderable
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'panel',
- bsStyle: 'default'
- };
- },
-
- handleSelect: function (e) {
- if (this.props.onSelect) {
- this._isChanging = true;
- this.props.onSelect(this.props.key);
- this._isChanging = false;
- }
-
- e.preventDefault();
-
- this.setState({
- expanded: !this.state.expanded
- });
- },
-
- shouldComponentUpdate: function () {
- return !this._isChanging;
- },
-
- getCollapsableDimensionValue: function () {
- return this.refs.body.getDOMNode().offsetHeight;
- },
-
- getCollapsableDOMNode: function () {
- if (!this.isMounted() || !this.refs || !this.refs.panel) {
- return null;
- }
-
- return this.refs.panel.getDOMNode();
- },
-
- render: function () {
- var classes = this.getBsClassSet();
- classes['panel'] = true;
-
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(classes), id:this.props.collapsable ? null : this.props.id, onSelect:null},
- this.renderHeading(),
- this.props.collapsable ? this.renderCollapsableBody() : this.renderBody(),
- this.renderFooter()
- )
- );
- },
-
- renderCollapsableBody: function () {
- return (
- React.DOM.div( {className:classSet(this.getCollapsableClassSet('panel-collapse')), id:this.props.id, ref:"panel"},
- this.renderBody()
- )
- );
- },
-
- renderBody: function () {
- return (
- React.DOM.div( {className:"panel-body", ref:"body"},
- this.props.children
- )
- );
- },
-
- renderHeading: function () {
- var header = this.props.header;
-
- if (!header) {
- return null;
- }
-
- if (!React.isValidComponent(header) || Array.isArray(header)) {
- header = this.props.collapsable ?
- this.renderCollapsableTitle(header) : header;
- } else if (this.props.collapsable) {
- header = cloneWithProps(header, {
- className: 'panel-title',
- children: this.renderAnchor(header.props.children)
- });
- } else {
- header = cloneWithProps(header, {
- className: 'panel-title'
- });
- }
-
- return (
- React.DOM.div( {className:"panel-heading"},
- header
- )
- );
- },
-
- renderAnchor: function (header) {
- return (
- React.DOM.a(
- {href:'#' + (this.props.id || ''),
- className:this.isExpanded() ? null : 'collapsed',
- onClick:this.handleSelect},
- header
- )
- );
- },
-
- renderCollapsableTitle: function (header) {
- return (
- React.DOM.h4( {className:"panel-title"},
- this.renderAnchor(header)
- )
- );
- },
-
- renderFooter: function () {
- if (!this.props.footer) {
- return null;
- }
-
- return (
- React.DOM.div( {className:"panel-footer"},
- this.props.footer
- )
- );
- }
-});
-
-module.exports = Panel;
-});
-
-define('PageItem',['require','exports','module','react','./utils/classSet'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-
-var PageItem = React.createClass({displayName: 'PageItem',
-
- propTypes: {
- disabled: React.PropTypes.bool,
- previous: React.PropTypes.bool,
- next: React.PropTypes.bool,
- onSelect: React.PropTypes.func
- },
-
- getDefaultProps: function () {
- return {
- href: '#'
- };
- },
-
- render: function () {
- var classes = {
- 'disabled': this.props.disabled,
- 'previous': this.props.previous,
- 'next': this.props.next
- };
-
- return this.transferPropsTo(
- React.DOM.li(
- {className:classSet(classes)},
- React.DOM.a(
- {href:this.props.href,
- title:this.props.title,
- onClick:this.handleSelect,
- ref:"anchor"},
- this.props.children
- )
- )
- );
- },
-
- handleSelect: function (e) {
- if (this.props.onSelect) {
- e.preventDefault();
-
- if (!this.props.disabled) {
- this.props.onSelect(this.props.key, this.props.href);
- }
- }
- }
-});
-
-module.exports = PageItem;
-});
-
-define('Pager',['require','exports','module','react','./utils/cloneWithProps','./utils/ValidComponentChildren','./utils/createChainedFunction'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var cloneWithProps = require('./utils/cloneWithProps');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-var createChainedFunction = require('./utils/createChainedFunction');
-
-var Pager = React.createClass({displayName: 'Pager',
-
- propTypes: {
- onSelect: React.PropTypes.func
- },
-
- render: function () {
- return this.transferPropsTo(
- React.DOM.ul(
- {className:"pager"},
- ValidComponentChildren.map(this.props.children, this.renderPageItem)
- )
- );
- },
-
- renderPageItem: function (child) {
- return cloneWithProps(
- child,
- {
- onSelect: createChainedFunction(child.props.onSelect, this.props.onSelect),
- ref: child.props.ref,
- key: child.props.key
- }
- );
- }
-});
-
-module.exports = Pager;
-});
-
-define('Popover',['require','exports','module','react','./utils/classSet','./BootstrapMixin'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-
-
-var Popover = React.createClass({displayName: 'Popover',
- mixins: [BootstrapMixin],
-
- propTypes: {
- placement: React.PropTypes.oneOf(['top','right', 'bottom', 'left']),
- positionLeft: React.PropTypes.number,
- positionTop: React.PropTypes.number,
- arrowOffsetLeft: React.PropTypes.number,
- arrowOffsetTop: React.PropTypes.number,
- title: React.PropTypes.renderable
- },
-
- getDefaultProps: function () {
- return {
- placement: 'right'
- };
- },
-
- render: function () {
- var classes = {};
- classes['popover'] = true;
- classes[this.props.placement] = true;
- classes['in'] = this.props.positionLeft != null || this.props.positionTop != null;
-
- var style = {};
- style['left'] = this.props.positionLeft;
- style['top'] = this.props.positionTop;
- style['display'] = 'block';
-
- var arrowStyle = {};
- arrowStyle['left'] = this.props.arrowOffsetLeft;
- arrowStyle['top'] = this.props.arrowOffsetTop;
-
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(classes), style:style, title:null},
- React.DOM.div( {className:"arrow", style:arrowStyle} ),
- this.props.title ? this.renderTitle() : null,
- React.DOM.div( {className:"popover-content"},
- this.props.children
- )
- )
- );
- },
-
- renderTitle: function() {
- return (
- React.DOM.h3( {className:"popover-title"}, this.props.title)
- );
- }
-});
-
-module.exports = Popover;
-});
-
-define('ProgressBar',['require','exports','module','react','./Interpolate','./BootstrapMixin','./utils/classSet','./utils/cloneWithProps','./utils/ValidComponentChildren'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var Interpolate = require('./Interpolate');
-var BootstrapMixin = require('./BootstrapMixin');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-
-
-var ProgressBar = React.createClass({displayName: 'ProgressBar',
- propTypes: {
- min: React.PropTypes.number,
- now: React.PropTypes.number,
- max: React.PropTypes.number,
- label: React.PropTypes.renderable,
- srOnly: React.PropTypes.bool,
- striped: React.PropTypes.bool,
- active: React.PropTypes.bool
- },
-
- mixins: [BootstrapMixin],
-
- getDefaultProps: function () {
- return {
- bsClass: 'progress-bar',
- min: 0,
- max: 100
- };
- },
-
- getPercentage: function (now, min, max) {
- return Math.ceil((now - min) / (max - min) * 100);
- },
-
- render: function () {
- var classes = {
- progress: true
- };
-
- if (this.props.active) {
- classes['progress-striped'] = true;
- classes['active'] = true;
- } else if (this.props.striped) {
- classes['progress-striped'] = true;
- }
-
- if (!ValidComponentChildren.hasValidComponent(this.props.children)) {
- if (!this.props.isChild) {
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(classes)},
- this.renderProgressBar()
- )
- );
- } else {
- return this.transferPropsTo(
- this.renderProgressBar()
- );
- }
- } else {
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(classes)},
- ValidComponentChildren.map(this.props.children, this.renderChildBar)
- )
- );
- }
- },
-
- renderChildBar: function (child) {
- return cloneWithProps(child, {
- isChild: true,
- key: child.props.key,
- ref: child.props.ref
- });
- },
-
- renderProgressBar: function () {
- var percentage = this.getPercentage(
- this.props.now,
- this.props.min,
- this.props.max
- );
-
- var label;
-
- if (typeof this.props.label === "string") {
- label = this.renderLabel(percentage);
- } else if (this.props.label) {
- label = this.props.label;
- }
-
- if (this.props.srOnly) {
- label = this.renderScreenReaderOnlyLabel(label);
- }
-
- return (
- React.DOM.div( {className:classSet(this.getBsClassSet()), role:"progressbar",
- style:{width: percentage + '%'},
- 'aria-valuenow':this.props.now,
- 'aria-valuemin':this.props.min,
- 'aria-valuemax':this.props.max},
- label
- )
- );
- },
-
- renderLabel: function (percentage) {
- var InterpolateClass = this.props.interpolateClass || Interpolate;
-
- return (
- InterpolateClass(
- {now:this.props.now,
- min:this.props.min,
- max:this.props.max,
- percent:percentage,
- bsStyle:this.props.bsStyle},
- this.props.label
- )
- );
- },
-
- renderScreenReaderOnlyLabel: function (label) {
- return (
- React.DOM.span( {className:"sr-only"},
- label
- )
- );
- }
-});
-
-module.exports = ProgressBar;
-
-});
-
-define('Row',['require','exports','module','react','./utils/CustomPropTypes'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var CustomPropTypes = require('./utils/CustomPropTypes');
-
-
-var Row = React.createClass({displayName: 'Row',
- propTypes: {
- componentClass: CustomPropTypes.componentClass.isRequired
- },
-
- getDefaultProps: function () {
- return {
- componentClass: React.DOM.div
- };
- },
-
- render: function () {
- var componentClass = this.props.componentClass;
-
- return this.transferPropsTo(
- componentClass( {className:"row"},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Row;
-});
-
-define('SplitButton',['require','exports','module','react','./utils/classSet','./BootstrapMixin','./DropdownStateMixin','./Button','./ButtonGroup','./DropdownMenu'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-var DropdownStateMixin = require('./DropdownStateMixin');
-var Button = require('./Button');
-var ButtonGroup = require('./ButtonGroup');
-var DropdownMenu = require('./DropdownMenu');
-
-var SplitButton = React.createClass({displayName: 'SplitButton',
- mixins: [BootstrapMixin, DropdownStateMixin],
-
- propTypes: {
- pullRight: React.PropTypes.bool,
- title: React.PropTypes.renderable,
- href: React.PropTypes.string,
- dropdownTitle: React.PropTypes.renderable,
- onClick: React.PropTypes.func,
- onSelect: React.PropTypes.func,
- disabled: React.PropTypes.bool
- },
-
- getDefaultProps: function () {
- return {
- dropdownTitle: 'Toggle dropdown'
- };
- },
-
- render: function () {
- var groupClasses = {
- 'open': this.state.open,
- 'dropup': this.props.dropup
- };
-
- var button = this.transferPropsTo(
- Button(
- {ref:"button",
- onClick:this.handleButtonClick,
- title:null,
- id:null},
- this.props.title
- )
- );
-
- var dropdownButton = this.transferPropsTo(
- Button(
- {ref:"dropdownButton",
- className:"dropdown-toggle",
- onClick:this.handleDropdownClick,
- title:null,
- id:null},
- React.DOM.span( {className:"sr-only"}, this.props.dropdownTitle),
- React.DOM.span( {className:"caret"} )
- )
- );
-
- return (
- ButtonGroup(
- {bsSize:this.props.bsSize,
- className:classSet(groupClasses),
- id:this.props.id},
- button,
- dropdownButton,
- DropdownMenu(
- {ref:"menu",
- onSelect:this.handleOptionSelect,
- 'aria-labelledby':this.props.id,
- pullRight:this.props.pullRight},
- this.props.children
- )
- )
- );
- },
-
- handleButtonClick: function (e) {
- if (this.state.open) {
- this.setDropdownState(false);
- }
-
- if (this.props.onClick) {
- this.props.onClick(e);
- }
- },
-
- handleDropdownClick: function (e) {
- e.preventDefault();
-
- this.setDropdownState(!this.state.open);
- },
-
- handleOptionSelect: function (key) {
- if (this.props.onSelect) {
- this.props.onSelect(key);
- }
-
- this.setDropdownState(false);
- }
-});
-
-module.exports = SplitButton;
-
-});
-
-define('SubNav',['require','exports','module','react','./utils/classSet','./utils/cloneWithProps','./utils/ValidComponentChildren','./utils/createChainedFunction','./BootstrapMixin'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var cloneWithProps = require('./utils/cloneWithProps');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-var createChainedFunction = require('./utils/createChainedFunction');
-var BootstrapMixin = require('./BootstrapMixin');
-
-
-var SubNav = React.createClass({displayName: 'SubNav',
- mixins: [BootstrapMixin],
-
- propTypes: {
- onSelect: React.PropTypes.func,
- active: React.PropTypes.bool,
- disabled: React.PropTypes.bool,
- href: React.PropTypes.string,
- title: React.PropTypes.string,
- text: React.PropTypes.renderable
- },
-
- getDefaultProps: function () {
- return {
- bsClass: 'nav'
- };
- },
-
- handleClick: function (e) {
- if (this.props.onSelect) {
- e.preventDefault();
-
- if (!this.props.disabled) {
- this.props.onSelect(this.props.key, this.props.href);
- }
- }
- },
-
- isActive: function () {
- return this.isChildActive(this);
- },
-
- isChildActive: function (child) {
- if (child.props.active) {
- return true;
- }
-
- if (this.props.activeKey != null && this.props.activeKey === child.props.key) {
- return true;
- }
-
- if (this.props.activeHref != null && this.props.activeHref === child.props.href) {
- return true;
- }
-
- if (child.props.children) {
- var isActive = false;
-
- ValidComponentChildren.forEach(
- child.props.children,
- function (child) {
- if (this.isChildActive(child)) {
- isActive = true;
- }
- },
- this
- );
-
- return isActive;
- }
-
- return false;
- },
-
- getChildActiveProp: function (child) {
- if (child.props.active) {
- return true;
- }
- if (this.props.activeKey != null) {
- if (child.props.key === this.props.activeKey) {
- return true;
- }
- }
- if (this.props.activeHref != null) {
- if (child.props.href === this.props.activeHref) {
- return true;
- }
- }
-
- return child.props.active;
- },
-
- render: function () {
- var classes = {
- 'active': this.isActive(),
- 'disabled': this.props.disabled
- };
-
- return this.transferPropsTo(
- React.DOM.li( {className:classSet(classes)},
- React.DOM.a(
- {href:this.props.href,
- title:this.props.title,
- onClick:this.handleClick,
- ref:"anchor"},
- this.props.text
- ),
- React.DOM.ul( {className:"nav"},
- ValidComponentChildren.map(this.props.children, this.renderNavItem)
- )
- )
- );
- },
-
- renderNavItem: function (child) {
- return cloneWithProps(
- child,
- {
- active: this.getChildActiveProp(child),
- onSelect: createChainedFunction(child.props.onSelect, this.props.onSelect),
- ref: child.props.ref,
- key: child.props.key
- }
- );
- }
-});
-
-module.exports = SubNav;
-
-});
-
-define('TabbedArea',['require','exports','module','react','./BootstrapMixin','./utils/cloneWithProps','./utils/ValidComponentChildren','./Nav','./NavItem'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var BootstrapMixin = require('./BootstrapMixin');
-var cloneWithProps = require('./utils/cloneWithProps');
-var ValidComponentChildren = require('./utils/ValidComponentChildren');
-var Nav = require('./Nav');
-var NavItem = require('./NavItem');
-
-function getDefaultActiveKeyFromChildren(children) {
- var defaultActiveKey;
-
- ValidComponentChildren.forEach(children, function(child) {
- if (defaultActiveKey == null) {
- defaultActiveKey = child.props.key;
- }
- });
-
- return defaultActiveKey;
-}
-
-var TabbedArea = React.createClass({displayName: 'TabbedArea',
- mixins: [BootstrapMixin],
-
- propTypes: {
- bsStyle: React.PropTypes.oneOf(['tabs','pills']),
- animation: React.PropTypes.bool,
- onSelect: React.PropTypes.func
- },
-
- getDefaultProps: function () {
- return {
- bsStyle: "tabs",
- animation: true
- };
- },
-
- getInitialState: function () {
- var defaultActiveKey = this.props.defaultActiveKey != null ?
- this.props.defaultActiveKey : getDefaultActiveKeyFromChildren(this.props.children);
-
- // TODO: In __DEV__ mode warn via `console.warn` if no `defaultActiveKey` has
- // been set by this point, invalid children or missing key properties are likely the cause.
-
- return {
- activeKey: defaultActiveKey,
- previousActiveKey: null
- };
- },
-
- componentWillReceiveProps: function (nextProps) {
- if (nextProps.activeKey != null && nextProps.activeKey !== this.props.activeKey) {
- this.setState({
- previousActiveKey: this.props.activeKey
- });
- }
- },
-
- handlePaneAnimateOutEnd: function () {
- this.setState({
- previousActiveKey: null
- });
- },
-
- render: function () {
- var activeKey =
- this.props.activeKey != null ? this.props.activeKey : this.state.activeKey;
-
- function renderTabIfSet(child) {
- return child.props.tab != null ? this.renderTab(child) : null;
- }
-
- var nav = this.transferPropsTo(
- Nav( {activeKey:activeKey, onSelect:this.handleSelect, ref:"tabs"},
- ValidComponentChildren.map(this.props.children, renderTabIfSet, this)
- )
- );
-
- return (
- React.DOM.div(null,
- nav,
- React.DOM.div( {id:this.props.id, className:"tab-content", ref:"panes"},
- ValidComponentChildren.map(this.props.children, this.renderPane)
- )
- )
- );
- },
-
- getActiveKey: function () {
- return this.props.activeKey != null ? this.props.activeKey : this.state.activeKey;
- },
-
- renderPane: function (child) {
- var activeKey = this.getActiveKey();
-
- return cloneWithProps(
- child,
- {
- active: (child.props.key === activeKey &&
- (this.state.previousActiveKey == null || !this.props.animation)),
- ref: child.props.ref,
- key: child.props.key,
- animation: this.props.animation,
- onAnimateOutEnd: (this.state.previousActiveKey != null &&
- child.props.key === this.state.previousActiveKey) ? this.handlePaneAnimateOutEnd: null
- }
- );
- },
-
- renderTab: function (child) {
- var key = child.props.key;
- return (
- NavItem(
- {ref:'tab' + key,
- key:key},
- child.props.tab
- )
- );
- },
-
- shouldComponentUpdate: function() {
- // Defer any updates to this component during the `onSelect` handler.
- return !this._isChanging;
- },
-
- handleSelect: function (key) {
- if (this.props.onSelect) {
- this._isChanging = true;
- this.props.onSelect(key);
- this._isChanging = false;
- } else if (key !== this.getActiveKey()) {
- this.setState({
- activeKey: key,
- previousActiveKey: this.getActiveKey()
- });
- }
- }
-});
-
-module.exports = TabbedArea;
-});
-
-define('Table',['require','exports','module','react','./utils/classSet'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-
-var Table = React.createClass({displayName: 'Table',
- propTypes: {
- striped: React.PropTypes.bool,
- bordered: React.PropTypes.bool,
- condensed: React.PropTypes.bool,
- hover: React.PropTypes.bool,
- responsive: React.PropTypes.bool
- },
-
- render: function () {
- var classes = {
- 'table': true,
- 'table-striped': this.props.striped,
- 'table-bordered': this.props.bordered,
- 'table-condensed': this.props.condensed,
- 'table-hover': this.props.hover
- };
- var table = this.transferPropsTo(
- React.DOM.table( {className:classSet(classes)},
- this.props.children
- )
- );
-
- return this.props.responsive ? (
- React.DOM.div( {className:"table-responsive"},
- table
- )
- ) : table;
- }
-});
-
-module.exports = Table;
-});
-
-define('TabPane',['require','exports','module','react','./utils/classSet','./utils/TransitionEvents'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var TransitionEvents = require('./utils/TransitionEvents');
-
-var TabPane = React.createClass({displayName: 'TabPane',
- getDefaultProps: function () {
- return {
- animation: true
- };
- },
-
- getInitialState: function () {
- return {
- animateIn: false,
- animateOut: false
- };
- },
-
- componentWillReceiveProps: function (nextProps) {
- if (this.props.animation) {
- if (!this.state.animateIn && nextProps.active && !this.props.active) {
- this.setState({
- animateIn: true
- });
- } else if (!this.state.animateOut && !nextProps.active && this.props.active) {
- this.setState({
- animateOut: true
- });
- }
- }
- },
-
- componentDidUpdate: function () {
- if (this.state.animateIn) {
- setTimeout(this.startAnimateIn, 0);
- }
- if (this.state.animateOut) {
- TransitionEvents.addEndEventListener(
- this.getDOMNode(),
- this.stopAnimateOut
- );
- }
- },
-
- startAnimateIn: function () {
- if (this.isMounted()) {
- this.setState({
- animateIn: false
- });
- }
- },
-
- stopAnimateOut: function () {
- if (this.isMounted()) {
- this.setState({
- animateOut: false
- });
-
- if (typeof this.props.onAnimateOutEnd === 'function') {
- this.props.onAnimateOutEnd();
- }
- }
- },
-
- render: function () {
- var classes = {
- 'tab-pane': true,
- 'fade': true,
- 'active': this.props.active || this.state.animateOut,
- 'in': this.props.active && !this.state.animateIn
- };
-
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(classes)},
- this.props.children
- )
- );
- }
-});
-
-module.exports = TabPane;
-});
-
-define('Tooltip',['require','exports','module','react','./utils/classSet','./BootstrapMixin'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-
-
-var Tooltip = React.createClass({displayName: 'Tooltip',
- mixins: [BootstrapMixin],
-
- propTypes: {
- placement: React.PropTypes.oneOf(['top','right', 'bottom', 'left']),
- positionLeft: React.PropTypes.number,
- positionTop: React.PropTypes.number,
- arrowOffsetLeft: React.PropTypes.number,
- arrowOffsetTop: React.PropTypes.number
- },
-
- getDefaultProps: function () {
- return {
- placement: 'right'
- };
- },
-
- render: function () {
- var classes = {};
- classes['tooltip'] = true;
- classes[this.props.placement] = true;
- classes['in'] = this.props.positionLeft != null || this.props.positionTop != null;
-
- var style = {};
- style['left'] = this.props.positionLeft;
- style['top'] = this.props.positionTop;
-
- var arrowStyle = {};
- arrowStyle['left'] = this.props.arrowOffsetLeft;
- arrowStyle['top'] = this.props.arrowOffsetTop;
-
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(classes), style:style},
- React.DOM.div( {className:"tooltip-arrow", style:arrowStyle} ),
- React.DOM.div( {className:"tooltip-inner"},
- this.props.children
- )
- )
- );
- }
-});
-
-module.exports = Tooltip;
-});
-
-define('Well',['require','exports','module','react','./utils/classSet','./BootstrapMixin'],function (require, exports, module) {/** @jsx React.DOM */
-
-var React = require('react');
-var classSet = require('./utils/classSet');
-var BootstrapMixin = require('./BootstrapMixin');
-
-var Well = React.createClass({displayName: 'Well',
- mixins: [BootstrapMixin],
-
- getDefaultProps: function () {
- return {
- bsClass: 'well'
- };
- },
-
- render: function () {
- var classes = this.getBsClassSet();
-
- return this.transferPropsTo(
- React.DOM.div( {className:classSet(classes)},
- this.props.children
- )
- );
- }
-});
-
-module.exports = Well;
-});
-
-/*global define */
-
-define('react-bootstrap',['require','./Accordion','./Affix','./AffixMixin','./Alert','./BootstrapMixin','./Badge','./Button','./ButtonGroup','./ButtonToolbar','./Carousel','./CarouselItem','./Col','./CollapsableMixin','./DropdownButton','./DropdownMenu','./DropdownStateMixin','./FadeMixin','./Glyphicon','./Grid','./Input','./Interpolate','./Jumbotron','./Label','./ListGroup','./ListGroupItem','./MenuItem','./Modal','./Nav','./Navbar','./NavItem','./ModalTrigger','./OverlayTrigger','./OverlayMixin','./PageHeader','./Panel','./PanelGroup','./PageItem','./Pager','./Popover','./ProgressBar','./Row','./SplitButton','./SubNav','./TabbedArea','./Table','./TabPane','./Tooltip','./Well'],function (require) {
-
-
- return {
- Accordion: require('./Accordion'),
- Affix: require('./Affix'),
- AffixMixin: require('./AffixMixin'),
- Alert: require('./Alert'),
- BootstrapMixin: require('./BootstrapMixin'),
- Badge: require('./Badge'),
- Button: require('./Button'),
- ButtonGroup: require('./ButtonGroup'),
- ButtonToolbar: require('./ButtonToolbar'),
- Carousel: require('./Carousel'),
- CarouselItem: require('./CarouselItem'),
- Col: require('./Col'),
- CollapsableMixin: require('./CollapsableMixin'),
- DropdownButton: require('./DropdownButton'),
- DropdownMenu: require('./DropdownMenu'),
- DropdownStateMixin: require('./DropdownStateMixin'),
- FadeMixin: require('./FadeMixin'),
- Glyphicon: require('./Glyphicon'),
- Grid: require('./Grid'),
- Input: require('./Input'),
- Interpolate: require('./Interpolate'),
- Jumbotron: require('./Jumbotron'),
- Label: require('./Label'),
- ListGroup: require('./ListGroup'),
- ListGroupItem: require('./ListGroupItem'),
- MenuItem: require('./MenuItem'),
- Modal: require('./Modal'),
- Nav: require('./Nav'),
- Navbar: require('./Navbar'),
- NavItem: require('./NavItem'),
- ModalTrigger: require('./ModalTrigger'),
- OverlayTrigger: require('./OverlayTrigger'),
- OverlayMixin: require('./OverlayMixin'),
- PageHeader: require('./PageHeader'),
- Panel: require('./Panel'),
- PanelGroup: require('./PanelGroup'),
- PageItem: require('./PageItem'),
- Pager: require('./Pager'),
- Popover: require('./Popover'),
- ProgressBar: require('./ProgressBar'),
- Row: require('./Row'),
- SplitButton: require('./SplitButton'),
- SubNav: require('./SubNav'),
- TabbedArea: require('./TabbedArea'),
- Table: require('./Table'),
- TabPane: require('./TabPane'),
- Tooltip: require('./Tooltip'),
- Well: require('./Well')
- };
-});
-
- //Register in the values from the outer closure for common dependencies
- //as local almond modules
- define('react', function () {
- return React;
- });
-
- //Use almond's special top-level, synchronous require to trigger factory
- //functions, get the final module value, and export it as the public
- //value.
- return require('react-bootstrap');
-}));
diff --git a/web/src/vendor/react-router/react-router.js b/web/src/vendor/react-router/react-router.js
index e2836135..683ab14e 100644
--- a/web/src/vendor/react-router/react-router.js
+++ b/web/src/vendor/react-router/react-router.js
@@ -53,6 +53,21 @@ var ImitateBrowserBehavior = {
module.exports = ImitateBrowserBehavior;
},{"../actions/LocationActions":1}],3:[function(_dereq_,module,exports){
+/**
+ * A scroll behavior that always scrolls to the top of the page
+ * after a transition.
+ */
+var ScrollToTopBehavior = {
+
+ updateScrollPosition: function () {
+ window.scrollTo(0, 0);
+ }
+
+};
+
+module.exports = ScrollToTopBehavior;
+
+},{}],4:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
var FakeNode = _dereq_('../mixins/FakeNode');
var PropTypes = _dereq_('../utils/PropTypes');
@@ -79,7 +94,7 @@ var DefaultRoute = React.createClass({
module.exports = DefaultRoute;
-},{"../mixins/FakeNode":13,"../utils/PropTypes":21}],4:[function(_dereq_,module,exports){
+},{"../mixins/FakeNode":14,"../utils/PropTypes":23}],5:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
var classSet = _dereq_('react/lib/cx');
var assign = _dereq_('react/lib/Object.assign');
@@ -188,7 +203,7 @@ var Link = React.createClass({
module.exports = Link;
-},{"../mixins/Navigation":14,"../mixins/State":17,"react/lib/Object.assign":36,"react/lib/cx":37}],5:[function(_dereq_,module,exports){
+},{"../mixins/Navigation":15,"../mixins/State":18,"react/lib/Object.assign":38,"react/lib/cx":39}],6:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
var FakeNode = _dereq_('../mixins/FakeNode');
var PropTypes = _dereq_('../utils/PropTypes');
@@ -216,7 +231,7 @@ var NotFoundRoute = React.createClass({
module.exports = NotFoundRoute;
-},{"../mixins/FakeNode":13,"../utils/PropTypes":21}],6:[function(_dereq_,module,exports){
+},{"../mixins/FakeNode":14,"../utils/PropTypes":23}],7:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
var FakeNode = _dereq_('../mixins/FakeNode');
var PropTypes = _dereq_('../utils/PropTypes');
@@ -242,7 +257,7 @@ var Redirect = React.createClass({
module.exports = Redirect;
-},{"../mixins/FakeNode":13,"../utils/PropTypes":21}],7:[function(_dereq_,module,exports){
+},{"../mixins/FakeNode":14,"../utils/PropTypes":23}],8:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
var FakeNode = _dereq_('../mixins/FakeNode');
@@ -301,7 +316,7 @@ var Route = React.createClass({
module.exports = Route;
-},{"../mixins/FakeNode":13}],8:[function(_dereq_,module,exports){
+},{"../mixins/FakeNode":14}],9:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
/**
@@ -361,7 +376,7 @@ var RouteHandler = React.createClass({
module.exports = RouteHandler;
-},{}],9:[function(_dereq_,module,exports){
+},{}],10:[function(_dereq_,module,exports){
exports.DefaultRoute = _dereq_('./components/DefaultRoute');
exports.Link = _dereq_('./components/Link');
exports.NotFoundRoute = _dereq_('./components/NotFoundRoute');
@@ -373,13 +388,16 @@ exports.HashLocation = _dereq_('./locations/HashLocation');
exports.HistoryLocation = _dereq_('./locations/HistoryLocation');
exports.RefreshLocation = _dereq_('./locations/RefreshLocation');
+exports.ImitateBrowserBehavior = _dereq_('./behaviors/ImitateBrowserBehavior');
+exports.ScrollToTopBehavior = _dereq_('./behaviors/ScrollToTopBehavior');
+
exports.Navigation = _dereq_('./mixins/Navigation');
exports.State = _dereq_('./mixins/State');
exports.create = _dereq_('./utils/createRouter');
exports.run = _dereq_('./utils/runRouter');
-},{"./components/DefaultRoute":3,"./components/Link":4,"./components/NotFoundRoute":5,"./components/Redirect":6,"./components/Route":7,"./components/RouteHandler":8,"./locations/HashLocation":10,"./locations/HistoryLocation":11,"./locations/RefreshLocation":12,"./mixins/Navigation":14,"./mixins/State":17,"./utils/createRouter":24,"./utils/runRouter":28}],10:[function(_dereq_,module,exports){
+},{"./behaviors/ImitateBrowserBehavior":2,"./behaviors/ScrollToTopBehavior":3,"./components/DefaultRoute":4,"./components/Link":5,"./components/NotFoundRoute":6,"./components/Redirect":7,"./components/Route":8,"./components/RouteHandler":9,"./locations/HashLocation":11,"./locations/HistoryLocation":12,"./locations/RefreshLocation":13,"./mixins/Navigation":15,"./mixins/State":18,"./utils/createRouter":26,"./utils/runRouter":30}],11:[function(_dereq_,module,exports){
var invariant = _dereq_('react/lib/invariant');
var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
var LocationActions = _dereq_('../actions/LocationActions');
@@ -486,7 +504,7 @@ var HashLocation = {
module.exports = HashLocation;
-},{"../actions/LocationActions":1,"../utils/Path":19,"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39}],11:[function(_dereq_,module,exports){
+},{"../actions/LocationActions":1,"../utils/Path":21,"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41}],12:[function(_dereq_,module,exports){
var invariant = _dereq_('react/lib/invariant');
var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
var LocationActions = _dereq_('../actions/LocationActions');
@@ -569,7 +587,7 @@ var HistoryLocation = {
module.exports = HistoryLocation;
-},{"../actions/LocationActions":1,"../utils/Path":19,"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39}],12:[function(_dereq_,module,exports){
+},{"../actions/LocationActions":1,"../utils/Path":21,"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41}],13:[function(_dereq_,module,exports){
var HistoryLocation = _dereq_('./HistoryLocation');
var Path = _dereq_('../utils/Path');
@@ -602,7 +620,7 @@ var RefreshLocation = {
module.exports = RefreshLocation;
-},{"../utils/Path":19,"./HistoryLocation":11}],13:[function(_dereq_,module,exports){
+},{"../utils/Path":21,"./HistoryLocation":12}],14:[function(_dereq_,module,exports){
var invariant = _dereq_('react/lib/invariant');
var FakeNode = {
@@ -619,7 +637,7 @@ var FakeNode = {
module.exports = FakeNode;
-},{"react/lib/invariant":39}],14:[function(_dereq_,module,exports){
+},{"react/lib/invariant":41}],15:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
/**
@@ -693,7 +711,7 @@ var Navigation = {
module.exports = Navigation;
-},{}],15:[function(_dereq_,module,exports){
+},{}],16:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
/**
@@ -723,55 +741,83 @@ var NavigationContext = {
module.exports = NavigationContext;
-},{}],16:[function(_dereq_,module,exports){
+},{}],17:[function(_dereq_,module,exports){
var invariant = _dereq_('react/lib/invariant');
var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
var getWindowScrollPosition = _dereq_('../utils/getWindowScrollPosition');
+function shouldUpdateScroll(state, prevState) {
+ if (!prevState)
+ return true;
+
+ // Don't update scroll position when only the query has changed.
+ if (state.pathname === prevState.pathname)
+ return false;
+
+ var routes = state.routes;
+ var prevRoutes = prevState.routes;
+
+ var sharedAncestorRoutes = routes.filter(function (route) {
+ return prevRoutes.indexOf(route) !== -1;
+ });
+
+ return !sharedAncestorRoutes.some(function (route) {
+ return route.ignoreScrollBehavior;
+ });
+}
+
/**
* Provides the router with the ability to manage window scroll position
* according to its scroll behavior.
*/
var Scrolling = {
+ statics: {
+ /**
+ * Records curent scroll position as the last known position for the given URL path.
+ */
+ recordScrollPosition: function (path) {
+ if (!this.scrollHistory)
+ this.scrollHistory = {};
+
+ this.scrollHistory[path] = getWindowScrollPosition();
+ },
+
+ /**
+ * Returns the last known scroll position for the given URL path.
+ */
+ getScrollPosition: function (path) {
+ if (!this.scrollHistory)
+ this.scrollHistory = {};
+
+ return this.scrollHistory[path] || null;
+ }
+ },
+
componentWillMount: function () {
invariant(
this.getScrollBehavior() == null || canUseDOM,
'Cannot use scroll behavior without a DOM'
);
-
- this._scrollHistory = {};
},
componentDidMount: function () {
this._updateScroll();
},
- componentWillUpdate: function () {
- this._scrollHistory[this.state.path] = getWindowScrollPosition();
+ componentDidUpdate: function (prevProps, prevState) {
+ this._updateScroll(prevState);
},
- componentDidUpdate: function () {
- this._updateScroll();
- },
-
- componentWillUnmount: function () {
- delete this._scrollHistory;
- },
-
- /**
- * Returns the last known scroll position for the given URL path.
- */
- getScrollPosition: function (path) {
- return this._scrollHistory[path] || null;
- },
+ _updateScroll: function (prevState) {
+ if (!shouldUpdateScroll(this.state, prevState))
+ return;
- _updateScroll: function () {
var scrollBehavior = this.getScrollBehavior();
if (scrollBehavior)
scrollBehavior.updateScrollPosition(
- this.getScrollPosition(this.state.path),
+ this.constructor.getScrollPosition(this.state.path),
this.state.action
);
}
@@ -780,7 +826,7 @@ var Scrolling = {
module.exports = Scrolling;
-},{"../utils/getWindowScrollPosition":26,"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39}],17:[function(_dereq_,module,exports){
+},{"../utils/getWindowScrollPosition":28,"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41}],18:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
/**
@@ -806,6 +852,7 @@ var State = {
contextTypes: {
getCurrentPath: React.PropTypes.func.isRequired,
getCurrentRoutes: React.PropTypes.func.isRequired,
+ getCurrentPathname: React.PropTypes.func.isRequired,
getCurrentParams: React.PropTypes.func.isRequired,
getCurrentQuery: React.PropTypes.func.isRequired,
isActive: React.PropTypes.func.isRequired
@@ -826,6 +873,13 @@ var State = {
},
/**
+ * Returns the current URL path without the query string.
+ */
+ getPathname: function () {
+ return this.context.getCurrentPathname();
+ },
+
+ /**
* Returns an object of the URL params that are currently active.
*/
getParams: function () {
@@ -851,7 +905,7 @@ var State = {
module.exports = State;
-},{}],18:[function(_dereq_,module,exports){
+},{}],19:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
var assign = _dereq_('react/lib/Object.assign');
var Path = _dereq_('../utils/Path');
@@ -898,6 +952,13 @@ var StateContext = {
},
/**
+ * Returns the current URL path without the query string.
+ */
+ getCurrentPathname: function () {
+ return this.state.pathname;
+ },
+
+ /**
* Returns a read-only object of the currently active URL parameters.
*/
getCurrentParams: function () {
@@ -926,6 +987,7 @@ var StateContext = {
childContextTypes: {
getCurrentPath: React.PropTypes.func.isRequired,
getCurrentRoutes: React.PropTypes.func.isRequired,
+ getCurrentPathname: React.PropTypes.func.isRequired,
getCurrentParams: React.PropTypes.func.isRequired,
getCurrentQuery: React.PropTypes.func.isRequired,
isActive: React.PropTypes.func.isRequired
@@ -935,6 +997,7 @@ var StateContext = {
return {
getCurrentPath: this.getCurrentPath,
getCurrentRoutes: this.getCurrentRoutes,
+ getCurrentPathname: this.getCurrentPathname,
getCurrentParams: this.getCurrentParams,
getCurrentQuery: this.getCurrentQuery,
isActive: this.isActive
@@ -945,7 +1008,16 @@ var StateContext = {
module.exports = StateContext;
-},{"../utils/Path":19,"react/lib/Object.assign":36}],19:[function(_dereq_,module,exports){
+},{"../utils/Path":21,"react/lib/Object.assign":38}],20:[function(_dereq_,module,exports){
+/**
+ * Represents a cancellation caused by navigating away
+ * before the previous transition has fully resolved.
+ */
+function Cancellation() { }
+
+module.exports = Cancellation;
+
+},{}],21:[function(_dereq_,module,exports){
var invariant = _dereq_('react/lib/invariant');
var merge = _dereq_('qs/lib/utils').merge;
var qs = _dereq_('qs');
@@ -1125,7 +1197,7 @@ var Path = {
module.exports = Path;
-},{"qs":30,"qs/lib/utils":34,"react/lib/invariant":39}],20:[function(_dereq_,module,exports){
+},{"qs":32,"qs/lib/utils":36,"react/lib/invariant":41}],22:[function(_dereq_,module,exports){
var Promise = _dereq_('when/lib/Promise');
// TODO: Use process.env.NODE_ENV check + envify to enable
@@ -1133,7 +1205,7 @@ var Promise = _dereq_('when/lib/Promise');
module.exports = Promise;
-},{"when/lib/Promise":41}],21:[function(_dereq_,module,exports){
+},{"when/lib/Promise":43}],23:[function(_dereq_,module,exports){
var PropTypes = {
/**
@@ -1148,7 +1220,7 @@ var PropTypes = {
module.exports = PropTypes;
-},{}],22:[function(_dereq_,module,exports){
+},{}],24:[function(_dereq_,module,exports){
/**
* Encapsulates a redirect to the given route.
*/
@@ -1160,7 +1232,7 @@ function Redirect(to, params, query) {
module.exports = Redirect;
-},{}],23:[function(_dereq_,module,exports){
+},{}],25:[function(_dereq_,module,exports){
var assign = _dereq_('react/lib/Object.assign');
var reversedArray = _dereq_('./reversedArray');
var Redirect = _dereq_('./Redirect');
@@ -1261,6 +1333,11 @@ function Transition(path, retry) {
assign(Transition.prototype, {
abort: function (reason) {
+ if (this.isAborted) {
+ // First abort wins.
+ return;
+ }
+
this.abortReason = reason;
this.isAborted = true;
},
@@ -1285,13 +1362,14 @@ assign(Transition.prototype, {
module.exports = Transition;
-},{"./Promise":20,"./Redirect":22,"./reversedArray":27,"react/lib/Object.assign":36}],24:[function(_dereq_,module,exports){
+},{"./Promise":22,"./Redirect":24,"./reversedArray":29,"react/lib/Object.assign":38}],26:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
var warning = _dereq_('react/lib/warning');
var invariant = _dereq_('react/lib/invariant');
var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
var ImitateBrowserBehavior = _dereq_('../behaviors/ImitateBrowserBehavior');
var RouteHandler = _dereq_('../components/RouteHandler');
+var LocationActions = _dereq_('../actions/LocationActions');
var HashLocation = _dereq_('../locations/HashLocation');
var HistoryLocation = _dereq_('../locations/HistoryLocation');
var RefreshLocation = _dereq_('../locations/RefreshLocation');
@@ -1303,6 +1381,7 @@ var supportsHistory = _dereq_('./supportsHistory');
var Transition = _dereq_('./Transition');
var PropTypes = _dereq_('./PropTypes');
var Redirect = _dereq_('./Redirect');
+var Cancellation = _dereq_('./Cancellation');
var Path = _dereq_('./Path');
/**
@@ -1330,7 +1409,9 @@ function defaultAbortHandler(abortReason, location) {
if (typeof location === 'string')
throw new Error('Unhandled aborted transition! Reason: ' + abortReason);
- if (abortReason instanceof Redirect) {
+ if (abortReason instanceof Cancellation) {
+ return;
+ } else if (abortReason instanceof Redirect) {
location.replace(this.makePath(abortReason.to, abortReason.params, abortReason.query));
} else {
location.pop();
@@ -1428,6 +1509,7 @@ function createRouter(options) {
var onAbort = options.onAbort || defaultAbortHandler;
var state = {};
var nextState = {};
+ var pendingTransition = null;
function updateState() {
state = nextState;
@@ -1499,7 +1581,14 @@ function createRouter(options) {
'You cannot use transitionTo with a static location'
);
- location.push(this.makePath(to, params, query));
+ var path = this.makePath(to, params, query);
+
+ if (pendingTransition) {
+ // Replace so pending location does not stay in history.
+ location.replace(path);
+ } else {
+ location.push(path);
+ }
},
/**
@@ -1528,11 +1617,11 @@ function createRouter(options) {
},
/**
- * Performs a match of the given path against this router and returns an object with
- * the { path, routes, params, query } that match. Returns null if no match can be made.
+ * Performs a match of the given pathname against this router and returns an object
+ * with the { routes, params } that match. Returns null if no match can be made.
*/
- match: function (path) {
- return findMatch(Path.withoutQuery(path), routes, this.defaultRoute, this.notFoundRoute) || null;
+ match: function (pathname) {
+ return findMatch(pathname, routes, this.defaultRoute, this.notFoundRoute) || null;
},
/**
@@ -1552,10 +1641,22 @@ function createRouter(options) {
* hooks wait, the transition is fully synchronous.
*/
dispatch: function (path, action, callback) {
- if (state.path === path)
+ if (pendingTransition) {
+ pendingTransition.abort(new Cancellation);
+ pendingTransition = null;
+ }
+
+ var prevPath = state.path;
+ if (prevPath === path)
return; // Nothing to do!
- var match = this.match(path);
+ // Record the scroll position as early as possible to
+ // get it before browsers try update it automatically.
+ if (prevPath && action !== LocationActions.REPLACE)
+ this.recordScrollPosition(prevPath);
+
+ var pathname = Path.withoutQuery(path);
+ var match = this.match(pathname);
warning(
match != null,
@@ -1588,6 +1689,7 @@ function createRouter(options) {
}
var transition = new Transition(path, this.replaceWith.bind(this, path));
+ pendingTransition = transition;
transition.from(fromRoutes, components, function (error) {
if (error || transition.isAborted)
@@ -1599,6 +1701,7 @@ function createRouter(options) {
nextState.path = path;
nextState.action = action;
+ nextState.pathname = pathname;
nextState.routes = nextRoutes;
nextState.params = nextParams;
nextState.query = nextQuery;
@@ -1617,6 +1720,8 @@ function createRouter(options) {
*/
run: function (callback) {
function dispatchHandler(error, transition) {
+ pendingTransition = null;
+
if (error) {
onError.call(router, error);
} else if (transition.isAborted) {
@@ -1716,7 +1821,7 @@ function createRouter(options) {
module.exports = createRouter;
-},{"../behaviors/ImitateBrowserBehavior":2,"../components/RouteHandler":8,"../locations/HashLocation":10,"../locations/HistoryLocation":11,"../locations/RefreshLocation":12,"../mixins/NavigationContext":15,"../mixins/Scrolling":16,"../mixins/StateContext":18,"./Path":19,"./PropTypes":21,"./Redirect":22,"./Transition":23,"./createRoutesFromChildren":25,"./supportsHistory":29,"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39,"react/lib/warning":40}],25:[function(_dereq_,module,exports){
+},{"../actions/LocationActions":1,"../behaviors/ImitateBrowserBehavior":2,"../components/RouteHandler":9,"../locations/HashLocation":11,"../locations/HistoryLocation":12,"../locations/RefreshLocation":13,"../mixins/NavigationContext":16,"../mixins/Scrolling":17,"../mixins/StateContext":19,"./Cancellation":20,"./Path":21,"./PropTypes":23,"./Redirect":24,"./Transition":25,"./createRoutesFromChildren":27,"./supportsHistory":31,"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41,"react/lib/warning":42}],27:[function(_dereq_,module,exports){
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
var warning = _dereq_('react/lib/warning');
var invariant = _dereq_('react/lib/invariant');
@@ -1774,6 +1879,10 @@ function createRoute(element, parentRoute, namedRoutes) {
var route = { name: props.name };
+ if (props.ignoreScrollBehavior) {
+ route.ignoreScrollBehavior = true;
+ }
+
if (type === Redirect.type) {
route.handler = createRedirectHandler(props.to, props.params, props.query);
props.path = props.path || props.from || '*';
@@ -1878,7 +1987,7 @@ function createRoutesFromChildren(children, parentRoute, namedRoutes) {
module.exports = createRoutesFromChildren;
-},{"../components/DefaultRoute":3,"../components/NotFoundRoute":5,"../components/Redirect":6,"../components/Route":7,"./Path":19,"react/lib/invariant":39,"react/lib/warning":40}],26:[function(_dereq_,module,exports){
+},{"../components/DefaultRoute":4,"../components/NotFoundRoute":6,"../components/Redirect":7,"../components/Route":8,"./Path":21,"react/lib/invariant":41,"react/lib/warning":42}],28:[function(_dereq_,module,exports){
var invariant = _dereq_('react/lib/invariant');
var canUseDOM = _dereq_('react/lib/ExecutionEnvironment').canUseDOM;
@@ -1899,14 +2008,14 @@ function getWindowScrollPosition() {
module.exports = getWindowScrollPosition;
-},{"react/lib/ExecutionEnvironment":35,"react/lib/invariant":39}],27:[function(_dereq_,module,exports){
+},{"react/lib/ExecutionEnvironment":37,"react/lib/invariant":41}],29:[function(_dereq_,module,exports){
function reversedArray(array) {
return array.slice(0).reverse();
}
module.exports = reversedArray;
-},{}],28:[function(_dereq_,module,exports){
+},{}],30:[function(_dereq_,module,exports){
var createRouter = _dereq_('./createRouter');
/**
@@ -1956,7 +2065,7 @@ function runRouter(routes, location, callback) {
module.exports = runRouter;
-},{"./createRouter":24}],29:[function(_dereq_,module,exports){
+},{"./createRouter":26}],31:[function(_dereq_,module,exports){
function supportsHistory() {
/*! taken from modernizr
* https://github.com/Modernizr/Modernizr/blob/master/LICENSE
@@ -1974,10 +2083,10 @@ function supportsHistory() {
module.exports = supportsHistory;
-},{}],30:[function(_dereq_,module,exports){
+},{}],32:[function(_dereq_,module,exports){
module.exports = _dereq_('./lib');
-},{"./lib":31}],31:[function(_dereq_,module,exports){
+},{"./lib":33}],33:[function(_dereq_,module,exports){
// Load modules
var Stringify = _dereq_('./stringify');
@@ -1994,7 +2103,7 @@ module.exports = {
parse: Parse
};
-},{"./parse":32,"./stringify":33}],32:[function(_dereq_,module,exports){
+},{"./parse":34,"./stringify":35}],34:[function(_dereq_,module,exports){
// Load modules
var Utils = _dereq_('./utils');
@@ -2150,7 +2259,7 @@ module.exports = function (str, options) {
return Utils.compact(obj);
};
-},{"./utils":34}],33:[function(_dereq_,module,exports){
+},{"./utils":36}],35:[function(_dereq_,module,exports){
// Load modules
var Utils = _dereq_('./utils');
@@ -2210,7 +2319,7 @@ module.exports = function (obj, options) {
return keys.join(delimiter);
};
-},{"./utils":34}],34:[function(_dereq_,module,exports){
+},{"./utils":36}],36:[function(_dereq_,module,exports){
// Load modules
@@ -2351,7 +2460,7 @@ exports.isBuffer = function (obj) {
}
};
-},{}],35:[function(_dereq_,module,exports){
+},{}],37:[function(_dereq_,module,exports){
/**
* Copyright 2013-2014, Facebook, Inc.
* All rights reserved.
@@ -2396,7 +2505,7 @@ var ExecutionEnvironment = {
module.exports = ExecutionEnvironment;
-},{}],36:[function(_dereq_,module,exports){
+},{}],38:[function(_dereq_,module,exports){
/**
* Copyright 2014, Facebook, Inc.
* All rights reserved.
@@ -2443,7 +2552,7 @@ function assign(target, sources) {
module.exports = assign;
-},{}],37:[function(_dereq_,module,exports){
+},{}],39:[function(_dereq_,module,exports){
/**
* Copyright 2013-2014, Facebook, Inc.
* All rights reserved.
@@ -2482,7 +2591,7 @@ function cx(classNames) {
module.exports = cx;
-},{}],38:[function(_dereq_,module,exports){
+},{}],40:[function(_dereq_,module,exports){
/**
* Copyright 2013-2014, Facebook, Inc.
* All rights reserved.
@@ -2516,7 +2625,7 @@ emptyFunction.thatReturnsArgument = function(arg) { return arg; };
module.exports = emptyFunction;
-},{}],39:[function(_dereq_,module,exports){
+},{}],41:[function(_dereq_,module,exports){
/**
* Copyright 2013-2014, Facebook, Inc.
* All rights reserved.
@@ -2571,7 +2680,7 @@ var invariant = function(condition, format, a, b, c, d, e, f) {
module.exports = invariant;
-},{}],40:[function(_dereq_,module,exports){
+},{}],42:[function(_dereq_,module,exports){
/**
* Copyright 2014, Facebook, Inc.
* All rights reserved.
@@ -2614,7 +2723,7 @@ if ("production" !== "production") {
module.exports = warning;
-},{"./emptyFunction":38}],41:[function(_dereq_,module,exports){
+},{"./emptyFunction":40}],43:[function(_dereq_,module,exports){
/** @license MIT License (c) copyright 2010-2014 original author or authors */
/** @author Brian Cavalier */
/** @author John Hann */
@@ -2633,7 +2742,7 @@ define(function (_dereq_) {
});
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(_dereq_); });
-},{"./Scheduler":43,"./async":44,"./makePromise":45}],42:[function(_dereq_,module,exports){
+},{"./Scheduler":45,"./async":46,"./makePromise":47}],44:[function(_dereq_,module,exports){
/** @license MIT License (c) copyright 2010-2014 original author or authors */
/** @author Brian Cavalier */
/** @author John Hann */
@@ -2705,7 +2814,7 @@ define(function() {
});
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
-},{}],43:[function(_dereq_,module,exports){
+},{}],45:[function(_dereq_,module,exports){
/** @license MIT License (c) copyright 2010-2014 original author or authors */
/** @author Brian Cavalier */
/** @author John Hann */
@@ -2789,7 +2898,7 @@ define(function(_dereq_) {
});
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(_dereq_); }));
-},{"./Queue":42}],44:[function(_dereq_,module,exports){
+},{"./Queue":44}],46:[function(_dereq_,module,exports){
/** @license MIT License (c) copyright 2010-2014 original author or authors */
/** @author Brian Cavalier */
/** @author John Hann */
@@ -2862,7 +2971,7 @@ define(function(_dereq_) {
});
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(_dereq_); }));
-},{}],45:[function(_dereq_,module,exports){
+},{}],47:[function(_dereq_,module,exports){
/** @license MIT License (c) copyright 2010-2014 original author or authors */
/** @author Brian Cavalier */
/** @author John Hann */
@@ -3660,6 +3769,6 @@ define(function() {
});
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
-},{}]},{},[9])
-(9)
+},{}]},{},[10])
+(10)
}); \ No newline at end of file