diff options
Diffstat (limited to 'web/src')
-rw-r--r-- | web/src/flows.json | 2012 | ||||
-rw-r--r-- | web/src/js/actions.js | 35 | ||||
-rw-r--r-- | web/src/js/app.js | 7 | ||||
-rw-r--r-- | web/src/js/components/flowdetail.jsx.js | 2 | ||||
-rw-r--r-- | web/src/js/components/mainview.jsx.js | 2 | ||||
-rw-r--r-- | web/src/js/connection.js | 52 | ||||
-rw-r--r-- | web/src/js/stores/flowstore.js | 69 | ||||
-rw-r--r-- | web/src/vendor/bootstrap/bootstrap.css | 535 | ||||
-rw-r--r-- | web/src/vendor/bootstrap/bootstrap.js | 566 | ||||
-rw-r--r-- | web/src/vendor/bootstrap/glyphicons-halflings-regular.svg | 2 | ||||
-rw-r--r-- | web/src/vendor/qunit/qunit.css | 33 | ||||
-rw-r--r-- | web/src/vendor/qunit/qunit.js | 1364 | ||||
-rw-r--r-- | web/src/vendor/react-bootstrap/react-bootstrap.js | 5346 | ||||
-rw-r--r-- | web/src/vendor/react-router/react-router.js | 253 |
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="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" /> <glyph unicode="" 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 ? " " : " "; + return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " "; }, // 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, " " ); + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); } 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/> "; - } -}; - -// 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 /> "; } }; @@ -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> "; + result.innerHTML = "Running...<br /> "; } } @@ -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 |