Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wire up search results and school pages #32

Closed
wants to merge 17 commits into from
Closed
1 change: 0 additions & 1 deletion _config.yml
Expand Up @@ -22,7 +22,6 @@ scripts:
# API configuration
api:
baseurl: https://ccapi-staging.18f.gov/
search: school/

# specify paths to exclude from copying to _site
# Note: files and directories with the '_' prefix are excluded
Expand Down
2 changes: 1 addition & 1 deletion _includes/search-form.html
Expand Up @@ -8,7 +8,7 @@ <h1>Find Schools</h1>

<h2>School Name</h2>
<label for="name-school">Specify a School Name</label>
<input id="name-school" name="school_name" type="text" placeholder="Name of School" {{ common_input_attributes }}>
<input id="name-school" name="name" type="text" placeholder="Name of School" {{ common_input_attributes }}>

</fieldset>

Expand Down
4 changes: 4 additions & 0 deletions _sass/_main.scss
Expand Up @@ -6,6 +6,10 @@ $pad-more: 1em;
color: yellow;
}

.hidden {
display: none;
}

.sr-only {
position: absolute;
left: -10000px;
Expand Down
15 changes: 14 additions & 1 deletion js/api.js
Expand Up @@ -34,7 +34,20 @@
};
};

API.search = API.endpoint('{{ site.api.search }}');
var schoolEndpoint = 'school/';
var idField = 'id';

API.search = API.endpoint(schoolEndpoint);

API.getSchool = function(id, done) {
var data = {};
data[idField] = id;
return API.get(schoolEndpoint, data, function(error, schools) {
return error || !schools.length
? done(error ? error.responseText : 'No such school found.')
: done(null, schools[0]);
});
};

exports.API = API;

Expand Down
45 changes: 45 additions & 0 deletions js/school.js
@@ -0,0 +1,45 @@
---
# // hey there
---
(function(exports) {

var id = getSchoolId();

if (!id) {
return showError('No school ID provided');
}

var root = document.querySelector('#school');

var directives = {
};

API.getSchool(id, function(error, school) {
if (error) {
return showError(error);
}

console.log('got school:', school);
root.classList.remove('hidden');
tagalong(root, school, directives);
});

function getSchoolId() {
if (!location.search) return null;
var match = location.search.match(/^\?(\d+)(\b|-)/);
return match ? match[1] : null;
}

function redirect(uri) {
window.location = uri || '../search/';
}

function showError(message) {
var container = document.querySelector('#error');
container.classList.remove('hidden');
var target = container.querySelector('.error-message') || container;
target.textContent = message;
return target;
}

})(this);
62 changes: 38 additions & 24 deletions js/search.js
Expand Up @@ -9,9 +9,10 @@

// TODO: include formdb, querystring, and tagalong
var form = new formdb.Form('#search-form');
var data = querystring.parse(query.substr(1));
console.debug('[search] form data:', data);
form.setData(data);
var values = querystring.parse(query.substr(1));
removeEmptyValues(values);
console.debug('[search] form values:', values);
form.setData(values);

