From 6d92b18242174313101f49bf7c0b80f9bb802a60 Mon Sep 17 00:00:00 2001 From: reekypete Date: Mon, 24 Jul 2017 13:30:55 +1000 Subject: [PATCH 1/2] Closes #333 - Negative disability feedback --- index.html | 8 +++++++- js/app.js | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index e57188d..3393466 100644 --- a/index.html +++ b/index.html @@ -77,8 +77,14 @@

Find a school

Information subject to change; by using this, you agree to our terms of use.

- +

Information for specialist support

+ + +

I live at:

Please provide your home address* to see your local school:

diff --git a/js/app.js b/js/app.js index 2530759..0ba1966 100644 --- a/js/app.js +++ b/js/app.js @@ -274,6 +274,10 @@ app = app || {}; app.findByName(inputText); })); + $('#specialist-support-click').click(function(){ + $('#specialist-support-info').toggle() + }); + // $("#address").keyup(function (event) { // if (event.keyCode === 13) { // app.util.log("keyup on #address, fake clicking #button-search-address"); From 9c16ac86cbc1ac62dec2aaaca90a08f4a403be7b Mon Sep 17 00:00:00 2001 From: reekypete Date: Mon, 4 Sep 2017 15:13:31 +1000 Subject: [PATCH 2/2] # WARNING: head commit changed in the meantime More crlf griefs --- css/style.css | 1533 +++++++++++++++++++++-------------------- js/geo/MapControls.js | 884 ++++++++++++------------ js/util.js | 144 ++-- 3 files changed, 1282 insertions(+), 1279 deletions(-) diff --git a/css/style.css b/css/style.css index 5f1ace3..a022b80 100644 --- a/css/style.css +++ b/css/style.css @@ -1,765 +1,768 @@ -html, body { width: 100%; height: 100%; padding: 0; margin: 0; } -body { - background-color: #39acc9; - color: #3e3e3e; - font-family: 'Source Sans Pro', 'Proxima Nova', 'Helvetica Neue', Helvetica, 'Open Sans', Arial, sans-serif; - font-weight: normal; -} - -.header h3 { - color: #f7f6f6; - margin-top: 0.5em; - padding-bottom: 0; - font-size: 34px; -} -.sitename { - text-align: right; -} -.sitename, .results-list .btn, .results-footer-btn, footer { - text-shadow: 0 0 1px #375a63; - text-shadow: 0 0 1px rgb(55, 90, 99); -} -.org-logo img { - height: 48px; - vertical-align: baseline; -} - -.org-logo a:focus, -.results-footer-btn:focus, -.footer a:focus, -.school-details a:focus { - box-shadow: 0 0 10px white; /* stand out against blue page background */ -} - -.block-intro input, .block-address input, .block-support select { - font-weight: normal; -} -.container .jumbotron { background-color: #f7f6f6; border-radius: 0; margin-bottom: 25em; } -.btn { - border: none; - border-radius: 0; - background-color: rgb(215, 45, 108); - color: white; -} -.btn:active, .btn:focus, .btn:hover { - background-color: #39acc9; - color: white; -} -.btn:focus { - outline: 2px dashed white; -} -.btn.working { - background-color: grey; -} - -/* if you want a random button to have a material box shadow effect, add the .material class */ -/* -.btn.material { - box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); -} -.btn.material:hover, -.btn.material:focus -{ - box-shadow: 0 7px 14px rgba(0,0,0,0.25), 0 5px 5px rgba(0,0,0,0.22); -} -*/ - - - - - -.footer { margin-bottom: 1.5em; } -.footer p { color: #f7f6f6; } -.footer p:first-child { - max-width: 85ex; - /* prevent unreadably long sentences. - also prevents long 2nd sentence from looking funny compared to short 1st sentence in our footer. */ -} - -.footer .list-inline { - display: inline-block; /* keep in-line with mail icon */ -} -.footer .list-inline li:not(:first-child) { - padding-left: 0; /* padding provided by .dot below */ -} -.footer .list-inline .dot:before { - /* dot to separate list items */ - content: '\b7'; /* middle dot */ - padding-right: 5px; - color: #f7f6f6; -} -.footer .list-inline a { - padding: 0; -} - -.footer a { - color: #f7f6f6; - font-weight: bold; - padding: 0 0.2em; -} -.footer a:hover { text-decoration: none; border-bottom: 1px solid; } -.footer .fa-inverse { color: #76BFD1; } -.footer .fa-stack { color: #f7f6f6; } -.footer .icon { - position: relative; - float: right; - top: -5px; - margin-left: 0.3em; -} -.footer a.icon:hover { - border-bottom: none; -} - -a .fa { - -webkit-transition: all 0.33s ease; - -moz-transition: all 0.33s ease; - -ms-transition: all 0.33s ease; - -o-transition: all 0.33s ease; - transition: all 0.33s ease; -} - -a:hover .fa-circle { - color: #f7f6f6; -} -a:hover .fa-stack-1x, -a:focus .fa-stack-1x { - color: #375a63; /* use same as circle's text shadow for increased contrast */ - text-shadow: none; -} - -#map-container { - margin-top: 25em; -} - -.map-legend { - margin: 10px; -} - -.cartodb-map { width: 100%; height:100%; height: 500px; background: black; } - -.leaflet-control .active-filter { - background-color: rgb(57, 172, 201); -} - -.leaflet-control .active-filter:hover { - background-color: rgb(25, 155, 186); /* slightly darker blue */ -} - -.leaflet-control-zoom a:focus { - background: rgb(57, 172, 201); - border: 1px solid black; - color: white; -} - -.leaflet-control-attribution a:focus:not(:active), -.cartodb-logo a:focus:not(:active) img { - background: rgb(57, 172, 201); - outline: 1px dashed darkblue !important; - box-shadow: 0 7px 14px rgba(0, 0, 0, 0.25), 0 5px 5px rgba(0, 0, 0, 0.22); - padding: 1em; - color: white; - display: inline-block; - font-weight: bold; -} - -.cartodb-logo a:focus:not(:active) img { - padding: 0; -} - - a.popup-schoolname { - display: inline-block; - font-weight: bold; - } - a.popup-schoolname:focus { - outline: 1px dashed darkblue; - margin: -3px 0; - padding: 9px; - } - - /* prevent funny resize (from padding change) when activated (usually by mouse press) */ - a.popup-schoolname:focus:active { - outline: none; - padding: 0; - } - - a.popup-schoolname:focus + .popup-meta { - margin-top: 6px; - } - - -/* Results */ -#results-container { - margin-bottom: 50px; -} - -.results-list .btn { - width: 100%; - text-align: left; - margin-bottom: 0.5em; - padding: 1em; -} - - .results-list .btn span.school-type { - display: block; - /* buttons can contain phrasing content like (and not flow content like
), - but we want these spans to look like block elements */ - } - -.btn.school-option { - white-space: normal; /* override bootstrap .btn: allow long button names to break into multiple lines */ -} - -/* A quasi-radio button control with raised buttons inspired by Material Design. */ -/* Unlike a radio button set, you use Tab (vs left/rigth/up/down) to change focus - to the different buttons, and activating one of them changes view and then focus - will shift to selected entry on the map. - Hat tip to Andrea for coming up with the behavior / interaction between focused/hovered - buttons and the previously selected button. */ -.material-radio { - margin-bottom: 0.5em; -} - - .material-radio .btn { - transition: box-shadow 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); - color: #333; - text-shadow: none; - background-color: transparent; - margin-bottom: 0; - /* margin: 0: buttons squished adjectly so when hover leaves one it'll enter another, - preventing flash of .selected button */ - } - - .material-radio .btn:hover, - .material-radio .btn:focus, - .material-radio .btn.selected { - font-weight: bold; - color: white; - background: rgb(57, 172, 201); /* blue */ - } - .material-radio .btn.red:hover, - .material-radio .btn.red:focus, - .material-radio .btn.red.selected { - background: rgb(215, 45, 108); /* red */ - } - - - .material-radio .btn:hover, - .material-radio .btn:focus { - box-shadow: 0 7px 14px rgba(0, 0, 0, 0.25), 0 5px 5px rgba(0, 0, 0, 0.22); - } - .material-radio .btn:focus:not(:active) { - outline: 2px dashed white; - } - - /* .dimmer added w/ a bit of help from listview.js since CSS can't select backwards */ - /* general sibling ~ selector only goes forwards */ - /* .material-radio .btn:not(.selected):hover ~ .btn.selected.dimmer, */ - .material-radio .btn.dimmer { - text-shadow: 0 0 1px #3a3a3a; - background: rgb(154, 208, 213); /* ie8 non-RGBa fallback */ - background: rgba(57, 172, 201, 0.5); /* lighter blue */ - } - .material-radio .btn.dimmer.red { - background: rgb(233, 145, 167); /* ie8 non-RGBa fallback */ - background: rgba(215, 45, 108, 0.5); /* lighter red */ - } - -.results-list .school-distance { - float: right; - font-weight: lighter; -} -.jumbotron p { - font-weight: normal; -} - -.results-list .school-type { - font-size: small; - font-style: italic; - font-weight: lighter; -} - -@media (min-width: 980px) { /* desktop and up */ - .school-details-container { - margin-right: 0; - margin-left: 0; - } - .school-email a, .school-website a { - font-size: small; /* so it fits in one line */ - } -} - - -#school-info-container { - /* margin/padding cancel each other out intentionally - adjustment so that jumping here keeps part of the map in view */ - margin-top: -1em; - padding-top: 1em; -} - - -.school-info { - padding-bottom: 20px; - border-bottom: 6px solid rgb(62, 62, 62); - padding-right: 1.5em; - padding-left: 1.5em; - background: rgb(247, 246, 246); -} - -.school-info-intro { - color: rgb(112, 112, 112); - color: #707070; - margin-top: 0.25em; -} -.school-details .field-label { - color: rgb(189, 239, 252); /* based on background blue but lighter for readability */ - text-shadow: 0 0 1px #3e3e3e; - font-weight: bold; -} -.expandable-text .body { display:none; } - -a.readmore { - font-weight: bold; - text-decoration: none; - color: #717171; -} -.readmore span { - margin-left: 4px; -} -.readmore-arrow:before { - content: " \2192 "; /* → is -> is \2192 */ - border-bottom: none; - display: inline-block; -} -.readmore-text { - border-bottom: 1px dotted; -} -.readmore-text:hover { - border-bottom-style: solid; -} - -.school-description .field-label { - font-size: 25px; - color: rgb(215, 45, 108); - font-weight: bolder; -} - -ul.school-details { - list-style: none; - background: #696767; - color: white; - margin-top: 35px; - padding: 1em; - border-radius: 15px; - height: 100%; -} - -.school-details a { - color: white; - /* text-decoration: underline; */ - border-bottom: 1px dotted rgb(225, 225, 225); - padding: 0.1em; -} -.school-details a:hover { - border-bottom: 1px solid white; - text-decoration: none; -} - -.school-details .school-website, .school-details .school-enrollment, .school-details .school-oshc { - /* keeps similar info grouped together */ - margin-bottom: 0.5em; -} - -.school-details .school-address a { - margin-left: 0.5em; -} - -.jumbotron h1 { - font-weight: 200; -} -.school-details .school-support ul { - margin-left: 1em; - padding-left: 0; -} -.school-details .school-support li { - margin-left: 1em; -} - -.school-details li { - line-height: 1.75em; -} - -.school-details .fa { - margin-right: 0.5em; - color: #696767; -} -.school-details .fa-inverse { - color: white; -} - -.school-name { - font-size: 40px; - font-weight: bold; - color: rgb(215, 45, 108); - text-decoration: none; - padding-top: 0.5em; - margin-bottom: 0.5em; -} - -.school-name .icon { - height: 65px; - top: 12px; - position: relative; - margin-right: 5px; -} - -/* End results */ - -#type-selector { - height: 100%; - width: 100%; - margin: 5em auto; - /* background: rgb(214, 214, 231); */ - text-align: center; -} -#type-selector h2 { - margin-bottom: 1em; -} - -.block-address, .block-support { - display: none; -} - - -/* -------------------- Select Box Styles: stackoverflow.com Method */ -/* -------------------- Source: http://stackoverflow.com/a/5809186 */ -#soflow, .styled-select { - -webkit-appearance: button; - -moz-appearance: none; - border-radius: 2px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - background-image: url(http://i62.tinypic.com/15xvbd5.png), -webkit-linear-gradient(#FAFAFA, #F4F4F4 40%, #E5E5E5); - background-position: 97% center; - background-repeat: no-repeat; - border: 1px solid #AAA; - color: #555; - font-size: inherit; - margin: 20px 0; - overflow: hidden; - padding: 5px 30px 5px 2px; - text-overflow: ellipsis; - white-space: nowrap; - width: 300px; -} - - -.nearby-schools-control-toggle label { - margin-right: 3.75em; - padding-left: 0.25em; - width: 142px; -} -.nearby-schools-control { - background-color: #f8f8f8; - background-color: rgba(255, 255, 255, 0.85); - padding: 1em; - margin: 1em; -} -.nearby-schools-control .close { - width: 100%; - font-weight: bold; - color: black; - background: white; - background: rgba(152, 110, 110, 0); - border-top: 1px solid rgb(146, 146, 146); - padding-top: 0.25em; -} -.nearby-schools-control button.toggle-filters { - background: none; - border: 1px solid rgb(219, 219, 219); - border-radius: 15px; - color: rgb(90, 90, 90); - width: 2em; - height: 2em; -} -.nearby-schools-control button.toggle-filters:hover, -.nearby-schools-control button.toggle-filters:focus { - background: rgb(57, 172, 201); - color: white; -} -.nearby-schools-control button.toggle-filters:focus { - outline: none; - /* box-shadow for circular outline halo effect */ - box-shadow: 0 0 1px 1px white, 0 0 1px 2px rgb(91, 157, 217); - border: 1px solid black; -} - -.nearby-schools-control h1 { - font-size: 14px; - margin: 0; -} -.nearby-schools-control .school-filters label { - font-weight: normal; -} -.nearby-schools-control label[for=nearby-schools-type] { - display: none; -} -#nearby-schools-type { - width: 210px; - margin: 0.5em 0 1em; -} - -.nearby-schools-filter-explanation { - font-style: italic; - max-width: 16em; - margin-bottom: 0.5em; - margin-left: 10px; -} -.nearby-schools-filter-explanation:empty { - margin: 0; -} - -.nearby-schools-options { - margin-top: 0.5em; -} -.nearby-schools-feature legend, -.nearby-schools-options legend { - border-bottom: none; - margin-bottom: 0.5em; - font-size: 14px; -} -.nearby-schools-feature label, -.nearby-schools-options label { - font-weight: normal; -} - -.nearby-schools-control input { - margin: 0 3px 0.25em 0; -} - -/* input#nearby-girls */ -#nearby-girls { - margin-left:1em; -} - - -/* Provide for narrow nav + content sections */ -@media (min-width: 768px) { - .container { - width: 100%; - } - .header, .jumbotron, .footer, .school-info { - max-width: 730px; - margin-right: auto; - margin-left: auto; - } -} -.container { - padding-left: 0; - padding-right: 0; - margin-left: 0; - margin-right: 0; -} - -.leaflet-popup-content-wrapper { - background-color: #f8f8f8; /* fallback */ - /* give a little transparency so we don't totally hide other markers. */ - background-color: rgba(255, 255, 255, 0.9); -} - -.block-intro .btn.school-level { - margin-bottom: 0.5em; /* vertically separate buttons on narrow screens */ - width: 100%; -} -@media (min-width: 620px) { /* layout breaks below this point for two buttons side by side */ - .block-intro .btn.school-level { - width: 42%; /* Make school level buttons equal width */ - } - - .school-name-search { - margin-right: 2em; - margin-left: 2em; - } -} - -.school-level-definition { - font-size: 0.7em; -} - - -.results-footer { - display: none; /* hidden until we have results */ - margin: 50px auto; - max-width: 730px; - margin-top: 25px; -} - -.results-footer-btn .fa { - margin-right: 1em; -} - -@media (min-width: 768px) { - .results-footer-btn-column { - padding-right: 0; - } -} - -.results-footer-btn { - display: block; - padding: 2em; - border: 1px solid #64bcd2; /* fallback */ - border: 1px solid rgba(255, 255, 255, 0.19); - background-color: transparent; - width: 100%; -} - -.results-footer-btn:hover { - border: 1px solid white; - background-color: transparent; - text-decoration: none; -} -.results-footer-btn span { - border-bottom: 1px dotted; -} -.results-footer-btn:hover span { - border-bottom-style: solid; -} - -.jumbotron #or { - text-transform: uppercase; - font-weight: bold; - margin-top: 0; - font-size: 21px; -} -.jumbotron p { - font-size: 18px; - margin-bottom: 1em; -} -.jumbotron .lead { - margin-bottom: 1em; - margin-top: 1em; -} -.jumbotron .disclaimer { - margin-top: 24px; - margin-bottom: 0; -} - -.jumbotron .lesser-text { - font-size: 16px; - color: #3e3e3e; -} -.lesser-text a { - color: inherit; - font-weight: bold; - text-decoration: none; - border-bottom: 1px dotted; - padding: 0.25em; -} -.lesser-text a:hover { - border-bottom-style: solid; -} -.lesser-text a:focus { - outline: 1px dashed darkblue; - text-decoration: underline; - border: none; -} - - -@media only screen and (min-width: 980px) { - .school-name { - padding-left: 15px; /* to keep flush-left with column below */ - } -} - -@media only screen and (max-width: 320px) { - .sitename { - font-size: 18px; - padding-left: 0; - } - .org-logo img { - height: 22px; - } -} - -@media only screen and (max-width: 767px) { - - .school-description .field-label { /* About */ - font-size: 20px; - } - #school-info-container .school-name { - font-size: 30px; - } - #school-info-container .school-name .icon { - height: 50px; - } -} - -@media only screen and (min-device-width: 320px) and (max-device-width: 480px) { /* and (orientation : portrait) */ - .cartodb-map { - height: 310px; - } - .nearby-schools-control { - max-height: 310px; - overflow: auto; - overflow-x:hidden; - } - #nearby-schools-type { - margin-bottom: 0.25em; - } - .nearby-schools-feature legend, .nearby-schools-options legend { - margin-bottom: 0; - } - .leaflet-top .leaflet-control { - margin-top: 5px; - } - .leaflet-left .leaflet-control { - margin-left: 5px; - } - .leaflet-right .leaflet-control { - margin-right: 5px; - } -} - -/* When we programmatically set focus on things, - the thing should be the container of a focusable item, - so we don't actually want users to know we've focused on it. - This is just so we can focus on newly added target containers - in the app -- the tabbing equivalent of scrolling to the element - (because when we scroll down, the next tab element naturally might - still be above the elements newly in view). - - This should be low enough specificity that it doesn't accidently - disable an outline on things we really want to be outlined. -*/ -[tabindex="-1"] { - outline: none; -} - -/* prevent iphone from autozooming on form fields */ -/* http://stackoverflow.com/a/9039885/1024811 - http://stackoverflow.com/a/16255670/1024811 */ -.ios select:focus, -.ios textarea:focus, -.ios input:focus { - font-size: 16px; -} - - - -li.school-more-info { - margin-bottom: 1em; -} - -li.school-admin-info { - border-top: 1px solid white; - padding-top: 0.5em; -} - -li.school-admin-info div, li.school-admin-info span.field-label { - margin-left: 1em; -} - -.school-admin-info span.field-label { - font-weight: normal; -} -span.field-category { - font-weight: bold; -} +html, body { width: 100%; height: 100%; padding: 0; margin: 0; } +body { + background-color: #39acc9; + color: #3e3e3e; + font-family: 'Source Sans Pro', 'Proxima Nova', 'Helvetica Neue', Helvetica, 'Open Sans', Arial, sans-serif; + font-weight: normal; +} + +.header h3 { + color: #f7f6f6; + margin-top: 0.5em; + padding-bottom: 0; + font-size: 34px; +} +.sitename { + text-align: right; +} +.sitename, .results-list .btn, .results-footer-btn, footer { + text-shadow: 0 0 1px #375a63; + text-shadow: 0 0 1px rgb(55, 90, 99); +} +.org-logo img { + height: 48px; + vertical-align: baseline; +} + +.org-logo a:focus, +.results-footer-btn:focus, +.footer a:focus, +.school-details a:focus { + box-shadow: 0 0 10px white; /* stand out against blue page background */ +} + +.block-intro input, .block-address input, .block-support select { + font-weight: normal; +} +.container .jumbotron { background-color: #f7f6f6; border-radius: 0; margin-bottom: 25em; } +.btn { + border: none; + border-radius: 0; + background-color: rgb(215, 45, 108); + color: white; +} +.btn:active, .btn:focus, .btn:hover { + background-color: #39acc9; + color: white; +} +.btn:focus { + outline: 2px dashed white; +} +.btn.working { + background-color: grey; +} + +/* if you want a random button to have a material box shadow effect, add the .material class */ +/* +.btn.material { + box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); +} +.btn.material:hover, +.btn.material:focus +{ + box-shadow: 0 7px 14px rgba(0,0,0,0.25), 0 5px 5px rgba(0,0,0,0.22); +} +*/ + + + + + +.footer { margin-bottom: 1.5em; } +.footer p { color: #f7f6f6; } +.footer p:first-child { + max-width: 85ex; + /* prevent unreadably long sentences. + also prevents long 2nd sentence from looking funny compared to short 1st sentence in our footer. */ +} + +.footer .list-inline { + display: inline-block; /* keep in-line with mail icon */ +} +.footer .list-inline li:not(:first-child) { + padding-left: 0; /* padding provided by .dot below */ +} +.footer .list-inline .dot:before { + /* dot to separate list items */ + content: '\b7'; /* middle dot */ + padding-right: 5px; + color: #f7f6f6; +} +.footer .list-inline a { + padding: 0; +} + +.footer a { + color: #f7f6f6; + font-weight: bold; + padding: 0 0.2em; +} +.footer a:hover { text-decoration: none; border-bottom: 1px solid; } +.footer .fa-inverse { color: #76BFD1; } +.footer .fa-stack { color: #f7f6f6; } +.footer .icon { + position: relative; + float: right; + top: -5px; + margin-left: 0.3em; +} +.footer a.icon:hover { + border-bottom: none; +} + +a .fa { + -webkit-transition: all 0.33s ease; + -moz-transition: all 0.33s ease; + -ms-transition: all 0.33s ease; + -o-transition: all 0.33s ease; + transition: all 0.33s ease; +} + +a:hover .fa-circle { + color: #f7f6f6; +} +a:hover .fa-stack-1x, +a:focus .fa-stack-1x { + color: #375a63; /* use same as circle's text shadow for increased contrast */ + text-shadow: none; +} + +#map-container { + margin-top: 25em; +} + +.map-legend { + margin: 10px; +} + +.cartodb-map { width: 100%; height:100%; height: 500px; background: black; } + +.leaflet-control .active-filter { + background-color: rgb(57, 172, 201); +} + +.leaflet-control .active-filter:hover { + background-color: rgb(25, 155, 186); /* slightly darker blue */ +} + +.leaflet-control-zoom a:focus { + background: rgb(57, 172, 201); + border: 1px solid black; + color: white; +} + +.leaflet-control-attribution a:focus:not(:active), +.cartodb-logo a:focus:not(:active) img { + background: rgb(57, 172, 201); + outline: 1px dashed darkblue !important; + box-shadow: 0 7px 14px rgba(0, 0, 0, 0.25), 0 5px 5px rgba(0, 0, 0, 0.22); + padding: 1em; + color: white; + display: inline-block; + font-weight: bold; +} + +.cartodb-logo a:focus:not(:active) img { + padding: 0; +} + + a.popup-schoolname { + display: inline-block; + font-weight: bold; + } + a.popup-schoolname:focus { + outline: 1px dashed darkblue; + margin: -3px 0; + padding: 9px; + } + + /* prevent funny resize (from padding change) when activated (usually by mouse press) */ + a.popup-schoolname:focus:active { + outline: none; + padding: 0; + } + + a.popup-schoolname:focus + .popup-meta { + margin-top: 6px; + } + + +/* Results */ +#results-container { + margin-bottom: 50px; +} + +.results-list .btn { + width: 100%; + text-align: left; + margin-bottom: 0.5em; + padding: 1em; +} + + .results-list .btn span.school-type { + display: block; + /* buttons can contain phrasing content like (and not flow content like
), + but we want these spans to look like block elements */ + } + +.btn.school-option { + white-space: normal; /* override bootstrap .btn: allow long button names to break into multiple lines */ +} + +/* A quasi-radio button control with raised buttons inspired by Material Design. */ +/* Unlike a radio button set, you use Tab (vs left/rigth/up/down) to change focus + to the different buttons, and activating one of them changes view and then focus + will shift to selected entry on the map. + Hat tip to Andrea for coming up with the behavior / interaction between focused/hovered + buttons and the previously selected button. */ +.material-radio { + margin-bottom: 0.5em; +} + + .material-radio .btn { + transition: box-shadow 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); + color: #333; + text-shadow: none; + background-color: transparent; + margin-bottom: 0; + /* margin: 0: buttons squished adjectly so when hover leaves one it'll enter another, + preventing flash of .selected button */ + } + + .material-radio .btn:hover, + .material-radio .btn:focus, + .material-radio .btn.selected { + font-weight: bold; + color: white; + background: rgb(57, 172, 201); /* blue */ + } + .material-radio .btn.red:hover, + .material-radio .btn.red:focus, + .material-radio .btn.red.selected { + background: rgb(215, 45, 108); /* red */ + } + + + .material-radio .btn:hover, + .material-radio .btn:focus { + box-shadow: 0 7px 14px rgba(0, 0, 0, 0.25), 0 5px 5px rgba(0, 0, 0, 0.22); + } + .material-radio .btn:focus:not(:active) { + outline: 2px dashed white; + } + + /* .dimmer added w/ a bit of help from listview.js since CSS can't select backwards */ + /* general sibling ~ selector only goes forwards */ + /* .material-radio .btn:not(.selected):hover ~ .btn.selected.dimmer, */ + .material-radio .btn.dimmer { + text-shadow: 0 0 1px #3a3a3a; + background: rgb(154, 208, 213); /* ie8 non-RGBa fallback */ + background: rgba(57, 172, 201, 0.5); /* lighter blue */ + } + .material-radio .btn.dimmer.red { + background: rgb(233, 145, 167); /* ie8 non-RGBa fallback */ + background: rgba(215, 45, 108, 0.5); /* lighter red */ + } + +.results-list .school-distance { + float: right; + font-weight: lighter; +} +.jumbotron p { + font-weight: normal; +} + +.results-list .school-type { + font-size: small; + font-style: italic; + font-weight: lighter; +} + +@media (min-width: 980px) { /* desktop and up */ + .school-details-container { + margin-right: 0; + margin-left: 0; + } + .school-email a, .school-website a { + font-size: small; /* so it fits in one line */ + } +} + + +#school-info-container { + /* margin/padding cancel each other out intentionally + adjustment so that jumping here keeps part of the map in view */ + margin-top: -1em; + padding-top: 1em; +} + + +.school-info { + padding-bottom: 20px; + border-bottom: 6px solid rgb(62, 62, 62); + padding-right: 1.5em; + padding-left: 1.5em; + background: rgb(247, 246, 246); +} + +.school-info-intro { + color: rgb(112, 112, 112); + color: #707070; + margin-top: 0.25em; +} +.school-details .field-label { + color: rgb(189, 239, 252); /* based on background blue but lighter for readability */ + text-shadow: 0 0 1px #3e3e3e; + font-weight: bold; +} +.expandable-text .body { display:none; } + +a.readmore { + font-weight: bold; + text-decoration: none; + color: #717171; +} +.readmore span { + margin-left: 4px; +} +.readmore-arrow:before { + content: " \2192 "; /* → is -> is \2192 */ + border-bottom: none; + display: inline-block; +} +.readmore-text { + border-bottom: 1px dotted; +} +.readmore-text:hover { + border-bottom-style: solid; +} + +.school-description .field-label { + font-size: 25px; + color: rgb(215, 45, 108); + font-weight: bolder; +} + +ul.school-details { + list-style: none; + background: #696767; + color: white; + margin-top: 35px; + padding: 1em; + border-radius: 15px; + height: 100%; +} + +.school-details a { + color: white; + /* text-decoration: underline; */ + border-bottom: 1px dotted rgb(225, 225, 225); + padding: 0.1em; +} +.school-details a:hover { + border-bottom: 1px solid white; + text-decoration: none; +} + +.school-details .school-website, .school-details .school-enrollment, .school-details .school-oshc { + /* keeps similar info grouped together */ + margin-bottom: 0.5em; +} + +.school-details .school-address a { + margin-left: 0.5em; +} + +.jumbotron h1 { + font-weight: 200; +} +.school-details .school-support ul { + margin-left: 1em; + padding-left: 0; +} +.school-details .school-support li { + margin-left: 1em; +} + +.school-details li { + line-height: 1.75em; +} + +.school-details .fa { + margin-right: 0.5em; + color: #696767; +} +.school-details .fa-inverse { + color: white; +} + +.school-name { + font-size: 40px; + font-weight: bold; + color: rgb(215, 45, 108); + text-decoration: none; + padding-top: 0.5em; + margin-bottom: 0.5em; +} + +.school-name .icon { + height: 65px; + top: 12px; + position: relative; + margin-right: 5px; +} + +/* End results */ + +#type-selector { + height: 100%; + width: 100%; + margin: 5em auto; + /* background: rgb(214, 214, 231); */ + text-align: center; +} +#type-selector h2 { + margin-bottom: 1em; +} + +.block-address, .block-support { + display: none; +} + + +/* -------------------- Select Box Styles: stackoverflow.com Method */ +/* -------------------- Source: http://stackoverflow.com/a/5809186 */ +#soflow, .styled-select { + -webkit-appearance: button; + -moz-appearance: none; + border-radius: 2px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + background-image: url(http://i62.tinypic.com/15xvbd5.png), -webkit-linear-gradient(#FAFAFA, #F4F4F4 40%, #E5E5E5); + background-position: 97% center; + background-repeat: no-repeat; + border: 1px solid #AAA; + color: #555; + font-size: inherit; + margin: 20px 0; + overflow: hidden; + padding: 5px 30px 5px 2px; + text-overflow: ellipsis; + white-space: nowrap; + width: 300px; +} + + +.nearby-schools-control-toggle label { + margin-right: 3.75em; + padding-left: 0.25em; + width: 142px; +} +.nearby-schools-control { + background-color: #696767;; + padding: 1em; + margin: 1em; + color: white; + opacity: 0.85; +} +.nearby-schools-control .close { + width: 100%; + font-weight: bold; + color: black; + background: white; + background: rgba(152, 110, 110, 0); + border-top: 1px solid rgb(146, 146, 146); + padding-top: 0.25em; +} +.nearby-schools-control button.toggle-filters { + background: none; + border: 1px solid rgb(219, 219, 219); + border-radius: 15px; +/* color: rgb(90, 90, 90); + */ color: white; + width: 2em; + height: 2em; +} +.nearby-schools-control button.toggle-filters:hover, +.nearby-schools-control button.toggle-filters:focus { + background: rgb(57, 172, 201); + color: white; +} +.nearby-schools-control button.toggle-filters:focus { + outline: none; + /* box-shadow for circular outline halo effect */ + box-shadow: 0 0 1px 1px white, 0 0 1px 2px rgb(91, 157, 217); + border: 1px solid black; +} + +.nearby-schools-control h1 { + font-size: 14px; + margin: 0; +} +.nearby-schools-control .school-filters label { + font-weight: normal; +} +.nearby-schools-control label[for=nearby-schools-type] { + display: none; +} +#nearby-schools-type { + width: 210px; + margin: 0.5em 0 1em; +} + +.nearby-schools-filter-explanation { + font-style: italic; + max-width: 16em; + margin-bottom: 0.5em; + margin-left: 10px; +} +.nearby-schools-filter-explanation:empty { + margin: 0; +} + +.nearby-schools-options { + margin-top: 0.5em; +} +.nearby-schools-feature legend, +.nearby-schools-options legend { + border-bottom: none; + margin-bottom: 0.5em; + font-size: 14px; + color: white; +} +.nearby-schools-feature label, +.nearby-schools-options label { + font-weight: normal; +} + +.nearby-schools-control input { + margin: 0 3px 0.25em 0; +} + +/* input#nearby-girls */ +#nearby-girls { + margin-left:1em; +} + + +/* Provide for narrow nav + content sections */ +@media (min-width: 768px) { + .container { + width: 100%; + } + .header, .jumbotron, .footer, .school-info { + max-width: 730px; + margin-right: auto; + margin-left: auto; + } +} +.container { + padding-left: 0; + padding-right: 0; + margin-left: 0; + margin-right: 0; +} + +.leaflet-popup-content-wrapper { + background-color: #f8f8f8; /* fallback */ + /* give a little transparency so we don't totally hide other markers. */ + background-color: rgba(255, 255, 255, 0.9); +} + +.block-intro .btn.school-level { + margin-bottom: 0.5em; /* vertically separate buttons on narrow screens */ + width: 100%; +} +@media (min-width: 620px) { /* layout breaks below this point for two buttons side by side */ + .block-intro .btn.school-level { + width: 42%; /* Make school level buttons equal width */ + } + + .school-name-search { + margin-right: 2em; + margin-left: 2em; + } +} + +.school-level-definition { + font-size: 0.7em; +} + + +.results-footer { + display: none; /* hidden until we have results */ + margin: 50px auto; + max-width: 730px; + margin-top: 25px; +} + +.results-footer-btn .fa { + margin-right: 1em; +} + +@media (min-width: 768px) { + .results-footer-btn-column { + padding-right: 0; + } +} + +.results-footer-btn { + display: block; + padding: 2em; + border: 1px solid #64bcd2; /* fallback */ + border: 1px solid rgba(255, 255, 255, 0.19); + background-color: transparent; + width: 100%; +} + +.results-footer-btn:hover { + border: 1px solid white; + background-color: transparent; + text-decoration: none; +} +.results-footer-btn span { + border-bottom: 1px dotted; +} +.results-footer-btn:hover span { + border-bottom-style: solid; +} + +.jumbotron #or { + text-transform: uppercase; + font-weight: bold; + margin-top: 0; + font-size: 21px; +} +.jumbotron p { + font-size: 18px; + margin-bottom: 1em; +} +.jumbotron .lead { + margin-bottom: 1em; + margin-top: 1em; +} +.jumbotron .disclaimer { + margin-top: 24px; + margin-bottom: 0; +} + +.jumbotron .lesser-text { + font-size: 16px; + color: #3e3e3e; +} +.lesser-text a { + color: inherit; + font-weight: bold; + text-decoration: none; + border-bottom: 1px dotted; + padding: 0.25em; +} +.lesser-text a:hover { + border-bottom-style: solid; +} +.lesser-text a:focus { + outline: 1px dashed darkblue; + text-decoration: underline; + border: none; +} + + +@media only screen and (min-width: 980px) { + .school-name { + padding-left: 15px; /* to keep flush-left with column below */ + } +} + +@media only screen and (max-width: 320px) { + .sitename { + font-size: 18px; + padding-left: 0; + } + .org-logo img { + height: 22px; + } +} + +@media only screen and (max-width: 767px) { + + .school-description .field-label { /* About */ + font-size: 20px; + } + #school-info-container .school-name { + font-size: 30px; + } + #school-info-container .school-name .icon { + height: 50px; + } +} + +@media only screen and (min-device-width: 320px) and (max-device-width: 480px) { /* and (orientation : portrait) */ + .cartodb-map { + height: 310px; + } + .nearby-schools-control { + max-height: 310px; + overflow: auto; + overflow-x:hidden; + } + #nearby-schools-type { + margin-bottom: 0.25em; + } + .nearby-schools-feature legend, .nearby-schools-options legend { + margin-bottom: 0; + } + .leaflet-top .leaflet-control { + margin-top: 5px; + } + .leaflet-left .leaflet-control { + margin-left: 5px; + } + .leaflet-right .leaflet-control { + margin-right: 5px; + } +} + +/* When we programmatically set focus on things, + the thing should be the container of a focusable item, + so we don't actually want users to know we've focused on it. + This is just so we can focus on newly added target containers + in the app -- the tabbing equivalent of scrolling to the element + (because when we scroll down, the next tab element naturally might + still be above the elements newly in view). + + This should be low enough specificity that it doesn't accidently + disable an outline on things we really want to be outlined. +*/ +[tabindex="-1"] { + outline: none; +} + +/* prevent iphone from autozooming on form fields */ +/* http://stackoverflow.com/a/9039885/1024811 + http://stackoverflow.com/a/16255670/1024811 */ +.ios select:focus, +.ios textarea:focus, +.ios input:focus { + font-size: 16px; +} + + + +li.school-more-info { + margin-bottom: 1em; +} + +li.school-admin-info { + border-top: 1px solid white; + padding-top: 0.5em; +} + +li.school-admin-info div, li.school-admin-info span.field-label { + margin-left: 1em; +} + +.school-admin-info span.field-label { + font-weight: normal; +} +span.field-category { + font-weight: bold; +} diff --git a/js/geo/MapControls.js b/js/geo/MapControls.js index 6a4800f..523246b 100644 --- a/js/geo/MapControls.js +++ b/js/geo/MapControls.js @@ -1,442 +1,442 @@ - -(function (app) { - - // Primary / Secondary (PS) levels key - var LegendPS = function () { - var legend = document.createElement('div'); - legend.className = 'map-legend'; - legend.innerHTML = '
' + - '
Intake areas:
' + - '    ' + - ' Primary

