From fa18734a59aded5f10c97ad0cfc224e318199f07 Mon Sep 17 00:00:00 2001 From: SaintPeter Date: Sat, 30 Jan 2016 11:01:37 -0800 Subject: [PATCH 1/3] Add Live Filter to Map - partial --- client/less/map.less | 15 +++++++++++---- client/main.js | 30 ++++++++++++++++++++++++++++++ server/views/map/show.jade | 23 ++++++++++++++--------- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/client/less/map.less b/client/less/map.less index 3bb9b58abf..f6c420044d 100644 --- a/client/less/map.less +++ b/client/less/map.less @@ -94,10 +94,17 @@ margin:25px 0; } } -.map-buttons button { +.map-buttons button, +.map-buttons .input-group{ width:300px; } +.map-buttons .input-group{ + margin-top: 10px; + margin-left: auto; + margin-right: auto; +} + .map-accordion { margin: 140px auto 0; width:700px; @@ -116,7 +123,7 @@ margin:15px 0; padding:0; &:first-child { - margin-top:25px + margin-top:25px } > a { padding-left: 40px; @@ -179,7 +186,7 @@ padding-right:20px; font-size:20px; } - } + } h3 { margin:10px 0; padding:0; @@ -188,7 +195,7 @@ font-size:20px; } } - } + } } .map-aside-action-item { diff --git a/client/main.js b/client/main.js index a51c262746..c78dffd8f2 100644 --- a/client/main.js +++ b/client/main.js @@ -391,6 +391,36 @@ $(document).ready(function() { } }); + // live filter + $('#map-filter').on('keyup', () => { + if($('#map-filter').val().length > 1) { + var regex = new RegExp($('#map-filter').val().replace(/ /g, '-'), "gi"); + $('.challenge-title').each((index, title) => { + //console.log("title:", JSON.stringify(title)); + if(regex.test($(title).attr('name'))) { + $(title).removeClass('hidden'); + } else { + $(title).addClass('hidden'); + } + + }); + $.each($('.map-collapse'), function(i, div) { + console.log("bing"); + if ($(div).find('.hidden').length === + $(div).find('p').length) { + console.log("hiding parents"); + $(div).addClass('hidden'); + $(div).find('h3').addClass('hidden'); + $(div).prev('h2').addClass('hidden'); + } + }); + } else { + $('.challenge-title').each((title) => { + $(title).removeClass('hidden'); + }); + } + }); + // keyboard shortcuts: open map window.Mousetrap.bind('g m', function() { var isCollapsed = $('.map-aside').hasClass('is-collapsed'); diff --git a/server/views/map/show.jade b/server/views/map/show.jade index 9b3134c168..aec2616d86 100644 --- a/server/views/map/show.jade +++ b/server/views/map/show.jade @@ -4,13 +4,18 @@ block content p Challenges required for certifications are marked with a * .row.map-buttons button.center-block.btn.btn-sm.btn-block.btn-primary.active#showAll Collapse all challenges + .row.map-buttons + .input-group + input#map-filter.form-control(type="text" placeholder="challenge name") + span.input-group-addon + i.fa.fa-search hr #accordion.map-accordion for superBlock, index in superBlocks h2 a(data-toggle='collapse', data-parent='#accordion', href='#collapse'+superBlock.name.split(' ').join('-')) span.no-link-underline - i.fa.fa-caret-down   + i.fa.fa-caret-down   | #{superBlock.name} div.margin-left-10(id = 'collapse'+superBlock.name.split(' ').join('-') class = "collapse in map-collapse no-transition") #nested @@ -18,18 +23,18 @@ block content h3 a(data-toggle='collapse', data-parent='#nested', href='#nested-collapse'+challengeBlock.name.replace(/(\W)/gi, '').split(' ').join('-')) span.no-link-underline - i.fa.fa-caret-down   + i.fa.fa-caret-down   | #{challengeBlock.name} span.challengeBlockTime (#{challengeBlock.time}) div.margin-left-10(id = "nested-collapse"+challengeBlock.name.replace(/\W/gi, '').split(' ').join('-') class = "collapse in map-collapse no-transition") for challenge in challengeBlock.challenges if challenge.completed - p.faded.text-primary.ion-checkmark-circled.padded-ionic-icon.negative-15(name="#{challenge.dashedName}") + p.challenge-title.faded.text-primary.ion-checkmark-circled.padded-ionic-icon.negative-15(name="#{challenge.dashedName}") a(href="/challenges/#{challenge.dashedName}" target='_parent') = challenge.title span.sr-only= " Complete" else if challenge.isRequired - p.ion-ios-circle-outline.padded-ionic-icon.negative-15(name="#{challenge.dashedName}") + p.challenge-title.ion-ios-circle-outline.padded-ionic-icon.negative-15(name="#{challenge.dashedName}") a(name="#{challenge.dashedName}" target='_parent' href="/challenges/#{challenge.dashedName}" class=challenge.isComingSoon ? 'disabled' : '') span= challenge.title span.sr-only= " Incomplete" @@ -44,7 +49,7 @@ block content span.text-primary     strong * else - p.ion-ios-circle-outline.padded-ionic-icon.negative-15(name="#{challenge.dashedName}") + p.challenge-title.ion-ios-circle-outline.padded-ionic-icon.negative-15(name="#{challenge.dashedName}") a(name="#{challenge.dashedName}" target='_parent' href="/challenges/#{challenge.dashedName}" class=challenge.isComingSoon ? 'disabled' : '') span= challenge.title span.sr-only= " Incomplete" @@ -67,7 +72,7 @@ block content a(data-toggle='collapse', data-parent='#nested', href='#nested-collapse-nonprofit-projects') span.no-link-underline i.fa.fa-caret-down   - | Nonprofit Projects + | Nonprofit Projects span.challengeBlockTime (800 hours) div.margin-left-10(id = "nested-collapse-nonprofit-projects" class = "collapse in map-collapse no-transition") p.challengeBlockDescription To qualify for these nonprofit projects, you must first earn all three foundational certifications: Front End, Data Visualization, and Back End @@ -76,7 +81,7 @@ block content strong * p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Greenfield Nonprofit Project #2") Greenfield Nonprofit Project #2 span.text-primary     - strong * + strong * p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Legacy Code Nonprofit Project #1") Legacy Code Nonprofit Project #1 span.text-primary     strong * @@ -95,7 +100,7 @@ block content a(data-toggle='collapse', data-parent='#nested', href='#nested-collapse-coding-interview-training') span.no-link-underline i.fa.fa-caret-down   - | Coding Interview Training + | Coding Interview Training span.challengeBlockTime (70 hours) div.margin-left-10(id = "nested-collapse-coding-interview-training" class = "collapse in map-collapse no-transition") p.challengeBlockDescription To qualify for this coding interview training, you must first earn all four certifications: Front End, Data Visualization, Back End, and Full Stack @@ -106,7 +111,7 @@ block content a(data-toggle='collapse', data-parent='#nested', href='#nested-collapse-mock-interviews') span.no-link-underline i.fa.fa-caret-down   - | Mock Interviews + | Mock Interviews span.challengeBlockTime (10 hours) div.margin-left-10(id = "nested-collapse-mock-interviews" class = "collapse in map-collapse no-transition") p.challengeBlockDescription To qualify for these mock interviews, you must first earn all four certifications: Front End, Data Visualization, Back End, and Full Stack From d1993ea4b6179757ecae5e9b0ea9d10272662fbc Mon Sep 17 00:00:00 2001 From: Hallaathrad Date: Sat, 30 Jan 2016 20:31:26 -0500 Subject: [PATCH 2/3] Filter functions almost ready. Our pretty bar changes visual state of the filtered elements, clears with the X, restores hidden elements when deleting characters. Etc. For the future: if a chapterBlock is collapsed but has results, expand it. No? Also, hopefully getting fontawesome to the latest version... Regardless of that, this is a great opportunity for a legendary 404. Expansion of containers achieved Still working on collapsing them back when search terms change. If users had just pressed "collapse all" before the search, they should remain thus afterwards. The UX focus here is not to change the users' expected behaviour and final result. Future: updating font awesome. Working on a legendary "not found" image to make FCC join the internet hall of fame. (btw, where would I keep that file in the server?) --- client/less/map.less | 82 ++++++++++++++++++++++++++------------ client/main.js | 62 +++++++++++++++++++++------- server/views/map/show.jade | 48 +++++++++++----------- 3 files changed, 130 insertions(+), 62 deletions(-) diff --git a/client/less/map.less b/client/less/map.less index f6c420044d..b6e74a62f8 100644 --- a/client/less/map.less +++ b/client/less/map.less @@ -43,15 +43,9 @@ flex: 1; width: 100%; height: 100%; - border: 0; - overflow: auto; - } -} - -.map-aside-body { - #nested { - margin:0 20px; + overflow: scroll; + -webkit-overflow-scrolling: touch; } } @@ -73,43 +67,69 @@ .map-fixed-header { position: fixed; background: white; - padding-top: 20px; + padding-top: 13px; width: 100%; z-index: 1; left: 0; top: 0; @media (max-width: 720px) { - padding-top:35px; + padding-top:30px; } -} -.map-fixed-header p { + p { margin: 10px 0 20px; - @media (max-width: 720px) { - margin-bottom:15px; + @media (max-width: 720px) { + margin-bottom:10px; + } } -} -.map-fixed-header hr { - margin:35px 0; - @media (max-width: 720px) { - margin:25px 0; + hr { + margin:30px 0; + @media (max-width: 720px) { + margin:25px 0; + } } -} + } .map-buttons button, .map-buttons .input-group{ width:300px; } .map-buttons .input-group{ - margin-top: 10px; + margin-top: 15px; margin-left: auto; margin-right: auto; } +#map-filter { + background:#fff; + border-color: darkgreen; +} +.input-group-addon { + width:40px; + color: darkgreen; + background: #fff; + border-color: darkgreen; + &.filled{ + background: darkgreen; + border-color: #000d00; + color: #fff; + cursor: pointer; + } + .fa { + position:absolute; + top:50%; + transform: translateY(-50%); + right:10px; + } +} + .map-accordion { - margin: 140px auto 0; + margin: 170px auto 0; width:700px; overflow-y: auto; position:relative; + #nested { + margin:0 15px; + } h2 > a { width:100%; display:block; @@ -132,11 +152,11 @@ } } - #nested div :before { + div.chapterBlock :before { margin-right: 15px; } - #nested div p { + div.chapterBlock p { text-indent: -15px; margin-left: 60px; padding-right: 20px @@ -176,7 +196,7 @@ left:0; right:0; width:100%; - margin-top:165px; + margin-top:205px; h2 { margin:15px 0; padding:0; @@ -234,6 +254,18 @@ } } +#noneFound { + display:none; + margin:60px 30px 0; + font-size:60px; + text-align: center; + color:darkgreen; + .fa { + display:block; + font-size:300px; + } +} + .map-aside-action-pop-out { margin-right: -4px; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMDAgMTcxLjQyOSIgZmlsbD0iIzNhMzEzMyI+PHBhdGggZD0iTTE1Ny4xNDMsMTAzLjU3MXYzNS43MTRjMCw4Ljg1NC0zLjE0NCwxNi40MjYtOS40MzEsMjIuNzEzcy0xMy44NTgsOS40MzEtMjIuNzEyLDkuNDMxSDMyLjE0MyBjLTguODU0LDAtMTYuNDI1LTMuMTQ0LTIyLjcxMi05LjQzMVMwLDE0OC4xNCwwLDEzOS4yODVWNDYuNDI5YzAtOC44NTQsMy4xNDQtMTYuNDI1LDkuNDMxLTIyLjcxMiBjNi4yODctNi4yODcsMTMuODU4LTkuNDMxLDIyLjcxMi05LjQzMWg3OC41NzJjMS4wNDEsMCwxLjg5NiwwLjMzNSwyLjU2NiwxLjAwNGMwLjY3LDAuNjcsMS4wMDQsMS41MjUsMS4wMDQsMi41NjdWMjUgYzAsMS4wNDItMC4zMzQsMS44OTctMS4wMDQsMi41NjdjLTAuNjcsMC42Ny0xLjUyNSwxLjAwNC0yLjU2NiwxLjAwNEgzMi4xNDNjLTQuOTExLDAtOS4xMTUsMS43NDktMTIuNjEyLDUuMjQ2IHMtNS4yNDYsNy43MDEtNS4yNDYsMTIuNjEydjkyLjg1NmMwLDQuOTExLDEuNzQ5LDkuMTE1LDUuMjQ2LDEyLjYxMnM3LjcwMSw1LjI0NSwxMi42MTIsNS4yNDVIMTI1YzQuOTEsMCw5LjExNS0xLjc0OCwxMi42MTEtNS4yNDUgYzMuNDk3LTMuNDk3LDUuMjQ2LTcuNzAxLDUuMjQ2LTEyLjYxMnYtMzUuNzE0YzAtMS4wNDIsMC4zMzQtMS44OTcsMS4wMDQtMi41NjdjMC42Ny0wLjY2OSwxLjUyNS0xLjAwNCwyLjU2Ny0xLjAwNGg3LjE0MyBjMS4wNDIsMCwxLjg5NywwLjMzNSwyLjU2NywxLjAwNEMxNTYuODA5LDEwMS42NzQsMTU3LjE0MywxMDIuNTI5LDE1Ny4xNDMsMTAzLjU3MXogTTIwMCw3LjE0M3Y1Ny4xNDMgYzAsMS45MzUtMC43MDcsMy42MDktMi4xMjEsNS4wMjJjLTEuNDEzLDEuNDE0LTMuMDg4LDIuMTIxLTUuMDIxLDIuMTIxYy0xLjkzNSwwLTMuNjA5LTAuNzA3LTUuMDIyLTIuMTIxbC0xOS42NDQtMTkuNjQzIGwtNzIuNzY3LDcyLjc2OWMtMC43NDQsMC43NDQtMS42LDEuMTE1LTIuNTY3LDEuMTE1cy0xLjgyMy0wLjM3MS0yLjU2Ny0xLjExNUw3Ny41NjcsMTA5LjcxYy0wLjc0NC0wLjc0NC0xLjExNi0xLjYtMS4xMTYtMi41NjcgYzAtMC45NjcsMC4zNzItMS44MjIsMS4xMTYtMi41NjZsNzIuNzY4LTcyLjc2OGwtMTkuNjQ0LTE5LjY0M2MtMS40MTMtMS40MTQtMi4xMi0zLjA4OC0yLjEyLTUuMDIyYzAtMS45MzUsMC43MDctMy42MDksMi4xMi01LjAyMiBDMTMyLjEwNSwwLjcwNywxMzMuNzc5LDAsMTM1LjcxNSwwaDU3LjE0M2MxLjkzNCwwLDMuNjA4LDAuNzA3LDUuMDIxLDIuMTIxQzE5OS4yOTMsMy41MzQsMjAwLDUuMjA4LDIwMCw3LjE0M3oiLz48L3N2Zz4=) diff --git a/client/main.js b/client/main.js index c78dffd8f2..ba0474ed56 100644 --- a/client/main.js +++ b/client/main.js @@ -392,34 +392,68 @@ $(document).ready(function() { }); // live filter - $('#map-filter').on('keyup', () => { + + function clearMapFilter(){ + $('#map-filter').val(''); + $('#map-filter').next().children().removeClass('fa-times').addClass('fa-search'); + $('#map-filter').next().removeClass('filled'); + $('.map-accordion').find('.hidden').removeClass('hidden'); + $('#noneFound').hide(); + } + + $('#map-filter').on('keyup', () => { if($('#map-filter').val().length > 1) { var regex = new RegExp($('#map-filter').val().replace(/ /g, '-'), "gi"); + $('.challenge-title').each((index, title) => { - //console.log("title:", JSON.stringify(title)); if(regex.test($(title).attr('name'))) { - $(title).removeClass('hidden'); + expandBlock($(title).closest('.chapterBlock')); + expandBlock($(title).closest('.chapterBlock').prev('h3')); + expandBlock($(title).closest('.certBlock')); + expandBlock($(title).closest('.certBlock').prev('h2')); + $(title).removeClass('hidden'); } else { $(title).addClass('hidden'); } - }); - $.each($('.map-collapse'), function(i, div) { - console.log("bing"); + + $.each($('.chapterBlock'), function(i, div) { if ($(div).find('.hidden').length === - $(div).find('p').length) { - console.log("hiding parents"); - $(div).addClass('hidden'); - $(div).find('h3').addClass('hidden'); - $(div).prev('h2').addClass('hidden'); + $(div).find('p').length) { + $(div).addClass('hidden'); + $(div).prev('h3').addClass('hidden'); + } else { + $(div).removeClass('hidden'); + $(div).prev('h3').removeClass('hidden'); } }); - } else { - $('.challenge-title').each((title) => { - $(title).removeClass('hidden'); + + $.each($('.certBlock'), function(i, div) { + if ($(div).children('#nested').children('h3.hidden').length === + $(div).children('#nested').children('h3').length) { + $(div).prev('h2').addClass('hidden'); + } else { + $(div).prev('h2').removeClass('hidden'); + } }); + } else if ($('#map-filter').val().length === 0) { + clearMapFilter(); + } else { + $('#map-filter').next() + .children() + .removeClass('fa-search') + .addClass('fa-times'); + $('#map-filter').next().addClass('filled'); + } + if ($.find('.certBlock').length===$('.map-accordion').children('.hidden').length) { + console.log("yass"); + $('#noneFound').show(); + } else { + $('#noneFound').hide(); } }); + + $('.map-buttons .input-group-addon').on('click', clearMapFilter); // keyboard shortcuts: open map window.Mousetrap.bind('g m', function() { diff --git a/server/views/map/show.jade b/server/views/map/show.jade index aec2616d86..1cb4c4dbc6 100644 --- a/server/views/map/show.jade +++ b/server/views/map/show.jade @@ -11,22 +11,24 @@ block content i.fa.fa-search hr #accordion.map-accordion + #noneFound Nope! Your search has produced no results + i.fa.fa-hand-spock-o for superBlock, index in superBlocks h2 a(data-toggle='collapse', data-parent='#accordion', href='#collapse'+superBlock.name.split(' ').join('-')) span.no-link-underline - i.fa.fa-caret-down   + i.fa.fa-caret-down | #{superBlock.name} - div.margin-left-10(id = 'collapse'+superBlock.name.split(' ').join('-') class = "collapse in map-collapse no-transition") + div.margin-left-10(id = 'collapse'+superBlock.name.split(' ').join('-') class = "collapse in map-collapse no-transition certBlock") #nested for challengeBlock in superBlock.blocks h3 a(data-toggle='collapse', data-parent='#nested', href='#nested-collapse'+challengeBlock.name.replace(/(\W)/gi, '').split(' ').join('-')) span.no-link-underline - i.fa.fa-caret-down   + i.fa.fa-caret-down | #{challengeBlock.name} span.challengeBlockTime (#{challengeBlock.time}) - div.margin-left-10(id = "nested-collapse"+challengeBlock.name.replace(/\W/gi, '').split(' ').join('-') class = "collapse in map-collapse no-transition") + div.margin-left-10(id = "nested-collapse"+challengeBlock.name.replace(/\W/gi, '').split(' ').join('-') class = "collapse in map-collapse no-transition chapterBlock") for challenge in challengeBlock.challenges if challenge.completed p.challenge-title.faded.text-primary.ion-checkmark-circled.padded-ionic-icon.negative-15(name="#{challenge.dashedName}") @@ -66,7 +68,7 @@ block content span.no-link-underline i.fa.fa-caret-down   | Full Stack Development Certification - div.margin-left-10(id = 'collapse-full-stack-development-certification' class = "collapse in map-collapse no-transition") + div.margin-left-10(id = 'collapse-full-stack-development-certification' class = "collapse in map-collapse no-transition certBlock") #nested h3 a(data-toggle='collapse', data-parent='#nested', href='#nested-collapse-nonprofit-projects') @@ -74,27 +76,27 @@ block content i.fa.fa-caret-down   | Nonprofit Projects span.challengeBlockTime (800 hours) - div.margin-left-10(id = "nested-collapse-nonprofit-projects" class = "collapse in map-collapse no-transition") - p.challengeBlockDescription To qualify for these nonprofit projects, you must first earn all three foundational certifications: Front End, Data Visualization, and Back End - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Greenfield Nonprofit Project #1") Greenfield Nonprofit Project #1 + div.margin-left-10(id = "nested-collapse-nonprofit-projects" class = "collapse in map-collapse no-transition chapterBlock") + .challengeBlockDescription To qualify for these nonprofit projects, you must first earn all three foundational certifications: Front End, Data Visualization, and Back End + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Greenfield Nonprofit Project #1") Greenfield Nonprofit Project #1 span.text-primary     strong * - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Greenfield Nonprofit Project #2") Greenfield Nonprofit Project #2 + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Greenfield Nonprofit Project #2") Greenfield Nonprofit Project #2 span.text-primary     strong * - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Legacy Code Nonprofit Project #1") Legacy Code Nonprofit Project #1 + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Legacy Code Nonprofit Project #1") Legacy Code Nonprofit Project #1 span.text-primary     strong * - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Legacy Code Nonprofit Project #2") Legacy Code Nonprofit Project #2 + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Legacy Code Nonprofit Project #2") Legacy Code Nonprofit Project #2 span.text-primary     strong * - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Claim your Full Stack Development Certification") Claim your Full Stack Development Certification + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Claim your Full Stack Development Certification") Claim your Full Stack Development Certification h2 a(data-toggle='collapse', data-parent='#accordion', href='#collapse-coding-interview-preparation') span.no-link-underline i.fa.fa-caret-down   | Coding Interview Preparation - div.margin-left-10(id = 'collapse-coding-interview-preparation' class = "collapse in map-collapse no-transition") + div.margin-left-10(id = 'collapse-coding-interview-preparation' class = "collapse in map-collapse no-transition certBlock") #nested h3 a(data-toggle='collapse', data-parent='#nested', href='#nested-collapse-coding-interview-training') @@ -102,20 +104,20 @@ block content i.fa.fa-caret-down   | Coding Interview Training span.challengeBlockTime (70 hours) - div.margin-left-10(id = "nested-collapse-coding-interview-training" class = "collapse in map-collapse no-transition") - p.challengeBlockDescription To qualify for this coding interview training, you must first earn all four certifications: Front End, Data Visualization, Back End, and Full Stack - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Soft Skill Training") Soft Skill Training - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Critical Thinking Training") Critical Thinking Training - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Whiteboard Coding Training") Whiteboard Coding Training + div.margin-left-10(id = "nested-collapse-coding-interview-training" class = "collapse in map-collapse no-transition chapterBlock") + .challengeBlockDescription To qualify for this coding interview training, you must first earn all four certifications: Front End, Data Visualization, Back End, and Full Stack + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Soft Skill Training") Soft Skill Training + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Critical Thinking Training") Critical Thinking Training + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Whiteboard Coding Training") Whiteboard Coding Training h3 a(data-toggle='collapse', data-parent='#nested', href='#nested-collapse-mock-interviews') span.no-link-underline i.fa.fa-caret-down   | Mock Interviews span.challengeBlockTime (10 hours) - div.margin-left-10(id = "nested-collapse-mock-interviews" class = "collapse in map-collapse no-transition") - p.challengeBlockDescription To qualify for these mock interviews, you must first earn all four certifications: Front End, Data Visualization, Back End, and Full Stack - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #1") Mock Interview #1 - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #2") Mock Interview #2 - p.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #3") Mock Interview #3 + div.margin-left-10(id = "nested-collapse-mock-interviews" class = "collapse in map-collapse no-transition chapterBlock") + .challengeBlockDescription To qualify for these mock interviews, you must first earn all four certifications: Front End, Data Visualization, Back End, and Full Stack + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #1") Mock Interview #1 + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #2") Mock Interview #2 + p.challenge-title.disabled.text-primary.ion-locked.padded-ionic-icon.negative-15(name="Mock Interview #3") Mock Interview #3 .spacer From a6fc2f2fd4457924a78deae7f1ab544c0ab985e0 Mon Sep 17 00:00:00 2001 From: SaintPeter Date: Sun, 31 Jan 2016 13:09:43 -0800 Subject: [PATCH 3/3] Final effeciency pass, fix search bug --- client/less/main.less | 8 --- client/less/map.less | 20 +++--- client/main.js | 142 ++++++++++++++++++++++--------------- server/views/map/show.jade | 9 ++- 4 files changed, 99 insertions(+), 80 deletions(-) diff --git a/client/less/main.less b/client/less/main.less index 9ac5f78e94..3e610dc2dc 100644 --- a/client/less/main.less +++ b/client/less/main.less @@ -1018,14 +1018,6 @@ hr { color: @gray-light; } -.asterisk-explanation { - margin-top: -15px; -} - -.map-buttons { - margin-top: -10px; -} - code { padding: 0; } diff --git a/client/less/map.less b/client/less/map.less index b6e74a62f8..4788375f2d 100644 --- a/client/less/map.less +++ b/client/less/map.less @@ -67,7 +67,7 @@ .map-fixed-header { position: fixed; background: white; - padding-top: 13px; + padding-top: 5px; width: 100%; z-index: 1; left: 0; @@ -76,7 +76,7 @@ padding-top:30px; } p { - margin: 10px 0 20px; + margin: 5px 0 20px; @media (max-width: 720px) { margin-bottom:10px; } @@ -87,7 +87,11 @@ margin:25px 0; } } - } + } + +.map-buttons { + margin-top: -10px; +} .map-buttons button, .map-buttons .input-group{ width:300px; @@ -107,8 +111,8 @@ width:40px; color: darkgreen; background: #fff; - border-color: darkgreen; - &.filled{ + border-color: darkgreen; + &.filled{ background: darkgreen; border-color: #000d00; color: #fff; @@ -123,7 +127,7 @@ } .map-accordion { - margin: 170px auto 0; + margin: 135px auto 0; width:700px; overflow-y: auto; position:relative; @@ -196,7 +200,7 @@ left:0; right:0; width:100%; - margin-top:205px; + margin-top:180px; h2 { margin:15px 0; padding:0; @@ -257,7 +261,7 @@ #noneFound { display:none; margin:60px 30px 0; - font-size:60px; + font-size:30px; text-align: center; color:darkgreen; .fa { diff --git a/client/main.js b/client/main.js index ba0474ed56..3b5c2f4148 100644 --- a/client/main.js +++ b/client/main.js @@ -340,7 +340,10 @@ $(document).ready(function() { $('.map-fixed-header').css('top', '50px'); } - // map + // map global selectors + var mapFilter = $('#map-filter'); + var mapShowAll = $('#showAll'); + $('#nav-map-btn').on('click', showMap); $('.map-aside-action-collapse').on('click', collapseMap); @@ -360,101 +363,122 @@ $(document).ready(function() { } $('#accordion').on('show.bs.collapse', function(e) { - expandCaret(e.target); - if ($('a[data-toggle=collapse]').length === $('.fa-caret-down').length) { - $('#showAll').text('Collapse all challenges'); - $('#showAll').addClass('active'); - } + expandCaret(e.target); + if ($('a[data-toggle=collapse]').length === $('.fa-caret-down').length) { + mapShowAll.text('Collapse all challenges'); + mapShowAll.addClass('active'); + } }).on('hide.bs.collapse', function(e) { - collapseCaret(e.target); - if ($('a[data-toggle=collapse]').length === $('.fa-caret-right').length) { - $('#showAll').text('Expand all challenges'); - $('#showAll').removeClass('active'); - } + collapseCaret(e.target); + if ($('a[data-toggle=collapse]').length === $('.fa-caret-right').length) { + mapShowAll.text('Expand all challenges'); + mapShowAll.removeClass('active'); + } }); - $('#showAll').on('click', () => { - var mapExpanded = $('#showAll').hasClass('active'); + mapShowAll.on('click', () => { + var mapExpanded = mapShowAll.hasClass('active'); if (!mapExpanded) { $.each($('.map-collapse:not(".in")'), function(i, div) { expandBlock(div); }); - $('#showAll').text('Collapse all challenges'); - return $('#showAll').addClass('active'); + mapShowAll.text('Collapse all challenges'); + return mapShowAll.addClass('active'); } else { $.each($('.map-collapse.in'), function(i, div) { collapseBlock(div); }); - $('#showAll').text('Expand all challenges'); - return $('#showAll').removeClass('active'); + mapShowAll.text('Expand all challenges'); + return mapShowAll.removeClass('active'); } }); - // live filter - - function clearMapFilter(){ - $('#map-filter').val(''); - $('#map-filter').next().children().removeClass('fa-times').addClass('fa-search'); - $('#map-filter').next().removeClass('filled'); - $('.map-accordion').find('.hidden').removeClass('hidden'); - $('#noneFound').hide(); - } - - $('#map-filter').on('keyup', () => { - if($('#map-filter').val().length > 1) { - var regex = new RegExp($('#map-filter').val().replace(/ /g, '-'), "gi"); - + // Map live filter + mapFilter.on('keyup', () => { + if (mapFilter.val().length > 0) { + var regex = new RegExp(mapFilter.val().replace(/ /g, '.'), 'i'); + + // Hide/unhide challenges that match the regex $('.challenge-title').each((index, title) => { - if(regex.test($(title).attr('name'))) { - expandBlock($(title).closest('.chapterBlock')); - expandBlock($(title).closest('.chapterBlock').prev('h3')); + if (regex.test($(title).attr('name'))) { + expandBlock($(title).closest('.chapterBlock')); expandBlock($(title).closest('.certBlock')); - expandBlock($(title).closest('.certBlock').prev('h2')); - $(title).removeClass('hidden'); + $(title).removeClass('hidden'); } else { $(title).addClass('hidden'); } }); - + + // Hide/unhide blocks with no matches $.each($('.chapterBlock'), function(i, div) { if ($(div).find('.hidden').length === - $(div).find('p').length) { - $(div).addClass('hidden'); - $(div).prev('h3').addClass('hidden'); + $(div).find('p').length) { + $(div).addClass('hidden'); + $(div).prev('h3').addClass('hidden'); } else { - $(div).removeClass('hidden'); - $(div).prev('h3').removeClass('hidden'); + $(div).removeClass('hidden'); + $(div).prev('h3').removeClass('hidden'); } }); - + + // Hide/unhide superblocks with no matches $.each($('.certBlock'), function(i, div) { if ($(div).children('#nested').children('h3.hidden').length === - $(div).children('#nested').children('h3').length) { - $(div).prev('h2').addClass('hidden'); + $(div).children('#nested').children('h3').length) { + $(div).prev('h2').addClass('hidden'); } else { - $(div).prev('h2').removeClass('hidden'); + $(div).prev('h2').removeClass('hidden'); } }); - } else if ($('#map-filter').val().length === 0) { - clearMapFilter(); + + // Display "Clear Filter" element + if (mapFilter.next().children().hasClass('fa-search')) { + mapFilter.next() + .children() + .removeClass('fa-search') + .addClass('fa-times'); + mapFilter.next().addClass('filled'); + // Scroll to the top of the page + $('html, body, .map-accordion').scrollTop(0); + } } else { - $('#map-filter').next() - .children() - .removeClass('fa-search') - .addClass('fa-times'); - $('#map-filter').next().addClass('filled'); + clearMapFilter(); } - if ($.find('.certBlock').length===$('.map-accordion').children('.hidden').length) { - console.log("yass"); - $('#noneFound').show(); - } else { - $('#noneFound').hide(); + + // Display not found if everything is hidden + if ($.find('.certBlock').length === + $('.map-accordion').children('.hidden').length) { + $('#noneFound').show(); + } else { + $('#noneFound').hide(); } }); - + + // Give focus to the search box by default + mapFilter.focus(); + + // Clicking the search button or x clears the map $('.map-buttons .input-group-addon').on('click', clearMapFilter); + function clearMapFilter() { + mapFilter.val(''); + mapFilter.next().children().removeClass('fa-times').addClass('fa-search'); + mapFilter.next().removeClass('filled'); + $('.map-accordion').find('.hidden').removeClass('hidden'); + $('#noneFound').hide(); + } + + // Clear the search on escape key + mapFilter.on('keydown', (e) => { + if (e.keyCode === 27) { + e.preventDefault(); + clearMapFilter(); + } + }); + + window.Mousetrap.bind('esc', clearMapFilter); + // keyboard shortcuts: open map window.Mousetrap.bind('g m', function() { var isCollapsed = $('.map-aside').hasClass('is-collapsed'); diff --git a/server/views/map/show.jade b/server/views/map/show.jade index 1cb4c4dbc6..c2aafb974c 100644 --- a/server/views/map/show.jade +++ b/server/views/map/show.jade @@ -1,23 +1,22 @@ extends ../layout-wide block content - .text-center.map-fixed-header.asterisk-explanation + .text-center.map-fixed-header p Challenges required for certifications are marked with a * .row.map-buttons button.center-block.btn.btn-sm.btn-block.btn-primary.active#showAll Collapse all challenges .row.map-buttons .input-group - input#map-filter.form-control(type="text" placeholder="challenge name") + input#map-filter.form-control(type="text" placeholder="Type a challenge name" autocomplete="off" value="") span.input-group-addon i.fa.fa-search hr #accordion.map-accordion - #noneFound Nope! Your search has produced no results - i.fa.fa-hand-spock-o + #noneFound No results found. Happy Coding! for superBlock, index in superBlocks h2 a(data-toggle='collapse', data-parent='#accordion', href='#collapse'+superBlock.name.split(' ').join('-')) span.no-link-underline - i.fa.fa-caret-down + i.fa.fa-caret-down | #{superBlock.name} div.margin-left-10(id = 'collapse'+superBlock.name.split(' ').join('-') class = "collapse in map-collapse no-transition certBlock") #nested