/**
* This is our format generator. Its methods are format generators for
Expand Down Expand Up @@ -44,49 +45,51 @@
return {
dollars: formatter('$,d', '$0'),
percent: formatter('%.0f', '--'),
number: formatter('d', '0'),
plural: function(key, plural) {
if (!plural) plural = 's';
number: formatter(',d', '0'),
plural: function(key, singular, plural) {
if (!plural) plural = singular + 's';
return function(d) {
return d[key] == 1 ? '' : this.getAttribute('data-plural') || plural;
return d[key] == 1 ? singular : plural;
};
}
};
})();

// these directives tell the template renderer how to format specific keys in
// the data, for instance as dollars or percentages.
var directives = {
branches: format.number('NUMBRANCH', '0'),
branches_plural: format.plural('NUMBRANCH', 'es'),
tuition_in: format.dollars('TUITIONFEE_IN'),
tuition_out: format.dollars('TUITIONFEE_OUT'),
pct_pell: format.percent('PCTPELL'),
pct_fed_loan: format.percent('PCTFLOAN'),
avg_fac_salary: format.dollars('AVGFACSAL'),
};

resultsRoot.classList.add('js-loading');
API.search({name: data.name}, function(error, rows) {
API.search(values, function(error, rows) {
resultsRoot.classList.remove('js-loading');
if (error) {
return showError(error);
}
console.log('loaded schools:', rows);
resultsRoot.classList.add('js-loaded');
var list = resultsRoot.querySelector('.schools-list');

console.time('[render]');

console.time('[render] template');
// render the basic DOM template for each school
tagalong(list, rows, directives);
tagalong(resultsRoot, {
count: rows.length,
}, {
results: format.plural('count', 'Result'),
count: format.number('count', '0')
});

var resultsList = resultsRoot.querySelector('.schools-list');
tagalong(resultsList, rows, {
link: {
'@href': function(d) {
var name = d.name.replace(/\W+/g, '-');
return ['../school/?', d.id, '-', name].join('');
}
}
});
console.timeEnd('[render] template');

console.time('[render] charts');
// bind all of the data to elements in d3, then
// call renderCharts() on the selection
d3.select(list)
d3.select(resultsRoot)
.selectAll('.school-item')
.data(rows)
.call(renderCharts);
Expand All @@ -96,7 +99,6 @@
});

function renderCharts(selection) {
// TODO
}

function showError(error) {
Expand All @@ -107,4 +109,16 @@
out.textContent = String(error);
}

function removeEmptyValues(obj) {
var empty = function(v) {
return v === null || v === '';
};
for (var key in obj) {
if (empty(obj[key])) {
delete obj[key];
}
}
return obj;
}

})(this);
2 changes: 1 addition & 1 deletion js/vendor/package.json
Expand Up @@ -15,6 +15,6 @@
"es6-promise": "^2.3.0",
"formdb": "^0.2.0",
"qs": "^3.1.0",
"tagalong": "^0.1.0"
"tagalong": "^0.1.2"
}
}
46 changes: 30 additions & 16 deletions js/vendor/tagalong.js
Expand Up @@ -13,7 +13,6 @@ var tagalong = function(node, data, directives) {

if (typeof directives === 'object') {
directives = expandKeys(directives);
applyDirectives(node, data, directives);
} else if (typeof directives === 'function') {
directives = directives.call(node, data) || {};
} else {
Expand All @@ -22,7 +21,11 @@ var tagalong = function(node, data, directives) {

if (Array.isArray(data)) {
return bindArray(node, data, directives);
} else if (typeof data === 'object') {
} else {
applyDirectives(node, data, directives);
}

if (typeof data === 'object') {
return bindObject(node, data, directives);
}

Expand Down Expand Up @@ -111,34 +114,45 @@ function getChildren(node) {
return children;
}

function access(getter, data, thisArg) {
if (typeof getter === 'function') {
return getter.call(thisArg, data);
function applyDirectives(node, data, directives) {
function access(key, attr) {
var value = directives[key];
if (typeof value === 'function') {
return value.call(node, data);
} if (value === true) {
return data[attr || key];
}
return (typeof value === 'object')
? value
: data[value];
}
return data[getter];
}

function applyDirectives(node, data, directives) {
var interpolated;
for (var key in directives) {
if (key.charAt(0) === '@') {
var attr = key.substr(1);
var value = directives[key] === true
? data[attr]
: access(directives[key], data, node);
var value = access(key, attr) || '';
node.setAttribute(attr, value);
} else {
// only interpolate scalars and functions;
// nested directives apply to children
if (typeof directives[key] !== 'object') {
switch (key) {
case 'text':
node.textContent = access(key) || '';
break;
}
if (typeof directives[key] === 'object') {
bindKey(node, key, data, directives[key]);
} else {
if (!interpolated) interpolated = {};
interpolated[key] = access(directives[key], data, node);
interpolated[key] = access(key);
}
}
}

if (interpolated) {
tagalong(node, interpolated);
return tagalong(node, interpolated);
}

return node;
}

function expandKeys(obj) {
Expand Down
2 changes: 1 addition & 1 deletion js/vendor/tagalong.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions school/index.html
@@ -0,0 +1,36 @@
---
title: School
layout: default
permalink: /school/
scripts:
- vendor/tagalong.min.js
body_scripts:
- school.js
---

<section id="error" class="hidden">
<h2>Error</h2>
<p class="error-message"></p>
<form target="../search/" method="GET">
<label for="name-school" >Try searching for a school by name:</h2>
<input id="name-school" name="name" type="text" placeholder="Name of School" autocomplete="off" autocorrect="off" autocapitalize="off">
<input type="submit" value="Search">
</form>
</section>

<!-- Search results -->
<section id="school" class="hidden">
<h1 class="name">School Name</h1>
<h2 class="location">
<span data-bind="city">City</span>,
<span data-bind="state">State</span>
@ <tt><span data-bind="longitude"></span>&deg;W,<span data-bind="latitude"></span>&deg;N</tt>
(region <b data-bind="region">X</b>)
</h2>
</section>

<!--
<section>
{% include search-form.html %}
</section>
-->
17 changes: 13 additions & 4 deletions search/index.html
Expand Up @@ -11,11 +11,20 @@

<!-- Search results -->
<section class="search-results">
<h1>Search Results</h1>
<div class="error hidden"></div>
<ul class="schools-list">
<div class="header">
<h1><span class="results-count" data-bind="count">0</span> <span data-bind="results">Results</span> Based on Your Criteria</h1>
<p>
<a href="#search-form" class="link-more">&lt; Edit Criteria</a>
</p>
</div>

<div class="error hidden">
<p class="error-message"></p>
</div>

<ul class="schools-list" data-bind="schools">
<li class="school-item">
<h2 class="name">School Name</h2>
<h2><a class="name" data-bind="link">School Name</a></h2>
<h3 class="location">
<span data-bind="city">City</span>,
<span data-bind="state">State</span>
Expand Down