' + - '    ' + - ' Secondary' + - '
'; - return legend; - }; - - - // Filter Schools - var SchoolsFilter = function () { - var controlUI = document.createElement('div'); - controlUI.className = 'nearby-schools-control leaflet-bar'; - - controlUI.appendChild(this.nearbySchoolsHeaderControl()); - controlUI.appendChild(optionControl('checkbox', 'school-filters', 'all', 'nearby-schools-show', 'nearby-schools-show', 'Show nearby schools', false, onNearbySchoolsClick)); - controlUI.appendChild(this.schoolFiltersControl()); - - this.container = controlUI; - - // return controlUI; - }; - - - var filters = { - // all { - // label: "All", - // category: "General", - // // sql: 'select * from dec_schools' but also vary based on if support needed, - // }, - primary: { - label: 'Primary', - category: 'General', - type: 'primary', - features: [ - {label: 'Any', name: 'any', matchTest: function () { return true; }}, - {label: 'Outside School Hours Care', name: 'oshc', sql: 's.oshc = true', matchLabel: 'This school offers Outside School Hours Care.', mismatchLabel: 'Not offered: Outside School Hours Care.', matchTest: function (s) { return s.oshc; }}, - {label: 'Opportunity Classes', name: 'oc', sql: 's.opportunity_class = true', matchLabel: 'This school offers opportunity classes.', mismatchLabel: 'Not offered: opportunity classes.', matchTest: function (s) { return s.opportunity_class; }}, - {label: 'Distance Classes', name: 'distance', sql: "(distance_education IN ('C', 'S'))", matchLabel: 'This is a distance school.', mismatchLabel: 'Not a distance school.', matchTest: function (s) { return s.distance_education !== 'false'; }}, - ], - options: [ - {label: 'Include Infant (K-2)', name: 'infants', type: 'infants'}, - {label: 'Include Central/Community (K-12)', name: 'central', type: 'central'} - ], - }, - secondary: { - label: 'Secondary', - category: 'General', - type: 'secondary', - features: [ - {label: 'Any', name: 'any'}, - {label: 'Boys', name: 'boys', sql: "s.gender = 'boys'", matchLabel: 'This is a boys school.', mismatchLabel: 'Not a boys school.', matchTest: function (s) { return s.gender === 'boys'; }}, - {label: 'Girls', name: 'girls', sql: "s.gender = 'girls'", matchLabel: 'This is a girls school.', mismatchLabel: 'Not a girls school.', matchTest: function (s) { return s.gender === 'girls'; }}, - {label: 'Selective option', name: 'selective', sql: "s.selective_school IN ('Partially Selective', 'Fully Selective')", matchLabel: 'This school offers an academically selective option.', mismatchLabel: 'Not offered: academically selective option.', matchTest: function (s) { return s.selective_school === 'Partially Selective' || s.selective_school === 'Fully Selective'; }}, - {label: 'Intensive English option', name: 'intensive_english', sql: 's.intensive_english_centre ', matchLabel: 'This school has an Intensive English Centre.', mismatchLabel: 'Not offered: Intensive English Centre.', matchTest: function (s) { return s.intensive_english_centre == true; }}, - {label: 'Specialty option', name: 'specialty', sql: "school_specialty_type NOT IN ('Comprehensive')", matchLabel: 'This school offers specialized classes', mismatchLabel: 'Not offered: specialized classes.', matchTest: function (s) { return s.school_specialty_type !== 'Comprehensive'; }}, - {label: 'Distance Classes', name: 'distance', sql: "(distance_education IN ('C', 'S'))", matchLabel: 'This is a distance school.', mismatchLabel: 'Not a distance schoool', matchTest: function (s) { return s.distance_education !== false; }}, - ], - options: [ - {label: 'Include Central/Community (K-12)', name: 'central', type: 'central'} - ], - }, - supported: { - label: 'Schools with special support', - //sql = ??? ssp OR (do annoying join) - category: 'General', - features: [ - {label: 'Any', name: 'any'}, - {label: 'Schools for Specific Purposes'}, - {label: 'Schools with support classes'} - ], - }, - distance: { - label: 'Distance / Online', - category: 'Specific', - // sql: "s.distance_education != 'false'", - type: 'distance', - }, - // environmental: { - // label: "Environmental Centre", - // category: "Specific", - // type: "environmental", - // }, - k12: { - label: 'Central / Community (K-12)', - category: 'Specific', - type: 'central', - }, - infants: { - label: 'Infant (K-2)', - category: 'Specific', - type: 'infants', - }, - other: { - label: 'Other', - category: 'Specific', - type: 'other', - } - }; - - - // helpers independent of other SchoolFilter bits - - var nearbySchoolsFeature = function () { - var div = document.createElement('div'); - div.className = 'nearby-schools-feature'; - - div.appendChild(selectPrimaryFeature()); - - div.appendChild(selectSecondaryFeature()); - - return div; - }; - - var selectPrimaryFeature = function () { - var fieldset = document.createElement('fieldset'); - fieldset.className = 'primary'; - - var legend = document.createElement('legend'); - legend.innerHTML = 'With feature:'; - fieldset.appendChild(legend); - - fieldset.appendChild(optionControl('radio', 'feature', 'any', 'nearby-any', 'feature-primary', 'Any', (typeof app.state.nearby.filterFeatureForType[app.state.nearby.type] === 'undefined' || app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'any'), radioClick)); - fieldset.appendChild(optionControl('radio', 'feature', 'oshc', 'nearby-oshc', 'feature-primary', 'Outside School Hours Care', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'oshc': false, radioClick)); - fieldset.appendChild(optionControl('radio', 'feature', 'oc', 'nearby-oc', 'feature-primary', 'Opportunity Classes', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'oc': false, radioClick)); - - return fieldset; - }; - - var selectSecondaryFeature = function () { - - var fieldset = document.createElement('fieldset'); - fieldset.className = 'secondary'; - - var legend = document.createElement('legend'); - legend.innerHTML = 'With feature:'; - fieldset.appendChild(legend); - - fieldset.appendChild(optionControl('radio', 'feature', 'any', 'nearby-any2', 'feature-secondary', 'Any', (typeof app.state.nearby.filterFeatureForType[app.state.nearby.type] === 'undefined' || app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'any'), radioClick)); - var boysGirls = optionControl('radio', 'feature', 'boys', 'nearby-boys', 'feature-secondary', 'Boys', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'boys': false, radioClick); - boysGirls = optionControl('radio', 'feature', 'girls', 'nearby-girls', 'feature-secondary', 'Girls', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'girls': false, radioClick, boysGirls); - fieldset.appendChild(boysGirls); - fieldset.appendChild(optionControl('radio', 'feature', 'selective', 'nearby-selective', 'feature-secondary', 'Academically selective option', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'selective': false, radioClick)); - fieldset.appendChild(optionControl('radio', 'feature', 'intensive_english', 'nearby-intensive_english_centre', 'feature-secondary', 'Intensive English Centre', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'nearby-intensive_english_centre': false, radioClick)); - fieldset.appendChild(optionControl('radio', 'feature', 'specialty', 'nearby-specialty', 'feature-secondary', 'Specialty option', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'nearby-specialty': false, radioClick)); - - return fieldset; - }; - - var selectOption = function (value, text, selected) { - var option = document.createElement('option'); - option.value = value; - option.text = text; - option.selected = selected; - return option; - }; - - var optionsFeature = function () { - var div = document.createElement('div'); - div.className = 'nearby-schools-options'; - - var fieldset = document.createElement('fieldset'); - fieldset.className = 'primary secondary nearby-schools-options'; - - var legend = document.createElement('legend'); - legend.innerHTML = 'Options:'; - fieldset.appendChild(legend); - - fieldset.appendChild(optionControl('checkbox', 'option primary', 'infants', 'nearby-infants', 'nearby-infants', 'Include Infant (K-2)', app.state.nearby.othersForType[app.state.nearby.type] == 'infants', nearbyCheckboxClick)); - fieldset.appendChild(optionControl('checkbox', 'option primary secondary', 'central', 'nearby-central', 'nearby-central', 'Include Central/Community (K-12)', app.state.nearby.othersForType[app.state.nearby.type] == 'central', nearbyCheckboxClick)); - - div.appendChild(fieldset); - - return div; - }; - - var optionControl = function (type, className, value, id, name, labeltext, checked, onClick, parent) { - - var container; - if (parent) { - container = parent; - } else { - container = document.createElement('div'); - container.className = className; - } - - var control = document.createElement('input'); - control.checked = checked; - control.type = type; - control.value = value; - control.id = id; - control.name = name; - if (onClick) - control.addEventListener('click', onClick); - container.appendChild(control); - - var label = document.createElement('label'); - label.htmlFor = id; - label.innerHTML = labeltext; - container.appendChild(label); - - return container; - }; - - - - - var onNearbySchoolsClick = function () { - var userWantsNearbyShown = $(this).is(':checked'); //is checked now, meaning it was unchecked before click. - app.state.showNearby = userWantsNearbyShown; - app.mapView.loadNearby(); - }; - - var radioClick = function () { - var featureName = $(this).attr('value'); - app.util.log('doing stuff for feature: ' + featureName); - var type = app.state.nearby.type; - var feature = _.find(filters[type].features, function (feature) { - return feature.name === featureName; - }); - app.util.log(feature); - if (feature) { - app.state.nearby.filterFeatureForType[type] = feature; - } - app.mapView.updateResultsPopups(); - app.mapView.loadNearby(); - }; - - var nearbyCheckboxClick = function () { - var type = $(this).attr('value'); - var includeThis = $(this).is(':checked'); - var others = app.state.nearby.othersForType[app.state.nearby.type]; - - if (includeThis) { - app.state.nearby.othersForType[app.state.nearby.type] = _.union(others, type); - } else { // unchecked; remove this type - app.state.nearby.othersForType[app.state.nearby.type] = _.without(others, type); - } - - app.mapView.loadNearby(); - }; - - - - SchoolsFilter.prototype = { - - nearbySchoolsHeaderControl: function () { - var toggleUI = document.createElement('div'); - toggleUI.className = 'nearby-schools-control-toggle'; - - var labelUI = document.createElement('label'); - labelUI.htmlFor = 'nearby-schools-control-expand'; - labelUI.innerHTML = 'Nearby schools'; - toggleUI.appendChild(labelUI); - - var buttonUI = document.createElement('button'); - buttonUI.className = 'toggle-filters'; - buttonUI.title = 'Expand'; - - buttonUI.addEventListener('click', $.proxy(this.toggleFilterVisibility, this)); - buttonUI.id = 'nearby-schools-control-expand'; - - var spanUI = document.createElement('span'); - spanUI.setAttribute('aria-hidden', true); - - var iUI = document.createElement('i'); - iUI.className = 'fa fa-caret-left'; - spanUI.appendChild(iUI); - buttonUI.appendChild(spanUI); - toggleUI.appendChild(buttonUI); - - return toggleUI; - }, - - schoolFiltersControl: function () { - var div = document.createElement('div'); - div.className = 'school-filters'; - - div.appendChild(this.schoolTypeControl()); - div.appendChild(nearbySchoolsFeature()); - div.appendChild(optionsFeature()); - - return div; - }, - - schoolTypeControl: function () { - var label = document.createElement('label'); - label.htmlFor = 'nearby-schools-type'; - label.innerHTML = 'Type:'; - - var selectList = document.createElement('select'); - selectList.id = 'nearby-schools-type'; - selectList.className = 'styled-select type-filter'; - selectList.addEventListener('change', this.getNearbySchoolsFilterOnChange()); - - var optgroup = document.createElement('optgroup'); - optgroup.label = 'General:'; - selectList.appendChild(optgroup); - - selectList.appendChild(selectOption('all', 'All', app.state.nearby.type == 'all')); - selectList.appendChild(selectOption('primary', 'Primary', app.state.nearby.type == 'primary')); - selectList.appendChild(selectOption('secondary', 'Secondary', app.state.nearby.type == 'secondary')); - selectList.appendChild(selectOption('ssp', 'Schools for Specific Purposes', app.state.nearby.type == 'ssp')); - - optgroup = document.createElement('optgroup'); - optgroup.label = 'Specific:'; - selectList.appendChild(optgroup); - - selectList.appendChild(selectOption('distance', 'Distance / Online', app.state.nearby.type == 'distance')); - selectList.appendChild(selectOption('central', 'Central / Community (K-12)', app.state.nearby.type == 'central')); - selectList.appendChild(selectOption('infants', 'Infant (K-2)', app.state.nearby.type == 'infants')); - selectList.appendChild(selectOption('other', 'Other', app.state.nearby.type == 'other')); - - return selectList; - }, - - toggleFilterVisibility: function () { - app.state.nearby.showFilters = !app.state.nearby.showFilters; - if (app.state.showNearby == null) - app.state.showNearby = true; - if (app.state.showNearby) - app.mapView.loadNearby(); - $('#nearby-schools-show').prop('checked', app.state.showNearby); - this.update(); - }, - - getNearbySchoolsFilterOnChange: function () { - var that = this; - return function () { - var selected = $('option:selected', this); - if (selected.length > 0) { - var type = $('option:selected', this)[0].value; - app.util.log('Type selected: ' + type); - app.state.nearby.type = type; - - app.mapView.updateResultsPopups(); - that.updateFilterUI(); - that.updateFeaturesUI(); - that.updateOptionsUI(); - app.mapView.loadNearby(); - } - }; - }, - - update: function () { - var container = this.container; - - // setup initial UI state based on app state - $('#nearby-schools-type', container).val(app.state.nearby.type); - this.updateFilterUI(); - - var toggleFilterButton = $('button.toggle-filters', container)[0]; - var toggleFilterIcon = $('i', toggleFilterButton); - - if (app.state.nearby.showFilters) { - $('.school-filters', container).show(); - toggleFilterIcon.removeClass('fa-caret-left').addClass('fa-caret-down'); - toggleFilterButton.title = 'Collapse'; - toggleFilterButton.setAttribute('aria-label', toggleFilterButton.title); - } else { - $('.school-filters', container).hide(); - toggleFilterIcon.removeClass('fa-caret-down').addClass('fa-caret-left'); - toggleFilterButton.title = 'Expand'; - toggleFilterButton.setAttribute('aria-label', toggleFilterButton.title); - } - - this.updateFeaturesUI(); - this.updateOptionsUI(); - }, - - updateFilterUI: function () { - var container = this.container, - type = app.state.nearby.type; - - var support = app.util.support_description(); - var explanation = support && app.support_needed ? '(supporting ' + support + ')' : ''; // app.support_needed - $('.nearby-schools-filter-explanation', container).text(explanation); - - $(container).find('.nearby-schools-feature fieldset').hide(); - $(container).find('.nearby-schools-feature fieldset.' + type).show(); - - $(container).find('.nearby-schools-options fieldset').hide(); - $(container).find('.nearby-schools-options fieldset div').hide(); - - $(container).find('.nearby-schools-options fieldset.' + type).show(); - $(container).find('.nearby-schools-options fieldset div.' + type).show(); - }, - - updateFeaturesUI: function () { - var container = this.container, - type = app.state.nearby.type, - feature = app.state.nearby.filterFeatureForType[type]; - - if (!type || (type != 'primary' && type != 'secondary')) { - // only primary, secondary have any features to update; - // skip for other school types - return; - } - - // uncheck all for this type - $('.nearby-schools-feature input[name=feature-' + type + ']:radio', container).prop('checked',false); - - // check just the feature stored in app.state - // note that one radio button's `value` should matches the feature's `name`. - if (feature) { - $('.nearby-schools-feature input[name=feature-' + type +'][value=' + feature.name + ']:radio', container).prop('checked', true); - } - }, - - updateOptionsUI: function () { - var container = this.container, - type = app.state.nearby.type; - - if (app.state.nearby.othersForType[type]) { - var others = app.state.nearby.othersForType[type]; //others: things like infants, central - - $('.nearby-schools-options input:checkbox', container).prop('checked', false); // reset: uncheck everything - others.forEach(function (otherType) { - $('#nearby-' + otherType, container).prop('checked', true); - }); - } - }, - - - }; // end prototype definition - - - - // export our defined functions - app.M.MapLegendPS = LegendPS; - app.M.MapControlSchoolsFilter = SchoolsFilter; - -}(app)); + +(function (app) { + + // Primary / Secondary (PS) levels key + var LegendPS = function () { + var legend = document.createElement('div'); + legend.className = 'map-legend'; + legend.innerHTML = '
' + + '
Intake areas:
' + + '    ' + + ' Primary

