From 46d5dbe1a80e64fe88a3058aa38164eb40b185c2 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Sat, 1 Jun 2013 21:16:08 +0100 Subject: [PATCH 01/19] Bailing early if no filters set --- openbadger.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbadger.js b/openbadger.js index 4687e30..62a32d5 100644 --- a/openbadger.js +++ b/openbadger.js @@ -57,6 +57,9 @@ function filterBadges(data, query) { ageGroup = query.age, program = query.program; + if (!category && !ageGroup && !program) + return data; + data = _.filter(data, function(item) { if (category && !_.contains(item.categories, category)) return false; From f172ece0d26550bc7e5e4910fde6aba772c2c39c Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Sun, 2 Jun 2013 14:43:11 +0100 Subject: [PATCH 02/19] Fixing pagination --- app.js | 1 + helpers.js | 91 +++++++++++++++++++++++++++++++++++++++++++++++ views/filter.html | 18 +--------- 3 files changed, 93 insertions(+), 17 deletions(-) diff --git a/app.js b/app.js index b993827..481cb1f 100644 --- a/app.js +++ b/app.js @@ -30,6 +30,7 @@ app.use(flash()); app.use(helpers.addCsrfToken); app.use(helpers.addRangeMethod); +app.use(helpers.addPaginateMethod); app.use(helpers.addMessages); require('./controllers/auth')(app); diff --git a/helpers.js b/helpers.js index a3f9578..348c43d 100644 --- a/helpers.js +++ b/helpers.js @@ -1,3 +1,5 @@ +const querystring = require('querystring'); +const url = require('url'); const _ = require('underscore'); @@ -13,6 +15,95 @@ exports.addRangeMethod = function addRangeMethod (req, res, next) { next(); }; +exports.addPaginateMethod = function addPaginateMethod (req, res, next) { + function page (options) { + var path = options.path, + pageNum = options.pageNum, + display = options.display, + className = options.className, + el = options.el; + + var query = querystring.parse(path.query), + content, + href; + + if (pageNum === 1) + delete query.page + else + query.page = pageNum + + query = querystring.stringify(query); + href = path.href.replace(/\?.*$/, '') + (query ? '?' + query : ''); + + if (pageNum === null) { + content = '' + display + ''; + } else { + content = '' + (display || pageNum) + ''; + } + + return '<' + el + (className ? ' class="' + className + '"' : '') + '>' + content + ''; + } + + function generatePageNumbers (total, current, extraItems) { + extraItems = extraItems || 2; + + var paged = {}, + pages = []; + + for (var i = 1; i <= Math.min(total, extraItems + 1); ++i) + (paged[i] = 1) && pages.push(i); + + if (!paged[Math.max(1, current - extraItems - 1)]) + pages.push('...'); + + for (var i = Math.max(1, current - extraItems); i <= Math.min(total, current + extraItems); ++i) + !paged[i] && (paged[i] = 1) && pages.push(i); + + if (!paged[Math.max(1, total - extraItems - 1)]) + pages.push('...'); + + for (var i = Math.max(1, total - extraItems); i <= total; ++i) + !paged[i] && (paged[i] = 1) && pages.push(i); + + return pages; + } + + res.locals.paginate = function (count, current, path, extraItems, el) { + current = current || 1; + path = url.parse(path || req.url); + el = el || 'li'; + + var pages = [], + pageNums = generatePageNumbers(count, current, extraItems), + pageNum; + + if (current === 1) + pages.push(page({path:path, display:'«', className:'disabled', el:el})); + else + pages.push(page({path:path, pageNum:current - 1, display:'«', el:el})); + + for (var i = 0, l = pageNums.length; i < l; ++i) { + pageNum = pageNums[i]; + + if (pageNum === current) + pages.push(page({path:path, pageNum:pageNum, className:'active', el:el})); + else if (!parseInt(pageNum,10)) + pages.push(page({path:path, display:pageNum, el:el})); + else + pages.push(page({path:path, pageNum:pageNum, el:el})); + } + + if (current === pages) + pages.push(page({path:path, display:'»', className:'disabled', el:el})); + else + pages.push(page({path:path, pageNum:current + 1, display:'»', el:el})); + + return pages.join(''); + } + + next(); +} + function extractMessageData (req) { var messages = {}; var fields = {}; diff --git a/views/filter.html b/views/filter.html index a7348f7..e63d199 100644 --- a/views/filter.html +++ b/views/filter.html @@ -74,23 +74,7 @@ {% if pages > 1 %} {% endif %} From c0460b5dad6f1f6a1a58d72a83c85ebf07991cb4 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Sun, 2 Jun 2013 14:55:36 +0100 Subject: [PATCH 03/19] Fixing API query generation bug `DEFAULT_QUERY` was remembering previous query --- api.js | 1 + 1 file changed, 1 insertion(+) diff --git a/api.js b/api.js index 3dadbad..1be419b 100644 --- a/api.js +++ b/api.js @@ -23,6 +23,7 @@ function middleware (method, default_query) { // Build query from various inputs var query = _.extend( + {}, DEFAULT_QUERY, default_query || {}, req.query || {}, From dbaad38eaa38043524d927788ee51decf3f0f1f3 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Sun, 2 Jun 2013 18:42:33 +0100 Subject: [PATCH 04/19] Fixing `openbadger` filtering --- openbadger.js | 148 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 130 insertions(+), 18 deletions(-) diff --git a/openbadger.js b/openbadger.js index f95b7e4..05b3b11 100644 --- a/openbadger.js +++ b/openbadger.js @@ -49,33 +49,132 @@ function normalizeProgram(program, id) { return program; } -function filterBadges(data, query) { - // TO DO - We should probably be a little less naive about this, and make sure - // that these values are from an allowed list +var categories = [ + {label: 'Science', value: 'science'}, + {label: 'Technology', value: 'technology'}, + {label: 'Engineering', value: 'engineering'}, + {label: 'Art', value: 'art'}, + {label: 'Math', value: 'math'} +]; +var ageRanges = [ + {label: 'Under 13', value: '0-13'}, + {label: '13-18', value: '13-18'}, + {label: '19-24', value: '19-24'} +]; +var activityTypes = [ + {label: 'Online', value: 'online'}, + {label: 'Offline', value: 'offline'} +]; +var badgeTypes = [ + {label: 'Participation', value: 'participation'}, + {label: 'Skill', value: 'skill'}, + {label: 'Activity', value: 'activity'} +]; +var issuers = []; - var category = query.category, - ageGroup = query.age, - program = query.program; +function updateIssuers (callback) { + if (typeof callback !== 'function') + callback = function () {}; - if (!category && !ageGroup && !program) + openbadger.getOrgs(function (err, data) { + if (err) + return callback(err); + + issuers = []; + + (data.issuers || data.orgs).forEach(function (issuer) { + issuers.push({ + label: issuer.name, + value: issuer.shortname + }); + }); + + callback(null, issuers); + }); +} + +function confirmFilterValue (value, list) { + if (!value && value !== 0) + return null; + + for (var i = 0, l = list.length; i < l; ++i) + if (list[i].value === value) + return value; + + return null; +} + +function applyFilter (data, query) { + return _.filter(data, function(item) { + var x = _.reduce(query, function(memo, value, field) { + console.log('Filtering:', value, field, item); + + if (!memo) // We've already failed a test - no point in continuing + return memo; + + if (!value && value !== 0) + return memo; + + var data = item; + + if (field.indexOf('.') > -1) { + var fieldParts = field.split('.').reverse(); + + while (data && fieldParts.length > 1) { + data = data[fieldParts.pop()]; + } + + field = fieldParts.reverse().join('.'); + } + + var itemValue = data ? data[field] : null; + + if (_.isArray(itemValue)) + return memo && _.contains(itemValue, value); + + return memo && (itemValue === value); + }, true); + console.log(query, x); + return x; + }) +} + +function filterBadges (data, query) { + var category = confirmFilterValue(query.category, categories), + ageGroup = confirmFilterValue(query.age, ageRanges), + badgeType = confirmFilterValue(query.type, badgeTypes), + activityType = confirmFilterValue(query.activity, activityTypes); + + if (!category && !ageGroup && !badgeType && !activityType) return data; - data = _.filter(data, function(item) { - if (category && !_.contains(item.categories, category)) - return false; - - if (ageGroup && !_.contains(item.ageRange, ageGroup)) - return false; - - if (program && item.program !== program) - return false; - - return true; + return applyFilter(data, { + 'categories': category, + 'ageRange': ageGroup, + 'badgeType': badgeType, + 'activityType': activityType }); return data; } +function filterPrograms (data, query) { + var category = confirmFilterValue(query.category, categories), + org = confirmFilterValue(query.org, issuers), + ageGroup = confirmFilterValue(query.age, ageRanges), + activityType = confirmFilterValue(query.activity, activityTypes); + + if (!category && !ageGroup && !badgeType && !activityType) + return data; + + return applyFilter(data, { + 'categories': category, + 'issuer.shortname': org, + 'ageRange': ageGroup, + 'activityType': activityType + }); +} + function getJWTToken(email) { var claims = { prn: email, @@ -129,6 +228,7 @@ var openbadger = new Api(ENDPOINT, { }); }); }, + filters: filterPrograms, paginate: true, key: 'programs' }, @@ -232,4 +332,16 @@ var openbadger = new Api(ENDPOINT, { }, }); +updateIssuers(); + module.exports = openbadger; +module.exports.getFilters = function getFilters () { + return { + categories: categories, + ageRanges: ageRanges, + issuers: issuers, + activityTypes: activityTypes, + badgeTypes: badgeTypes + }; +} +module.exports.updateIssuers = updateIssuers; \ No newline at end of file From 3150d8d41f2dd41372464f2585a4d6ea08eb2bc4 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Sun, 2 Jun 2013 20:59:47 +0100 Subject: [PATCH 05/19] Fixing filter styling --- static/media/css/core.css | 14 ++++++++++++++ static/media/less/core.less | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/static/media/css/core.css b/static/media/css/core.css index 43355f3..334ccd4 100644 --- a/static/media/css/core.css +++ b/static/media/css/core.css @@ -736,3 +736,17 @@ body.home #cl_i_vid { height: 25px; text-indent: -9000px; } +.filter { + color: #EEE; +} +.filter select { + margin-right: 10px; + width: 115px; + vertical-align: baseline; +} +.filter input { + vertical-align: baseline; +} +.filter .navbar-inner { + padding-left: 10px; +} diff --git a/static/media/less/core.less b/static/media/less/core.less index 94cc627..54ca7a0 100644 --- a/static/media/less/core.less +++ b/static/media/less/core.less @@ -851,3 +851,21 @@ body.home { text-indent:-9000px; } } + +.filter { + color: #EEE; + + select { + margin-right: 10px; + width: 115px; + vertical-align: baseline; + } + + input { + vertical-align: baseline; + } + + .navbar-inner { + padding-left: 10px; + } +} From 4a25343684903db9ef5be842c943054594487681 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Sun, 2 Jun 2013 21:00:15 +0100 Subject: [PATCH 06/19] Updating filtering template --- controllers/program.js | 106 +++++++---------------------------------- openbadger.js | 61 +++++++++++++++++------- views/filter.html | 29 ++++++----- 3 files changed, 74 insertions(+), 122 deletions(-) diff --git a/controllers/program.js b/controllers/program.js index 904d734..c2d68e4 100644 --- a/controllers/program.js +++ b/controllers/program.js @@ -11,96 +11,22 @@ var evidence = db.model('Evidence'); module.exports = function (app) { - function getFilters() { - var filters = [], - requested; + function getFilters(query, subset) { + var all = badger.getFilters(), + filters = []; - if (arguments.length) { - requested = Array.prototype.splice.call(arguments, 0); - } else { - requested = ['categories', 'grouped_programs', 'ages']; - } + query = query || {}; - requested.forEach(function(filter) { - switch (filter) { - case 'categories': - case 'category': - filters.push({ - name: 'category', - label: 'Category', - options: { - science: 'Science', - technology: 'Technology', - engineering: 'Engineering', - art: 'Art', - math: 'Math' - } - }); - break; - case 'orgs': - case 'org': - filters.push({ - name: 'org', - label: 'Organization', - options: { - 'org1': 'Org 1', - 'org2': 'Org 2', - 'org3': 'Org 3', - } - }); - break; - case 'programs': - case 'program': - filters.push({ - name: 'program', - label: 'Program', - options: { - 'p1': 'Program 1', - 'p2': 'Program 2', - 'p3': 'Program 3', - 'p4': 'Program 4', - 'p5': 'Program 5', - 'p6': 'Program 6' - } - }); - break; - case 'grouped_programs': - case 'grouped_program': - filters.push({ - name: 'program', - label: 'Program', - options: { - 'Org 1': { - 'p1': 'Program 1', - 'p2': 'Program 2' - }, - 'Org 2': { - 'p3': 'Program 3', - 'p4': 'Program 4' - }, - 'Org 3': { - 'p5': 'Program 5', - 'p6': 'Program 6' - } - }, - is_grouped: true - }); - break; - case 'ages': - case 'age': - filters.push({ - name: 'age', - label: 'Age Group', - options: { - 'lt-13': 'Under 13', - '13-14': '13 to 14', - '15-16': '15 to 16', - '17-18': '17 to 18', - 'gt-18': 'Over 18' - } - }); - break; - } + if (!subset || !subset.length) + subset = _.keys(all); + + if (subset && !_.isArray(subset)) + subset = [subset]; + + _.each(subset, function (item) { + var filter = all[item] || {name:item, label: item, options: []}; + filter.selected = query[filter.name]; + filters.push(filter); }); return filters; @@ -120,7 +46,7 @@ module.exports = function (app) { var data = req.remote; res.render('programs/list.html', { - filters: getFilters('categories', 'orgs', 'ages'), + filters: getFilters(req.query, ['categories', 'orgs', 'ageRanges', 'activityTypes']), items: data.programs, page: data.page, pages: data.pages @@ -285,7 +211,7 @@ module.exports = function (app) { var data = req.remote; res.render('badges/list.html', { - filters: getFilters(), + filters: getFilters(req.query, ['categories', 'ageRanges', 'badgeTypes', 'activityTypes']), items: data.badges, page: data.page, pages: data.pages diff --git a/openbadger.js b/openbadger.js index 05b3b11..18e6827 100644 --- a/openbadger.js +++ b/openbadger.js @@ -70,9 +70,9 @@ var badgeTypes = [ {label: 'Skill', value: 'skill'}, {label: 'Activity', value: 'activity'} ]; -var issuers = []; +var orgs = []; -function updateIssuers (callback) { +function updateOrgs (callback) { if (typeof callback !== 'function') callback = function () {}; @@ -80,16 +80,23 @@ function updateIssuers (callback) { if (err) return callback(err); - issuers = []; + orgs = []; - (data.issuers || data.orgs).forEach(function (issuer) { - issuers.push({ - label: issuer.name, - value: issuer.shortname + (data.orgs || data.issuers).forEach(function (org) { + orgs.push({ + label: org.name, + value: org.shortname }); }); - callback(null, issuers); + orgs.sort(function(a, b) { + var aVal = (a && a.label || '').toLowerCase().replace(/^\s*the\s+/, ''), + bVal = (b && b.label || '').toLowerCase().replace(/^\s*the\s+/, ''); + + return aVal.localeCompare(bVal); + }); + + callback(null, orgs); }); } @@ -160,11 +167,11 @@ function filterBadges (data, query) { function filterPrograms (data, query) { var category = confirmFilterValue(query.category, categories), - org = confirmFilterValue(query.org, issuers), + org = confirmFilterValue(query.org, orgs), ageGroup = confirmFilterValue(query.age, ageRanges), activityType = confirmFilterValue(query.activity, activityTypes); - if (!category && !ageGroup && !badgeType && !activityType) + if (!category && !org && !ageGroup && !activityType) return data; return applyFilter(data, { @@ -332,16 +339,36 @@ var openbadger = new Api(ENDPOINT, { }, }); -updateIssuers(); +updateOrgs(); module.exports = openbadger; module.exports.getFilters = function getFilters () { return { - categories: categories, - ageRanges: ageRanges, - issuers: issuers, - activityTypes: activityTypes, - badgeTypes: badgeTypes + categories: { + name: 'category', + label: 'Category', + options: categories + }, + ageRanges: { + name: 'age', + label: 'Age', + options: ageRanges + }, + orgs: { + name: 'org', + label: 'Organization', + options: orgs + }, + activityTypes: { + name: 'activity', + label: 'Activity', + options: activityTypes + }, + badgeTypes: { + name: 'type', + label: 'Type', + options: badgeTypes + } }; } -module.exports.updateIssuers = updateIssuers; \ No newline at end of file +module.exports.updateOrgs = updateOrgs; \ No newline at end of file diff --git a/views/filter.html b/views/filter.html index a7348f7..a3ffdf2 100644 --- a/views/filter.html +++ b/views/filter.html @@ -5,26 +5,25 @@ {% block filter %} {% if filters %}
-

What is this badge about?

-

{{ badge.description }}

+

+ Issued by: + {% if badge.program.issuer.url %} + + {% endif %} + {{ badge.program.issuer.name }} + {% if badge.program.issuer.url %} + + {% endif %} +

+ +

+ Issued to: {{ user.email }} +

+ +

What is this badge about?

+

{{ badge.description }}

{% endblock %} From f52fa2408a641a6fcfeef27e463c66e14901450e Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Sun, 2 Jun 2013 21:24:46 +0100 Subject: [PATCH 08/19] Fixing `pageNum` not being `null` problem --- helpers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helpers.js b/helpers.js index 348c43d..6d3e695 100644 --- a/helpers.js +++ b/helpers.js @@ -35,7 +35,7 @@ exports.addPaginateMethod = function addPaginateMethod (req, res, next) { query = querystring.stringify(query); href = path.href.replace(/\?.*$/, '') + (query ? '?' + query : ''); - if (pageNum === null) { + if (!pageNum) { content = '' + display + ''; } else { content = '' + (display || pageNum) + ''; @@ -86,7 +86,7 @@ exports.addPaginateMethod = function addPaginateMethod (req, res, next) { pageNum = pageNums[i]; if (pageNum === current) - pages.push(page({path:path, pageNum:pageNum, className:'active', el:el})); + pages.push(page({path:path, display:pageNum, className:'active', el:el})); else if (!parseInt(pageNum,10)) pages.push(page({path:path, display:pageNum, el:el})); else From 93f423cbaf424f10850997a35e6804150ec27860 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 2 Jun 2013 16:33:53 -0400 Subject: [PATCH 09/19] Add delete button to badge detail page Not wired up to any action yet --- views/user/badge.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/views/user/badge.html b/views/user/badge.html index e483a34..9771593 100644 --- a/views/user/badge.html +++ b/views/user/badge.html @@ -6,6 +6,9 @@
+
+ Delete +

From 40ba66409d28d3fd1741af5897e60c38489d7dc4 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Sun, 2 Jun 2013 21:34:49 +0100 Subject: [PATCH 10/19] Removing pointless logging --- openbadger.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/openbadger.js b/openbadger.js index 18e6827..6d12928 100644 --- a/openbadger.js +++ b/openbadger.js @@ -113,9 +113,7 @@ function confirmFilterValue (value, list) { function applyFilter (data, query) { return _.filter(data, function(item) { - var x = _.reduce(query, function(memo, value, field) { - console.log('Filtering:', value, field, item); - + return _.reduce(query, function(memo, value, field) { if (!memo) // We've already failed a test - no point in continuing return memo; @@ -141,8 +139,6 @@ function applyFilter (data, query) { return memo && (itemValue === value); }, true); - console.log(query, x); - return x; }) } @@ -278,8 +274,6 @@ var openbadger = new Api(ENDPOINT, { if (err) return callback(err, data); - - console.log(data); badges = _.map(data.badges, normalizeBadgeInstance) return callback(null, { From b7b5baabe653ea51ef1d6616149b88e5650f4969 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 2 Jun 2013 17:02:00 -0400 Subject: [PATCH 11/19] Moved badge thumbnail into an include for reuse --- views/filter.html | 15 +-------------- views/includes/badge-thumbnail.html | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) create mode 100644 views/includes/badge-thumbnail.html diff --git a/views/filter.html b/views/filter.html index 92c0834..218278e 100644 --- a/views/filter.html +++ b/views/filter.html @@ -45,20 +45,7 @@ {% if item.template %} {% include item.template %} {% else %} -

- -
-

{{ item.name }}

-

{{ item.description | default('description tbd') | truncate(20) }}

- {% block item_actions_wrapper %} -

- {% block item_actions %} - Details - {% endblock %} -

- {% endblock %} -
-
+ {% include "includes/badge-thumbnail.html" %} {% endif %} {% endblock %} diff --git a/views/includes/badge-thumbnail.html b/views/includes/badge-thumbnail.html new file mode 100644 index 0000000..84af7a3 --- /dev/null +++ b/views/includes/badge-thumbnail.html @@ -0,0 +1,15 @@ +{# A badge in a list or grid context #} +
+ +
+

{{ item.name }}

+

{{ item.description | default('description tbd') | truncate(20) }}

+ {% block item_actions_wrapper %} +

+ {% block item_actions %} + Details + {% endblock %} +

+ {% endblock %} +
+
From f18eaca3194d9fa9335bd8ce80140093f8bcfaef Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 2 Jun 2013 17:08:54 -0400 Subject: [PATCH 12/19] Add rough display of similar badges in detail view --- controllers/backpack.js | 34 +++++++++++++++++++++++++++++++++- views/user/badge.html | 14 ++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/controllers/backpack.js b/controllers/backpack.js index cd93dd4..1964def 100644 --- a/controllers/backpack.js +++ b/controllers/backpack.js @@ -86,10 +86,42 @@ module.exports = function (app) { ], function (req, res, next) { var data = req.remote; + // XXX: replace with API call to openbadger + var similar = [ + { + url: "/mybadges/this-badge", + image: "http://openbadger-csol.mofostaging.net/badge/image/this-badge.png", + name: "Test Badge CLM", + description: "This is a test badge!" + }, + { + url: "/mybadges/this-badge", + image: "http://openbadger-csol.mofostaging.net/badge/image/this-badge.png", + name: "Test Badge CLM", + description: "This is a test badge!" + }, + { + url: "/mybadges/this-badge", + image: "http://openbadger-csol.mofostaging.net/badge/image/this-badge.png", + name: "Test Badge CLM", + description: "This is a test badge!" + }, + { + url: "/mybadges/this-badge", + image: "http://openbadger-csol.mofostaging.net/badge/image/this-badge.png", + name: "Test Badge CLM", + description: "This is a test badge!" + } + ]; + + const NSIMILAR = 4; + console.log(data.badge); + res.render('user/badge.html', { badge: data.badge, - user: req.session.user + user: req.session.user, + similar: similar.slice(0, NSIMILAR) }); }); diff --git a/views/user/badge.html b/views/user/badge.html index 9771593..51f85f3 100644 --- a/views/user/badge.html +++ b/views/user/badge.html @@ -30,4 +30,18 @@

{{ badge.description }}

+ +
+

Similar Badges

+

Cupcake link to Badges page something about badges + should go here.

+ + + {% for item in similar %} +
+ {% include "includes/badge-thumbnail.html" %} +
+ {% endfor %} + +
{% endblock %} From 8e99417e4e176d0536c663bdd23533637142dba1 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Sun, 2 Jun 2013 23:40:27 +0100 Subject: [PATCH 13/19] Fixing upload form accessibility --- static/media/js/jquery.uploader.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/static/media/js/jquery.uploader.js b/static/media/js/jquery.uploader.js index b500232..ebf7c8c 100644 --- a/static/media/js/jquery.uploader.js +++ b/static/media/js/jquery.uploader.js @@ -72,7 +72,7 @@ $template = $(options.template), $buttons = $(options.buttonContainer), $description = $(document.createElement('div')), - $label = $(document.createElement('label')), + $btn = $(document.createElement('span')), itemSelector = '.' + $template[0].className.replace(/\s+/g, '.'), itemCount = 0, xhr = (window.XMLHttpRequest && new XMLHttpRequest()) || {}; @@ -81,16 +81,20 @@ $template.remove(); + $template.find('input[type="file"]').attr('tabIndex', -1); + $description .addClass('description') .html('Drop photos and videos here or') .prependTo($template); - $label + $btn .addClass('btn') .text('Choose photos and videos to upload') .appendTo($description) - .click(function() { $(this).parents('.item').find('input').click(); }); + .attr('tabIndex', 0) + .click(function() { $(this).parents('.item').find('input').click(); }) + .keypress(function() { $(this).click(); }); if (xhr.upload && window.FormData) { goAsync(); From d24d38aaa1195c399fa8f3f64000d8c00d2ab9f0 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 2 Jun 2013 21:42:46 -0400 Subject: [PATCH 14/19] Converting back to tabs per IRC comment --- views/filter.html | 42 ++++++++--------- views/includes/badge-thumbnail.html | 26 ++++++----- views/user/backpack.html | 70 ++++++++++++++--------------- 3 files changed, 70 insertions(+), 68 deletions(-) diff --git a/views/filter.html b/views/filter.html index 218278e..2f828a5 100644 --- a/views/filter.html +++ b/views/filter.html @@ -36,27 +36,27 @@ {% endif %} {% endblock %} {% block list_wrapper %} - {% if items.length %} -
    - {% block list %} - {% for item in items %} - {% block item %} -
  • - {% if item.template %} - {% include item.template %} - {% else %} - {% include "includes/badge-thumbnail.html" %} - {% endif %} - {% endblock %} -
  • - {% endfor %} - {% endblock %} -
- {% else %} - {% block no_data %} - No data found. - {% endblock %} - {% endif %} + {% if items.length %} +
    + {% block list %} + {% for item in items %} + {% block item %} +
  • + {% if item.template %} + {% include item.template %} + {% else %} + {% include "includes/badge-thumbnail.html" %} + {% endif %} + {% endblock %} +
  • + {% endfor %} + {% endblock %} +
+ {% else %} + {% block no_data %} + No data found. + {% endblock %} + {% endif %} {% endblock %} {% block pagination %} {% if pages > 1 %} diff --git a/views/includes/badge-thumbnail.html b/views/includes/badge-thumbnail.html index 84af7a3..304f782 100644 --- a/views/includes/badge-thumbnail.html +++ b/views/includes/badge-thumbnail.html @@ -1,15 +1,17 @@ {# A badge in a list or grid context #}
- -
-

{{ item.name }}

-

{{ item.description | default('description tbd') | truncate(20) }}

- {% block item_actions_wrapper %} -

- {% block item_actions %} - Details - {% endblock %} -

- {% endblock %} -
+ +
+

{{ item.name }}

+ {% if item.description %} +

{{ item.description | truncate(20) }}

+ {% endif %} + {% block item_actions_wrapper %} +

+ {% block item_actions %} + Details + {% endblock %} +

+ {% endblock %} +
diff --git a/views/user/backpack.html b/views/user/backpack.html index 7e85610..ad1a9ba 100644 --- a/views/user/backpack.html +++ b/views/user/backpack.html @@ -3,45 +3,45 @@ {% set navItem = 'backpack' %} {% block list %} - {{ super() }} -
  • -
    - -
    -

    Claim another badge!

    -

    +1

    -
    -
    -
  • + {{ super() }} +
  • +
    + +
    +

    Claim another badge!

    +

    +1

    +
    +
    +
  • {% endblock %} {% block item_actions %} - {{ super() }} - - + {{ super() }} + + {% endblock %} {% block modal %} - - - + + + {% endblock %} From 8c0531b70c043f25e30fc2196739b849eea06138 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 2 Jun 2013 21:47:12 -0400 Subject: [PATCH 15/19] Remove stubbed out delete buttons for now --- views/user/backpack.html | 3 ++- views/user/badge.html | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/views/user/backpack.html b/views/user/backpack.html index ad1a9ba..365dabc 100644 --- a/views/user/backpack.html +++ b/views/user/backpack.html @@ -16,9 +16,10 @@ {% endblock %} {% block item_actions %} +{# {{ super() }} - +#} {% endblock %} {% block modal %} diff --git a/views/user/badge.html b/views/user/badge.html index 51f85f3..26a65df 100644 --- a/views/user/badge.html +++ b/views/user/badge.html @@ -6,9 +6,6 @@
    -
    - Delete -

    From f5ade92d58ce5e5f33bf29dc8118078067606797 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 2 Jun 2013 21:53:19 -0400 Subject: [PATCH 16/19] Minor --- views/user/badge.html | 1 - 1 file changed, 1 deletion(-) diff --git a/views/user/badge.html b/views/user/badge.html index 26a65df..f7460ac 100644 --- a/views/user/badge.html +++ b/views/user/badge.html @@ -33,7 +33,6 @@

    Cupcake link to Badges page something about badges should go here.

    - {% for item in similar %}
    {% include "includes/badge-thumbnail.html" %} From 0024705249ac3383354e5527042fa1613fbf5d5e Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Mon, 3 Jun 2013 11:17:48 +0100 Subject: [PATCH 17/19] Fixing 'running over' issue --- helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers.js b/helpers.js index 6d3e695..821c760 100644 --- a/helpers.js +++ b/helpers.js @@ -93,7 +93,7 @@ exports.addPaginateMethod = function addPaginateMethod (req, res, next) { pages.push(page({path:path, pageNum:pageNum, el:el})); } - if (current === pages) + if (current === count) pages.push(page({path:path, display:'»', className:'disabled', el:el})); else pages.push(page({path:path, pageNum:current + 1, display:'»', el:el})); From b4f425d11f20dfd26245ccb718ad39a893d05e76 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Mon, 3 Jun 2013 11:18:27 +0100 Subject: [PATCH 18/19] Rebuilding page number generation --- helpers.js | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/helpers.js b/helpers.js index 821c760..6628b82 100644 --- a/helpers.js +++ b/helpers.js @@ -44,26 +44,47 @@ exports.addPaginateMethod = function addPaginateMethod (req, res, next) { return '<' + el + (className ? ' class="' + className + '"' : '') + '>' + content + ''; } - function generatePageNumbers (total, current, extraItems) { - extraItems = extraItems || 2; + function generatePageNumbers (total, current, maxItems) { + maxItems = maxItems || 12; - var paged = {}, - pages = []; + if (total <= maxItems) + return Array(total).join(',').split(',').map(function(e,i){return i+1;}); - for (var i = 1; i <= Math.min(total, extraItems + 1); ++i) - (paged[i] = 1) && pages.push(i); + var paged = {} + pages = [], + count = 1, + extraItems = Math.min(3, Math.floor((maxItems - 3) / 4)); - if (!paged[Math.max(1, current - extraItems - 1)]) - pages.push('...'); + paged[current] = current; - for (var i = Math.max(1, current - extraItems); i <= Math.min(total, current + extraItems); ++i) - !paged[i] && (paged[i] = 1) && pages.push(i); - - if (!paged[Math.max(1, total - extraItems - 1)]) - pages.push('...'); + for (var i = 1, max = Math.min(total, extraItems + 1); i <= max; ++i) + (paged[i] = i) && count++; for (var i = Math.max(1, total - extraItems); i <= total; ++i) - !paged[i] && (paged[i] = 1) && pages.push(i); + (paged[i] = i) && count++; + + var i = 1; + + while (count < maxItems - 1) { + if (!paged[current - i] && (current - i) >= 1) + (paged[current - i] = current - i) && count++; + if (!paged[current + i] && (current + i) <= total) + (paged[current + i] = current + i) && count++; + i++; + } + + var previous, + current; + + for (var i in paged) { + current = paged[i]; + if (previous === current - 2) + pages.push(current - 1); + else if (previous <= current - 3) + pages.push('...'); + pages.push(current); + previous = current; + } return pages; } From 2065c8908f8a8f71c16b243d58c9870dfe61e3ea Mon Sep 17 00:00:00 2001 From: Michael Ballard Date: Mon, 3 Jun 2013 13:00:58 -0400 Subject: [PATCH 19/19] open menu bug fix --- static/media/css/core.css | 38 ++++++++++++++++++------------------- static/media/less/core.less | 4 ++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/static/media/css/core.css b/static/media/css/core.css index 75315fc..f1595c6 100644 --- a/static/media/css/core.css +++ b/static/media/css/core.css @@ -107,24 +107,24 @@ ol { background: #fff; text-align: center; } -.navbar .nav-wrap ul { +.navbar .nav-wrap ul.nav { display: inline-block; margin: 0 0 0 0; } -.navbar .nav-wrap ul > li { +.navbar .nav-wrap ul.nav > li { float: none; display: inline-block; } -.navbar .nav-wrap ul > li > a { +.navbar .nav-wrap ul.nav > li > a { text-shadow: none; color: #333333; text-transform: uppercase; } -.navbar .nav-wrap ul > li > a:focus, -.navbar .nav-wrap ul > li > a:hover { +.navbar .nav-wrap ul.nav > li > a:focus, +.navbar .nav-wrap ul.nav > li > a:hover { color: #c0c0c0; } -.navbar .nav-wrap ul > li:last-child { +.navbar .nav-wrap ul.nav > li:last-child { border-right: none; } .navbar .brand { @@ -563,26 +563,26 @@ body.home .navbar .nav-wrap { z-index: 1; box-shadow: none; } -body.home .navbar .nav-wrap ul { +body.home .navbar .nav-wrap ul.nav { padding-top: 200px; left: -6px; } -body.home .navbar .nav-wrap ul > li { +body.home .navbar .nav-wrap ul.nav > li { text-align: left; display: block; line-height: 9px; } -body.home .navbar .nav-wrap ul > li > a { +body.home .navbar .nav-wrap ul.nav > li > a { text-transform: inherit; font-size: 22px; color: #f4fc00; text-transform: lowercase; } -body.home .navbar .nav-wrap ul > li.learn > a:first-letter { +body.home .navbar .nav-wrap ul.nav > li.learn > a:first-letter { text-transform: capitalize; } -body.home .navbar .nav-wrap ul > li.log-in > a, -body.home .navbar .nav-wrap ul > li.about > a { +body.home .navbar .nav-wrap ul.nav > li.log-in > a, +body.home .navbar .nav-wrap ul.nav > li.about > a { font-size: 18px; color: #fff; text-transform: lowercase; @@ -590,19 +590,19 @@ body.home .navbar .nav-wrap ul > li.about > a { text-align: center; line-height: 24px; } -body.home .navbar .nav-wrap ul > li.claim > a { +body.home .navbar .nav-wrap ul.nav > li.claim > a { text-align: center; text-transform: capitalize; margin-top: 5px; } -body.home .navbar .nav-wrap ul > li.claim > a:before, -body.home .navbar .nav-wrap ul > li.claim > a:after { +body.home .navbar .nav-wrap ul.nav > li.claim > a:before, +body.home .navbar .nav-wrap ul.nav > li.claim > a:after { content: '-'; } -body.home .navbar .nav-wrap ul > li.video { +body.home .navbar .nav-wrap ul.nav > li.video { margin: 30px 0; } -body.home .navbar .nav-wrap ul > li.video a { +body.home .navbar .nav-wrap ul.nav > li.video a { color: #fff; border-radius: 7px; margin: auto; @@ -619,10 +619,10 @@ body.home .navbar .nav-wrap ul > li.video a { background: linear-gradient(to bottom, #e82202 0%, #e5381d 44%, #e56854 100%); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e82202', endColorstr='#e56854', GradientType=0); } -body.home .navbar .nav-wrap ul > li span { +body.home .navbar .nav-wrap ul.nav > li span { color: #fff; } -body.home .navbar .nav-wrap ul > li:nth-child(even) { +body.home .navbar .nav-wrap ul.nav > li:nth-child(even) { border-left: none; border-right: none; } diff --git a/static/media/less/core.less b/static/media/less/core.less index 5180841..a2554e1 100644 --- a/static/media/less/core.less +++ b/static/media/less/core.less @@ -114,7 +114,7 @@ ol { box-shadow:0 0 8px 3px rgba(0, 0, 0, 0.25); background:#fff; text-align:center; - ul { + ul.nav { display:inline-block; margin:0 0 0 0; & > li { @@ -663,7 +663,7 @@ body.home { position:relative; z-index:1; box-shadow:none; - ul { + ul.nav { padding-top:200px; left:-6px; & > li {