' + + '    ' + + ' Secondary' + + '
'; + return legend; + }; + + + // Filter Schools + var SchoolsFilter = function () { + var controlUI = document.createElement('div'); + controlUI.className = 'nearby-schools-control leaflet-bar'; + + controlUI.appendChild(this.nearbySchoolsHeaderControl()); + controlUI.appendChild(optionControl('checkbox', 'school-filters', 'all', 'nearby-schools-show', 'nearby-schools-show', 'Show nearby schools', false, onNearbySchoolsClick)); + controlUI.appendChild(this.schoolFiltersControl()); + + this.container = controlUI; + + // return controlUI; + }; + + + var filters = { + // all { + // label: "All", + // category: "General", + // // sql: 'select * from dec_schools' but also vary based on if support needed, + // }, + primary: { + label: 'Primary', + category: 'General', + type: 'primary', + features: [ + {label: 'Any', name: 'any', matchTest: function () { return true; }}, + {label: 'Outside School Hours Care', name: 'oshc', sql: 's.oshc = true', matchLabel: 'This school offers Outside School Hours Care.', mismatchLabel: 'Not offered: Outside School Hours Care.', matchTest: function (s) { return s.oshc; }}, + {label: 'Opportunity Classes', name: 'oc', sql: 's.opportunity_class = true', matchLabel: 'This school offers opportunity classes.', mismatchLabel: 'Not offered: opportunity classes.', matchTest: function (s) { return s.opportunity_class; }}, + {label: 'Distance Classes', name: 'distance', sql: "(distance_education IN ('C', 'S'))", matchLabel: 'This is a distance school.', mismatchLabel: 'Not a distance school.', matchTest: function (s) { return s.distance_education !== 'false'; }}, + ], + options: [ + {label: 'Include Infant (K-2)', name: 'infants', type: 'infants'}, + {label: 'Include Central/Community (K-12)', name: 'central', type: 'central'} + ], + }, + secondary: { + label: 'Secondary', + category: 'General', + type: 'secondary', + features: [ + {label: 'Any', name: 'any'}, + {label: 'Boys', name: 'boys', sql: "s.gender = 'boys'", matchLabel: 'This is a boys school.', mismatchLabel: 'Not a boys school.', matchTest: function (s) { return s.gender === 'boys'; }}, + {label: 'Girls', name: 'girls', sql: "s.gender = 'girls'", matchLabel: 'This is a girls school.', mismatchLabel: 'Not a girls school.', matchTest: function (s) { return s.gender === 'girls'; }}, + {label: 'Selective option', name: 'selective', sql: "s.selective_school IN ('Partially Selective', 'Fully Selective')", matchLabel: 'This school offers an academically selective option.', mismatchLabel: 'Not offered: academically selective option.', matchTest: function (s) { return s.selective_school === 'Partially Selective' || s.selective_school === 'Fully Selective'; }}, + {label: 'Intensive English option', name: 'intensive_english', sql: 's.intensive_english_centre ', matchLabel: 'This school has an Intensive English Centre.', mismatchLabel: 'Not offered: Intensive English Centre.', matchTest: function (s) { return s.intensive_english_centre == true; }}, + {label: 'Specialty option', name: 'specialty', sql: "school_specialty_type NOT IN ('Comprehensive')", matchLabel: 'This school offers specialized classes', mismatchLabel: 'Not offered: specialized classes.', matchTest: function (s) { return s.school_specialty_type !== 'Comprehensive'; }}, + {label: 'Distance Classes', name: 'distance', sql: "(distance_education IN ('C', 'S'))", matchLabel: 'This is a distance school.', mismatchLabel: 'Not a distance schoool', matchTest: function (s) { return s.distance_education !== false; }}, + ], + options: [ + {label: 'Include Central/Community (K-12)', name: 'central', type: 'central'} + ], + }, + supported: { + label: 'Schools with special support', + //sql = ??? ssp OR (do annoying join) + category: 'General', + features: [ + {label: 'Any', name: 'any'}, + {label: 'Schools for Specific Purposes'}, + {label: 'Schools with support classes'} + ], + }, + distance: { + label: 'Distance / Online', + category: 'Specific', + // sql: "s.distance_education != 'false'", + type: 'distance', + }, + // environmental: { + // label: "Environmental Centre", + // category: "Specific", + // type: "environmental", + // }, + k12: { + label: 'Central / Community (K-12)', + category: 'Specific', + type: 'central', + }, + infants: { + label: 'Infant (K-2)', + category: 'Specific', + type: 'infants', + }, + other: { + label: 'Other', + category: 'Specific', + type: 'other', + } + }; + + + // helpers independent of other SchoolFilter bits + + var nearbySchoolsFeature = function () { + var div = document.createElement('div'); + div.className = 'nearby-schools-feature'; + + div.appendChild(selectPrimaryFeature()); + + div.appendChild(selectSecondaryFeature()); + + return div; + }; + + var selectPrimaryFeature = function () { + var fieldset = document.createElement('fieldset'); + fieldset.className = 'primary'; + + var legend = document.createElement('legend'); + legend.innerHTML = 'With feature:'; + fieldset.appendChild(legend); + + fieldset.appendChild(optionControl('radio', 'feature', 'any', 'nearby-any', 'feature-primary', 'Any', (typeof app.state.nearby.filterFeatureForType[app.state.nearby.type] === 'undefined' || app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'any'), radioClick)); + fieldset.appendChild(optionControl('radio', 'feature', 'oshc', 'nearby-oshc', 'feature-primary', 'Outside School Hours Care', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'oshc': false, radioClick)); + fieldset.appendChild(optionControl('radio', 'feature', 'oc', 'nearby-oc', 'feature-primary', 'Opportunity Classes', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'oc': false, radioClick)); + + return fieldset; + }; + + var selectSecondaryFeature = function () { + + var fieldset = document.createElement('fieldset'); + fieldset.className = 'secondary'; + + var legend = document.createElement('legend'); + legend.innerHTML = 'With feature:'; + fieldset.appendChild(legend); + + fieldset.appendChild(optionControl('radio', 'feature', 'any', 'nearby-any2', 'feature-secondary', 'Any', (typeof app.state.nearby.filterFeatureForType[app.state.nearby.type] === 'undefined' || app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'any'), radioClick)); + var boysGirls = optionControl('radio', 'feature', 'boys', 'nearby-boys', 'feature-secondary', 'Boys', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'boys': false, radioClick); + boysGirls = optionControl('radio', 'feature', 'girls', 'nearby-girls', 'feature-secondary', 'Girls', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'girls': false, radioClick, boysGirls); + fieldset.appendChild(boysGirls); + fieldset.appendChild(optionControl('radio', 'feature', 'selective', 'nearby-selective', 'feature-secondary', 'Academically selective option', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'selective': false, radioClick)); + fieldset.appendChild(optionControl('radio', 'feature', 'intensive_english', 'nearby-intensive_english_centre', 'feature-secondary', 'Intensive English Centre', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'nearby-intensive_english_centre': false, radioClick)); + fieldset.appendChild(optionControl('radio', 'feature', 'specialty', 'nearby-specialty', 'feature-secondary', 'Specialty option', app.state.nearby.filterFeatureForType[app.state.nearby.type] ? app.state.nearby.filterFeatureForType[app.state.nearby.type].name == 'nearby-specialty': false, radioClick)); + + return fieldset; + }; + + var selectOption = function (value, text, selected) { + var option = document.createElement('option'); + option.value = value; + option.text = text; + option.selected = selected; + return option; + }; + + var optionsFeature = function () { + var div = document.createElement('div'); + div.className = 'nearby-schools-options'; + + var fieldset = document.createElement('fieldset'); + fieldset.className = 'primary secondary nearby-schools-options'; + + var legend = document.createElement('legend'); + legend.innerHTML = 'Options:'; + fieldset.appendChild(legend); + + fieldset.appendChild(optionControl('checkbox', 'option primary', 'infants', 'nearby-infants', 'nearby-infants', 'Include Infant (K-2)', app.state.nearby.othersForType[app.state.nearby.type] == 'infants', nearbyCheckboxClick)); + fieldset.appendChild(optionControl('checkbox', 'option primary secondary', 'central', 'nearby-central', 'nearby-central', 'Include Central/Community (K-12)', app.state.nearby.othersForType[app.state.nearby.type] == 'central', nearbyCheckboxClick)); + + div.appendChild(fieldset); + + return div; + }; + + var optionControl = function (type, className, value, id, name, labeltext, checked, onClick, parent) { + + var container; + if (parent) { + container = parent; + } else { + container = document.createElement('div'); + container.className = className; + } + + var control = document.createElement('input'); + control.checked = checked; + control.type = type; + control.value = value; + control.id = id; + control.name = name; + if (onClick) + control.addEventListener('click', onClick); + container.appendChild(control); + + var label = document.createElement('label'); + label.htmlFor = id; + label.innerHTML = labeltext; + container.appendChild(label); + + return container; + }; + + + + + var onNearbySchoolsClick = function () { + var userWantsNearbyShown = $(this).is(':checked'); //is checked now, meaning it was unchecked before click. + app.state.showNearby = userWantsNearbyShown; + app.mapView.loadNearby(); + }; + + var radioClick = function () { + var featureName = $(this).attr('value'); + app.util.log('doing stuff for feature: ' + featureName); + var type = app.state.nearby.type; + var feature = _.find(filters[type].features, function (feature) { + return feature.name === featureName; + }); + app.util.log(feature); + if (feature) { + app.state.nearby.filterFeatureForType[type] = feature; + } + app.mapView.updateResultsPopups(); + app.mapView.loadNearby(); + }; + + var nearbyCheckboxClick = function () { + var type = $(this).attr('value'); + var includeThis = $(this).is(':checked'); + var others = app.state.nearby.othersForType[app.state.nearby.type]; + + if (includeThis) { + app.state.nearby.othersForType[app.state.nearby.type] = _.union(others, type); + } else { // unchecked; remove this type + app.state.nearby.othersForType[app.state.nearby.type] = _.without(others, type); + } + + app.mapView.loadNearby(); + }; + + + + SchoolsFilter.prototype = { + + nearbySchoolsHeaderControl: function () { + var toggleUI = document.createElement('div'); + toggleUI.className = 'nearby-schools-control-toggle'; + + var labelUI = document.createElement('label'); + labelUI.htmlFor = 'nearby-schools-control-expand'; + labelUI.innerHTML = 'Show nearby schools'; + toggleUI.appendChild(labelUI); + + var buttonUI = document.createElement('button'); + buttonUI.className = 'toggle-filters'; + buttonUI.title = 'Expand'; + + buttonUI.addEventListener('click', $.proxy(this.toggleFilterVisibility, this)); + buttonUI.id = 'nearby-schools-control-expand'; + + var spanUI = document.createElement('span'); + spanUI.setAttribute('aria-hidden', true); + + var iUI = document.createElement('i'); + iUI.className = 'fa fa-caret-left'; + spanUI.appendChild(iUI); + buttonUI.appendChild(spanUI); + toggleUI.appendChild(buttonUI); + + return toggleUI; + }, + + schoolFiltersControl: function () { + var div = document.createElement('div'); + div.className = 'school-filters'; + + div.appendChild(this.schoolTypeControl()); + div.appendChild(nearbySchoolsFeature()); + div.appendChild(optionsFeature()); + + return div; + }, + + schoolTypeControl: function () { + var label = document.createElement('label'); + label.htmlFor = 'nearby-schools-type'; + label.innerHTML = 'Type:'; + + var selectList = document.createElement('select'); + selectList.id = 'nearby-schools-type'; + selectList.className = 'styled-select type-filter'; + selectList.addEventListener('change', this.getNearbySchoolsFilterOnChange()); + + var optgroup = document.createElement('optgroup'); + optgroup.label = 'General:'; + selectList.appendChild(optgroup); + + selectList.appendChild(selectOption('all', 'All', app.state.nearby.type == 'all')); + selectList.appendChild(selectOption('primary', 'Primary', app.state.nearby.type == 'primary')); + selectList.appendChild(selectOption('secondary', 'Secondary', app.state.nearby.type == 'secondary')); + selectList.appendChild(selectOption('ssp', 'Schools for Specific Purposes', app.state.nearby.type == 'ssp')); + + optgroup = document.createElement('optgroup'); + optgroup.label = 'Specific:'; + selectList.appendChild(optgroup); + + selectList.appendChild(selectOption('distance', 'Distance / Online', app.state.nearby.type == 'distance')); + selectList.appendChild(selectOption('central', 'Central / Community (K-12)', app.state.nearby.type == 'central')); + selectList.appendChild(selectOption('infants', 'Infant (K-2)', app.state.nearby.type == 'infants')); + selectList.appendChild(selectOption('other', 'Other', app.state.nearby.type == 'other')); + + return selectList; + }, + + toggleFilterVisibility: function () { + app.state.nearby.showFilters = !app.state.nearby.showFilters; + if (app.state.showNearby == null) + app.state.showNearby = true; + if (app.state.showNearby) + app.mapView.loadNearby(); + $('#nearby-schools-show').prop('checked', app.state.showNearby); + this.update(); + }, + + getNearbySchoolsFilterOnChange: function () { + var that = this; + return function () { + var selected = $('option:selected', this); + if (selected.length > 0) { + var type = $('option:selected', this)[0].value; + app.util.log('Type selected: ' + type); + app.state.nearby.type = type; + + app.mapView.updateResultsPopups(); + that.updateFilterUI(); + that.updateFeaturesUI(); + that.updateOptionsUI(); + app.mapView.loadNearby(); + } + }; + }, + + update: function () { + var container = this.container; + + // setup initial UI state based on app state + $('#nearby-schools-type', container).val(app.state.nearby.type); + this.updateFilterUI(); + + var toggleFilterButton = $('button.toggle-filters', container)[0]; + var toggleFilterIcon = $('i', toggleFilterButton); + + if (app.state.nearby.showFilters) { + $('.school-filters', container).show(); + toggleFilterIcon.removeClass('fa-caret-left').addClass('fa-caret-down'); + toggleFilterButton.title = 'Collapse'; + toggleFilterButton.setAttribute('aria-label', toggleFilterButton.title); + } else { + $('.school-filters', container).hide(); + toggleFilterIcon.removeClass('fa-caret-down').addClass('fa-caret-left'); + toggleFilterButton.title = 'Expand'; + toggleFilterButton.setAttribute('aria-label', toggleFilterButton.title); + } + + this.updateFeaturesUI(); + this.updateOptionsUI(); + }, + + updateFilterUI: function () { + var container = this.container, + type = app.state.nearby.type; + + var support = app.util.support_description(); + var explanation = support && app.support_needed ? '(supporting ' + support + ')' : ''; // app.support_needed + $('.nearby-schools-filter-explanation', container).text(explanation); + + $(container).find('.nearby-schools-feature fieldset').hide(); + $(container).find('.nearby-schools-feature fieldset.' + type).show(); + + $(container).find('.nearby-schools-options fieldset').hide(); + $(container).find('.nearby-schools-options fieldset div').hide(); + + $(container).find('.nearby-schools-options fieldset.' + type).show(); + $(container).find('.nearby-schools-options fieldset div.' + type).show(); + }, + + updateFeaturesUI: function () { + var container = this.container, + type = app.state.nearby.type, + feature = app.state.nearby.filterFeatureForType[type]; + + if (!type || (type != 'primary' && type != 'secondary')) { + // only primary, secondary have any features to update; + // skip for other school types + return; + } + + // uncheck all for this type + $('.nearby-schools-feature input[name=feature-' + type + ']:radio', container).prop('checked',false); + + // check just the feature stored in app.state + // note that one radio button's `value` should matches the feature's `name`. + if (feature) { + $('.nearby-schools-feature input[name=feature-' + type +'][value=' + feature.name + ']:radio', container).prop('checked', true); + } + }, + + updateOptionsUI: function () { + var container = this.container, + type = app.state.nearby.type; + + if (app.state.nearby.othersForType[type]) { + var others = app.state.nearby.othersForType[type]; //others: things like infants, central + + $('.nearby-schools-options input:checkbox', container).prop('checked', false); // reset: uncheck everything + others.forEach(function (otherType) { + $('#nearby-' + otherType, container).prop('checked', true); + }); + } + }, + + + }; // end prototype definition + + + + // export our defined functions + app.M.MapLegendPS = LegendPS; + app.M.MapControlSchoolsFilter = SchoolsFilter; + +}(app)); diff --git a/js/util.js b/js/util.js index 1c7077e..8b706ff 100644 --- a/js/util.js +++ b/js/util.js @@ -1,72 +1,72 @@ -app = app || {}; -app.util = app.util || {}; - -(function () { - - Handlebars.registerHelper('search_radius', function () { - return app.config.searchRadius / 1000 + ' km'; - }); - - Handlebars.registerHelper('search_radius', function () { - return app.config.searchRadius / 1000 + ' km'; - }); - - Handlebars.registerHelper('round', function (num) { - return Math.round(num); - }); - - app.util.support_description = function () { - var support_wanted = _.find(app.supports, function (s) { return s.shortcode === app.support; }); - if (support_wanted) { - return support_wanted.long_description; - } - return ''; - }; - - // function roundToTwo(num) { - // return +(Math.round(num + "e+2") + "e-2"); - // } - - app.util.roundToOne = function (num) { - return +(Math.round(num + 'e+1') + 'e-1'); - }; - - app.util.schoolNameCompleter = function (request, response) { - var $input = $(this.element); - - var processResults = function (data) { - var autocompleteResponses = []; - var haveResponses = false; - data.rows.forEach(function (row) { - autocompleteResponses.push({value: row.school_name}); - haveResponses = true; - }); - if (haveResponses) { - // show suggestions - response(autocompleteResponses); - } else { - $input.autocomplete('close'); - } - }; - - // ask cartodb for all school names starting with the request - // SELECT * FROM dec_schools WHERE school_name ILIKE '%sydney%' - var query = "SELECT school_name FROM dec_schools WHERE school_name ILIKE '" + request.term + "%' ORDER BY school_name"; - app.sql.execute(query).done(processResults); - }; - - // polyfill console object so IE9 & below don't give 'console is undefined' errors - // based on http://stackoverflow.com/a/11638491/1024811 - window.console = window.console || (function() { - var c = {}; - c.log = c.warn = c.debug = c.info = c.error = function(){}; - return c; - })(); - - if (app.debug) { - app.util.log = console.log.bind(console); // eslint-disable-line no-console - } else { - app.util.log = function () {}; // don't console log in production - } - -}()); +app = app || {}; +app.util = app.util || {}; + +(function () { + + Handlebars.registerHelper('search_radius', function () { + return app.config.searchRadius / 1000 + ' km'; + }); + + Handlebars.registerHelper('search_radius', function () { + return app.config.searchRadius / 1000 + ' km'; + }); + + Handlebars.registerHelper('round', function (num) { + return Math.round(num); + }); + + app.util.support_description = function () { + var support_wanted = _.find(app.supports, function (s) { return s.shortcode === app.support; }); + if (support_wanted) { + return support_wanted.long_description; + } + return ''; + }; + + // function roundToTwo(num) { + // return +(Math.round(num + "e+2") + "e-2"); + // } + + app.util.roundToOne = function (num) { + return +(Math.round(num + 'e+1') + 'e-1'); + }; + + app.util.schoolNameCompleter = function (request, response) { + var $input = $(this.element); + + var processResults = function (data) { + var autocompleteResponses = []; + var haveResponses = false; + data.rows.forEach(function (row) { + autocompleteResponses.push({value: row.school_name}); + haveResponses = true; + }); + if (haveResponses) { + // show suggestions + response(autocompleteResponses); + } else { + $input.autocomplete('close'); + } + }; + + // ask cartodb for all school names starting with the request + // SELECT * FROM dec_schools WHERE school_name ILIKE '%sydney%' + var query = "SELECT school_name FROM dec_schools WHERE school_name ILIKE '%" + request.term + "%' ORDER BY school_name"; + app.sql.execute(query).done(processResults); + }; + + // polyfill console object so IE9 & below don't give 'console is undefined' errors + // based on http://stackoverflow.com/a/11638491/1024811 + window.console = window.console || (function() { + var c = {}; + c.log = c.warn = c.debug = c.info = c.error = function(){}; + return c; + })(); + + if (app.debug) { + app.util.log = console.log.bind(console); // eslint-disable-line no-console + } else { + app.util.log = function () {}; // don't console log in production + } + +}());